From 8dfc8dd05c2c77ee8b02a1a27f3a1578f7137447 Mon Sep 17 00:00:00 2001 From: Martin Felis Date: Fri, 21 Apr 2023 11:55:36 +0200 Subject: [PATCH] Started thedmd/imgui-node-editor integration --- .../.github/workflows/build.yml | 61 + 3rdparty/imgui-node-editor/.gitignore | 11 + 3rdparty/imgui-node-editor/LICENSE | 21 + 3rdparty/imgui-node-editor/crude_json.cpp | 903 ++ 3rdparty/imgui-node-editor/crude_json.h | 261 + 3rdparty/imgui-node-editor/docs/CHANGELOG.txt | 223 + 3rdparty/imgui-node-editor/docs/README.md | 169 + 3rdparty/imgui-node-editor/docs/TODO.md | 14 + .../imgui-node-editor/examples/CMakeLists.txt | 134 + .../examples/application/CMakeLists.txt | 112 + .../application/include/application.h | 57 + .../application/source/application.cpp | 244 + .../examples/application/source/config.h.in | 4 + .../application/source/entry_point.cpp | 21 + .../application/source/imgui_extra_keys.h | 48 + .../application/source/imgui_impl_dx11.cpp | 681 ++ .../application/source/imgui_impl_dx11.h | 29 + .../application/source/imgui_impl_glfw.cpp | 382 + .../application/source/imgui_impl_glfw.h | 36 + .../application/source/imgui_impl_opengl3.cpp | 690 ++ .../application/source/imgui_impl_opengl3.h | 87 + .../application/source/imgui_impl_win32.cpp | 458 + .../application/source/imgui_impl_win32.h | 37 + .../examples/application/source/platform.h | 60 + .../application/source/platform_glfw.cpp | 287 + .../application/source/platform_win32.cpp | 313 + .../examples/application/source/renderer.h | 32 + .../application/source/renderer_dx11.cpp | 195 + .../application/source/renderer_ogl3.cpp | 205 + .../examples/application/source/setup.h | 98 + .../examples/application/support/Icon.icns | Bin 0 -> 172448 bytes .../examples/application/support/Icon.ico | Bin 0 -> 39257 bytes .../examples/application/support/Icon.png | Bin 0 -> 52666 bytes .../application/support/Info.plist.in | 41 + .../application/support/Resource.rc.in | 3 + .../basic-interaction-example/CMakeLists.txt | 3 + .../basic-interaction-example.cpp | 216 + .../blueprints-example/CMakeLists.txt | 9 + .../blueprints-example/blueprints-example.cpp | 1821 ++++ .../data/BlueprintBackground.png | Bin 0 -> 5513 bytes .../data/ic_restore_white_24dp.png | Bin 0 -> 332 bytes .../data/ic_save_white_24dp.png | Bin 0 -> 168 bytes .../blueprints-example/utilities/builders.cpp | 314 + .../blueprints-example/utilities/builders.h | 81 + .../blueprints-example/utilities/drawing.cpp | 252 + .../blueprints-example/utilities/drawing.h | 12 + .../blueprints-example/utilities/widgets.cpp | 16 + .../blueprints-example/utilities/widgets.h | 13 + .../examples/canvas-example/CMakeLists.txt | 5 + .../canvas-example/canvas-example.cpp | 251 + .../examples/data/Cuprum-Bold.ttf | Bin 0 -> 96364 bytes .../examples/data/Cuprum-OFL.txt | 93 + .../examples/data/Oswald-OFL.txt | 93 + .../examples/data/Oswald-Regular.ttf | Bin 0 -> 91400 bytes .../examples/data/Play-OFL.txt | 93 + .../examples/data/Play-Regular.ttf | Bin 0 -> 183852 bytes .../examples/simple-example/CMakeLists.txt | 3 + .../simple-example/simple-example.cpp | 63 + .../examples/widgets-example/CMakeLists.txt | 3 + .../widgets-example/widgets-example.cpp | 432 + .../external/ScopeGuard/CMakeLists.txt | 12 + .../external/ScopeGuard/ScopeGuard.h | 42 + .../external/gl3w/CMakeLists.txt | 19 + .../external/gl3w/Include/GL/gl3w.h | 1234 +++ .../external/gl3w/Include/GL/glcorearb.h | 4533 ++++++++++ .../external/gl3w/Source/gl3w.c | 1344 +++ .../external/stb_image/CMakeLists.txt | 12 + .../external/stb_image/stb_image.h | 7462 +++++++++++++++++ .../imgui-node-editor/imgui_bezier_math.h | 144 + .../imgui-node-editor/imgui_bezier_math.inl | 689 ++ 3rdparty/imgui-node-editor/imgui_canvas.cpp | 550 ++ 3rdparty/imgui-node-editor/imgui_canvas.h | 268 + 3rdparty/imgui-node-editor/imgui_extra_math.h | 73 + .../imgui-node-editor/imgui_extra_math.inl | 189 + .../imgui-node-editor/imgui_node_editor.cpp | 5780 +++++++++++++ .../imgui-node-editor/imgui_node_editor.h | 511 ++ .../imgui_node_editor_api.cpp | 774 ++ .../imgui_node_editor_internal.h | 1568 ++++ .../imgui_node_editor_internal.inl | 65 + .../misc/cmake-modules/FindScopeGuard.cmake | 17 + .../misc/cmake-modules/Findgl3w.cmake | 17 + .../misc/cmake-modules/Findimgui.cmake | 17 + .../cmake-modules/Findimgui_node_editor.cmake | 49 + .../misc/cmake-modules/Findstb_image.cmake | 17 + .../imgui-node-editor/misc/crude_json.natvis | 18 + .../misc/imgui_node_editor.natvis | 64 + CMakeLists.txt | 12 + src/main.cc | 133 +- 88 files changed, 35298 insertions(+), 5 deletions(-) create mode 100644 3rdparty/imgui-node-editor/.github/workflows/build.yml create mode 100644 3rdparty/imgui-node-editor/.gitignore create mode 100644 3rdparty/imgui-node-editor/LICENSE create mode 100644 3rdparty/imgui-node-editor/crude_json.cpp create mode 100644 3rdparty/imgui-node-editor/crude_json.h create mode 100644 3rdparty/imgui-node-editor/docs/CHANGELOG.txt create mode 100644 3rdparty/imgui-node-editor/docs/README.md create mode 100644 3rdparty/imgui-node-editor/docs/TODO.md create mode 100644 3rdparty/imgui-node-editor/examples/CMakeLists.txt create mode 100644 3rdparty/imgui-node-editor/examples/application/CMakeLists.txt create mode 100644 3rdparty/imgui-node-editor/examples/application/include/application.h create mode 100644 3rdparty/imgui-node-editor/examples/application/source/application.cpp create mode 100644 3rdparty/imgui-node-editor/examples/application/source/config.h.in create mode 100644 3rdparty/imgui-node-editor/examples/application/source/entry_point.cpp create mode 100644 3rdparty/imgui-node-editor/examples/application/source/imgui_extra_keys.h create mode 100644 3rdparty/imgui-node-editor/examples/application/source/imgui_impl_dx11.cpp create mode 100644 3rdparty/imgui-node-editor/examples/application/source/imgui_impl_dx11.h create mode 100644 3rdparty/imgui-node-editor/examples/application/source/imgui_impl_glfw.cpp create mode 100644 3rdparty/imgui-node-editor/examples/application/source/imgui_impl_glfw.h create mode 100644 3rdparty/imgui-node-editor/examples/application/source/imgui_impl_opengl3.cpp create mode 100644 3rdparty/imgui-node-editor/examples/application/source/imgui_impl_opengl3.h create mode 100644 3rdparty/imgui-node-editor/examples/application/source/imgui_impl_win32.cpp create mode 100644 3rdparty/imgui-node-editor/examples/application/source/imgui_impl_win32.h create mode 100644 3rdparty/imgui-node-editor/examples/application/source/platform.h create mode 100644 3rdparty/imgui-node-editor/examples/application/source/platform_glfw.cpp create mode 100644 3rdparty/imgui-node-editor/examples/application/source/platform_win32.cpp create mode 100644 3rdparty/imgui-node-editor/examples/application/source/renderer.h create mode 100644 3rdparty/imgui-node-editor/examples/application/source/renderer_dx11.cpp create mode 100644 3rdparty/imgui-node-editor/examples/application/source/renderer_ogl3.cpp create mode 100644 3rdparty/imgui-node-editor/examples/application/source/setup.h create mode 100644 3rdparty/imgui-node-editor/examples/application/support/Icon.icns create mode 100644 3rdparty/imgui-node-editor/examples/application/support/Icon.ico create mode 100644 3rdparty/imgui-node-editor/examples/application/support/Icon.png create mode 100644 3rdparty/imgui-node-editor/examples/application/support/Info.plist.in create mode 100644 3rdparty/imgui-node-editor/examples/application/support/Resource.rc.in create mode 100644 3rdparty/imgui-node-editor/examples/basic-interaction-example/CMakeLists.txt create mode 100644 3rdparty/imgui-node-editor/examples/basic-interaction-example/basic-interaction-example.cpp create mode 100644 3rdparty/imgui-node-editor/examples/blueprints-example/CMakeLists.txt create mode 100644 3rdparty/imgui-node-editor/examples/blueprints-example/blueprints-example.cpp create mode 100644 3rdparty/imgui-node-editor/examples/blueprints-example/data/BlueprintBackground.png create mode 100644 3rdparty/imgui-node-editor/examples/blueprints-example/data/ic_restore_white_24dp.png create mode 100644 3rdparty/imgui-node-editor/examples/blueprints-example/data/ic_save_white_24dp.png create mode 100644 3rdparty/imgui-node-editor/examples/blueprints-example/utilities/builders.cpp create mode 100644 3rdparty/imgui-node-editor/examples/blueprints-example/utilities/builders.h create mode 100644 3rdparty/imgui-node-editor/examples/blueprints-example/utilities/drawing.cpp create mode 100644 3rdparty/imgui-node-editor/examples/blueprints-example/utilities/drawing.h create mode 100644 3rdparty/imgui-node-editor/examples/blueprints-example/utilities/widgets.cpp create mode 100644 3rdparty/imgui-node-editor/examples/blueprints-example/utilities/widgets.h create mode 100644 3rdparty/imgui-node-editor/examples/canvas-example/CMakeLists.txt create mode 100644 3rdparty/imgui-node-editor/examples/canvas-example/canvas-example.cpp create mode 100644 3rdparty/imgui-node-editor/examples/data/Cuprum-Bold.ttf create mode 100644 3rdparty/imgui-node-editor/examples/data/Cuprum-OFL.txt create mode 100644 3rdparty/imgui-node-editor/examples/data/Oswald-OFL.txt create mode 100644 3rdparty/imgui-node-editor/examples/data/Oswald-Regular.ttf create mode 100644 3rdparty/imgui-node-editor/examples/data/Play-OFL.txt create mode 100644 3rdparty/imgui-node-editor/examples/data/Play-Regular.ttf create mode 100644 3rdparty/imgui-node-editor/examples/simple-example/CMakeLists.txt create mode 100644 3rdparty/imgui-node-editor/examples/simple-example/simple-example.cpp create mode 100644 3rdparty/imgui-node-editor/examples/widgets-example/CMakeLists.txt create mode 100644 3rdparty/imgui-node-editor/examples/widgets-example/widgets-example.cpp create mode 100644 3rdparty/imgui-node-editor/external/ScopeGuard/CMakeLists.txt create mode 100644 3rdparty/imgui-node-editor/external/ScopeGuard/ScopeGuard.h create mode 100644 3rdparty/imgui-node-editor/external/gl3w/CMakeLists.txt create mode 100755 3rdparty/imgui-node-editor/external/gl3w/Include/GL/gl3w.h create mode 100755 3rdparty/imgui-node-editor/external/gl3w/Include/GL/glcorearb.h create mode 100755 3rdparty/imgui-node-editor/external/gl3w/Source/gl3w.c create mode 100644 3rdparty/imgui-node-editor/external/stb_image/CMakeLists.txt create mode 100644 3rdparty/imgui-node-editor/external/stb_image/stb_image.h create mode 100644 3rdparty/imgui-node-editor/imgui_bezier_math.h create mode 100644 3rdparty/imgui-node-editor/imgui_bezier_math.inl create mode 100644 3rdparty/imgui-node-editor/imgui_canvas.cpp create mode 100644 3rdparty/imgui-node-editor/imgui_canvas.h create mode 100644 3rdparty/imgui-node-editor/imgui_extra_math.h create mode 100644 3rdparty/imgui-node-editor/imgui_extra_math.inl create mode 100644 3rdparty/imgui-node-editor/imgui_node_editor.cpp create mode 100644 3rdparty/imgui-node-editor/imgui_node_editor.h create mode 100644 3rdparty/imgui-node-editor/imgui_node_editor_api.cpp create mode 100644 3rdparty/imgui-node-editor/imgui_node_editor_internal.h create mode 100644 3rdparty/imgui-node-editor/imgui_node_editor_internal.inl create mode 100644 3rdparty/imgui-node-editor/misc/cmake-modules/FindScopeGuard.cmake create mode 100644 3rdparty/imgui-node-editor/misc/cmake-modules/Findgl3w.cmake create mode 100644 3rdparty/imgui-node-editor/misc/cmake-modules/Findimgui.cmake create mode 100644 3rdparty/imgui-node-editor/misc/cmake-modules/Findimgui_node_editor.cmake create mode 100644 3rdparty/imgui-node-editor/misc/cmake-modules/Findstb_image.cmake create mode 100644 3rdparty/imgui-node-editor/misc/crude_json.natvis create mode 100644 3rdparty/imgui-node-editor/misc/imgui_node_editor.natvis diff --git a/3rdparty/imgui-node-editor/.github/workflows/build.yml b/3rdparty/imgui-node-editor/.github/workflows/build.yml new file mode 100644 index 0000000..6c2ebc2 --- /dev/null +++ b/3rdparty/imgui-node-editor/.github/workflows/build.yml @@ -0,0 +1,61 @@ +name: build + +on: + push: + pull_request: + workflow_run: + # Use a workflow as a trigger of scheduled builds. Forked repositories can disable scheduled builds by disabling + # "scheduled" workflow, while maintaining ability to perform local CI builds. + workflows: + - scheduled + branches: + - master + - develop + types: + - requested + +env: + # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) + BUILD_TYPE: Release + +jobs: + Windows: + runs-on: windows-2019 + env: + VS_PATH: C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\ + MSBUILD_PATH: C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\ + + steps: + - uses: actions/checkout@v2 + - name: Configure CMake + run: cmake -S examples -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} + - name: Build + run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} + + macOS: + runs-on: macos-latest + + steps: + - name: Install Dependencies + run: | + brew install glfw3 + - uses: actions/checkout@v2 + - name: Configure CMake + run: cmake -S examples -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} + - name: Build + run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} + + Linux: + runs-on: ubuntu-latest + + steps: + - name: Install Dependencies + run: | + sudo apt-get update + sudo apt-get install -y libglfw3-dev + - uses: actions/checkout@v2 + - name: Configure CMake + run: cmake -S examples -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} + - name: Build + run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} + diff --git a/3rdparty/imgui-node-editor/.gitignore b/3rdparty/imgui-node-editor/.gitignore new file mode 100644 index 0000000..996f468 --- /dev/null +++ b/3rdparty/imgui-node-editor/.gitignore @@ -0,0 +1,11 @@ +.vs +.vscode +.build* +.DS_Store +bin +[Bb]uild +*.VC.db +*.VC.opendb +*.user +*.ini +*.json diff --git a/3rdparty/imgui-node-editor/LICENSE b/3rdparty/imgui-node-editor/LICENSE new file mode 100644 index 0000000..ae0db1a --- /dev/null +++ b/3rdparty/imgui-node-editor/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Michał Cichoń + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/3rdparty/imgui-node-editor/crude_json.cpp b/3rdparty/imgui-node-editor/crude_json.cpp new file mode 100644 index 0000000..38617e5 --- /dev/null +++ b/3rdparty/imgui-node-editor/crude_json.cpp @@ -0,0 +1,903 @@ +//Disable a bunch of warnings for now +#ifndef _MSC_VER +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wshadow" +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +// Crude implementation of JSON value object and parser. +// +// VERSION 0.1 +// +// LICENSE +// This software is dual-licensed to the public domain and under the following +// license: you are granted a perpetual, irrevocable license to copy, modify, +// publish, and distribute this file as you see fit. +// +// CREDITS +// Written by Michal Cichon +# include "crude_json.h" +# include +# include +# include +# include +# include +# include +# if CRUDE_JSON_IO +# include +# include +# endif + +namespace crude_json { + +value::value(value&& other) + : m_Type(other.m_Type) +{ + switch (m_Type) + { + case type_t::object: construct(m_Storage, std::move( *object_ptr(other.m_Storage))); break; + case type_t::array: construct(m_Storage, std::move( *array_ptr(other.m_Storage))); break; + case type_t::string: construct(m_Storage, std::move( *string_ptr(other.m_Storage))); break; + case type_t::boolean: construct(m_Storage, std::move(*boolean_ptr(other.m_Storage))); break; + case type_t::number: construct(m_Storage, std::move( *number_ptr(other.m_Storage))); break; + default: break; + } + destruct(other.m_Storage, other.m_Type); + other.m_Type = type_t::null; +} + +value::value(const value& other) + : m_Type(other.m_Type) +{ + switch (m_Type) + { + case type_t::object: construct(m_Storage, *object_ptr(other.m_Storage)); break; + case type_t::array: construct(m_Storage, *array_ptr(other.m_Storage)); break; + case type_t::string: construct(m_Storage, *string_ptr(other.m_Storage)); break; + case type_t::boolean: construct(m_Storage, *boolean_ptr(other.m_Storage)); break; + case type_t::number: construct(m_Storage, *number_ptr(other.m_Storage)); break; + default: break; + } +} + +value& value::operator[](size_t index) +{ + if (is_null()) + m_Type = construct(m_Storage, type_t::array); + + if (is_array()) + { + auto& v = *array_ptr(m_Storage); + if (index >= v.size()) + v.insert(v.end(), index - v.size() + 1, value()); + + return v[index]; + } + + CRUDE_ASSERT(false && "operator[] on unsupported type"); + std::terminate(); +} + +const value& value::operator[](size_t index) const +{ + if (is_array()) + return (*array_ptr(m_Storage))[index]; + + CRUDE_ASSERT(false && "operator[] on unsupported type"); + std::terminate(); +} + +value& value::operator[](const string& key) +{ + if (is_null()) + m_Type = construct(m_Storage, type_t::object); + + if (is_object()) + return (*object_ptr(m_Storage))[key]; + + CRUDE_ASSERT(false && "operator[] on unsupported type"); + std::terminate(); +} + +const value& value::operator[](const string& key) const +{ + if (is_object()) + { + auto& o = *object_ptr(m_Storage); + auto it = o.find(key); + CRUDE_ASSERT(it != o.end()); + return it->second; + } + + CRUDE_ASSERT(false && "operator[] on unsupported type"); + std::terminate(); +} + +bool value::contains(const string& key) const +{ + if (is_object()) + { + auto& o = *object_ptr(m_Storage); + auto it = o.find(key); + return it != o.end(); + } + + return false; +} + +void value::push_back(const value& value) +{ + if (is_null()) + m_Type = construct(m_Storage, type_t::array); + + if (is_array()) + { + auto& v = *array_ptr(m_Storage); + v.push_back(value); + } + else + { + CRUDE_ASSERT(false && "operator[] on unsupported type"); + std::terminate(); + } +} + +void value::push_back(value&& value) +{ + if (is_null()) + m_Type = construct(m_Storage, type_t::array); + + if (is_array()) + { + auto& v = *array_ptr(m_Storage); + v.push_back(std::move(value)); + } + else + { + CRUDE_ASSERT(false && "operator[] on unsupported type"); + std::terminate(); + } +} + +size_t value::erase(const string& key) +{ + if (!is_object()) + return 0; + + auto& o = *object_ptr(m_Storage); + auto it = o.find(key); + + if (it == o.end()) + return 0; + + o.erase(it); + + return 1; +} + +void value::swap(value& other) +{ + using std::swap; + + if (m_Type == other.m_Type) + { + switch (m_Type) + { + case type_t::object: swap(*object_ptr(m_Storage), *object_ptr(other.m_Storage)); break; + case type_t::array: swap(*array_ptr(m_Storage), *array_ptr(other.m_Storage)); break; + case type_t::string: swap(*string_ptr(m_Storage), *string_ptr(other.m_Storage)); break; + case type_t::boolean: swap(*boolean_ptr(m_Storage), *boolean_ptr(other.m_Storage)); break; + case type_t::number: swap(*number_ptr(m_Storage), *number_ptr(other.m_Storage)); break; + default: break; + } + } + else + { + value tmp(std::move(other)); + other.~value(); + new (&other) value(std::move(*this)); + this->~value(); + new (this) value(std::move(tmp)); + } +} + +string value::dump(const int indent, const char indent_char) const +{ + dump_context_t context(indent, indent_char); + + context.out.precision(std::numeric_limits::max_digits10 + 1); + context.out << std::defaultfloat; + + dump(context, 0); + return context.out.str(); +} + +void value::dump_context_t::write_indent(int level) +{ + if (indent <= 0 || level == 0) + return; + + out.fill(indent_char); + out.width(indent * level); + out << indent_char; + out.width(0); +} + +void value::dump_context_t::write_separator() +{ + if (indent < 0) + return; + + out.put(' '); +} + +void value::dump_context_t::write_newline() +{ + if (indent < 0) + return; + + out.put('\n'); +} + +void value::dump(dump_context_t& context, int level) const +{ + context.write_indent(level); + + switch (m_Type) + { + case type_t::null: + context.out << "null"; + break; + + case type_t::object: + context.out << '{'; + { + context.write_newline(); + bool first = true; + for (auto& entry : *object_ptr(m_Storage)) + { + if (!first) { context.out << ','; context.write_newline(); } else first = false; + context.write_indent(level + 1); + context.out << '\"' << entry.first << "\":"; + if (!entry.second.is_structured()) + { + context.write_separator(); + entry.second.dump(context, 0); + } + else + { + context.write_newline(); + entry.second.dump(context, level + 1); + } + } + if (!first) + context.write_newline(); + } + context.write_indent(level); + context.out << '}'; + break; + + case type_t::array: + context.out << '['; + { + context.write_newline(); + bool first = true; + for (auto& entry : *array_ptr(m_Storage)) + { + if (!first) { context.out << ','; context.write_newline(); } else first = false; + if (!entry.is_structured()) + { + context.write_indent(level + 1); + entry.dump(context, 0); + } + else + { + entry.dump(context, level + 1); + } + } + if (!first) + context.write_newline(); + } + context.write_indent(level); + context.out << ']'; + break; + + case type_t::string: + context.out << '\"'; + + if (string_ptr(m_Storage)->find_first_of("\"\\/\b\f\n\r") != string::npos || string_ptr(m_Storage)->find('\0') != string::npos) + { + for (auto c : *string_ptr(m_Storage)) + { + if (c == '\"') context.out << "\\\""; + else if (c == '\\') context.out << "\\\\"; + else if (c == '/') context.out << "\\/"; + else if (c == '\b') context.out << "\\b"; + else if (c == '\f') context.out << "\\f"; + else if (c == '\n') context.out << "\\n"; + else if (c == '\r') context.out << "\\r"; + else if (c == '\t') context.out << "\\t"; + else if (c == 0) context.out << "\\u0000"; + else context.out << c; + } + } + else + context.out << *string_ptr(m_Storage); + context.out << '\"'; + break; + + + case type_t::boolean: + if (*boolean_ptr(m_Storage)) + context.out << "true"; + else + context.out << "false"; + break; + + case type_t::number: + context.out << *number_ptr(m_Storage); + break; + + default: + break; + } +} + +struct value::parser +{ + parser(const char* begin, const char* end) + : m_Cursor(begin) + , m_End(end) + { + } + + value parse() + { + value v; + + // Switch to C locale to make strtod and strtol work as expected + auto previous_locale = std::setlocale(LC_NUMERIC, "C"); + + // Accept single value only when end of the stream is reached. + if (!accept_element(v) || !eof()) + v = value(type_t::discarded); + + if (previous_locale && strcmp(previous_locale, "C") != 0) + std::setlocale(LC_NUMERIC, previous_locale); + + return v; + } + +private: + struct cursor_state + { + cursor_state(parser* p) + : m_Owner(p) + , m_LastCursor(p->m_Cursor) + { + } + + void reset() + { + m_Owner->m_Cursor = m_LastCursor; + } + + bool operator()(bool accept) + { + if (!accept) + reset(); + else + m_LastCursor = m_Owner->m_Cursor; + return accept; + } + + private: + parser* m_Owner; + const char* m_LastCursor; + }; + + cursor_state state() + { + return cursor_state(this); + } + + bool accept_value(value& result) + { + return accept_object(result) + || accept_array(result) + || accept_string(result) + || accept_number(result) + || accept_boolean(result) + || accept_null(result); + } + + bool accept_object(value& result) + { + auto s = state(); + + object o; + if (s(accept('{') && accept_ws() && accept('}'))) + { + result = o; + return true; + } + else if (s(accept('{') && accept_members(o) && accept('}'))) + { + result = std::move(o); + return true; + } + + return false; + } + + bool accept_members(object& o) + { + if (!accept_member(o)) + return false; + + while (true) + { + auto s = state(); + if (!s(accept(',') && accept_member(o))) + break; + } + + return true; + } + + bool accept_member(object& o) + { + auto s = state(); + + value key; + value v; + if (s(accept_ws() && accept_string(key) && accept_ws() && accept(':') && accept_element(v))) + { + o.emplace(std::move(key.get()), std::move(v)); + return true; + } + + return false; + } + + bool accept_array(value& result) + { + auto s = state(); + + if (s(accept('[') && accept_ws() && accept(']'))) + { + result = array(); + return true; + } + + array a; + if (s(accept('[') && accept_elements(a) && accept(']'))) + { + result = std::move(a); + return true; + } + + return false; + } + + bool accept_elements(array& a) + { + value v; + if (!accept_element(v)) + return false; + + a.emplace_back(std::move(v)); + while (true) + { + auto s = state(); + v = nullptr; + if (!s(accept(',') && accept_element(v))) + break; + a.emplace_back(std::move(v)); + } + + return true; + } + + bool accept_element(value& result) + { + auto s = state(); + return s(accept_ws() && accept_value(result) && accept_ws()); + } + + bool accept_string(value& result) + { + auto s = state(); + + string v; + if (s(accept('\"') && accept_characters(v) && accept('\"'))) + { + result = std::move(v); + return true; + } + else + return false; + } + + bool accept_characters(string& result) + { + int c; + while (accept_character(c)) + { + CRUDE_ASSERT(c < 128); // #todo: convert characters > 127 to UTF-8 + result.push_back(static_cast(c)); + } + + return true; + } + + bool accept_character(int& c) + { + auto s = state(); + + if (accept('\\')) + { + return accept_escape(c); + } + else if (expect('\"')) + return false; + + // #todo: Handle UTF-8 sequences. + return s((c = peek()) >= 0) && advance(); + } + + bool accept_escape(int& c) + { + if (accept('\"')) { c = '\"'; return true; } + if (accept('\\')) { c = '\\'; return true; } + if (accept('/')) { c = '/'; return true; } + if (accept('b')) { c = '\b'; return true; } + if (accept('f')) { c = '\f'; return true; } + if (accept('n')) { c = '\n'; return true; } + if (accept('r')) { c = '\r'; return true; } + if (accept('t')) { c = '\t'; return true; } + + auto s = state(); + + string hex; + hex.reserve(4); + if (s(accept('u') && accept_hex(hex) && accept_hex(hex) && accept_hex(hex) && accept_hex(hex))) + { + char* end = nullptr; + auto v = std::strtol(hex.c_str(), &end, 16); + if (end != hex.c_str() + hex.size()) + return false; + + c = v; + return true; + } + + return false; + } + + bool accept_hex(string& result) + { + if (accept_digit(result)) + return true; + + auto c = peek(); + if ((c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')) + { + advance(); + result.push_back(static_cast(c)); + return true; + } + + return false; + } + + bool accept_number(value& result) + { + auto s = state(); + + string n; + if (s(accept_int(n) && accept_frac(n) && accept_exp(n))) + { + char* end = nullptr; + auto v = std::strtod(n.c_str(), &end); + if (end != n.c_str() + n.size()) + return false; + + if (v != 0 && !std::isnormal(v)) + return false; + + result = v; + return true; + } + + return false; + } + + bool accept_int(string& result) + { + auto s = state(); + + string part; + if (s(accept_onenine(part) && accept_digits(part))) + { + result += std::move(part); + return true; + } + + part.resize(0); + if (accept_digit(part)) + { + result += std::move(part); + return true; + } + + part.resize(0); + if (s(accept('-') && accept_onenine(part) && accept_digits(part))) + { + result += '-'; + result += std::move(part); + return true; + } + + part.resize(0); + if (s(accept('-') && accept_digit(part))) + { + result += '-'; + result += std::move(part); + return true; + } + + return false; + } + + bool accept_digits(string& result) + { + string part; + if (!accept_digit(part)) + return false; + + while (accept_digit(part)) + ; + + result += std::move(part); + + return true; + } + + bool accept_digit(string& result) + { + if (accept('0')) + { + result.push_back('0'); + return true; + } + else if (accept_onenine(result)) + return true; + + return false; + } + + bool accept_onenine(string& result) + { + auto c = peek(); + if (c >= '1' && c <= '9') + { + result.push_back(static_cast(c)); + return advance(); + } + + return false; + } + + bool accept_frac(string& result) + { + auto s = state(); + + string part; + if (s(accept('.') && accept_digits(part))) + { + result += '.'; + result += std::move(part); + } + + return true; + } + + bool accept_exp(string& result) + { + auto s = state(); + + string part; + if (s(accept('e') && accept_sign(part) && accept_digits(part))) + { + result += 'e'; + result += std::move(part); + return true; + } + part.resize(0); + if (s(accept('E') && accept_sign(part) && accept_digits(part))) + { + result += 'E'; + result += std::move(part); + } + + return true; + } + + bool accept_sign(string& result) + { + if (accept('+')) + result.push_back('+'); + else if (accept('-')) + result.push_back('-'); + + return true; + } + + bool accept_ws() + { + while (expect('\x09') || expect('\x0A') || expect('\x0D') || expect('\x20')) + advance(); + return true; + } + + bool accept_boolean(value& result) + { + if (accept("true")) + { + result = true; + return true; + } + else if (accept("false")) + { + result = false; + return true; + } + + return false; + } + + bool accept_null(value& result) + { + if (accept("null")) + { + result = nullptr; + return true; + } + + return false; + } + + bool accept(char c) + { + if (expect(c)) + return advance(); + else + return false; + } + + bool accept(const char* str) + { + auto last = m_Cursor; + + while (*str) + { + if (eof() || *str != *m_Cursor) + { + m_Cursor = last; + return false; + } + + advance(); + ++str; + } + + return true; + } + + int peek() const + { + if (!eof()) + return *m_Cursor; + else + return -1; + } + + bool expect(char c) + { + return peek() == c; + } + + bool advance(int count = 1) + { + if (m_Cursor + count > m_End) + { + m_Cursor = m_End; + return false; + } + + m_Cursor += count; + + return true; + } + + bool eof() const + { + return m_Cursor == m_End; + } + + const char* m_Cursor; + const char* m_End; +}; + +value value::parse(const string& data) +{ + auto p = parser(data.c_str(), data.c_str() + data.size()); + + auto v = p.parse(); + + return v; +} + +# if CRUDE_JSON_IO +std::pair value::load(const string& path) +{ + // Modern C++, so beautiful... + std::unique_ptr file{nullptr, [](FILE* file) { if (file) fclose(file); }}; +# if defined(_MSC_VER) || (defined(__STDC_LIB_EXT1__) && __STDC_WANT_LIB_EXT1__) + FILE* handle = nullptr; + if (fopen_s(&handle, path.c_str(), "rb") != 0) + return {value{}, false}; + file.reset(handle); +# else + file.reset(fopen(path.c_str(), "rb")); +# endif + + if (!file) + return {value{}, false}; + + fseek(file.get(), 0, SEEK_END); + auto size = static_cast(ftell(file.get())); + fseek(file.get(), 0, SEEK_SET); + + string data; + data.resize(size); + if (fread(const_cast(data.data()), size, 1, file.get()) != 1) + return {value{}, false}; + + return {parse(data), true}; +} + +bool value::save(const string& path, const int indent, const char indent_char) const +{ + // Modern C++, so beautiful... + std::unique_ptr file{nullptr, [](FILE* file) { if (file) fclose(file); }}; +# if defined(_MSC_VER) || (defined(__STDC_LIB_EXT1__) && __STDC_WANT_LIB_EXT1__) + FILE* handle = nullptr; + if (fopen_s(&handle, path.c_str(), "wb") != 0) + return false; + file.reset(handle); +# else + file.reset(fopen(path.c_str(), "wb")); +# endif + + if (!file) + return false; + + auto data = dump(indent, indent_char); + + if (fwrite(data.data(), data.size(), 1, file.get()) != 1) + return false; + + return true; +} + +# endif + +} // namespace crude_json + +//Disable a bunch of warnings for now +#ifndef _MSC_VER +#pragma GCC diagnostic pop +#endif diff --git a/3rdparty/imgui-node-editor/crude_json.h b/3rdparty/imgui-node-editor/crude_json.h new file mode 100644 index 0000000..48e7dff --- /dev/null +++ b/3rdparty/imgui-node-editor/crude_json.h @@ -0,0 +1,261 @@ +//Disable a bunch of warnings for now +#ifndef _MSC_VER +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wshadow" +#endif + +// Crude implementation of JSON value object and parser. +// +// VERSION 0.1 +// +// LICENSE +// This software is dual-licensed to the public domain and under the following +// license: you are granted a perpetual, irrevocable license to copy, modify, +// publish, and distribute this file as you see fit. +// +// CREDITS +// Written by Michal Cichon +# ifndef __CRUDE_JSON_H__ +# define __CRUDE_JSON_H__ +# pragma once + +# include +# include +# include +# include +# include +# include +# include + +# ifndef CRUDE_ASSERT +# include +# define CRUDE_ASSERT(expr) assert(expr) +# endif + +# ifndef CRUDE_JSON_IO +# define CRUDE_JSON_IO 1 +# endif + +namespace crude_json { + +struct value; + +using string = std::string; +using object = std::map; +using array = std::vector; +using number = double; +using boolean = bool; +using null = std::nullptr_t; + +enum class type_t +{ + null, + object, + array, + string, + boolean, + number, + discarded +}; + +struct value +{ + value(type_t type = type_t::null): m_Type(construct(m_Storage, type)) {} + value(value&& other); + value(const value& other); + + value( null) : m_Type(construct(m_Storage, null())) {} + value( object&& v): m_Type(construct(m_Storage, std::move(v))) {} + value(const object& v): m_Type(construct(m_Storage, v)) {} + value( array&& v): m_Type(construct(m_Storage, std::move(v))) {} + value(const array& v): m_Type(construct(m_Storage, v)) {} + value( string&& v): m_Type(construct(m_Storage, std::move(v))) {} + value(const string& v): m_Type(construct(m_Storage, v)) {} + value(const char* v): m_Type(construct(m_Storage, v)) {} + value( boolean v): m_Type(construct(m_Storage, v)) {} + value( number v): m_Type(construct(m_Storage, v)) {} + ~value() { destruct(m_Storage, m_Type); } + + value& operator=(value&& other) { if (this != &other) { value(std::move(other)).swap(*this); } return *this; } + value& operator=(const value& other) { if (this != &other) { value( other).swap(*this); } return *this; } + + value& operator=( null) { auto other = value( ); swap(other); return *this; } + value& operator=( object&& v) { auto other = value(std::move(v)); swap(other); return *this; } + value& operator=(const object& v) { auto other = value( v); swap(other); return *this; } + value& operator=( array&& v) { auto other = value(std::move(v)); swap(other); return *this; } + value& operator=(const array& v) { auto other = value( v); swap(other); return *this; } + value& operator=( string&& v) { auto other = value(std::move(v)); swap(other); return *this; } + value& operator=(const string& v) { auto other = value( v); swap(other); return *this; } + value& operator=(const char* v) { auto other = value( v); swap(other); return *this; } + value& operator=( boolean v) { auto other = value( v); swap(other); return *this; } + value& operator=( number v) { auto other = value( v); swap(other); return *this; } + + type_t type() const { return m_Type; } + + operator type_t() const { return m_Type; } + + value& operator[](size_t index); + const value& operator[](size_t index) const; + value& operator[](const string& key); + const value& operator[](const string& key) const; + + bool contains(const string& key) const; + + void push_back(const value& value); + void push_back(value&& value); + + size_t erase(const string& key); + + bool is_primitive() const { return is_string() || is_number() || is_boolean() || is_null(); } + bool is_structured() const { return is_object() || is_array(); } + bool is_null() const { return m_Type == type_t::null; } + bool is_object() const { return m_Type == type_t::object; } + bool is_array() const { return m_Type == type_t::array; } + bool is_string() const { return m_Type == type_t::string; } + bool is_boolean() const { return m_Type == type_t::boolean; } + bool is_number() const { return m_Type == type_t::number; } + bool is_discarded() const { return m_Type == type_t::discarded; } + + template const T& get() const; + template T& get(); + + template const T* get_ptr() const; + template T* get_ptr(); + + string dump(const int indent = -1, const char indent_char = ' ') const; + + void swap(value& other); + + inline friend void swap(value& lhs, value& rhs) { lhs.swap(rhs); } + + // Returns discarded value for invalid inputs. + static value parse(const string& data); + +# if CRUDE_JSON_IO + static std::pair load(const string& path); + bool save(const string& path, const int indent = -1, const char indent_char = ' ') const; +# endif + +private: + struct parser; + + // VS2015: std::max() is not constexpr yet. +# define CRUDE_MAX2(a, b) ((a) < (b) ? (b) : (a)) +# define CRUDE_MAX3(a, b, c) CRUDE_MAX2(CRUDE_MAX2(a, b), c) +# define CRUDE_MAX4(a, b, c, d) CRUDE_MAX2(CRUDE_MAX3(a, b, c), d) +# define CRUDE_MAX5(a, b, c, d, e) CRUDE_MAX2(CRUDE_MAX4(a, b, c, d), e) + enum + { + max_size = CRUDE_MAX5( sizeof(string), sizeof(object), sizeof(array), sizeof(number), sizeof(boolean)), + max_align = CRUDE_MAX5(alignof(string), alignof(object), alignof(array), alignof(number), alignof(boolean)) + }; +# undef CRUDE_MAX5 +# undef CRUDE_MAX4 +# undef CRUDE_MAX3 +# undef CRUDE_MAX2 + using storage_t = std::aligned_storage::type; + + static object* object_ptr( storage_t& storage) { return reinterpret_cast< object*>(&storage); } + static const object* object_ptr(const storage_t& storage) { return reinterpret_cast(&storage); } + static array* array_ptr( storage_t& storage) { return reinterpret_cast< array*>(&storage); } + static const array* array_ptr(const storage_t& storage) { return reinterpret_cast(&storage); } + static string* string_ptr( storage_t& storage) { return reinterpret_cast< string*>(&storage); } + static const string* string_ptr(const storage_t& storage) { return reinterpret_cast(&storage); } + static boolean* boolean_ptr( storage_t& storage) { return reinterpret_cast< boolean*>(&storage); } + static const boolean* boolean_ptr(const storage_t& storage) { return reinterpret_cast(&storage); } + static number* number_ptr( storage_t& storage) { return reinterpret_cast< number*>(&storage); } + static const number* number_ptr(const storage_t& storage) { return reinterpret_cast(&storage); } + + static type_t construct(storage_t& storage, type_t type) + { + switch (type) + { + case type_t::object: new (&storage) object(); break; + case type_t::array: new (&storage) array(); break; + case type_t::string: new (&storage) string(); break; + case type_t::boolean: new (&storage) boolean(); break; + case type_t::number: new (&storage) number(); break; + default: break; + } + + return type; + } + + static type_t construct(storage_t& storage, null) { (void)storage; return type_t::null; } + static type_t construct(storage_t& storage, object&& value) { new (&storage) object(std::forward(value)); return type_t::object; } + static type_t construct(storage_t& storage, const object& value) { new (&storage) object(value); return type_t::object; } + static type_t construct(storage_t& storage, array&& value) { new (&storage) array(std::forward(value)); return type_t::array; } + static type_t construct(storage_t& storage, const array& value) { new (&storage) array(value); return type_t::array; } + static type_t construct(storage_t& storage, string&& value) { new (&storage) string(std::forward(value)); return type_t::string; } + static type_t construct(storage_t& storage, const string& value) { new (&storage) string(value); return type_t::string; } + static type_t construct(storage_t& storage, const char* value) { new (&storage) string(value); return type_t::string; } + static type_t construct(storage_t& storage, boolean value) { new (&storage) boolean(value); return type_t::boolean; } + static type_t construct(storage_t& storage, number value) { new (&storage) number(value); return type_t::number; } + + static void destruct(storage_t& storage, type_t type) + { + switch (type) + { + case type_t::object: object_ptr(storage)->~object(); break; + case type_t::array: array_ptr(storage)->~array(); break; + case type_t::string: string_ptr(storage)->~string(); break; + default: break; + } + } + + struct dump_context_t + { + std::ostringstream out; + const int indent = -1; + const char indent_char = ' '; + + // VS2015: Aggregate initialization isn't a thing yet. + dump_context_t(const int indent, const char indent_char) + : indent(indent) + , indent_char(indent_char) + { + } + + void write_indent(int level); + void write_separator(); + void write_newline(); + }; + + void dump(dump_context_t& context, int level) const; + + storage_t m_Storage; + type_t m_Type; +}; + +template <> inline const object& value::get() const { CRUDE_ASSERT(m_Type == type_t::object); return *object_ptr(m_Storage); } +template <> inline const array& value::get() const { CRUDE_ASSERT(m_Type == type_t::array); return *array_ptr(m_Storage); } +template <> inline const string& value::get() const { CRUDE_ASSERT(m_Type == type_t::string); return *string_ptr(m_Storage); } +template <> inline const boolean& value::get() const { CRUDE_ASSERT(m_Type == type_t::boolean); return *boolean_ptr(m_Storage); } +template <> inline const number& value::get() const { CRUDE_ASSERT(m_Type == type_t::number); return *number_ptr(m_Storage); } + +template <> inline object& value::get() { CRUDE_ASSERT(m_Type == type_t::object); return *object_ptr(m_Storage); } +template <> inline array& value::get() { CRUDE_ASSERT(m_Type == type_t::array); return *array_ptr(m_Storage); } +template <> inline string& value::get() { CRUDE_ASSERT(m_Type == type_t::string); return *string_ptr(m_Storage); } +template <> inline boolean& value::get() { CRUDE_ASSERT(m_Type == type_t::boolean); return *boolean_ptr(m_Storage); } +template <> inline number& value::get() { CRUDE_ASSERT(m_Type == type_t::number); return *number_ptr(m_Storage); } + +template <> inline const object* value::get_ptr() const { if (m_Type == type_t::object) return object_ptr(m_Storage); else return nullptr; } +template <> inline const array* value::get_ptr() const { if (m_Type == type_t::array) return array_ptr(m_Storage); else return nullptr; } +template <> inline const string* value::get_ptr() const { if (m_Type == type_t::string) return string_ptr(m_Storage); else return nullptr; } +template <> inline const boolean* value::get_ptr() const { if (m_Type == type_t::boolean) return boolean_ptr(m_Storage); else return nullptr; } +template <> inline const number* value::get_ptr() const { if (m_Type == type_t::number) return number_ptr(m_Storage); else return nullptr; } + +template <> inline object* value::get_ptr() { if (m_Type == type_t::object) return object_ptr(m_Storage); else return nullptr; } +template <> inline array* value::get_ptr() { if (m_Type == type_t::array) return array_ptr(m_Storage); else return nullptr; } +template <> inline string* value::get_ptr() { if (m_Type == type_t::string) return string_ptr(m_Storage); else return nullptr; } +template <> inline boolean* value::get_ptr() { if (m_Type == type_t::boolean) return boolean_ptr(m_Storage); else return nullptr; } +template <> inline number* value::get_ptr() { if (m_Type == type_t::number) return number_ptr(m_Storage); else return nullptr; } + +} // namespace crude_json + +# endif // __CRUDE_JSON_H__ + +//Disable a bunch of warnings for now +#ifndef _MSC_VER +#pragma GCC diagnostic pop +#endif diff --git a/3rdparty/imgui-node-editor/docs/CHANGELOG.txt b/3rdparty/imgui-node-editor/docs/CHANGELOG.txt new file mode 100644 index 0000000..78da356 --- /dev/null +++ b/3rdparty/imgui-node-editor/docs/CHANGELOG.txt @@ -0,0 +1,223 @@ +v0.9.1 (WIP): + + CHANGE: Remove unwanted extra frame height from node bottom + + CHANGE: Allow to specify if links of deleted node should also be automatically deleted + Now it is possible to delete only node without automatically serving links, + application can choose to do this operation by itself and for example + short circuit flow links ot do any other special operation. + + CHANGE: Canvas: Allow to overlap canvas widget + + CHANGE: Natvis: Move crude_json natvis to separate file + + CHANGE: Natvis: Show readable NodeId/PinId/LinkId + + CHANGE: Make Navigate action to honor duration + + CHANGE: Travis: Use Ubuntu Bionic (18.04) for CI, to get newer version of GLFW3 + + CHANGE: Editor: Make action button internally configurable + + CHANGE: Make Node Editor forward compatible with ImGui 1.80+ (#112) + We're keeping backward compatibility with pre 1.8x versions. + + CHANGE: Update internal copy ImGui to 1.84 (WIP) (3512f2c2c283ec86) (#107) + Internal copy has two PR's merged: + https://github.com/thedmd/imgui/tree/feature/layout - used in blueprints example only + https://github.com/thedmd/imgui/tree/feature/extra-keys - optional: used by Node Editor if present + + CHANGE: Use github actions instead of Travis and AppVeyor (#113) + + CHANGE: Delete operation on node/link will remove internal object (#173) + + CHANGE: Natvis: Add crude_json::value visualization + + NEW: All source components are now versioned + + NEW: Make view state independent of window resolution. + + NEW: Editor can now break links connected specified node or pin + New API: + int BreakLinks(NodeId nodeId); + int BreakLinks(PinId pinId); + + NEW: Editor can now tell if node or pin has any links attached + New API: + bool HasAnyLinks(NodeId nodeId); + bool HasAnyLinks(PinId pinId); + + NEW: Editor can be queried if particular node or link is selected + New API: + bool IsNodeSelected(NodeId nodeId); + bool IsLinkSelected(LinkId linkId); + + NEW: Editor now can return pins of the link + New API: + bool GetLinkPins(LinkId linkId, PinId* startPinId, PinId* endPinId); + + `startPinId` and `endPinId` may be null if caller is not interested + in particular id. + + NEW: Editor now return ids of hovered node/pin/link + New API: + NodeId GetHoveredNode(); + PinId GetHoveredPin(); + LinkId GetHoveredLink(); + + NEW: Add SetGroupSize() to explicitly set group size + New API: + void SetGroupSize(NodeId nodeId, const ImVec2& size); + + NEW: crude_json: Add save() and load() + + When CRUDE_JSON_IO == 1 value will have load() and save() + function implemented using stdio.h FILE. + + NEW: crude_json: Add erase() and get_ptr() + + NEW: Application overhaul + - Convert from function based to inheritable class + - Add ability to close app and change title from code + - Add ability to control main window flags (ex. show menubar) + - Save ImGui state to ini file + - Render using pre-multiplied alpha textures + - Add extra fonts to examples. + + NEW: Reintegrate Widgets example from @crolando (#77) + + NEW: User can now override button indices for various actions (#88) + New API in Config: + int DragButtonIndex; // Mouse button index drag action will react to (0-left, 1-right, 2-middle) + int SelectButtonIndex; // Mouse button index select action will react to (0-left, 1-right, 2-middle) + int NavigateButtonIndex; // Mouse button index navigate action will react to (0-left, 1-right, 2-middle) + int ContextMenuButtonIndex; // Mouse button index context menu action will react to (0-left, 1-right, 2-middle) + + NEW: Flow direction can now be picked per flow (#104) + New API: + enum class FlowDirection + { + Forward, + Backward + }; + + void Flow(LinkId linkId, FlowDirection direction = FlowDirection::Forward); + + NEW: Editor can now return number of submitted nodes (#81) + New API: + int GetNodeCount(); // Returns number of submitted nodes since Begin() call + + NEW: Editor can now return nodes in order they are drawn (#81) + New API: + int GetOrderedNodeIds(NodeId* nodes, int size); // Fills an array with node id's in order they're drawn; up to 'size` elements are set. Returns actual size of filled id's. + + NEW: Editor now allow to set Z position for nodes (#109) + + Nodes with higher Z position are drawn on top of ones with lower. + + New API: + void SetNodeZPosition(NodeId nodeId, float z); // Sets node z position, nodes with higher value are drawn over nodes with lower value + float GetNodeZPosition(NodeId nodeId); // Returns node z position, defaults is 0.0f + + NEW: Editor: SaveReasonFlags now inform about node creation/deletion + + NEW: Editor: Expose button index background was clicked with + New API: + ImGuiMouseButton GetBackgroundClickButtonIndex(); // -1 if none + ImGuiMouseButton GetBackgroundDoubleClickButtonIndex(); // -1 if none + + NEW: Editor: Expose configuration editor was created with + New API: + const Config& GetConfig(EditorContext* ctx = nullptr); + + NEW: Editor: Add highlighting of Links connected to selected Node (#175) + New API: + StyleColor_HighlightLinkBorder + StyleVar_HighlightConnectedLinks + + NEW: Editor: Add ability to snap link origin to pin direction (#167) + New API: + StyleVar_SnapLinkToPinDir + + NEW: Editor: Add way to override default zoom levels (#174) + New API: + ImVector Config::CustomZoomLevels; + + NEW: Editor: Add canvas size mode (#170) + + Config can now decide how editor should resize view when changing size. + + New API: + enum class CanvasSizeMode; + Config::CanvasSizeMode; + + BUGFIX: Avoid crash while destroying editor. + + BUGFIX: Save draw list used by editor between Begin() and End() + There is a chance ImGui::GetWindowDrawList() will return different draw list + while nodes are being composed. To avoid troubles of manipulating incorrect + draw list one obtained in Begin() is remembered and used. + + BUGFIX: Avoid division by zero in ImCubicBezierBoundingRect + + BUGFIX: Don't stuck in delete action if user does not handle it + + BUGFIX: Enable use channel splitter inside Begin/End for node and pin. #28 + + BUGFIX: Don't manipulate channels when editor is suspended #28 + + BUGFIX: Fix ObjectId serialization + + BUGFIX: GroupNode resize instead of move on low zoom #87 + + BUGFIX: Make Canvas work with Viewports (#91, #90) + + BUGFIX: Explicitly choose embedded GL3W as OpenGL extension loader (#96) + + BUGFIX: Application: Don't apply HiDPI logic for (-FLT_MAX,-FLT_MAX) mouse position + + BUGFIX: Editor: Clamp over-the-edge drag distance to prevent scrolling to infinity on focus lost + + BUGFIX: Editor: Consume scroll event (#73) (require ImGui 17909 or later) + + BUGFIX: Editor: Respect window focus while handling actions (#99) + + BUGFIX: Examples: Correct case of `data` directory (#97) + + BUGFIX: Canvas: Save/Restore CursorMaxPos only in Begin/End (#101) + + BUGFIX: Editor: Don't implicitly capture keyboard (#83) + + BUGFIX: Application: Reset key down state after loosing keyboard focus + + BUGFIX: Editor: Make off-screen dragging work again + + BUGFIX: ImGui: Disable obsolete functions (#103) + + BUGFIX: Editor: Allow nodes with zero size (#134) + + BUGFIX: Canvas: Update call ImGui::IsClippedEx() on ImGui > 18415 (#138) + + BUGFIX: Canvas: Disable pink debug outline around widget (#150) + + BUGFIX: Editor: Remove node settings when it is explicitly deleted (#153) + + BUGFIX: Editor: Improve link dragging with fast movement (#156) + + BUGFIX: Editor: Make selection rect start at click point + + BUGFIX: Editor: Make selection rect sharp + + BUGFIX: Editor: Don't populate unused channels with empty draw command, fixes memory leak (#168, #165) + + BUGFIX: Application: Correctly set DX11 View for NULL textures (#162) + + BUGFIX: Application: Recreate DX11 resources lazily (related to #162) + + BUGFIX: Editor: Don't steal input from active user widget (#172) + + BUGFIX: Editor: Delete item from internal list only when action accepts (#178) + + BUGFIX: Editor: Cycle canvas to correctly restore view on first frame (#159) + + BUGFIX: Editor: Don't relay on ImGui CursorMaxPos to apply padding (https://github.com/ocornut/imgui/issues/5548) \ No newline at end of file diff --git a/3rdparty/imgui-node-editor/docs/README.md b/3rdparty/imgui-node-editor/docs/README.md new file mode 100644 index 0000000..8a33c65 --- /dev/null +++ b/3rdparty/imgui-node-editor/docs/README.md @@ -0,0 +1,169 @@ +# Node Editor in ImGui + +[![build](https://github.com/thedmd/imgui-node-editor/actions/workflows/build.yml/badge.svg)](https://github.com/thedmd/imgui-node-editor/actions/workflows/build.yml) + +## About + +An implementation of node editor with ImGui-like API. + +Project purpose is to serve as a basis for more complex solutions like blueprint editors. + +![node_editor_overview](https://user-images.githubusercontent.com/1197433/89328475-c01bc680-d68d-11ea-88bf-8c4155480927.gif) + +Node Editor is build around an idea "draw your content, we do the rest", which mean interactions are handled by editor, content rendering is handled by user. Editor will take care of: + * placing your node in the word + * dragging nodes + * zoom and scrolling + * selection + * various interaction that can be queried by API (creation, deletion, selection changes, etc.) + +Here are some highlights: + * Node movement and selection is handled internally + * Node and pin contents are fully customizable + * Fully styled, default theme is modeled after UE4 blueprints + - Flexible enough to produce such nodes: + + ![image](https://user-images.githubusercontent.com/1197433/60381408-c3895b00-9a54-11e9-8312-d9fc9af63347.png) + ![image](https://user-images.githubusercontent.com/1197433/60381400-a3599c00-9a54-11e9-9c51-a88f25f7db07.png) + ![image](https://user-images.githubusercontent.com/1197433/60381589-7d81c680-9a57-11e9-87b1-9f73ec33bea4.png) + - Customizable links based on Bézier curves: + + ![image](https://user-images.githubusercontent.com/1197433/60381475-ac973880-9a55-11e9-9ad9-5862975cd2b8.png) + ![image](https://user-images.githubusercontent.com/1197433/60381467-9db08600-9a55-11e9-9868-2ae849f67de9.png) + ![image](https://user-images.githubusercontent.com/1197433/60381488-cd5f8e00-9a55-11e9-8346-1f4c8d6bea22.png) + * Automatic highlights for nodes, pins and links: + + ![image](https://user-images.githubusercontent.com/1197433/60381536-9e95e780-9a56-11e9-80bb-dad0d3d9557a.png) + * Smooth navigation and selection + * Node state can be saved in user context, so layout will not break + * Selection rectangles and group dragging + * Context menu support + * Basic shortcuts support (cut/copy/paste/delete) + * ImGui style API + +Editor is used to implement blueprint editor in Spark CE engine, it proved itself there by allowing to do everything we needed. Therefore it is now slowly moving into stable state from beeing a prototype. + +Note: Project recently was restructured to mimic ImGui layout. + +Please report issues or questions if something isn't clear. + +## Dependencies + + * Vanilla ImGui 1.72+ + * C++14 + +### Dependencies for examples: + * https://github.com/thedmd/imgui/tree/feature/layout (used in blueprints sample only) + +### Optional extension you can pull into your local copy of ImGui node editor can take advantage of: + * ~~https://github.com/thedmd/imgui/tree/feature/draw-list-fringe-scale (for sharp rendering, while zooming)~~ It is part of ImGui since 1.80 release + * https://github.com/thedmd/imgui/tree/feature/extra-keys (for extra shortcuts) + +## Building / Installing + +Node Editor sources are located in root project directory. To use it, simply copy&paste sources into your project. Exactly like you can do with ImGui. + +### Examples +[Examples](../examples) can be build with CMake: +``` +Windows: + cmake -S examples -B build -G "Visual Studio 15 2017 Win64" + or + cmake -S examples -B build -G "Visual Studio 16 2019" -A x64 + +macOS: + cmake -S examples -B build -G "Xcode" + +Linux: + cmake -S examples -B build -G "Unix Makefiles" + +Build: + cmake --build build --config Release +``` +Executables will be located in `build\bin` directory. + +### Quick Start + +Main node editor header is located in [imgui_node_editor.h](../imgui_node_editor.h). + +Minimal example of one node can be found in [simple-example.cpp](../examples/simple-example/simple-example.cpp). +Press 'F' in editor to focus on editor content if you see only grid. +```cpp +# include +# include +# include + +namespace ed = ax::NodeEditor; + +struct Example: + public Application +{ + using Application::Application; + + void OnStart() override + { + ed::Config config; + config.SettingsFile = "Simple.json"; + m_Context = ed::CreateEditor(&config); + } + + void OnStop() override + { + ed::DestroyEditor(m_Context); + } + + void OnFrame(float deltaTime) override + { + auto& io = ImGui::GetIO(); + + ImGui::Text("FPS: %.2f (%.2gms)", io.Framerate, io.Framerate ? 1000.0f / io.Framerate : 0.0f); + + ImGui::Separator(); + + ed::SetCurrentEditor(m_Context); + ed::Begin("My Editor", ImVec2(0.0, 0.0f)); + int uniqueId = 1; + // Start drawing nodes. + ed::BeginNode(uniqueId++); + ImGui::Text("Node A"); + ed::BeginPin(uniqueId++, ed::PinKind::Input); + ImGui::Text("-> In"); + ed::EndPin(); + ImGui::SameLine(); + ed::BeginPin(uniqueId++, ed::PinKind::Output); + ImGui::Text("Out ->"); + ed::EndPin(); + ed::EndNode(); + ed::End(); + ed::SetCurrentEditor(nullptr); + + //ImGui::ShowMetricsWindow(); + } + + ed::EditorContext* m_Context = nullptr; +}; + +int Main(int argc, char** argv) +{ + Example exampe("Simple", argc, argv); + + if (exampe.Create()) + return exampe.Run(); + + return 0; +} +``` + +Result: + +![00-Simple](https://user-images.githubusercontent.com/1197433/89328516-cca01f00-d68d-11ea-9959-2da159851101.png) + +For more details please visit [examples](../examples) folder. + +### Blueprints Example + +![Preview2](https://user-images.githubusercontent.com/1197433/60053458-2f2b9b00-96d8-11e9-92f9-08aff63b2023.png) + +### Here is Node Editor at work in Spark CE +![image](https://user-images.githubusercontent.com/1197433/60381756-174a7300-9a5a-11e9-9a04-00f10565e05e.png) +![image](https://user-images.githubusercontent.com/1197433/60381760-2f21f700-9a5a-11e9-9053-c0547a9cc40a.png) diff --git a/3rdparty/imgui-node-editor/docs/TODO.md b/3rdparty/imgui-node-editor/docs/TODO.md new file mode 100644 index 0000000..46bb274 --- /dev/null +++ b/3rdparty/imgui-node-editor/docs/TODO.md @@ -0,0 +1,14 @@ +In random order: +* Documentation: Make one + +Done: +* ~~ImGui: Factor out changes to ImGui to use vanilla version.~~ +* ~~Editor: Fix variable naming (mainly add `m_` prefix)~~ +* ~~Editor: Split NodeEditorImpl.cpp to multiple files, file has grown too big.~~ +* ~~Editor: Factor out use of `picojson.h`~~ +* ~~Editor: Move use of `` to optional code extensions~~ + + + + +#57 - join `ax::NodeEditor::EditorContext` with `struct EditorContext` and remove `reinterpret_cast<>` \ No newline at end of file diff --git a/3rdparty/imgui-node-editor/examples/CMakeLists.txt b/3rdparty/imgui-node-editor/examples/CMakeLists.txt new file mode 100644 index 0000000..20604a9 --- /dev/null +++ b/3rdparty/imgui-node-editor/examples/CMakeLists.txt @@ -0,0 +1,134 @@ +cmake_minimum_required(VERSION 3.12) + +project(imgui-node-editor) + +# Define IMGUI_NODE_EDITOR_ROOT_DIR pointing to project root directory +get_filename_component(IMGUI_NODE_EDITOR_ROOT_DIR ${CMAKE_SOURCE_DIR}/.. ABSOLUTE CACHE) + +# Enable solution folders in Visual Studio and Folders in Xcode +set_property(GLOBAL PROPERTY USE_FOLDERS ON) + +# Point CMake where to look for module files. +list(APPEND CMAKE_MODULE_PATH ${IMGUI_NODE_EDITOR_ROOT_DIR}/misc/cmake-modules) + +# Node editor use C++14 +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED YES) + + + + + +# Macro that will configure an example application +macro(add_example_executable name) + project(${name}) + + set(_Example_Sources + ${ARGN} + ) + + #source_group("" FILES ${_Example_Sources}) + source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${_Example_Sources}) + + file(GLOB _Example_CommonResources CONFIGURE_DEPENDS "${IMGUI_NODE_EDITOR_ROOT_DIR}/examples/data/*") + file(GLOB _Example_Resources CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/data/*") + #message(FATAL_ERROR "_Example_Resources = ${_Example_Resources}") + + set(_Example_Type) + if (WIN32) + set(_Example_Type WIN32) + + set(ApplicationIcon ${IMGUI_NODE_EDITOR_ROOT_DIR}/examples/Application/Support/Icon.ico) + file(TO_NATIVE_PATH "${ApplicationIcon}" ApplicationIcon) + string(REPLACE "\\" "\\\\" ApplicationIcon "${ApplicationIcon}") + configure_file( + ${IMGUI_NODE_EDITOR_ROOT_DIR}/examples/Application/Support/Resource.rc.in + ${CMAKE_CURRENT_BINARY_DIR}/Resource.rc + ) + source_group(TREE "${IMGUI_NODE_EDITOR_ROOT_DIR}/examples" FILES ${_Example_CommonResources}) + source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES ${_Example_Resources}) + list(APPEND _Example_Resources + ${CMAKE_CURRENT_BINARY_DIR}/Resource.rc + ${_Example_CommonResources} + ) + source_group("resources" FILES ${CMAKE_CURRENT_BINARY_DIR}/Resource.rc) + elseif (APPLE) + set(_Example_Type MACOSX_BUNDLE) + + set_source_files_properties(${_Example_Resources} ${_Example_CommonResources} PROPERTIES + MACOSX_PACKAGE_LOCATION "Resources/data" + ) + set(_Example_Icon "${IMGUI_NODE_EDITOR_ROOT_DIR}/examples/application/support/Icon.icns") + list(APPEND _Example_Resources ${_Example_Icon}) + set_source_files_properties(${_Example_Icon} PROPERTIES + MACOSX_PACKAGE_LOCATION "Resources" + ) + endif() + + add_executable(${name} ${_Example_Type} ${_Example_Sources} ${_Example_Resources} ${_Example_CommonResources}) + + find_package(imgui REQUIRED) + find_package(imgui_node_editor REQUIRED) + target_link_libraries(${name} PRIVATE imgui imgui_node_editor application) + + set(_ExampleBinDir ${CMAKE_BINARY_DIR}/bin) + + set_target_properties(${name} PROPERTIES + FOLDER "examples" + RUNTIME_OUTPUT_DIRECTORY "${_ExampleBinDir}" + RUNTIME_OUTPUT_DIRECTORY_DEBUG "${_ExampleBinDir}" + RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${_ExampleBinDir}" + RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${_ExampleBinDir}" + RUNTIME_OUTPUT_DIRECTORY_RELEASE "${_ExampleBinDir}" + DEBUG_POSTFIX _d + RELWITHDEBINGO_POSTFIX _rd + MINSIZEREL_POSTFIX _r + VS_DEBUGGER_WORKING_DIRECTORY ${_ExampleBinDir} + MACOSX_BUNDLE_INFO_PLIST "${IMGUI_NODE_EDITOR_ROOT_DIR}/examples/application/support/Info.plist.in" + MACOSX_BUNDLE_BUNDLE_NAME "${PACKAGE_NAME}" + MACOSX_BUNDLE_GUI_IDENTIFIER "com.sandbox.collisions" + MACOSX_BUNDLE_LONG_VERSION_STRING "${PACKAGE_VERSION}" + MACOSX_BUNDLE_SHORT_VERSION_STRING "${PACKAGE_VERSION_MAJOR}.${PACKAGE_VERSION_MINOR}" + MACOSX_BUNDLE_ICON_FILE Icon.icns + ) + + add_custom_command( + TARGET ${name} + PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory ARGS ${_ExampleBinDir}/data + ) + + set(_ResourceRoot ${CMAKE_CURRENT_SOURCE_DIR}) + foreach(_Resource ROOT "${IMGUI_NODE_EDITOR_ROOT_DIR}/examples/data" ${_Example_CommonResources} ROOT "${CMAKE_CURRENT_SOURCE_DIR}/data" ${_Example_Resources}) + if (_Resource STREQUAL ROOT) + set(_ResourceRoot FALSE) + continue() + elseif(NOT _ResourceRoot) + set(_ResourceRoot ${_Resource}) + continue() + endif() + + if ("${_Resource}" MATCHES "\.DS_Store$") + list(REMOVE_ITEM _Example_Resources ${_Resource}) + list(REMOVE_ITEM _Example_CommonResources ${_Resource}) + continue() + endif() + + file(RELATIVE_PATH _RelResource ${_ResourceRoot} ${_Resource}) + + add_custom_command( + TARGET ${name} + PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different ARGS ${_Resource} ${_ExampleBinDir}/data/${_RelResource} + ) + endforeach() + +endmacro() + +add_subdirectory(application) + +add_subdirectory(canvas-example) +add_subdirectory(simple-example) +add_subdirectory(widgets-example) +add_subdirectory(basic-interaction-example) +add_subdirectory(blueprints-example) diff --git a/3rdparty/imgui-node-editor/examples/application/CMakeLists.txt b/3rdparty/imgui-node-editor/examples/application/CMakeLists.txt new file mode 100644 index 0000000..ccd055b --- /dev/null +++ b/3rdparty/imgui-node-editor/examples/application/CMakeLists.txt @@ -0,0 +1,112 @@ +project(application) + +set(_Application_Sources + include/application.h + source/application.cpp + source/entry_point.cpp + source/imgui_extra_keys.h + source/config.h.in + source/setup.h + source/platform.h + source/platform_win32.cpp + source/platform_glfw.cpp + source/renderer.h + source/renderer_dx11.cpp + source/renderer_ogl3.cpp +) + +add_library(application STATIC) + +target_include_directories(application PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) + +find_package(imgui REQUIRED) +find_package(stb_image REQUIRED) +find_package(ScopeGuard REQUIRED) +target_link_libraries(application PUBLIC imgui) +target_link_libraries(application PRIVATE stb_image ScopeGuard) + +if (WIN32) + list(APPEND _Application_Sources + source/imgui_impl_dx11.cpp + source/imgui_impl_dx11.h + source/imgui_impl_win32.cpp + source/imgui_impl_win32.h + ) + + set(_DXSDK_Dir ${IMGUI_NODE_EDITOR_ROOT_DIR}/external/DXSDK) + set(_DXSDK_Arch x86) + if (${CMAKE_SIZEOF_VOID_P} EQUAL 8) + set(_DXSDK_Arch x64) + endif() + + add_library(dxerr STATIC ${_DXSDK_Dir}/src/dxerr.cpp) + target_include_directories(dxerr PUBLIC "${_DXSDK_Dir}/include") + set_property(TARGET dxerr PROPERTY FOLDER "external") + + add_library(d3dx11 UNKNOWN IMPORTED) + set_target_properties(d3dx11 PROPERTIES + IMPORTED_LOCATION "${_DXSDK_Dir}/lib/${_DXSDK_Arch}/d3dx11.lib" + IMPORTED_LOCATION_DEBUG "${_DXSDK_Dir}/lib/${_DXSDK_Arch}/d3dx11d.lib" + INTERFACE_INCLUDE_DIRECTORIES "${_DXSDK_Dir}/include" + INTERFACE_LINK_LIBRARIES "$<$:dxerr>" + ) + + target_link_libraries(application PRIVATE d3d11.lib d3dcompiler.lib d3dx11) +else() + find_package(OpenGL REQUIRED) + find_package(glfw3 3 REQUIRED) + + if (APPLE) + target_link_libraries(application PRIVATE + "-framework CoreFoundation" + "-framework Cocoa" + "-framework IOKit" + "-framework CoreVideo" + ) + endif() +endif() + +if (OpenGL_FOUND) + set(HAVE_OPENGL YES) + + find_package(gl3w REQUIRED) + # Explicitly select embedded GL3W loader + target_compile_definitions(application PRIVATE IMGUI_IMPL_OPENGL_LOADER_GL3W) + + target_include_directories(application PRIVATE ${OPENGL_INCLUDE_DIR}) + target_link_libraries(application PRIVATE ${OPENGL_gl_LIBRARY} gl3w) + list(APPEND _Application_Sources + source/imgui_impl_opengl3.cpp + source/imgui_impl_opengl3.h + ) +endif() + +if (glfw3_FOUND) + set(HAVE_GLFW3 YES) + + list(APPEND _Application_Sources + source/imgui_impl_glfw.cpp + source/imgui_impl_glfw.h + ) + target_link_libraries(application PRIVATE + glfw + ) +endif() + +configure_file( + source/config.h.in + ${CMAKE_CURRENT_BINARY_DIR}/source/config.h +) + +target_compile_definitions(application PRIVATE + #BACKEND_CONFIG=IMGUI_GLFW + #RENDERER_CONFIG=IMGUI_OGL3 +) + +target_include_directories(application PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/source) + +source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES ${_Application_Sources}) + +target_sources(application PRIVATE ${_Application_Sources}) + +set_property(TARGET application PROPERTY FOLDER "examples") \ No newline at end of file diff --git a/3rdparty/imgui-node-editor/examples/application/include/application.h b/3rdparty/imgui-node-editor/examples/application/include/application.h new file mode 100644 index 0000000..88a39bd --- /dev/null +++ b/3rdparty/imgui-node-editor/examples/application/include/application.h @@ -0,0 +1,57 @@ +# pragma once +# include +# include +# include + +struct Platform; +struct Renderer; + +struct Application +{ + Application(const char* name); + Application(const char* name, int argc, char** argv); + ~Application(); + + bool Create(int width = -1, int height = -1); + + int Run(); + + void SetTitle(const char* title); + + bool Close(); + void Quit(); + + const std::string& GetName() const; + + ImFont* DefaultFont() const; + ImFont* HeaderFont() const; + + ImTextureID LoadTexture(const char* path); + ImTextureID CreateTexture(const void* data, int width, int height); + void DestroyTexture(ImTextureID texture); + int GetTextureWidth(ImTextureID texture); + int GetTextureHeight(ImTextureID texture); + + virtual void OnStart() {} + virtual void OnStop() {} + virtual void OnFrame(float deltaTime) {} + + virtual ImGuiWindowFlags GetWindowFlags() const; + + virtual bool CanClose() { return true; } + +private: + void RecreateFontAtlas(); + + void Frame(); + + std::string m_Name; + std::string m_IniFilename; + std::unique_ptr m_Platform; + std::unique_ptr m_Renderer; + ImGuiContext* m_Context = nullptr; + ImFont* m_DefaultFont = nullptr; + ImFont* m_HeaderFont = nullptr; +}; + +int Main(int argc, char** argv); \ No newline at end of file diff --git a/3rdparty/imgui-node-editor/examples/application/source/application.cpp b/3rdparty/imgui-node-editor/examples/application/source/application.cpp new file mode 100644 index 0000000..aa1b326 --- /dev/null +++ b/3rdparty/imgui-node-editor/examples/application/source/application.cpp @@ -0,0 +1,244 @@ +# include "application.h" +# include "setup.h" +# include "platform.h" +# include "renderer.h" + +extern "C" { +#define STB_IMAGE_IMPLEMENTATION +#define STB_IMAGE_STATIC +#include "stb_image.h" +} + + +Application::Application(const char* name) + : Application(name, 0, nullptr) +{ +} + +Application::Application(const char* name, int argc, char** argv) + : m_Name(name) + , m_Platform(CreatePlatform(*this)) + , m_Renderer(CreateRenderer()) +{ + m_Platform->ApplicationStart(argc, argv); +} + +Application::~Application() +{ + m_Renderer->Destroy(); + + m_Platform->ApplicationStop(); + + if (m_Context) + { + ImGui::DestroyContext(m_Context); + m_Context= nullptr; + } +} + +bool Application::Create(int width /*= -1*/, int height /*= -1*/) +{ + m_Context = ImGui::CreateContext(); + ImGui::SetCurrentContext(m_Context); + + if (!m_Platform->OpenMainWindow("Application", width, height)) + return false; + + if (!m_Renderer->Create(*m_Platform)) + return false; + + m_IniFilename = m_Name + ".ini"; + + ImGuiIO& io = ImGui::GetIO(); + //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + io.IniFilename = m_IniFilename.c_str(); + io.LogFilename = nullptr; + + ImGui::StyleColorsDark(); + + RecreateFontAtlas(); + + m_Platform->AcknowledgeWindowScaleChanged(); + m_Platform->AcknowledgeFramebufferScaleChanged(); + + OnStart(); + + Frame(); + + return true; +} + +int Application::Run() +{ + m_Platform->ShowMainWindow(); + + while (m_Platform->ProcessMainWindowEvents()) + { + if (!m_Platform->IsMainWindowVisible()) + continue; + + Frame(); + } + + OnStop(); + + return 0; +} + +void Application::RecreateFontAtlas() +{ + ImGuiIO& io = ImGui::GetIO(); + + IM_DELETE(io.Fonts); + + io.Fonts = IM_NEW(ImFontAtlas); + + ImFontConfig config; + config.OversampleH = 4; + config.OversampleV = 4; + config.PixelSnapH = false; + + m_DefaultFont = io.Fonts->AddFontFromFileTTF("data/Play-Regular.ttf", 18.0f, &config); + m_HeaderFont = io.Fonts->AddFontFromFileTTF("data/Cuprum-Bold.ttf", 20.0f, &config); + + io.Fonts->Build(); +} + +void Application::Frame() +{ + auto& io = ImGui::GetIO(); + + if (m_Platform->HasWindowScaleChanged()) + m_Platform->AcknowledgeWindowScaleChanged(); + + if (m_Platform->HasFramebufferScaleChanged()) + { + RecreateFontAtlas(); + m_Platform->AcknowledgeFramebufferScaleChanged(); + } + + const float windowScale = m_Platform->GetWindowScale(); + const float framebufferScale = m_Platform->GetFramebufferScale(); + + if (io.WantSetMousePos) + { + io.MousePos.x *= windowScale; + io.MousePos.y *= windowScale; + } + + m_Platform->NewFrame(); + + // Don't touch "uninitialized" mouse position + if (io.MousePos.x > -FLT_MAX && io.MousePos.y > -FLT_MAX) + { + io.MousePos.x /= windowScale; + io.MousePos.y /= windowScale; + } + io.DisplaySize.x /= windowScale; + io.DisplaySize.y /= windowScale; + + io.DisplayFramebufferScale.x = framebufferScale; + io.DisplayFramebufferScale.y = framebufferScale; + + m_Renderer->NewFrame(); + + ImGui::NewFrame(); + + ImGui::SetNextWindowPos(ImVec2(0, 0)); + ImGui::SetNextWindowSize(io.DisplaySize); + const auto windowBorderSize = ImGui::GetStyle().WindowBorderSize; + const auto windowRounding = ImGui::GetStyle().WindowRounding; + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + ImGui::Begin("Content", nullptr, GetWindowFlags()); + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, windowBorderSize); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, windowRounding); + + OnFrame(io.DeltaTime); + + ImGui::PopStyleVar(2); + ImGui::End(); + ImGui::PopStyleVar(2); + + // Rendering + m_Renderer->Clear(ImColor(32, 32, 32, 255)); + ImGui::Render(); + m_Renderer->RenderDrawData(ImGui::GetDrawData()); + + m_Platform->FinishFrame(); +} + +void Application::SetTitle(const char* title) +{ + m_Platform->SetMainWindowTitle(title); +} + +bool Application::Close() +{ + return m_Platform->CloseMainWindow(); +} + +void Application::Quit() +{ + m_Platform->Quit(); +} + +const std::string& Application::GetName() const +{ + return m_Name; +} + +ImFont* Application::DefaultFont() const +{ + return m_DefaultFont; +} + +ImFont* Application::HeaderFont() const +{ + return m_HeaderFont; +} + +ImTextureID Application::LoadTexture(const char* path) +{ + int width = 0, height = 0, component = 0; + if (auto data = stbi_load(path, &width, &height, &component, 4)) + { + auto texture = CreateTexture(data, width, height); + stbi_image_free(data); + return texture; + } + else + return nullptr; +} + +ImTextureID Application::CreateTexture(const void* data, int width, int height) +{ + return m_Renderer->CreateTexture(data, width, height); +} + +void Application::DestroyTexture(ImTextureID texture) +{ + m_Renderer->DestroyTexture(texture); +} + +int Application::GetTextureWidth(ImTextureID texture) +{ + return m_Renderer->GetTextureWidth(texture); +} + +int Application::GetTextureHeight(ImTextureID texture) +{ + return m_Renderer->GetTextureHeight(texture); +} + +ImGuiWindowFlags Application::GetWindowFlags() const +{ + return + ImGuiWindowFlags_NoTitleBar | + ImGuiWindowFlags_NoResize | + ImGuiWindowFlags_NoMove | + ImGuiWindowFlags_NoScrollbar | + ImGuiWindowFlags_NoScrollWithMouse | + ImGuiWindowFlags_NoSavedSettings | + ImGuiWindowFlags_NoBringToFrontOnFocus; +} diff --git a/3rdparty/imgui-node-editor/examples/application/source/config.h.in b/3rdparty/imgui-node-editor/examples/application/source/config.h.in new file mode 100644 index 0000000..07973c7 --- /dev/null +++ b/3rdparty/imgui-node-editor/examples/application/source/config.h.in @@ -0,0 +1,4 @@ +# pragma once + +# cmakedefine01 HAVE_GLFW3 +# cmakedefine01 HAVE_OPENGL \ No newline at end of file diff --git a/3rdparty/imgui-node-editor/examples/application/source/entry_point.cpp b/3rdparty/imgui-node-editor/examples/application/source/entry_point.cpp new file mode 100644 index 0000000..cbf6a23 --- /dev/null +++ b/3rdparty/imgui-node-editor/examples/application/source/entry_point.cpp @@ -0,0 +1,21 @@ +# include "application.h" +# include "platform.h" + +# if PLATFORM(WINDOWS) +# define NOMINMAX +# define WIN32_LEAN_AND_MEAN +# include +# include // __argc, argv +# endif + +# if defined(_WIN32) && !defined(_CONSOLE) +int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nShowCmd) +{ + return Main(__argc, __argv); +} +# else +int main(int argc, char** argv) +{ + return Main(argc, argv); +} +# endif diff --git a/3rdparty/imgui-node-editor/examples/application/source/imgui_extra_keys.h b/3rdparty/imgui-node-editor/examples/application/source/imgui_extra_keys.h new file mode 100644 index 0000000..850d51a --- /dev/null +++ b/3rdparty/imgui-node-editor/examples/application/source/imgui_extra_keys.h @@ -0,0 +1,48 @@ +# pragma once +# include +# include + +// https://stackoverflow.com/a/8597498 +# define DECLARE_HAS_NESTED(Name, Member) \ + \ + template \ + struct has_nested_ ## Name \ + { \ + typedef char yes; \ + typedef yes(&no)[2]; \ + \ + template static yes test(decltype(U::Member)*); \ + template static no test(...); \ + \ + static bool const value = sizeof(test(0)) == sizeof(yes); \ + }; + +# define DECLARE_KEY_TESTER(Key) \ + DECLARE_HAS_NESTED(Key, Key) \ + struct KeyTester_ ## Key \ + { \ + template \ + static int Get(typename std::enable_if::value, T>::type*) \ + { \ + return T::Key; \ + } \ + \ + template \ + static int Get(typename std::enable_if::value, T>::type*) \ + { \ + return -1; \ + } \ + } + +DECLARE_KEY_TESTER(ImGuiKey_F); +DECLARE_KEY_TESTER(ImGuiKey_D); + +static inline int GetEnumValueForF() +{ + return KeyTester_ImGuiKey_F::Get(nullptr); +} + +static inline int GetEnumValueForD() +{ + return KeyTester_ImGuiKey_D::Get(nullptr); +} diff --git a/3rdparty/imgui-node-editor/examples/application/source/imgui_impl_dx11.cpp b/3rdparty/imgui-node-editor/examples/application/source/imgui_impl_dx11.cpp new file mode 100644 index 0000000..a91fd9c --- /dev/null +++ b/3rdparty/imgui-node-editor/examples/application/source/imgui_impl_dx11.cpp @@ -0,0 +1,681 @@ +// dear imgui: Renderer for DirectX11 +// This needs to be used along with a Platform Binding (e.g. Win32) + +// Implemented features: +// [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID in imgui.cpp. +// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bits indices. + +// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. +// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp +// https://github.com/ocornut/imgui + +// CHANGELOG +// (minor and older changes stripped away, please see git history for details) +// 2019-05-29: DirectX11: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag. +// 2019-04-30: DirectX11: Added support for special ImDrawCallback_ResetRenderState callback to reset render state. +// 2018-12-03: Misc: Added #pragma comment statement to automatically link with d3dcompiler.lib when using D3DCompile(). +// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window. +// 2018-08-01: DirectX11: Querying for IDXGIFactory instead of IDXGIFactory1 to increase compatibility. +// 2018-07-13: DirectX11: Fixed unreleased resources in Init and Shutdown functions. +// 2018-06-08: Misc: Extracted imgui_impl_dx11.cpp/.h away from the old combined DX11+Win32 example. +// 2018-06-08: DirectX11: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle. +// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX11_RenderDrawData() in the .h file so you can call it yourself. +// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves. +// 2016-05-07: DirectX11: Disabling depth-write. + +#include "imgui.h" +#include "imgui_impl_dx11.h" + +// DirectX +struct IUnknown; +#include +#include +#include +#ifdef _MSC_VER +#pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below. +#endif + +struct TEXTURE; + +// DirectX data +static ID3D11Device* g_pd3dDevice = NULL; +static ID3D11DeviceContext* g_pd3dDeviceContext = NULL; +static IDXGIFactory* g_pFactory = NULL; +static ID3D11Buffer* g_pVB = NULL; +static ID3D11Buffer* g_pIB = NULL; +static ID3D10Blob* g_pVertexShaderBlob = NULL; +static ID3D11VertexShader* g_pVertexShader = NULL; +static ID3D11InputLayout* g_pInputLayout = NULL; +static ID3D11Buffer* g_pVertexConstantBuffer = NULL; +static ID3D10Blob* g_pPixelShaderBlob = NULL; +static ID3D11PixelShader* g_pPixelShader = NULL; +static ID3D11SamplerState* g_pFontSampler = NULL; +static ImTextureID g_pFontTextureID = NULL; +static ID3D11RasterizerState* g_pRasterizerState = NULL; +static ID3D11BlendState* g_pBlendState = NULL; +static ID3D11DepthStencilState* g_pDepthStencilState = NULL; +static int g_VertexBufferSize = 5000, g_IndexBufferSize = 10000; +static ImVector g_Textures; + +struct VERTEX_CONSTANT_BUFFER +{ + float mvp[4][4]; +}; + +struct TEXTURE +{ + TEXTURE() + { + View = NULL; + Width = 0; + Height = 0; + } + + ID3D11ShaderResourceView* View; + int Width; + int Height; + ImVector Data; +}; + +// Forward Declarations +static bool ImGui_UploadTexture(TEXTURE* texture); +static void ImGui_ReleaseTexture(TEXTURE* texture); + +static void ImGui_ImplDX11_SetupRenderState(ImDrawData* draw_data, ID3D11DeviceContext* ctx) +{ + // Setup viewport + D3D11_VIEWPORT vp; + memset(&vp, 0, sizeof(D3D11_VIEWPORT)); + vp.Width = draw_data->DisplaySize.x * draw_data->FramebufferScale.x; + vp.Height = draw_data->DisplaySize.y * draw_data->FramebufferScale.y; + vp.MinDepth = 0.0f; + vp.MaxDepth = 1.0f; + vp.TopLeftX = vp.TopLeftY = 0; + ctx->RSSetViewports(1, &vp); + + // Setup shader and vertex buffers + unsigned int stride = sizeof(ImDrawVert); + unsigned int offset = 0; + ctx->IASetInputLayout(g_pInputLayout); + ctx->IASetVertexBuffers(0, 1, &g_pVB, &stride, &offset); + ctx->IASetIndexBuffer(g_pIB, sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0); + ctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + ctx->VSSetShader(g_pVertexShader, NULL, 0); + ctx->VSSetConstantBuffers(0, 1, &g_pVertexConstantBuffer); + ctx->PSSetShader(g_pPixelShader, NULL, 0); + ctx->PSSetSamplers(0, 1, &g_pFontSampler); + + // Setup blend state + const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f }; + ctx->OMSetBlendState(g_pBlendState, blend_factor, 0xffffffff); + ctx->OMSetDepthStencilState(g_pDepthStencilState, 0); + ctx->RSSetState(g_pRasterizerState); +} + +// Render function +// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop) +void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data) +{ + // Avoid rendering when minimized + if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f) + return; + + ID3D11DeviceContext* ctx = g_pd3dDeviceContext; + + // Create and grow vertex/index buffers if needed + if (!g_pVB || g_VertexBufferSize < draw_data->TotalVtxCount) + { + if (g_pVB) { g_pVB->Release(); g_pVB = NULL; } + g_VertexBufferSize = draw_data->TotalVtxCount + 5000; + D3D11_BUFFER_DESC desc; + memset(&desc, 0, sizeof(D3D11_BUFFER_DESC)); + desc.Usage = D3D11_USAGE_DYNAMIC; + desc.ByteWidth = g_VertexBufferSize * sizeof(ImDrawVert); + desc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + desc.MiscFlags = 0; + if (g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pVB) < 0) + return; + } + if (!g_pIB || g_IndexBufferSize < draw_data->TotalIdxCount) + { + if (g_pIB) { g_pIB->Release(); g_pIB = NULL; } + g_IndexBufferSize = draw_data->TotalIdxCount + 10000; + D3D11_BUFFER_DESC desc; + memset(&desc, 0, sizeof(D3D11_BUFFER_DESC)); + desc.Usage = D3D11_USAGE_DYNAMIC; + desc.ByteWidth = g_IndexBufferSize * sizeof(ImDrawIdx); + desc.BindFlags = D3D11_BIND_INDEX_BUFFER; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + if (g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pIB) < 0) + return; + } + + // Upload vertex/index data into a single contiguous GPU buffer + D3D11_MAPPED_SUBRESOURCE vtx_resource, idx_resource; + if (ctx->Map(g_pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &vtx_resource) != S_OK) + return; + if (ctx->Map(g_pIB, 0, D3D11_MAP_WRITE_DISCARD, 0, &idx_resource) != S_OK) + return; + ImDrawVert* vtx_dst = (ImDrawVert*)vtx_resource.pData; + ImDrawIdx* idx_dst = (ImDrawIdx*)idx_resource.pData; + for (int n = 0; n < draw_data->CmdListsCount; n++) + { + const ImDrawList* cmd_list = draw_data->CmdLists[n]; + memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); + memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); + vtx_dst += cmd_list->VtxBuffer.Size; + idx_dst += cmd_list->IdxBuffer.Size; + } + ctx->Unmap(g_pVB, 0); + ctx->Unmap(g_pIB, 0); + + // Setup orthographic projection matrix into our constant buffer + // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps. + { + D3D11_MAPPED_SUBRESOURCE mapped_resource; + if (ctx->Map(g_pVertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK) + return; + VERTEX_CONSTANT_BUFFER* constant_buffer = (VERTEX_CONSTANT_BUFFER*)mapped_resource.pData; + float L = draw_data->DisplayPos.x; + float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x; + float T = draw_data->DisplayPos.y; + float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y; + float mvp[4][4] = + { + { 2.0f/(R-L), 0.0f, 0.0f, 0.0f }, + { 0.0f, 2.0f/(T-B), 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.5f, 0.0f }, + { (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f }, + }; + memcpy(&constant_buffer->mvp, mvp, sizeof(mvp)); + ctx->Unmap(g_pVertexConstantBuffer, 0); + } + + // Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!) + struct BACKUP_DX11_STATE + { + UINT ScissorRectsCount, ViewportsCount; + D3D11_RECT ScissorRects[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; + D3D11_VIEWPORT Viewports[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; + ID3D11RasterizerState* RS; + ID3D11BlendState* BlendState; + FLOAT BlendFactor[4]; + UINT SampleMask; + UINT StencilRef; + ID3D11DepthStencilState* DepthStencilState; + ID3D11ShaderResourceView* PSShaderResource; + ID3D11SamplerState* PSSampler; + ID3D11PixelShader* PS; + ID3D11VertexShader* VS; + UINT PSInstancesCount, VSInstancesCount; + ID3D11ClassInstance* PSInstances[256], *VSInstances[256]; // 256 is max according to PSSetShader documentation + D3D11_PRIMITIVE_TOPOLOGY PrimitiveTopology; + ID3D11Buffer* IndexBuffer, *VertexBuffer, *VSConstantBuffer; + UINT IndexBufferOffset, VertexBufferStride, VertexBufferOffset; + DXGI_FORMAT IndexBufferFormat; + ID3D11InputLayout* InputLayout; + }; + BACKUP_DX11_STATE old; + old.ScissorRectsCount = old.ViewportsCount = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; + ctx->RSGetScissorRects(&old.ScissorRectsCount, old.ScissorRects); + ctx->RSGetViewports(&old.ViewportsCount, old.Viewports); + ctx->RSGetState(&old.RS); + ctx->OMGetBlendState(&old.BlendState, old.BlendFactor, &old.SampleMask); + ctx->OMGetDepthStencilState(&old.DepthStencilState, &old.StencilRef); + ctx->PSGetShaderResources(0, 1, &old.PSShaderResource); + ctx->PSGetSamplers(0, 1, &old.PSSampler); + old.PSInstancesCount = old.VSInstancesCount = 256; + ctx->PSGetShader(&old.PS, old.PSInstances, &old.PSInstancesCount); + ctx->VSGetShader(&old.VS, old.VSInstances, &old.VSInstancesCount); + ctx->VSGetConstantBuffers(0, 1, &old.VSConstantBuffer); + ctx->IAGetPrimitiveTopology(&old.PrimitiveTopology); + ctx->IAGetIndexBuffer(&old.IndexBuffer, &old.IndexBufferFormat, &old.IndexBufferOffset); + ctx->IAGetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); + ctx->IAGetInputLayout(&old.InputLayout); + + // Setup desired DX state + ImGui_ImplDX11_SetupRenderState(draw_data, ctx); + + // Render command lists + // (Because we merged all buffers into a single one, we maintain our own offset into them) + int global_idx_offset = 0; + int global_vtx_offset = 0; + + // Will project scissor/clipping rectangles into framebuffer space + ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports + ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2) + for (int n = 0; n < draw_data->CmdListsCount; n++) + { + const ImDrawList* cmd_list = draw_data->CmdLists[n]; + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) + { + const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; + if (pcmd->UserCallback != NULL) + { + // User callback, registered via ImDrawList::AddCallback() + // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) + if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) + ImGui_ImplDX11_SetupRenderState(draw_data, ctx); + else + pcmd->UserCallback(cmd_list, pcmd); + } + else + { + ImVec4 clip_rect; + clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x; + clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y; + clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x; + clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y; + + // Apply scissor/clipping rectangle + const D3D11_RECT r = { (LONG)clip_rect.x, (LONG)clip_rect.y, (LONG)clip_rect.z, (LONG)clip_rect.w }; + ctx->RSSetScissorRects(1, &r); + + // Bind texture, Draw + TEXTURE* texture = (TEXTURE*)pcmd->TextureId; + ID3D11ShaderResourceView* textureView = texture ? texture->View : nullptr; + ctx->PSSetShaderResources(0, 1, &textureView); + ctx->DrawIndexed(pcmd->ElemCount, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset); + } + } + global_idx_offset += cmd_list->IdxBuffer.Size; + global_vtx_offset += cmd_list->VtxBuffer.Size; + } + + // Restore modified DX state + ctx->RSSetScissorRects(old.ScissorRectsCount, old.ScissorRects); + ctx->RSSetViewports(old.ViewportsCount, old.Viewports); + ctx->RSSetState(old.RS); if (old.RS) old.RS->Release(); + ctx->OMSetBlendState(old.BlendState, old.BlendFactor, old.SampleMask); if (old.BlendState) old.BlendState->Release(); + ctx->OMSetDepthStencilState(old.DepthStencilState, old.StencilRef); if (old.DepthStencilState) old.DepthStencilState->Release(); + ctx->PSSetShaderResources(0, 1, &old.PSShaderResource); if (old.PSShaderResource) old.PSShaderResource->Release(); + ctx->PSSetSamplers(0, 1, &old.PSSampler); if (old.PSSampler) old.PSSampler->Release(); + ctx->PSSetShader(old.PS, old.PSInstances, old.PSInstancesCount); if (old.PS) old.PS->Release(); + for (UINT i = 0; i < old.PSInstancesCount; i++) if (old.PSInstances[i]) old.PSInstances[i]->Release(); + ctx->VSSetShader(old.VS, old.VSInstances, old.VSInstancesCount); if (old.VS) old.VS->Release(); + ctx->VSSetConstantBuffers(0, 1, &old.VSConstantBuffer); if (old.VSConstantBuffer) old.VSConstantBuffer->Release(); + for (UINT i = 0; i < old.VSInstancesCount; i++) if (old.VSInstances[i]) old.VSInstances[i]->Release(); + ctx->IASetPrimitiveTopology(old.PrimitiveTopology); + ctx->IASetIndexBuffer(old.IndexBuffer, old.IndexBufferFormat, old.IndexBufferOffset); if (old.IndexBuffer) old.IndexBuffer->Release(); + ctx->IASetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); if (old.VertexBuffer) old.VertexBuffer->Release(); + ctx->IASetInputLayout(old.InputLayout); if (old.InputLayout) old.InputLayout->Release(); +} + +static void ImGui_ImplDX11_CreateFontsTexture() +{ + // Build texture atlas + ImGuiIO& io = ImGui::GetIO(); + unsigned char* pixels; + int width, height; + io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); + + g_pFontTextureID = ImGui_CreateTexture(pixels, width, height); + + io.Fonts->TexID = g_pFontTextureID; + + + // Create texture sampler + { + D3D11_SAMPLER_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; + desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; + desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; + desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; + desc.MipLODBias = 0.f; + desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; + desc.MinLOD = 0.f; + desc.MaxLOD = 0.f; + g_pd3dDevice->CreateSamplerState(&desc, &g_pFontSampler); + } +} + +bool ImGui_ImplDX11_CreateDeviceObjects() +{ + if (!g_pd3dDevice) + return false; + if (g_pFontSampler) + ImGui_ImplDX11_InvalidateDeviceObjects(); + + // By using D3DCompile() from / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A) + // If you would like to use this DX11 sample code but remove this dependency you can: + // 1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [preferred solution] + // 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL. + // See https://github.com/ocornut/imgui/pull/638 for sources and details. + + // Create the vertex shader + { + static const char* vertexShader = + "cbuffer vertexBuffer : register(b0) \ + {\ + float4x4 ProjectionMatrix; \ + };\ + struct VS_INPUT\ + {\ + float2 pos : POSITION;\ + float4 col : COLOR0;\ + float2 uv : TEXCOORD0;\ + };\ + \ + struct PS_INPUT\ + {\ + float4 pos : SV_POSITION;\ + float4 col : COLOR0;\ + float2 uv : TEXCOORD0;\ + };\ + \ + PS_INPUT main(VS_INPUT input)\ + {\ + PS_INPUT output;\ + output.pos = mul( ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));\ + output.col = input.col;\ + output.uv = input.uv;\ + return output;\ + }"; + + D3DCompile(vertexShader, strlen(vertexShader), NULL, NULL, NULL, "main", "vs_4_0", 0, 0, &g_pVertexShaderBlob, NULL); + if (g_pVertexShaderBlob == NULL) // NB: Pass ID3D10Blob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob! + return false; + if (g_pd3dDevice->CreateVertexShader((DWORD*)g_pVertexShaderBlob->GetBufferPointer(), g_pVertexShaderBlob->GetBufferSize(), NULL, &g_pVertexShader) != S_OK) + return false; + + // Create the input layout + D3D11_INPUT_ELEMENT_DESC local_layout[] = + { + { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->pos), D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->uv), D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (size_t)(&((ImDrawVert*)0)->col), D3D11_INPUT_PER_VERTEX_DATA, 0 }, + }; + if (g_pd3dDevice->CreateInputLayout(local_layout, 3, g_pVertexShaderBlob->GetBufferPointer(), g_pVertexShaderBlob->GetBufferSize(), &g_pInputLayout) != S_OK) + return false; + + // Create the constant buffer + { + D3D11_BUFFER_DESC desc; + desc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER); + desc.Usage = D3D11_USAGE_DYNAMIC; + desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + desc.MiscFlags = 0; + g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pVertexConstantBuffer); + } + } + + // Create the pixel shader + { + static const char* pixelShader = + "struct PS_INPUT\ + {\ + float4 pos : SV_POSITION;\ + float4 col : COLOR0;\ + float2 uv : TEXCOORD0;\ + };\ + sampler sampler0;\ + Texture2D texture0;\ + \ + float4 main(PS_INPUT input) : SV_Target\ + {\ + float4 out_col = input.col * texture0.Sample(sampler0, input.uv); \ + out_col.rgb *= out_col.a; \ + return out_col; \ + }"; + + D3DCompile(pixelShader, strlen(pixelShader), NULL, NULL, NULL, "main", "ps_4_0", 0, 0, &g_pPixelShaderBlob, NULL); + if (g_pPixelShaderBlob == NULL) // NB: Pass ID3D10Blob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob! + return false; + if (g_pd3dDevice->CreatePixelShader((DWORD*)g_pPixelShaderBlob->GetBufferPointer(), g_pPixelShaderBlob->GetBufferSize(), NULL, &g_pPixelShader) != S_OK) + return false; + } + + // Create the blending setup + { + D3D11_BLEND_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + desc.AlphaToCoverageEnable = false; + desc.RenderTarget[0].BlendEnable = true; + desc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE; + desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; + desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; + desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; + desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; + desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; + desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; + g_pd3dDevice->CreateBlendState(&desc, &g_pBlendState); + } + + // Create the rasterizer state + { + D3D11_RASTERIZER_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + desc.FillMode = D3D11_FILL_SOLID; + desc.CullMode = D3D11_CULL_NONE; + desc.ScissorEnable = true; + desc.DepthClipEnable = true; + g_pd3dDevice->CreateRasterizerState(&desc, &g_pRasterizerState); + } + + // Create depth-stencil State + { + D3D11_DEPTH_STENCIL_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + desc.DepthEnable = false; + desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; + desc.DepthFunc = D3D11_COMPARISON_ALWAYS; + desc.StencilEnable = false; + desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; + desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + desc.BackFace = desc.FrontFace; + g_pd3dDevice->CreateDepthStencilState(&desc, &g_pDepthStencilState); + } + + ImGui_ImplDX11_CreateFontsTexture(); + + for (auto& texture : g_Textures) + ImGui_UploadTexture(texture); + + return true; +} + +void ImGui_ImplDX11_InvalidateDeviceObjects() +{ + if (!g_pd3dDevice) + return; + + for (auto& texture : g_Textures) + ImGui_ReleaseTexture(texture); + + if (g_pFontTextureID) + { + ImGui_DestroyTexture(g_pFontTextureID); + g_pFontTextureID = NULL; + } + + if (g_pFontSampler) { g_pFontSampler->Release(); g_pFontSampler = NULL; } + if (g_pIB) { g_pIB->Release(); g_pIB = NULL; } + if (g_pVB) { g_pVB->Release(); g_pVB = NULL; } + + if (g_pBlendState) { g_pBlendState->Release(); g_pBlendState = NULL; } + if (g_pDepthStencilState) { g_pDepthStencilState->Release(); g_pDepthStencilState = NULL; } + if (g_pRasterizerState) { g_pRasterizerState->Release(); g_pRasterizerState = NULL; } + if (g_pPixelShader) { g_pPixelShader->Release(); g_pPixelShader = NULL; } + if (g_pPixelShaderBlob) { g_pPixelShaderBlob->Release(); g_pPixelShaderBlob = NULL; } + if (g_pVertexConstantBuffer) { g_pVertexConstantBuffer->Release(); g_pVertexConstantBuffer = NULL; } + if (g_pInputLayout) { g_pInputLayout->Release(); g_pInputLayout = NULL; } + if (g_pVertexShader) { g_pVertexShader->Release(); g_pVertexShader = NULL; } + if (g_pVertexShaderBlob) { g_pVertexShaderBlob->Release(); g_pVertexShaderBlob = NULL; } +} + +bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context) +{ + // Setup back-end capabilities flags + ImGuiIO& io = ImGui::GetIO(); + io.BackendRendererName = "imgui_impl_dx11"; + io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. + + // Get factory from device + IDXGIDevice* pDXGIDevice = NULL; + IDXGIAdapter* pDXGIAdapter = NULL; + IDXGIFactory* pFactory = NULL; + + if (device->QueryInterface(IID_PPV_ARGS(&pDXGIDevice)) == S_OK) + if (pDXGIDevice->GetParent(IID_PPV_ARGS(&pDXGIAdapter)) == S_OK) + if (pDXGIAdapter->GetParent(IID_PPV_ARGS(&pFactory)) == S_OK) + { + g_pd3dDevice = device; + g_pd3dDeviceContext = device_context; + g_pFactory = pFactory; + } + if (pDXGIDevice) pDXGIDevice->Release(); + if (pDXGIAdapter) pDXGIAdapter->Release(); + g_pd3dDevice->AddRef(); + g_pd3dDeviceContext->AddRef(); + + g_Textures.reserve(16); + + return true; +} + +void ImGui_ImplDX11_Shutdown() +{ + ImGui_ImplDX11_InvalidateDeviceObjects(); + if (g_pFactory) { g_pFactory->Release(); g_pFactory = NULL; } + if (g_pd3dDevice) { g_pd3dDevice->Release(); g_pd3dDevice = NULL; } + if (g_pd3dDeviceContext) { g_pd3dDeviceContext->Release(); g_pd3dDeviceContext = NULL; } +} + +void ImGui_ImplDX11_NewFrame() +{ + if (!g_pFontSampler) + ImGui_ImplDX11_CreateDeviceObjects(); +} + +extern "C" { +#define STB_IMAGE_IMPLEMENTATION +#define STB_IMAGE_STATIC +#include "stb_image.h" +} + +ImTextureID ImGui_LoadTexture(const char* path) +{ + int width = 0, height = 0, component = 0; + if (auto data = stbi_load(path, &width, &height, &component, 4)) + { + auto texture = ImGui_CreateTexture(data, width, height); + stbi_image_free(data); + return texture; + } + else + return nullptr; +} + +ImTextureID ImGui_CreateTexture(const void* data, int width, int height) +{ + auto texture = IM_NEW(TEXTURE); + texture->Width = width; + texture->Height = height; + texture->Data.resize(width * height * 4); + memcpy(texture->Data.Data, data, texture->Data.Size); + + if (!ImGui_UploadTexture(texture)) + { + IM_DELETE(texture); + return nullptr; + } + + g_Textures.push_back(texture); + + return (ImTextureID)texture; +} + +void ImGui_DestroyTexture(ImTextureID texture) +{ + if (!texture) + return; + + TEXTURE* texture_object = (TEXTURE*)(texture); + + ImGui_ReleaseTexture(texture_object); + + for (TEXTURE** it = g_Textures.begin(), **itEnd = g_Textures.end(); it != itEnd; ++it) + { + if (*it == texture_object) + { + g_Textures.erase(it); + break; + } + } + + IM_DELETE(texture_object); +} + +static bool ImGui_UploadTexture(TEXTURE* texture) +{ + if (!g_pd3dDevice || !texture) + return false; + + if (texture->View) + return true; + + D3D11_TEXTURE2D_DESC desc = {}; + desc.Width = texture->Width; + desc.Height = texture->Height; + desc.MipLevels = 1; + desc.ArraySize = 1; + desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + desc.SampleDesc.Count = 1; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + desc.CPUAccessFlags = 0; + + D3D11_SUBRESOURCE_DATA subResource = {}; + subResource.pSysMem = texture->Data.Data; + subResource.SysMemPitch = desc.Width * 4; + subResource.SysMemSlicePitch = 0; + + ID3D11Texture2D *pTexture = nullptr; + g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture); + + if (!pTexture) + return false; + + // Create texture view + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; + srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + srvDesc.Texture2D.MipLevels = desc.MipLevels; + srvDesc.Texture2D.MostDetailedMip = 0; + + g_pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &texture->View); + pTexture->Release(); + + return true; +} + +static void ImGui_ReleaseTexture(TEXTURE* texture) +{ + if (texture) + { + if (texture->View) + { + texture->View->Release(); + texture->View = nullptr; + } + } +} + +int ImGui_GetTextureWidth(ImTextureID texture) +{ + if (TEXTURE* tex = (TEXTURE*)(texture)) + return tex->Width; + else + return 0; +} + +int ImGui_GetTextureHeight(ImTextureID texture) +{ + if (TEXTURE* tex = (TEXTURE*)(texture)) + return tex->Height; + else + return 0; +} \ No newline at end of file diff --git a/3rdparty/imgui-node-editor/examples/application/source/imgui_impl_dx11.h b/3rdparty/imgui-node-editor/examples/application/source/imgui_impl_dx11.h new file mode 100644 index 0000000..eb032fc --- /dev/null +++ b/3rdparty/imgui-node-editor/examples/application/source/imgui_impl_dx11.h @@ -0,0 +1,29 @@ +// dear imgui: Renderer for DirectX11 +// This needs to be used along with a Platform Binding (e.g. Win32) + +// Implemented features: +// [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID in imgui.cpp. + +// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. +// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. +// https://github.com/ocornut/imgui + +#pragma once + +struct ID3D11Device; +struct ID3D11DeviceContext; + +IMGUI_IMPL_API bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context); +IMGUI_IMPL_API void ImGui_ImplDX11_Shutdown(); +IMGUI_IMPL_API void ImGui_ImplDX11_NewFrame(); +IMGUI_IMPL_API void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data); + +// Use if you want to reset your rendering device without losing ImGui state. +IMGUI_IMPL_API void ImGui_ImplDX11_InvalidateDeviceObjects(); +IMGUI_IMPL_API bool ImGui_ImplDX11_CreateDeviceObjects(); + +IMGUI_IMPL_API ImTextureID ImGui_LoadTexture(const char* path); +IMGUI_IMPL_API ImTextureID ImGui_CreateTexture(const void* data, int width, int height); +IMGUI_IMPL_API void ImGui_DestroyTexture(ImTextureID texture); +IMGUI_IMPL_API int ImGui_GetTextureWidth(ImTextureID texture); +IMGUI_IMPL_API int ImGui_GetTextureHeight(ImTextureID texture); diff --git a/3rdparty/imgui-node-editor/examples/application/source/imgui_impl_glfw.cpp b/3rdparty/imgui-node-editor/examples/application/source/imgui_impl_glfw.cpp new file mode 100644 index 0000000..e24bb3e --- /dev/null +++ b/3rdparty/imgui-node-editor/examples/application/source/imgui_impl_glfw.cpp @@ -0,0 +1,382 @@ +// dear imgui: Platform Binding for GLFW +// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan..) +// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.) +// (Requires: GLFW 3.1+) + +// Implemented features: +// [X] Platform: Clipboard support. +// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. +// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+). +// [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE). + +// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. +// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. +// https://github.com/ocornut/imgui + +// CHANGELOG +// (minor and older changes stripped away, please see git history for details) +// 2020-01-17: Inputs: Disable error callback while assigning mouse cursors because some X11 setup don't have them and it generates errors. +// 2019-12-05: Inputs: Added support for new mouse cursors added in GLFW 3.4+ (resizing cursors, not allowed cursor). +// 2019-10-18: Misc: Previously installed user callbacks are now restored on shutdown. +// 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter. +// 2019-05-11: Inputs: Don't filter value from character callback before calling AddInputCharacter(). +// 2019-03-12: Misc: Preserve DisplayFramebufferScale when main window is minimized. +// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window. +// 2018-11-07: Inputs: When installing our GLFW callbacks, we save user's previously installed ones - if any - and chain call them. +// 2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls. +// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor. +// 2018-06-08: Misc: Extracted imgui_impl_glfw.cpp/.h away from the old combined GLFW+OpenGL/Vulkan examples. +// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag. +// 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value, passed to glfwSetCursor()). +// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves. +// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space. +// 2018-01-25: Inputs: Added gamepad support if ImGuiConfigFlags_NavEnableGamepad is set. +// 2018-01-25: Inputs: Honoring the io.WantSetMousePos by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavMoveMouse is set). +// 2018-01-20: Inputs: Added Horizontal Mouse Wheel support. +// 2018-01-18: Inputs: Added mapping for ImGuiKey_Insert. +// 2017-08-25: Inputs: MousePos set to -FLT_MAX,-FLT_MAX when mouse is unavailable/missing (instead of -1,-1). +// 2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers. + +#include "imgui.h" +#include "imgui_impl_glfw.h" +#include "imgui_extra_keys.h" + +// GLFW +#include +#ifdef _WIN32 +#undef APIENTRY +#define GLFW_EXPOSE_NATIVE_WIN32 +#include // for glfwGetWin32Window +#endif +#define GLFW_HAS_WINDOW_TOPMOST (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ GLFW_FLOATING +#define GLFW_HAS_WINDOW_HOVERED (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ GLFW_HOVERED +#define GLFW_HAS_WINDOW_ALPHA (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwSetWindowOpacity +#define GLFW_HAS_PER_MONITOR_DPI (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwGetMonitorContentScale +#define GLFW_HAS_VULKAN (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ glfwCreateWindowSurface +#ifdef GLFW_RESIZE_NESW_CURSOR // let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2019-11-29 (cursors defines) // FIXME: Remove when GLFW 3.4 is released? +#define GLFW_HAS_NEW_CURSORS (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3400) // 3.4+ GLFW_RESIZE_ALL_CURSOR, GLFW_RESIZE_NESW_CURSOR, GLFW_RESIZE_NWSE_CURSOR, GLFW_NOT_ALLOWED_CURSOR +#else +#define GLFW_HAS_NEW_CURSORS (0) +#endif + +// Data +enum GlfwClientApi +{ + GlfwClientApi_Unknown, + GlfwClientApi_OpenGL, + GlfwClientApi_Vulkan +}; +static GLFWwindow* g_Window = NULL; // Main window +static GlfwClientApi g_ClientApi = GlfwClientApi_Unknown; +static double g_Time = 0.0; +static bool g_MouseJustPressed[ImGuiMouseButton_COUNT] = {}; +static GLFWcursor* g_MouseCursors[ImGuiMouseCursor_COUNT] = {}; +static bool g_InstalledCallbacks = false; + +// Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any. +static GLFWmousebuttonfun g_PrevUserCallbackMousebutton = NULL; +static GLFWscrollfun g_PrevUserCallbackScroll = NULL; +static GLFWkeyfun g_PrevUserCallbackKey = NULL; +static GLFWcharfun g_PrevUserCallbackChar = NULL; + +static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data) +{ + return glfwGetClipboardString((GLFWwindow*)user_data); +} + +static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text) +{ + glfwSetClipboardString((GLFWwindow*)user_data, text); +} + +void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods) +{ + if (g_PrevUserCallbackMousebutton != NULL) + g_PrevUserCallbackMousebutton(window, button, action, mods); + + if (action == GLFW_PRESS && button >= 0 && button < IM_ARRAYSIZE(g_MouseJustPressed)) + g_MouseJustPressed[button] = true; +} + +void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset) +{ + if (g_PrevUserCallbackScroll != NULL) + g_PrevUserCallbackScroll(window, xoffset, yoffset); + + ImGuiIO& io = ImGui::GetIO(); + io.MouseWheelH += (float)xoffset; + io.MouseWheel += (float)yoffset; +} + +void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) +{ + if (g_PrevUserCallbackKey != NULL) + g_PrevUserCallbackKey(window, key, scancode, action, mods); + + ImGuiIO& io = ImGui::GetIO(); + if (action == GLFW_PRESS) + io.KeysDown[key] = true; + if (action == GLFW_RELEASE) + io.KeysDown[key] = false; + + // Modifiers are not reliable across systems + io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL]; + io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT]; + io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT]; +#ifdef _WIN32 + io.KeySuper = false; +#else + io.KeySuper = io.KeysDown[GLFW_KEY_LEFT_SUPER] || io.KeysDown[GLFW_KEY_RIGHT_SUPER]; +#endif +} + +void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c) +{ + if (g_PrevUserCallbackChar != NULL) + g_PrevUserCallbackChar(window, c); + + ImGuiIO& io = ImGui::GetIO(); + io.AddInputCharacter(c); +} + +static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api) +{ + g_Window = window; + g_Time = 0.0; + + // Setup back-end capabilities flags + ImGuiIO& io = ImGui::GetIO(); + io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) + io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) + io.BackendPlatformName = "imgui_impl_glfw"; + + // Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array. + io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; + io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT; + io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT; + io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP; + io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN; + io.KeyMap[ImGuiKey_PageUp] = GLFW_KEY_PAGE_UP; + io.KeyMap[ImGuiKey_PageDown] = GLFW_KEY_PAGE_DOWN; + io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME; + io.KeyMap[ImGuiKey_End] = GLFW_KEY_END; + io.KeyMap[ImGuiKey_Insert] = GLFW_KEY_INSERT; + io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE; + io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE; + io.KeyMap[ImGuiKey_Space] = GLFW_KEY_SPACE; + io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER; + io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE; + io.KeyMap[ImGuiKey_KeyPadEnter] = GLFW_KEY_KP_ENTER; + io.KeyMap[ImGuiKey_A] = GLFW_KEY_A; + io.KeyMap[ImGuiKey_C] = GLFW_KEY_C; + io.KeyMap[ImGuiKey_V] = GLFW_KEY_V; + io.KeyMap[ImGuiKey_X] = GLFW_KEY_X; + io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y; + io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z; + + int f_index = GetEnumValueForF(); + int d_index = GetEnumValueForD(); + if (f_index >= 0) + io.KeyMap[f_index] = GLFW_KEY_F; + if (d_index >= 0) + io.KeyMap[d_index] = GLFW_KEY_D; + + io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText; + io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText; + io.ClipboardUserData = g_Window; +#if defined(_WIN32) + //io.ImeWindowHandle = (void*)glfwGetWin32Window(g_Window); +#endif + + // Create mouse cursors + // (By design, on X11 cursors are user configurable and some cursors may be missing. When a cursor doesn't exist, + // GLFW will emit an error which will often be printed by the app, so we temporarily disable error reporting. + // Missing cursors will return NULL and our _UpdateMouseCursor() function will use the Arrow cursor instead.) + GLFWerrorfun prev_error_callback = glfwSetErrorCallback(NULL); + g_MouseCursors[ImGuiMouseCursor_Arrow] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); + g_MouseCursors[ImGuiMouseCursor_TextInput] = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR); + g_MouseCursors[ImGuiMouseCursor_ResizeNS] = glfwCreateStandardCursor(GLFW_VRESIZE_CURSOR); + g_MouseCursors[ImGuiMouseCursor_ResizeEW] = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR); + g_MouseCursors[ImGuiMouseCursor_Hand] = glfwCreateStandardCursor(GLFW_HAND_CURSOR); +#if GLFW_HAS_NEW_CURSORS + g_MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_RESIZE_ALL_CURSOR); + g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_RESIZE_NESW_CURSOR); + g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_RESIZE_NWSE_CURSOR); + g_MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_NOT_ALLOWED_CURSOR); +#else + g_MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); + g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); + g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); + g_MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); +#endif + glfwSetErrorCallback(prev_error_callback); + + // Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any. + g_PrevUserCallbackMousebutton = NULL; + g_PrevUserCallbackScroll = NULL; + g_PrevUserCallbackKey = NULL; + g_PrevUserCallbackChar = NULL; + if (install_callbacks) + { + g_InstalledCallbacks = true; + g_PrevUserCallbackMousebutton = glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback); + g_PrevUserCallbackScroll = glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback); + g_PrevUserCallbackKey = glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback); + g_PrevUserCallbackChar = glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback); + } + + g_ClientApi = client_api; + return true; +} + +bool ImGui_ImplGlfw_InitForNone(GLFWwindow* window, bool install_callbacks) +{ + return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Unknown); +} + +bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks) +{ + return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_OpenGL); +} + +bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks) +{ + return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Vulkan); +} + +void ImGui_ImplGlfw_Shutdown() +{ + if (g_InstalledCallbacks) + { + glfwSetMouseButtonCallback(g_Window, g_PrevUserCallbackMousebutton); + glfwSetScrollCallback(g_Window, g_PrevUserCallbackScroll); + glfwSetKeyCallback(g_Window, g_PrevUserCallbackKey); + glfwSetCharCallback(g_Window, g_PrevUserCallbackChar); + g_InstalledCallbacks = false; + } + + for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++) + { + glfwDestroyCursor(g_MouseCursors[cursor_n]); + g_MouseCursors[cursor_n] = NULL; + } + g_ClientApi = GlfwClientApi_Unknown; +} + +static void ImGui_ImplGlfw_UpdateMousePosAndButtons() +{ + // Update buttons + ImGuiIO& io = ImGui::GetIO(); + for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) + { + // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. + io.MouseDown[i] = g_MouseJustPressed[i] || glfwGetMouseButton(g_Window, i) != 0; + g_MouseJustPressed[i] = false; + } + + // Update mouse position + const ImVec2 mouse_pos_backup = io.MousePos; + io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX); +#ifdef __EMSCRIPTEN__ + const bool focused = true; // Emscripten +#else + const bool focused = glfwGetWindowAttrib(g_Window, GLFW_FOCUSED) != 0; +#endif + if (focused) + { + if (io.WantSetMousePos) + { + glfwSetCursorPos(g_Window, (double)mouse_pos_backup.x, (double)mouse_pos_backup.y); + } + else + { + double mouse_x, mouse_y; + glfwGetCursorPos(g_Window, &mouse_x, &mouse_y); + io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); + } + } +} + +static void ImGui_ImplGlfw_UpdateMouseCursor() +{ + ImGuiIO& io = ImGui::GetIO(); + if ((io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) || glfwGetInputMode(g_Window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED) + return; + + ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor(); + if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor) + { + // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor + glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); + } + else + { + // Show OS mouse cursor + // FIXME-PLATFORM: Unfocused windows seems to fail changing the mouse cursor with GLFW 3.2, but 3.3 works here. + glfwSetCursor(g_Window, g_MouseCursors[imgui_cursor] ? g_MouseCursors[imgui_cursor] : g_MouseCursors[ImGuiMouseCursor_Arrow]); + glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); + } +} + +static void ImGui_ImplGlfw_UpdateGamepads() +{ + ImGuiIO& io = ImGui::GetIO(); + memset(io.NavInputs, 0, sizeof(io.NavInputs)); + if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) + return; + + // Update gamepad inputs + #define MAP_BUTTON(NAV_NO, BUTTON_NO) { if (buttons_count > BUTTON_NO && buttons[BUTTON_NO] == GLFW_PRESS) io.NavInputs[NAV_NO] = 1.0f; } + #define MAP_ANALOG(NAV_NO, AXIS_NO, V0, V1) { float v = (axes_count > AXIS_NO) ? axes[AXIS_NO] : V0; v = (v - V0) / (V1 - V0); if (v > 1.0f) v = 1.0f; if (io.NavInputs[NAV_NO] < v) io.NavInputs[NAV_NO] = v; } + int axes_count = 0, buttons_count = 0; + const float* axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1, &axes_count); + const unsigned char* buttons = glfwGetJoystickButtons(GLFW_JOYSTICK_1, &buttons_count); + MAP_BUTTON(ImGuiNavInput_Activate, 0); // Cross / A + MAP_BUTTON(ImGuiNavInput_Cancel, 1); // Circle / B + MAP_BUTTON(ImGuiNavInput_Menu, 2); // Square / X + MAP_BUTTON(ImGuiNavInput_Input, 3); // Triangle / Y + MAP_BUTTON(ImGuiNavInput_DpadLeft, 13); // D-Pad Left + MAP_BUTTON(ImGuiNavInput_DpadRight, 11); // D-Pad Right + MAP_BUTTON(ImGuiNavInput_DpadUp, 10); // D-Pad Up + MAP_BUTTON(ImGuiNavInput_DpadDown, 12); // D-Pad Down + MAP_BUTTON(ImGuiNavInput_FocusPrev, 4); // L1 / LB + MAP_BUTTON(ImGuiNavInput_FocusNext, 5); // R1 / RB + MAP_BUTTON(ImGuiNavInput_TweakSlow, 4); // L1 / LB + MAP_BUTTON(ImGuiNavInput_TweakFast, 5); // R1 / RB + MAP_ANALOG(ImGuiNavInput_LStickLeft, 0, -0.3f, -0.9f); + MAP_ANALOG(ImGuiNavInput_LStickRight,0, +0.3f, +0.9f); + MAP_ANALOG(ImGuiNavInput_LStickUp, 1, +0.3f, +0.9f); + MAP_ANALOG(ImGuiNavInput_LStickDown, 1, -0.3f, -0.9f); + #undef MAP_BUTTON + #undef MAP_ANALOG + if (axes_count > 0 && buttons_count > 0) + io.BackendFlags |= ImGuiBackendFlags_HasGamepad; + else + io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad; +} + +void ImGui_ImplGlfw_NewFrame() +{ + ImGuiIO& io = ImGui::GetIO(); + IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame()."); + + // Setup display size (every frame to accommodate for window resizing) + int w, h; + int display_w, display_h; + glfwGetWindowSize(g_Window, &w, &h); + glfwGetFramebufferSize(g_Window, &display_w, &display_h); + io.DisplaySize = ImVec2((float)w, (float)h); + if (w > 0 && h > 0) + io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h); + + // Setup time step + double current_time = glfwGetTime(); + io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f / 60.0f); + g_Time = current_time; + + ImGui_ImplGlfw_UpdateMousePosAndButtons(); + ImGui_ImplGlfw_UpdateMouseCursor(); + + // Update game controllers (if enabled and available) + ImGui_ImplGlfw_UpdateGamepads(); +} diff --git a/3rdparty/imgui-node-editor/examples/application/source/imgui_impl_glfw.h b/3rdparty/imgui-node-editor/examples/application/source/imgui_impl_glfw.h new file mode 100644 index 0000000..b051279 --- /dev/null +++ b/3rdparty/imgui-node-editor/examples/application/source/imgui_impl_glfw.h @@ -0,0 +1,36 @@ +// dear imgui: Platform Binding for GLFW +// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan..) +// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.) + +// Implemented features: +// [X] Platform: Clipboard support. +// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. +// [x] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: 3 cursors types are missing from GLFW. +// [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE). + +// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. +// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. +// https://github.com/ocornut/imgui + +// About GLSL version: +// The 'glsl_version' initialization parameter defaults to "#version 150" if NULL. +// Only override if your GL version doesn't handle this GLSL version. Keep NULL if unsure! + +#pragma once +#include "imgui.h" // IMGUI_IMPL_API + +struct GLFWwindow; + +IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForNone(GLFWwindow* window, bool install_callbacks); +IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks); +IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks); +IMGUI_IMPL_API void ImGui_ImplGlfw_Shutdown(); +IMGUI_IMPL_API void ImGui_ImplGlfw_NewFrame(); + +// GLFW callbacks +// - When calling Init with 'install_callbacks=true': GLFW callbacks will be installed for you. They will call user's previously installed callbacks, if any. +// - When calling Init with 'install_callbacks=false': GLFW callbacks won't be installed. You will need to call those function yourself from your own GLFW callbacks. +IMGUI_IMPL_API void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods); +IMGUI_IMPL_API void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset); +IMGUI_IMPL_API void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods); +IMGUI_IMPL_API void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c); diff --git a/3rdparty/imgui-node-editor/examples/application/source/imgui_impl_opengl3.cpp b/3rdparty/imgui-node-editor/examples/application/source/imgui_impl_opengl3.cpp new file mode 100644 index 0000000..3e55698 --- /dev/null +++ b/3rdparty/imgui-node-editor/examples/application/source/imgui_impl_opengl3.cpp @@ -0,0 +1,690 @@ +// dear imgui: Renderer for modern OpenGL with shaders / programmatic pipeline +// - Desktop GL: 2.x 3.x 4.x +// - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0) +// This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..) + +// Implemented features: +// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID! +// [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bit indices. + +// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. +// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. +// https://github.com/ocornut/imgui + +// CHANGELOG +// (minor and older changes stripped away, please see git history for details) +// 2020-07-10: OpenGL: Added support for glad2 OpenGL loader. +// 2020-05-08: OpenGL: Made default GLSL version 150 (instead of 130) on OSX. +// 2020-04-21: OpenGL: Fixed handling of glClipControl(GL_UPPER_LEFT) by inverting projection matrix. +// 2020-04-12: OpenGL: Fixed context version check mistakenly testing for 4.0+ instead of 3.2+ to enable ImGuiBackendFlags_RendererHasVtxOffset. +// 2020-03-24: OpenGL: Added support for glbinding 2.x OpenGL loader. +// 2020-01-07: OpenGL: Added support for glbinding 3.x OpenGL loader. +// 2019-10-25: OpenGL: Using a combination of GL define and runtime GL version to decide whether to use glDrawElementsBaseVertex(). Fix building with pre-3.2 GL loaders. +// 2019-09-22: OpenGL: Detect default GL loader using __has_include compiler facility. +// 2019-09-16: OpenGL: Tweak initialization code to allow application calling ImGui_ImplOpenGL3_CreateFontsTexture() before the first NewFrame() call. +// 2019-05-29: OpenGL: Desktop GL only: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag. +// 2019-04-30: OpenGL: Added support for special ImDrawCallback_ResetRenderState callback to reset render state. +// 2019-03-29: OpenGL: Not calling glBindBuffer more than necessary in the render loop. +// 2019-03-15: OpenGL: Added a GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized GL function loaders early. +// 2019-03-03: OpenGL: Fix support for ES 2.0 (WebGL 1.0). +// 2019-02-20: OpenGL: Fix for OSX not supporting OpenGL 4.5, we don't try to read GL_CLIP_ORIGIN even if defined by the headers/loader. +// 2019-02-11: OpenGL: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display. +// 2019-02-01: OpenGL: Using GLSL 410 shaders for any version over 410 (e.g. 430, 450). +// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window. +// 2018-11-13: OpenGL: Support for GL 4.5's glClipControl(GL_UPPER_LEFT) / GL_CLIP_ORIGIN. +// 2018-08-29: OpenGL: Added support for more OpenGL loaders: glew and glad, with comments indicative that any loader can be used. +// 2018-08-09: OpenGL: Default to OpenGL ES 3 on iOS and Android. GLSL version default to "#version 300 ES". +// 2018-07-30: OpenGL: Support for GLSL 300 ES and 410 core. Fixes for Emscripten compilation. +// 2018-07-10: OpenGL: Support for more GLSL versions (based on the GLSL version string). Added error output when shaders fail to compile/link. +// 2018-06-08: Misc: Extracted imgui_impl_opengl3.cpp/.h away from the old combined GLFW/SDL+OpenGL3 examples. +// 2018-06-08: OpenGL: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle. +// 2018-05-25: OpenGL: Removed unnecessary backup/restore of GL_ELEMENT_ARRAY_BUFFER_BINDING since this is part of the VAO state. +// 2018-05-14: OpenGL: Making the call to glBindSampler() optional so 3.2 context won't fail if the function is a NULL pointer. +// 2018-03-06: OpenGL: Added const char* glsl_version parameter to ImGui_ImplOpenGL3_Init() so user can override the GLSL version e.g. "#version 150". +// 2018-02-23: OpenGL: Create the VAO in the render function so the setup can more easily be used with multiple shared GL context. +// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplSdlGL3_RenderDrawData() in the .h file so you can call it yourself. +// 2018-01-07: OpenGL: Changed GLSL shader version from 330 to 150. +// 2017-09-01: OpenGL: Save and restore current bound sampler. Save and restore current polygon mode. +// 2017-05-01: OpenGL: Fixed save and restore of current blend func state. +// 2017-05-01: OpenGL: Fixed save and restore of current GL_ACTIVE_TEXTURE. +// 2016-09-05: OpenGL: Fixed save and restore of current scissor rectangle. +// 2016-07-29: OpenGL: Explicitly setting GL_UNPACK_ROW_LENGTH to reduce issues because SDL changes it. (#752) + +//---------------------------------------- +// OpenGL GLSL GLSL +// version version string +//---------------------------------------- +// 2.0 110 "#version 110" +// 2.1 120 "#version 120" +// 3.0 130 "#version 130" +// 3.1 140 "#version 140" +// 3.2 150 "#version 150" +// 3.3 330 "#version 330 core" +// 4.0 400 "#version 400 core" +// 4.1 410 "#version 410 core" +// 4.2 420 "#version 410 core" +// 4.3 430 "#version 430 core" +// ES 2.0 100 "#version 100" = WebGL 1.0 +// ES 3.0 300 "#version 300 es" = WebGL 2.0 +//---------------------------------------- + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include "imgui.h" +#include "imgui_impl_opengl3.h" +#include +#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier +#include // intptr_t +#else +#include // intptr_t +#endif + + +// GL includes +#if defined(IMGUI_IMPL_OPENGL_ES2) +#include +#elif defined(IMGUI_IMPL_OPENGL_ES3) +#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV)) +#include // Use GL ES 3 +#else +#include // Use GL ES 3 +#endif +#else +// About Desktop OpenGL function loaders: +// Modern desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers. +// Helper libraries are often used for this purpose! Here we are supporting a few common ones (gl3w, glew, glad). +// You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own. +#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) +#include // Needs to be initialized with gl3wInit() in user's code +#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) +#include // Needs to be initialized with glewInit() in user's code. +#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) +#include // Needs to be initialized with gladLoadGL() in user's code. +#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2) +#include // Needs to be initialized with gladLoadGL(...) or gladLoaderLoadGL() in user's code. +#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2) +#ifndef GLFW_INCLUDE_NONE +#define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors. +#endif +#include // Needs to be initialized with glbinding::Binding::initialize() in user's code. +#include +using namespace gl; +#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3) +#ifndef GLFW_INCLUDE_NONE +#define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors. +#endif +#include // Needs to be initialized with glbinding::initialize() in user's code. +#include +using namespace gl; +#else +#include IMGUI_IMPL_OPENGL_LOADER_CUSTOM +#endif +#endif + +// Desktop GL 3.2+ has glDrawElementsBaseVertex() which GL ES and WebGL don't have. +#if defined(IMGUI_IMPL_OPENGL_ES2) || defined(IMGUI_IMPL_OPENGL_ES3) || !defined(GL_VERSION_3_2) +#define IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET 0 +#else +#define IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET 1 +#endif + +// OpenGL Data +static GLuint g_GlVersion = 0; // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries (e.g. 320 for GL 3.2) +static char g_GlslVersionString[32] = ""; // Specified by user or detected based on compile time GL settings. +static GLuint g_FontTexture = 0; +static GLuint g_ShaderHandle = 0, g_VertHandle = 0, g_FragHandle = 0; +static GLint g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0; // Uniforms location +static GLuint g_AttribLocationVtxPos = 0, g_AttribLocationVtxUV = 0, g_AttribLocationVtxColor = 0; // Vertex attributes location +static unsigned int g_VboHandle = 0, g_ElementsHandle = 0; + +// Functions +bool ImGui_ImplOpenGL3_Init(const char* glsl_version) +{ + // Query for GL version (e.g. 320 for GL 3.2) +#if !defined(IMGUI_IMPL_OPENGL_ES2) + GLint major, minor; + glGetIntegerv(GL_MAJOR_VERSION, &major); + glGetIntegerv(GL_MINOR_VERSION, &minor); + g_GlVersion = (GLuint)(major * 100 + minor * 10); +#else + g_GlVersion = 200; // GLES 2 +#endif + + // Setup back-end capabilities flags + ImGuiIO& io = ImGui::GetIO(); + io.BackendRendererName = "imgui_impl_opengl3"; +#if IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET + if (g_GlVersion >= 320) + io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. +#endif + + // Store GLSL version string so we can refer to it later in case we recreate shaders. + // Note: GLSL version is NOT the same as GL version. Leave this to NULL if unsure. +#if defined(IMGUI_IMPL_OPENGL_ES2) + if (glsl_version == NULL) + glsl_version = "#version 100"; +#elif defined(IMGUI_IMPL_OPENGL_ES3) + if (glsl_version == NULL) + glsl_version = "#version 300 es"; +#elif defined(__APPLE__) + if (glsl_version == NULL) + glsl_version = "#version 150"; +#else + if (glsl_version == NULL) + glsl_version = "#version 130"; +#endif + IM_ASSERT((int)strlen(glsl_version) + 2 < IM_ARRAYSIZE(g_GlslVersionString)); + strcpy(g_GlslVersionString, glsl_version); + strcat(g_GlslVersionString, "\n"); + + // Debugging construct to make it easily visible in the IDE and debugger which GL loader has been selected. + // The code actually never uses the 'gl_loader' variable! It is only here so you can read it! + // If auto-detection fails or doesn't select the same GL loader file as used by your application, + // you are likely to get a crash below. + // You can explicitly select a loader by using '#define IMGUI_IMPL_OPENGL_LOADER_XXX' in imconfig.h or compiler command-line. + const char* gl_loader = "Unknown"; + IM_UNUSED(gl_loader); +#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) + gl_loader = "GL3W"; +#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) + gl_loader = "GLEW"; +#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) + gl_loader = "GLAD"; +#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2) + gl_loader = "GLAD2"; +#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2) + gl_loader = "glbinding2"; +#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3) + gl_loader = "glbinding3"; +#elif defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM) + gl_loader = "custom"; +#else + gl_loader = "none"; +#endif + + // Make an arbitrary GL call (we don't actually need the result) + // IF YOU GET A CRASH HERE: it probably means that you haven't initialized the OpenGL function loader used by this code. + // Desktop OpenGL 3/4 need a function loader. See the IMGUI_IMPL_OPENGL_LOADER_xxx explanation above. + GLint current_texture; + glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_texture); + + return true; +} + +void ImGui_ImplOpenGL3_Shutdown() +{ + ImGui_ImplOpenGL3_DestroyDeviceObjects(); +} + +void ImGui_ImplOpenGL3_NewFrame() +{ + if (!g_ShaderHandle) + ImGui_ImplOpenGL3_CreateDeviceObjects(); +} + +static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height, GLuint vertex_array_object) +{ + // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill + glEnable(GL_BLEND); + glBlendEquation(GL_FUNC_ADD); + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + glEnable(GL_SCISSOR_TEST); +#ifdef GL_POLYGON_MODE + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); +#endif + + // Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT) + bool clip_origin_lower_left = true; +#if defined(GL_CLIP_ORIGIN) && !defined(__APPLE__) + GLenum current_clip_origin = 0; glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)¤t_clip_origin); + if (current_clip_origin == GL_UPPER_LEFT) + clip_origin_lower_left = false; +#endif + + // Setup viewport, orthographic projection matrix + // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps. + glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height); + float L = draw_data->DisplayPos.x; + float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x; + float T = draw_data->DisplayPos.y; + float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y; + if (!clip_origin_lower_left) { float tmp = T; T = B; B = tmp; } // Swap top and bottom if origin is upper left + const float ortho_projection[4][4] = + { + { 2.0f/(R-L), 0.0f, 0.0f, 0.0f }, + { 0.0f, 2.0f/(T-B), 0.0f, 0.0f }, + { 0.0f, 0.0f, -1.0f, 0.0f }, + { (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f }, + }; + glUseProgram(g_ShaderHandle); + glUniform1i(g_AttribLocationTex, 0); + glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]); +#ifdef GL_SAMPLER_BINDING + glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 may set that otherwise. +#endif + + (void)vertex_array_object; +#ifndef IMGUI_IMPL_OPENGL_ES2 + glBindVertexArray(vertex_array_object); +#endif + + // Bind vertex/index buffers and setup attributes for ImDrawVert + glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_ElementsHandle); + glEnableVertexAttribArray(g_AttribLocationVtxPos); + glEnableVertexAttribArray(g_AttribLocationVtxUV); + glEnableVertexAttribArray(g_AttribLocationVtxColor); + glVertexAttribPointer(g_AttribLocationVtxPos, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, pos)); + glVertexAttribPointer(g_AttribLocationVtxUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, uv)); + glVertexAttribPointer(g_AttribLocationVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, col)); +} + +// OpenGL3 Render function. +// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop) +// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly, in order to be able to run within any OpenGL engine that doesn't do so. +void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) +{ + // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) + int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); + int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); + if (fb_width <= 0 || fb_height <= 0) + return; + + // Backup GL state + GLenum last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint*)&last_active_texture); + glActiveTexture(GL_TEXTURE0); + GLuint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&last_program); + GLuint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)&last_texture); +#ifdef GL_SAMPLER_BINDING + GLuint last_sampler; glGetIntegerv(GL_SAMPLER_BINDING, (GLint*)&last_sampler); +#endif + GLuint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, (GLint*)&last_array_buffer); +#ifndef IMGUI_IMPL_OPENGL_ES2 + GLuint last_vertex_array_object; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, (GLint*)&last_vertex_array_object); +#endif +#ifdef GL_POLYGON_MODE + GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode); +#endif + GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport); + GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box); + GLenum last_blend_src_rgb; glGetIntegerv(GL_BLEND_SRC_RGB, (GLint*)&last_blend_src_rgb); + GLenum last_blend_dst_rgb; glGetIntegerv(GL_BLEND_DST_RGB, (GLint*)&last_blend_dst_rgb); + GLenum last_blend_src_alpha; glGetIntegerv(GL_BLEND_SRC_ALPHA, (GLint*)&last_blend_src_alpha); + GLenum last_blend_dst_alpha; glGetIntegerv(GL_BLEND_DST_ALPHA, (GLint*)&last_blend_dst_alpha); + GLenum last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, (GLint*)&last_blend_equation_rgb); + GLenum last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, (GLint*)&last_blend_equation_alpha); + GLboolean last_enable_blend = glIsEnabled(GL_BLEND); + GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE); + GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST); + GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST); + + // Setup desired GL state + // Recreate the VAO every time (this is to easily allow multiple GL contexts to be rendered to. VAO are not shared among GL contexts) + // The renderer would actually work without any VAO bound, but then our VertexAttrib calls would overwrite the default one currently bound. + GLuint vertex_array_object = 0; +#ifndef IMGUI_IMPL_OPENGL_ES2 + glGenVertexArrays(1, &vertex_array_object); +#endif + ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object); + + // Will project scissor/clipping rectangles into framebuffer space + ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports + ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2) + + // Render command lists + for (int n = 0; n < draw_data->CmdListsCount; n++) + { + const ImDrawList* cmd_list = draw_data->CmdLists[n]; + + // Upload vertex/index buffers + glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)cmd_list->VtxBuffer.Size * (int)sizeof(ImDrawVert), (const GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)cmd_list->IdxBuffer.Size * (int)sizeof(ImDrawIdx), (const GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW); + + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) + { + const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; + if (pcmd->UserCallback != NULL) + { + // User callback, registered via ImDrawList::AddCallback() + // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) + if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) + ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object); + else + pcmd->UserCallback(cmd_list, pcmd); + } + else + { + // Project scissor/clipping rectangles into framebuffer space + ImVec4 clip_rect; + clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x; + clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y; + clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x; + clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y; + + if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f) + { + // Apply scissor/clipping rectangle + glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y)); + + // Bind texture, Draw + glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId); +#if IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET + if (g_GlVersion >= 320) + glDrawElementsBaseVertex(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)), (GLint)pcmd->VtxOffset); + else +#endif + glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx))); + } + } + } + } + + // Destroy the temporary VAO +#ifndef IMGUI_IMPL_OPENGL_ES2 + glDeleteVertexArrays(1, &vertex_array_object); +#endif + + // Restore modified GL state + glUseProgram(last_program); + glBindTexture(GL_TEXTURE_2D, last_texture); +#ifdef GL_SAMPLER_BINDING + glBindSampler(0, last_sampler); +#endif + glActiveTexture(last_active_texture); +#ifndef IMGUI_IMPL_OPENGL_ES2 + glBindVertexArray(last_vertex_array_object); +#endif + glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer); + glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha); + glBlendFuncSeparate(last_blend_src_rgb, last_blend_dst_rgb, last_blend_src_alpha, last_blend_dst_alpha); + if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND); + if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE); + if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST); + if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST); +#ifdef GL_POLYGON_MODE + glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]); +#endif + glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]); + glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]); +} + +bool ImGui_ImplOpenGL3_CreateFontsTexture() +{ + // Build texture atlas + ImGuiIO& io = ImGui::GetIO(); + unsigned char* pixels; + int width, height; + io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory. + + // Upload texture to graphics system + GLint last_texture; + glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); + glGenTextures(1, &g_FontTexture); + glBindTexture(GL_TEXTURE_2D, g_FontTexture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); +#ifdef GL_UNPACK_ROW_LENGTH + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); +#endif + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + + // Store our identifier + io.Fonts->TexID = (ImTextureID)(intptr_t)g_FontTexture; + + // Restore state + glBindTexture(GL_TEXTURE_2D, last_texture); + + return true; +} + +void ImGui_ImplOpenGL3_DestroyFontsTexture() +{ + if (g_FontTexture) + { + ImGuiIO& io = ImGui::GetIO(); + glDeleteTextures(1, &g_FontTexture); + io.Fonts->TexID = 0; + g_FontTexture = 0; + } +} + +// If you get an error please report on github. You may try different GL context version or GLSL version. See GL<>GLSL version table at the top of this file. +static bool CheckShader(GLuint handle, const char* desc) +{ + GLint status = 0, log_length = 0; + glGetShaderiv(handle, GL_COMPILE_STATUS, &status); + glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &log_length); + if ((GLboolean)status == GL_FALSE) + fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to compile %s!\n", desc); + if (log_length > 1) + { + ImVector buf; + buf.resize((int)(log_length + 1)); + glGetShaderInfoLog(handle, log_length, NULL, (GLchar*)buf.begin()); + fprintf(stderr, "%s\n", buf.begin()); + } + return (GLboolean)status == GL_TRUE; +} + +// If you get an error please report on GitHub. You may try different GL context version or GLSL version. +static bool CheckProgram(GLuint handle, const char* desc) +{ + GLint status = 0, log_length = 0; + glGetProgramiv(handle, GL_LINK_STATUS, &status); + glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &log_length); + if ((GLboolean)status == GL_FALSE) + fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to link %s! (with GLSL '%s')\n", desc, g_GlslVersionString); + if (log_length > 1) + { + ImVector buf; + buf.resize((int)(log_length + 1)); + glGetProgramInfoLog(handle, log_length, NULL, (GLchar*)buf.begin()); + fprintf(stderr, "%s\n", buf.begin()); + } + return (GLboolean)status == GL_TRUE; +} + +bool ImGui_ImplOpenGL3_CreateDeviceObjects() +{ + // Backup GL state + GLint last_texture, last_array_buffer; + glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); + glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer); +#ifndef IMGUI_IMPL_OPENGL_ES2 + GLint last_vertex_array; + glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array); +#endif + + // Parse GLSL version string + int glsl_version = 130; + sscanf(g_GlslVersionString, "#version %d", &glsl_version); + + const GLchar* vertex_shader_glsl_120 = + "uniform mat4 ProjMtx;\n" + "attribute vec2 Position;\n" + "attribute vec2 UV;\n" + "attribute vec4 Color;\n" + "varying vec2 Frag_UV;\n" + "varying vec4 Frag_Color;\n" + "void main()\n" + "{\n" + " Frag_UV = UV;\n" + " Frag_Color = Color;\n" + " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n" + "}\n"; + + const GLchar* vertex_shader_glsl_130 = + "uniform mat4 ProjMtx;\n" + "in vec2 Position;\n" + "in vec2 UV;\n" + "in vec4 Color;\n" + "out vec2 Frag_UV;\n" + "out vec4 Frag_Color;\n" + "void main()\n" + "{\n" + " Frag_UV = UV;\n" + " Frag_Color = Color;\n" + " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n" + "}\n"; + + const GLchar* vertex_shader_glsl_300_es = + "precision mediump float;\n" + "layout (location = 0) in vec2 Position;\n" + "layout (location = 1) in vec2 UV;\n" + "layout (location = 2) in vec4 Color;\n" + "uniform mat4 ProjMtx;\n" + "out vec2 Frag_UV;\n" + "out vec4 Frag_Color;\n" + "void main()\n" + "{\n" + " Frag_UV = UV;\n" + " Frag_Color = Color;\n" + " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n" + "}\n"; + + const GLchar* vertex_shader_glsl_410_core = + "layout (location = 0) in vec2 Position;\n" + "layout (location = 1) in vec2 UV;\n" + "layout (location = 2) in vec4 Color;\n" + "uniform mat4 ProjMtx;\n" + "out vec2 Frag_UV;\n" + "out vec4 Frag_Color;\n" + "void main()\n" + "{\n" + " Frag_UV = UV;\n" + " Frag_Color = Color;\n" + " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n" + "}\n"; + + const GLchar* fragment_shader_glsl_120 = + "#ifdef GL_ES\n" + " precision mediump float;\n" + "#endif\n" + "uniform sampler2D Texture;\n" + "varying vec2 Frag_UV;\n" + "varying vec4 Frag_Color;\n" + "void main()\n" + "{\n" + " vec4 col = Frag_Color * texture2D(Texture, Frag_UV.st);\n" + " col.xyz *= col.w;" + " gl_FragColor = col;\n" + "}\n"; + + const GLchar* fragment_shader_glsl_130 = + "uniform sampler2D Texture;\n" + "in vec2 Frag_UV;\n" + "in vec4 Frag_Color;\n" + "out vec4 Out_Color;\n" + "void main()\n" + "{\n" + " vec4 col = Frag_Color * texture2D(Texture, Frag_UV.st);\n" + " col.xyz *= col.w;" + " gl_FragColor = col;\n" + "}\n"; + + const GLchar* fragment_shader_glsl_300_es = + "precision mediump float;\n" + "uniform sampler2D Texture;\n" + "in vec2 Frag_UV;\n" + "in vec4 Frag_Color;\n" + "layout (location = 0) out vec4 Out_Color;\n" + "void main()\n" + "{\n" + " vec4 col = Frag_Color * texture2D(Texture, Frag_UV.st);\n" + " col.xyz *= col.w;" + " gl_FragColor = col;\n" + "}\n"; + + const GLchar* fragment_shader_glsl_410_core = + "in vec2 Frag_UV;\n" + "in vec4 Frag_Color;\n" + "uniform sampler2D Texture;\n" + "layout (location = 0) out vec4 Out_Color;\n" + "void main()\n" + "{\n" + " vec4 col = Frag_Color * texture2D(Texture, Frag_UV.st);\n" + " col.xyz *= col.w;" + " gl_FragColor = col;\n" + "}\n"; + + // Select shaders matching our GLSL versions + const GLchar* vertex_shader = NULL; + const GLchar* fragment_shader = NULL; + if (glsl_version < 130) + { + vertex_shader = vertex_shader_glsl_120; + fragment_shader = fragment_shader_glsl_120; + } + else if (glsl_version >= 410) + { + vertex_shader = vertex_shader_glsl_410_core; + fragment_shader = fragment_shader_glsl_410_core; + } + else if (glsl_version == 300) + { + vertex_shader = vertex_shader_glsl_300_es; + fragment_shader = fragment_shader_glsl_300_es; + } + else + { + vertex_shader = vertex_shader_glsl_130; + fragment_shader = fragment_shader_glsl_130; + } + + // Create shaders + const GLchar* vertex_shader_with_version[2] = { g_GlslVersionString, vertex_shader }; + g_VertHandle = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(g_VertHandle, 2, vertex_shader_with_version, NULL); + glCompileShader(g_VertHandle); + CheckShader(g_VertHandle, "vertex shader"); + + const GLchar* fragment_shader_with_version[2] = { g_GlslVersionString, fragment_shader }; + g_FragHandle = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(g_FragHandle, 2, fragment_shader_with_version, NULL); + glCompileShader(g_FragHandle); + CheckShader(g_FragHandle, "fragment shader"); + + g_ShaderHandle = glCreateProgram(); + glAttachShader(g_ShaderHandle, g_VertHandle); + glAttachShader(g_ShaderHandle, g_FragHandle); + glLinkProgram(g_ShaderHandle); + CheckProgram(g_ShaderHandle, "shader program"); + + g_AttribLocationTex = glGetUniformLocation(g_ShaderHandle, "Texture"); + g_AttribLocationProjMtx = glGetUniformLocation(g_ShaderHandle, "ProjMtx"); + g_AttribLocationVtxPos = (GLuint)glGetAttribLocation(g_ShaderHandle, "Position"); + g_AttribLocationVtxUV = (GLuint)glGetAttribLocation(g_ShaderHandle, "UV"); + g_AttribLocationVtxColor = (GLuint)glGetAttribLocation(g_ShaderHandle, "Color"); + + // Create buffers + glGenBuffers(1, &g_VboHandle); + glGenBuffers(1, &g_ElementsHandle); + + ImGui_ImplOpenGL3_CreateFontsTexture(); + + // Restore modified GL state + glBindTexture(GL_TEXTURE_2D, last_texture); + glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer); +#ifndef IMGUI_IMPL_OPENGL_ES2 + glBindVertexArray(last_vertex_array); +#endif + + return true; +} + +void ImGui_ImplOpenGL3_DestroyDeviceObjects() +{ + if (g_VboHandle) { glDeleteBuffers(1, &g_VboHandle); g_VboHandle = 0; } + if (g_ElementsHandle) { glDeleteBuffers(1, &g_ElementsHandle); g_ElementsHandle = 0; } + if (g_ShaderHandle && g_VertHandle) { glDetachShader(g_ShaderHandle, g_VertHandle); } + if (g_ShaderHandle && g_FragHandle) { glDetachShader(g_ShaderHandle, g_FragHandle); } + if (g_VertHandle) { glDeleteShader(g_VertHandle); g_VertHandle = 0; } + if (g_FragHandle) { glDeleteShader(g_FragHandle); g_FragHandle = 0; } + if (g_ShaderHandle) { glDeleteProgram(g_ShaderHandle); g_ShaderHandle = 0; } + + ImGui_ImplOpenGL3_DestroyFontsTexture(); +} diff --git a/3rdparty/imgui-node-editor/examples/application/source/imgui_impl_opengl3.h b/3rdparty/imgui-node-editor/examples/application/source/imgui_impl_opengl3.h new file mode 100644 index 0000000..14eb284 --- /dev/null +++ b/3rdparty/imgui-node-editor/examples/application/source/imgui_impl_opengl3.h @@ -0,0 +1,87 @@ +// dear imgui: Renderer for modern OpenGL with shaders / programmatic pipeline +// - Desktop GL: 2.x 3.x 4.x +// - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0) +// This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..) + +// Implemented features: +// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID! +// [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bit indices. + +// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. +// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. +// https://github.com/ocornut/imgui + +// About Desktop OpenGL function loaders: +// Modern Desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers. +// Helper libraries are often used for this purpose! Here we are supporting a few common ones (gl3w, glew, glad). +// You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own. + +// About GLSL version: +// The 'glsl_version' initialization parameter should be NULL (default) or a "#version XXX" string. +// On computer platform the GLSL version default to "#version 130". On OpenGL ES 3 platform it defaults to "#version 300 es" +// Only override if your GL version doesn't handle this GLSL version. See GLSL version table at the top of imgui_impl_opengl3.cpp. + +#pragma once +#include "imgui.h" // IMGUI_IMPL_API + +// Backend API +IMGUI_IMPL_API bool ImGui_ImplOpenGL3_Init(const char* glsl_version = NULL); +IMGUI_IMPL_API void ImGui_ImplOpenGL3_Shutdown(); +IMGUI_IMPL_API void ImGui_ImplOpenGL3_NewFrame(); +IMGUI_IMPL_API void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data); + +// (Optional) Called by Init/NewFrame/Shutdown +IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateFontsTexture(); +IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyFontsTexture(); +IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateDeviceObjects(); +IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects(); + +// Specific OpenGL ES versions +//#define IMGUI_IMPL_OPENGL_ES2 // Auto-detected on Emscripten +//#define IMGUI_IMPL_OPENGL_ES3 // Auto-detected on iOS/Android + +// Attempt to auto-detect the default Desktop GL loader based on available header files. +// If auto-detection fails or doesn't select the same GL loader file as used by your application, +// you are likely to get a crash in ImGui_ImplOpenGL3_Init(). +// You can explicitly select a loader by using one of the '#define IMGUI_IMPL_OPENGL_LOADER_XXX' in imconfig.h or compiler command-line. +#if !defined(IMGUI_IMPL_OPENGL_ES2) \ + && !defined(IMGUI_IMPL_OPENGL_ES3) \ + && !defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) \ + && !defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) \ + && !defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) \ + && !defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2) \ + && !defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2) \ + && !defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3) \ + && !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM) + +// Try to detect GLES on matching platforms +#if defined(__APPLE__) +#include "TargetConditionals.h" +#endif +#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV)) || (defined(__ANDROID__)) +#define IMGUI_IMPL_OPENGL_ES3 // iOS, Android -> GL ES 3, "#version 300 es" +#elif defined(__EMSCRIPTEN__) +#define IMGUI_IMPL_OPENGL_ES2 // Emscripten -> GL ES 2, "#version 100" + +// Otherwise try to detect supported Desktop OpenGL loaders.. +#elif defined(__has_include) +#if __has_include() + #define IMGUI_IMPL_OPENGL_LOADER_GLEW +#elif __has_include() + #define IMGUI_IMPL_OPENGL_LOADER_GLAD +#elif __has_include() + #define IMGUI_IMPL_OPENGL_LOADER_GLAD2 +#elif __has_include() + #define IMGUI_IMPL_OPENGL_LOADER_GL3W +#elif __has_include() + #define IMGUI_IMPL_OPENGL_LOADER_GLBINDING3 +#elif __has_include() + #define IMGUI_IMPL_OPENGL_LOADER_GLBINDING2 +#else + #error "Cannot detect OpenGL loader!" +#endif +#else + #define IMGUI_IMPL_OPENGL_LOADER_GL3W // Default to GL3W embedded in our repository +#endif + +#endif diff --git a/3rdparty/imgui-node-editor/examples/application/source/imgui_impl_win32.cpp b/3rdparty/imgui-node-editor/examples/application/source/imgui_impl_win32.cpp new file mode 100644 index 0000000..6f158de --- /dev/null +++ b/3rdparty/imgui-node-editor/examples/application/source/imgui_impl_win32.cpp @@ -0,0 +1,458 @@ +// dear imgui: Platform Binding for Windows (standard windows API for 32 and 64 bits applications) +// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..) + +// Implemented features: +// [X] Platform: Clipboard support (for Win32 this is actually part of core dear imgui) +// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. +// [X] Platform: Keyboard arrays indexed using VK_* Virtual Key Codes, e.g. ImGui::IsKeyPressed(VK_SPACE). +// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. + +#include "imgui.h" +#include "imgui_impl_win32.h" +#include "imgui_extra_keys.h" +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#include + +// Using XInput library for gamepad (with recent Windows SDK this may leads to executables which won't run on Windows 7) +#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD +#include +#else +#define IMGUI_IMPL_WIN32_DISABLE_LINKING_XINPUT +#endif +#if defined(_MSC_VER) && !defined(IMGUI_IMPL_WIN32_DISABLE_LINKING_XINPUT) +#pragma comment(lib, "xinput") +//#pragma comment(lib, "Xinput9_1_0") +#endif + +// CHANGELOG +// (minor and older changes stripped away, please see git history for details) +// 2020-03-03: Inputs: Calling AddInputCharacterUTF16() to support surrogate pairs leading to codepoint >= 0x10000 (for more complete CJK inputs) +// 2020-02-17: Added ImGui_ImplWin32_EnableDpiAwareness(), ImGui_ImplWin32_GetDpiScaleForHwnd(), ImGui_ImplWin32_GetDpiScaleForMonitor() helper functions. +// 2020-01-14: Inputs: Added support for #define IMGUI_IMPL_WIN32_DISABLE_GAMEPAD/IMGUI_IMPL_WIN32_DISABLE_LINKING_XINPUT. +// 2019-12-05: Inputs: Added support for ImGuiMouseCursor_NotAllowed mouse cursor. +// 2019-05-11: Inputs: Don't filter value from WM_CHAR before calling AddInputCharacter(). +// 2019-01-17: Misc: Using GetForegroundWindow()+IsChild() instead of GetActiveWindow() to be compatible with windows created in a different thread or parent. +// 2019-01-17: Inputs: Added support for mouse buttons 4 and 5 via WM_XBUTTON* messages. +// 2019-01-15: Inputs: Added support for XInput gamepads (if ImGuiConfigFlags_NavEnableGamepad is set by user application). +// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window. +// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor. +// 2018-06-10: Inputs: Fixed handling of mouse wheel messages to support fine position messages (typically sent by track-pads). +// 2018-06-08: Misc: Extracted imgui_impl_win32.cpp/.h away from the old combined DX9/DX10/DX11/DX12 examples. +// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors and ImGuiBackendFlags_HasSetMousePos flags + honor ImGuiConfigFlags_NoMouseCursorChange flag. +// 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value and WM_SETCURSOR message handling). +// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space. +// 2018-02-06: Inputs: Honoring the io.WantSetMousePos by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavMoveMouse is set). +// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves. +// 2018-01-20: Inputs: Added Horizontal Mouse Wheel support. +// 2018-01-08: Inputs: Added mapping for ImGuiKey_Insert. +// 2018-01-05: Inputs: Added WM_LBUTTONDBLCLK double-click handlers for window classes with the CS_DBLCLKS flag. +// 2017-10-23: Inputs: Added WM_SYSKEYDOWN / WM_SYSKEYUP handlers so e.g. the VK_MENU key can be read. +// 2017-10-23: Inputs: Using Win32 ::SetCapture/::GetCapture() to retrieve mouse positions outside the client area when dragging. +// 2016-11-12: Inputs: Only call Win32 ::SetCursor(NULL) when io.MouseDrawCursor is set. + +// Win32 Data +static HWND g_hWnd = NULL; +static INT64 g_Time = 0; +static INT64 g_TicksPerSecond = 0; +static ImGuiMouseCursor g_LastMouseCursor = ImGuiMouseCursor_COUNT; +static bool g_HasGamepad = false; +static bool g_WantUpdateHasGamepad = true; + +// Functions +bool ImGui_ImplWin32_Init(void* hwnd) +{ + if (!::QueryPerformanceFrequency((LARGE_INTEGER*)&g_TicksPerSecond)) + return false; + if (!::QueryPerformanceCounter((LARGE_INTEGER*)&g_Time)) + return false; + + // Setup back-end capabilities flags + g_hWnd = (HWND)hwnd; + ImGuiIO& io = ImGui::GetIO(); + io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) + io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) + io.BackendPlatformName = "imgui_impl_win32"; + //io.ImeWindowHandle = hwnd; + + // Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array that we will update during the application lifetime. + io.KeyMap[ImGuiKey_Tab] = VK_TAB; + io.KeyMap[ImGuiKey_LeftArrow] = VK_LEFT; + io.KeyMap[ImGuiKey_RightArrow] = VK_RIGHT; + io.KeyMap[ImGuiKey_UpArrow] = VK_UP; + io.KeyMap[ImGuiKey_DownArrow] = VK_DOWN; + io.KeyMap[ImGuiKey_PageUp] = VK_PRIOR; + io.KeyMap[ImGuiKey_PageDown] = VK_NEXT; + io.KeyMap[ImGuiKey_Home] = VK_HOME; + io.KeyMap[ImGuiKey_End] = VK_END; + io.KeyMap[ImGuiKey_Insert] = VK_INSERT; + io.KeyMap[ImGuiKey_Delete] = VK_DELETE; + io.KeyMap[ImGuiKey_Backspace] = VK_BACK; + io.KeyMap[ImGuiKey_Space] = VK_SPACE; + io.KeyMap[ImGuiKey_Enter] = VK_RETURN; + io.KeyMap[ImGuiKey_Escape] = VK_ESCAPE; + io.KeyMap[ImGuiKey_KeyPadEnter] = VK_RETURN; + io.KeyMap[ImGuiKey_A] = 'A'; + io.KeyMap[ImGuiKey_C] = 'C'; + io.KeyMap[ImGuiKey_V] = 'V'; + io.KeyMap[ImGuiKey_X] = 'X'; + io.KeyMap[ImGuiKey_Y] = 'Y'; + io.KeyMap[ImGuiKey_Z] = 'Z'; + + int f_index = GetEnumValueForF(); + int d_index = GetEnumValueForD(); + if (f_index >= 0) + io.KeyMap[f_index] = 'F'; + if (d_index >= 0) + io.KeyMap[d_index] = 'D'; + + return true; +} + +void ImGui_ImplWin32_Shutdown() +{ + g_hWnd = (HWND)0; +} + +static bool ImGui_ImplWin32_UpdateMouseCursor() +{ + ImGuiIO& io = ImGui::GetIO(); + if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) + return false; + + ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor(); + if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor) + { + // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor + ::SetCursor(NULL); + } + else + { + // Show OS mouse cursor + LPTSTR win32_cursor = IDC_ARROW; + switch (imgui_cursor) + { + case ImGuiMouseCursor_Arrow: win32_cursor = IDC_ARROW; break; + case ImGuiMouseCursor_TextInput: win32_cursor = IDC_IBEAM; break; + case ImGuiMouseCursor_ResizeAll: win32_cursor = IDC_SIZEALL; break; + case ImGuiMouseCursor_ResizeEW: win32_cursor = IDC_SIZEWE; break; + case ImGuiMouseCursor_ResizeNS: win32_cursor = IDC_SIZENS; break; + case ImGuiMouseCursor_ResizeNESW: win32_cursor = IDC_SIZENESW; break; + case ImGuiMouseCursor_ResizeNWSE: win32_cursor = IDC_SIZENWSE; break; + case ImGuiMouseCursor_Hand: win32_cursor = IDC_HAND; break; + case ImGuiMouseCursor_NotAllowed: win32_cursor = IDC_NO; break; + } + ::SetCursor(::LoadCursor(NULL, win32_cursor)); + } + return true; +} + +static void ImGui_ImplWin32_UpdateMousePos() +{ + ImGuiIO& io = ImGui::GetIO(); + + // Set OS mouse position if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user) + if (io.WantSetMousePos) + { + POINT pos = { (int)(io.MousePos.x), (int)(io.MousePos.y) }; + ::ClientToScreen(g_hWnd, &pos); + ::SetCursorPos(pos.x, pos.y); + } + + // Set mouse position + io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX); + POINT pos; + if (HWND active_window = ::GetForegroundWindow()) + if (active_window == g_hWnd || ::IsChild(active_window, g_hWnd)) + if (::GetCursorPos(&pos) && ::ScreenToClient(g_hWnd, &pos)) + io.MousePos = ImVec2((float)pos.x, (float)pos.y); +} + +// Gamepad navigation mapping +static void ImGui_ImplWin32_UpdateGamepads() +{ +#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD + ImGuiIO& io = ImGui::GetIO(); + memset(io.NavInputs, 0, sizeof(io.NavInputs)); + if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) + return; + + // Calling XInputGetState() every frame on disconnected gamepads is unfortunately too slow. + // Instead we refresh gamepad availability by calling XInputGetCapabilities() _only_ after receiving WM_DEVICECHANGE. + if (g_WantUpdateHasGamepad) + { + XINPUT_CAPABILITIES caps; + g_HasGamepad = (XInputGetCapabilities(0, XINPUT_FLAG_GAMEPAD, &caps) == ERROR_SUCCESS); + g_WantUpdateHasGamepad = false; + } + + XINPUT_STATE xinput_state; + io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad; + if (g_HasGamepad && XInputGetState(0, &xinput_state) == ERROR_SUCCESS) + { + const XINPUT_GAMEPAD& gamepad = xinput_state.Gamepad; + io.BackendFlags |= ImGuiBackendFlags_HasGamepad; + + #define MAP_BUTTON(NAV_NO, BUTTON_ENUM) { io.NavInputs[NAV_NO] = (gamepad.wButtons & BUTTON_ENUM) ? 1.0f : 0.0f; } + #define MAP_ANALOG(NAV_NO, VALUE, V0, V1) { float vn = (float)(VALUE - V0) / (float)(V1 - V0); if (vn > 1.0f) vn = 1.0f; if (vn > 0.0f && io.NavInputs[NAV_NO] < vn) io.NavInputs[NAV_NO] = vn; } + MAP_BUTTON(ImGuiNavInput_Activate, XINPUT_GAMEPAD_A); // Cross / A + MAP_BUTTON(ImGuiNavInput_Cancel, XINPUT_GAMEPAD_B); // Circle / B + MAP_BUTTON(ImGuiNavInput_Menu, XINPUT_GAMEPAD_X); // Square / X + MAP_BUTTON(ImGuiNavInput_Input, XINPUT_GAMEPAD_Y); // Triangle / Y + MAP_BUTTON(ImGuiNavInput_DpadLeft, XINPUT_GAMEPAD_DPAD_LEFT); // D-Pad Left + MAP_BUTTON(ImGuiNavInput_DpadRight, XINPUT_GAMEPAD_DPAD_RIGHT); // D-Pad Right + MAP_BUTTON(ImGuiNavInput_DpadUp, XINPUT_GAMEPAD_DPAD_UP); // D-Pad Up + MAP_BUTTON(ImGuiNavInput_DpadDown, XINPUT_GAMEPAD_DPAD_DOWN); // D-Pad Down + MAP_BUTTON(ImGuiNavInput_FocusPrev, XINPUT_GAMEPAD_LEFT_SHOULDER); // L1 / LB + MAP_BUTTON(ImGuiNavInput_FocusNext, XINPUT_GAMEPAD_RIGHT_SHOULDER); // R1 / RB + MAP_BUTTON(ImGuiNavInput_TweakSlow, XINPUT_GAMEPAD_LEFT_SHOULDER); // L1 / LB + MAP_BUTTON(ImGuiNavInput_TweakFast, XINPUT_GAMEPAD_RIGHT_SHOULDER); // R1 / RB + MAP_ANALOG(ImGuiNavInput_LStickLeft, gamepad.sThumbLX, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768); + MAP_ANALOG(ImGuiNavInput_LStickRight, gamepad.sThumbLX, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767); + MAP_ANALOG(ImGuiNavInput_LStickUp, gamepad.sThumbLY, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767); + MAP_ANALOG(ImGuiNavInput_LStickDown, gamepad.sThumbLY, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32767); + #undef MAP_BUTTON + #undef MAP_ANALOG + } +#endif // #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD +} + +void ImGui_ImplWin32_NewFrame() +{ + ImGuiIO& io = ImGui::GetIO(); + IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame()."); + + // Setup display size (every frame to accommodate for window resizing) + RECT rect; + ::GetClientRect(g_hWnd, &rect); + io.DisplaySize = ImVec2((float)(rect.right - rect.left), (float)(rect.bottom - rect.top)); + + // Setup time step + INT64 current_time; + ::QueryPerformanceCounter((LARGE_INTEGER*)¤t_time); + io.DeltaTime = (float)(current_time - g_Time) / g_TicksPerSecond; + g_Time = current_time; + + // Read keyboard modifiers inputs + io.KeyCtrl = (::GetKeyState(VK_CONTROL) & 0x8000) != 0; + io.KeyShift = (::GetKeyState(VK_SHIFT) & 0x8000) != 0; + io.KeyAlt = (::GetKeyState(VK_MENU) & 0x8000) != 0; + io.KeySuper = false; + // io.KeysDown[], io.MousePos, io.MouseDown[], io.MouseWheel: filled by the WndProc handler below. + + // Update OS mouse position + ImGui_ImplWin32_UpdateMousePos(); + + // Update OS mouse cursor with the cursor requested by imgui + ImGuiMouseCursor mouse_cursor = io.MouseDrawCursor ? ImGuiMouseCursor_None : ImGui::GetMouseCursor(); + if (g_LastMouseCursor != mouse_cursor) + { + g_LastMouseCursor = mouse_cursor; + ImGui_ImplWin32_UpdateMouseCursor(); + } + + // Update game controllers (if enabled and available) + ImGui_ImplWin32_UpdateGamepads(); +} + +// Allow compilation with old Windows SDK. MinGW doesn't have default _WIN32_WINNT/WINVER versions. +#ifndef WM_MOUSEHWHEEL +#define WM_MOUSEHWHEEL 0x020E +#endif +#ifndef DBT_DEVNODES_CHANGED +#define DBT_DEVNODES_CHANGED 0x0007 +#endif + +// Win32 message handler (process Win32 mouse/keyboard inputs, etc.) +// Call from your application's message handler. +// When implementing your own back-end, you can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if Dear ImGui wants to use your inputs. +// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application. +// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application. +// Generally you may always pass all inputs to Dear ImGui, and hide them from your application based on those two flags. +// PS: In this Win32 handler, we use the capture API (GetCapture/SetCapture/ReleaseCapture) to be able to read mouse coordinates when dragging mouse outside of our window bounds. +// PS: We treat DBLCLK messages as regular mouse down messages, so this code will work on windows classes that have the CS_DBLCLKS flag set. Our own example app code doesn't set this flag. +#if 0 +// Copy this line into your .cpp file to forward declare the function. +extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); +#endif +IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + if (ImGui::GetCurrentContext() == NULL) + return 0; + + ImGuiIO& io = ImGui::GetIO(); + switch (msg) + { + case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK: + case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK: + case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK: + case WM_XBUTTONDOWN: case WM_XBUTTONDBLCLK: + { + int button = 0; + if (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONDBLCLK) { button = 0; } + if (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONDBLCLK) { button = 1; } + if (msg == WM_MBUTTONDOWN || msg == WM_MBUTTONDBLCLK) { button = 2; } + if (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONDBLCLK) { button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) ? 3 : 4; } + if (!ImGui::IsAnyMouseDown() && ::GetCapture() == NULL) + ::SetCapture(hwnd); + io.MouseDown[button] = true; + return 0; + } + case WM_LBUTTONUP: + case WM_RBUTTONUP: + case WM_MBUTTONUP: + case WM_XBUTTONUP: + { + int button = 0; + if (msg == WM_LBUTTONUP) { button = 0; } + if (msg == WM_RBUTTONUP) { button = 1; } + if (msg == WM_MBUTTONUP) { button = 2; } + if (msg == WM_XBUTTONUP) { button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) ? 3 : 4; } + io.MouseDown[button] = false; + if (!ImGui::IsAnyMouseDown() && ::GetCapture() == hwnd) + ::ReleaseCapture(); + return 0; + } + case WM_MOUSEWHEEL: + io.MouseWheel += (float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA; + return 0; + case WM_MOUSEHWHEEL: + io.MouseWheelH += (float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA; + return 0; + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + if (wParam < 256) + io.KeysDown[wParam] = 1; + return 0; + case WM_KEYUP: + case WM_SYSKEYUP: + if (wParam < 256) + io.KeysDown[wParam] = 0; + return 0; + case WM_CHAR: + // You can also use ToAscii()+GetKeyboardState() to retrieve characters. + if (wParam > 0 && wParam < 0x10000) + io.AddInputCharacterUTF16((unsigned short)wParam); + return 0; + case WM_SETCURSOR: + if (LOWORD(lParam) == HTCLIENT && ImGui_ImplWin32_UpdateMouseCursor()) + return 1; + return 0; + case WM_DEVICECHANGE: + if ((UINT)wParam == DBT_DEVNODES_CHANGED) + g_WantUpdateHasGamepad = true; + return 0; + case WM_KILLFOCUS: + for (int n = 0; n < IM_ARRAYSIZE(io.KeysDown); n++) + io.KeysDown[n] = false; + break; + } + return 0; +} + + +//-------------------------------------------------------------------------------------------------------- +// DPI-related helpers (optional) +//-------------------------------------------------------------------------------------------------------- +// - Use to enable DPI awareness without having to create an application manifest. +// - Your own app may already do this via a manifest or explicit calls. This is mostly useful for our examples/ apps. +// - In theory we could call simple functions from Windows SDK such as SetProcessDPIAware(), SetProcessDpiAwareness(), etc. +// but most of the functions provided by Microsoft require Windows 8.1/10+ SDK at compile time and Windows 8/10+ at runtime, +// neither we want to require the user to have. So we dynamically select and load those functions to avoid dependencies. +//--------------------------------------------------------------------------------------------------------- +// This is the scheme successfully used by GLFW (from which we borrowed some of the code) and other apps aiming to be highly portable. +// ImGui_ImplWin32_EnableDpiAwareness() is just a helper called by main.cpp, we don't call it automatically. +// If you are trying to implement your own back-end for your own engine, you may ignore that noise. +//--------------------------------------------------------------------------------------------------------- + +// Implement some of the functions and types normally declared in recent Windows SDK. +#if !defined(_versionhelpers_H_INCLUDED_) && !defined(_INC_VERSIONHELPERS) +static BOOL IsWindowsVersionOrGreater(WORD major, WORD minor, WORD sp) +{ + OSVERSIONINFOEXW osvi = { sizeof(osvi), major, minor, 0, 0, { 0 }, sp, 0, 0, 0, 0 }; + DWORD mask = VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR; + ULONGLONG cond = ::VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL); + cond = ::VerSetConditionMask(cond, VER_MINORVERSION, VER_GREATER_EQUAL); + cond = ::VerSetConditionMask(cond, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); + return ::VerifyVersionInfoW(&osvi, mask, cond); +} +#define IsWindows8Point1OrGreater() IsWindowsVersionOrGreater(HIBYTE(0x0602), LOBYTE(0x0602), 0) // _WIN32_WINNT_WINBLUE +#endif + +#ifndef DPI_ENUMS_DECLARED +typedef enum { PROCESS_DPI_UNAWARE = 0, PROCESS_SYSTEM_DPI_AWARE = 1, PROCESS_PER_MONITOR_DPI_AWARE = 2 } PROCESS_DPI_AWARENESS; +typedef enum { MDT_EFFECTIVE_DPI = 0, MDT_ANGULAR_DPI = 1, MDT_RAW_DPI = 2, MDT_DEFAULT = MDT_EFFECTIVE_DPI } MONITOR_DPI_TYPE; +#endif +#ifndef _DPI_AWARENESS_CONTEXTS_ +DECLARE_HANDLE(DPI_AWARENESS_CONTEXT); +#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE (DPI_AWARENESS_CONTEXT)-3 +#endif +#ifndef DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 +#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 (DPI_AWARENESS_CONTEXT)-4 +#endif +typedef HRESULT(WINAPI* PFN_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS); // Shcore.lib + dll, Windows 8.1+ +typedef HRESULT(WINAPI* PFN_GetDpiForMonitor)(HMONITOR, MONITOR_DPI_TYPE, UINT*, UINT*); // Shcore.lib + dll, Windows 8.1+ +typedef DPI_AWARENESS_CONTEXT(WINAPI* PFN_SetThreadDpiAwarenessContext)(DPI_AWARENESS_CONTEXT); // User32.lib + dll, Windows 10 v1607+ (Creators Update) + +// Helper function to enable DPI awareness without setting up a manifest +void ImGui_ImplWin32_EnableDpiAwareness() +{ + // if (IsWindows10OrGreater()) // This needs a manifest to succeed. Instead we try to grab the function pointer! + { + static HINSTANCE user32_dll = ::LoadLibraryA("user32.dll"); // Reference counted per-process + if (PFN_SetThreadDpiAwarenessContext SetThreadDpiAwarenessContextFn = (PFN_SetThreadDpiAwarenessContext)::GetProcAddress(user32_dll, "SetThreadDpiAwarenessContext")) + { + SetThreadDpiAwarenessContextFn(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); + return; + } + } + if (IsWindows8Point1OrGreater()) + { + static HINSTANCE shcore_dll = ::LoadLibraryA("shcore.dll"); // Reference counted per-process + if (PFN_SetProcessDpiAwareness SetProcessDpiAwarenessFn = (PFN_SetProcessDpiAwareness)::GetProcAddress(shcore_dll, "SetProcessDpiAwareness")) + { + SetProcessDpiAwarenessFn(PROCESS_PER_MONITOR_DPI_AWARE); + return; + } + } +#if _WIN32_WINNT >= 0x0600 + ::SetProcessDPIAware(); +#endif +} + +#if defined(_MSC_VER) && !defined(NOGDI) +#pragma comment(lib, "gdi32") // Link with gdi32.lib for GetDeviceCaps() +#endif + +float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor) +{ + UINT xdpi = 96, ydpi = 96; + static BOOL bIsWindows8Point1OrGreater = IsWindows8Point1OrGreater(); + if (bIsWindows8Point1OrGreater) + { + static HINSTANCE shcore_dll = ::LoadLibraryA("shcore.dll"); // Reference counted per-process + if (PFN_GetDpiForMonitor GetDpiForMonitorFn = (PFN_GetDpiForMonitor)::GetProcAddress(shcore_dll, "GetDpiForMonitor")) + GetDpiForMonitorFn((HMONITOR)monitor, MDT_EFFECTIVE_DPI, &xdpi, &ydpi); + } +#ifndef NOGDI + else + { + const HDC dc = ::GetDC(NULL); + xdpi = ::GetDeviceCaps(dc, LOGPIXELSX); + ydpi = ::GetDeviceCaps(dc, LOGPIXELSY); + ::ReleaseDC(NULL, dc); + } +#endif + IM_ASSERT(xdpi == ydpi); // Please contact me if you hit this assert! + return xdpi / 96.0f; +} + +float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd) +{ + HMONITOR monitor = ::MonitorFromWindow((HWND)hwnd, MONITOR_DEFAULTTONEAREST); + return ImGui_ImplWin32_GetDpiScaleForMonitor(monitor); +} + +//--------------------------------------------------------------------------------------------------------- diff --git a/3rdparty/imgui-node-editor/examples/application/source/imgui_impl_win32.h b/3rdparty/imgui-node-editor/examples/application/source/imgui_impl_win32.h new file mode 100644 index 0000000..8923bd6 --- /dev/null +++ b/3rdparty/imgui-node-editor/examples/application/source/imgui_impl_win32.h @@ -0,0 +1,37 @@ +// dear imgui: Platform Binding for Windows (standard windows API for 32 and 64 bits applications) +// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..) + +// Implemented features: +// [X] Platform: Clipboard support (for Win32 this is actually part of core dear imgui) +// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. +// [X] Platform: Keyboard arrays indexed using VK_* Virtual Key Codes, e.g. ImGui::IsKeyPressed(VK_SPACE). +// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. + +#pragma once +#include "imgui.h" // IMGUI_IMPL_API + +IMGUI_IMPL_API bool ImGui_ImplWin32_Init(void* hwnd); +IMGUI_IMPL_API void ImGui_ImplWin32_Shutdown(); +IMGUI_IMPL_API void ImGui_ImplWin32_NewFrame(); + +// Configuration +// - Disable gamepad support or linking with xinput.lib +//#define IMGUI_IMPL_WIN32_DISABLE_GAMEPAD +//#define IMGUI_IMPL_WIN32_DISABLE_LINKING_XINPUT + +// Win32 message handler your application need to call. +// - Intentionally commented out in a '#if 0' block to avoid dragging dependencies on from this helper. +// - You should COPY the line below into your .cpp code to forward declare the function and then you can call it. +#if 0 +extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); +#endif + +// DPI-related helpers (optional) +// - Use to enable DPI awareness without having to create an application manifest. +// - Your own app may already do this via a manifest or explicit calls. This is mostly useful for our examples/ apps. +// - In theory we could call simple functions from Windows SDK such as SetProcessDPIAware(), SetProcessDpiAwareness(), etc. +// but most of the functions provided by Microsoft require Windows 8.1/10+ SDK at compile time and Windows 8/10+ at runtime, +// neither we want to require the user to have. So we dynamically select and load those functions to avoid dependencies. +IMGUI_IMPL_API void ImGui_ImplWin32_EnableDpiAwareness(); +IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd); // HWND hwnd +IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor); // HMONITOR monitor diff --git a/3rdparty/imgui-node-editor/examples/application/source/platform.h b/3rdparty/imgui-node-editor/examples/application/source/platform.h new file mode 100644 index 0000000..79afd16 --- /dev/null +++ b/3rdparty/imgui-node-editor/examples/application/source/platform.h @@ -0,0 +1,60 @@ +# pragma once +# include "setup.h" +# include + +struct Application; +struct Renderer; + +struct Platform +{ + virtual ~Platform() {}; + + virtual bool ApplicationStart(int argc, char** argv) = 0; + virtual void ApplicationStop() = 0; + + virtual bool OpenMainWindow(const char* title, int width, int height) = 0; + virtual bool CloseMainWindow() = 0; + virtual void* GetMainWindowHandle() const = 0; + virtual void SetMainWindowTitle(const char* title) = 0; + virtual void ShowMainWindow() = 0; + virtual bool ProcessMainWindowEvents() = 0; + virtual bool IsMainWindowVisible() const = 0; + + virtual void SetRenderer(Renderer* renderer) = 0; + + virtual void NewFrame() = 0; + virtual void FinishFrame() = 0; + + virtual void Quit() = 0; + + bool HasWindowScaleChanged() const { return m_WindowScaleChanged; } + void AcknowledgeWindowScaleChanged() { m_WindowScaleChanged = false; } + float GetWindowScale() const { return m_WindowScale; } + void SetWindowScale(float windowScale) + { + if (windowScale == m_WindowScale) + return; + m_WindowScale = windowScale; + m_WindowScaleChanged = true; + } + + bool HasFramebufferScaleChanged() const { return m_FramebufferScaleChanged; } + void AcknowledgeFramebufferScaleChanged() { m_FramebufferScaleChanged = false; } + float GetFramebufferScale() const { return m_FramebufferScale; } + void SetFramebufferScale(float framebufferScale) + { + if (framebufferScale == m_FramebufferScale) + return; + m_FramebufferScale = framebufferScale; + m_FramebufferScaleChanged = true; + } + + +private: + bool m_WindowScaleChanged = false; + float m_WindowScale = 1.0f; + bool m_FramebufferScaleChanged = false; + float m_FramebufferScale = 1.0f; +}; + +std::unique_ptr CreatePlatform(Application& application); diff --git a/3rdparty/imgui-node-editor/examples/application/source/platform_glfw.cpp b/3rdparty/imgui-node-editor/examples/application/source/platform_glfw.cpp new file mode 100644 index 0000000..6fe71b5 --- /dev/null +++ b/3rdparty/imgui-node-editor/examples/application/source/platform_glfw.cpp @@ -0,0 +1,287 @@ +# include "platform.h" +# include "setup.h" + +# if BACKEND(IMGUI_GLFW) + +# include "application.h" +# include "renderer.h" + +# include + +# if PLATFORM(WINDOWS) +# define GLFW_EXPOSE_NATIVE_WIN32 +# include +# endif + +# include +# include "imgui_impl_glfw.h" + +struct PlatformGLFW final + : Platform +{ + static PlatformGLFW* s_Instance; + + PlatformGLFW(Application& application); + + bool ApplicationStart(int argc, char** argv) override; + void ApplicationStop() override; + bool OpenMainWindow(const char* title, int width, int height) override; + bool CloseMainWindow() override; + void* GetMainWindowHandle() const override; + void SetMainWindowTitle(const char* title) override; + void ShowMainWindow() override; + bool ProcessMainWindowEvents() override; + bool IsMainWindowVisible() const override; + void SetRenderer(Renderer* renderer) override; + void NewFrame() override; + void FinishFrame() override; + void Quit() override; + + void UpdatePixelDensity(); + + Application& m_Application; + GLFWwindow* m_Window = nullptr; + bool m_QuitRequested = false; + bool m_IsMinimized = false; + bool m_WasMinimized = false; + Renderer* m_Renderer = nullptr; +}; + +std::unique_ptr CreatePlatform(Application& application) +{ + return std::make_unique(application); +} + +PlatformGLFW::PlatformGLFW(Application& application) + : m_Application(application) +{ +} + +bool PlatformGLFW::ApplicationStart(int argc, char** argv) +{ + if (!glfwInit()) + return false; + + return true; +} + +void PlatformGLFW::ApplicationStop() +{ + glfwTerminate(); +} + +bool PlatformGLFW::OpenMainWindow(const char* title, int width, int height) +{ + if (m_Window) + return false; + + glfwWindowHint(GLFW_VISIBLE, 0); + + using InitializerType = bool (*)(GLFWwindow* window, bool install_callbacks); + + InitializerType initializer = nullptr; + +# if RENDERER(IMGUI_OGL3) + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); +# if PLATFORM(MACOS) + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); +# ifdef GLFW_COCOA_RETINA_FRAMEBUFFER + glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GL_TRUE); +# endif +# ifdef GLFW_COCOA_GRAPHICS_SWITCHING + glfwWindowHint(GLFW_COCOA_GRAPHICS_SWITCHING, GL_TRUE); +# endif +# endif + initializer = &ImGui_ImplGlfw_InitForOpenGL; +# else + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + initializer = &ImGui_ImplGlfw_InitForNone; +# endif + glfwWindowHint(GLFW_SCALE_TO_MONITOR, GL_TRUE); + + width = width < 0 ? 1440 : width; + height = height < 0 ? 800 : height; + + m_Window = glfwCreateWindow(width, height, title, nullptr, nullptr); + if (!m_Window) + return false; + + if (!initializer || !initializer(m_Window, true)) + { + glfwDestroyWindow(m_Window); + m_Window = nullptr; + return false; + } + + glfwSetWindowUserPointer(m_Window, this); + + glfwSetWindowCloseCallback(m_Window, [](GLFWwindow* window) + { + auto self = reinterpret_cast(glfwGetWindowUserPointer(window)); + if (!self->m_QuitRequested) + self->CloseMainWindow(); + }); + + glfwSetWindowIconifyCallback(m_Window, [](GLFWwindow* window, int iconified) + { + auto self = reinterpret_cast(glfwGetWindowUserPointer(window)); + if (iconified) + { + self->m_IsMinimized = true; + self->m_WasMinimized = true; + } + else + { + self->m_IsMinimized = false; + } + }); + + auto onFramebuferSizeChanged = [](GLFWwindow* window, int width, int height) + { + auto self = reinterpret_cast(glfwGetWindowUserPointer(window)); + if (self->m_Renderer) + { + self->m_Renderer->Resize(width, height); + self->UpdatePixelDensity(); + } + }; + + glfwSetFramebufferSizeCallback(m_Window, onFramebuferSizeChanged); + + auto onWindowContentScaleChanged = [](GLFWwindow* window, float xscale, float yscale) + { + auto self = reinterpret_cast(glfwGetWindowUserPointer(window)); + self->UpdatePixelDensity(); + }; + + glfwSetWindowContentScaleCallback(m_Window, onWindowContentScaleChanged); + + UpdatePixelDensity(); + + glfwMakeContextCurrent(m_Window); + + glfwSwapInterval(1); // Enable vsync + + return true; +} + +bool PlatformGLFW::CloseMainWindow() +{ + if (m_Window == nullptr) + return true; + + auto canClose = m_Application.CanClose(); + + glfwSetWindowShouldClose(m_Window, canClose ? 1 : 0); + + return canClose; +} + +void* PlatformGLFW::GetMainWindowHandle() const +{ +# if PLATFORM(WINDOWS) + return m_Window ? glfwGetWin32Window(m_Window) : nullptr; +# else + return nullptr; +# endif +} + +void PlatformGLFW::SetMainWindowTitle(const char* title) +{ + glfwSetWindowTitle(m_Window, title); +} + +void PlatformGLFW::ShowMainWindow() +{ + if (m_Window == nullptr) + return; + + glfwShowWindow(m_Window); +} + +bool PlatformGLFW::ProcessMainWindowEvents() +{ + if (m_Window == nullptr) + return false; + + if (m_IsMinimized) + glfwWaitEvents(); + else + glfwPollEvents(); + + if (m_QuitRequested || glfwWindowShouldClose(m_Window)) + { + ImGui_ImplGlfw_Shutdown(); + + glfwDestroyWindow(m_Window); + + return false; + } + + return true; +} + +bool PlatformGLFW::IsMainWindowVisible() const +{ + if (m_Window == nullptr) + return false; + + if (m_IsMinimized) + return false; + + return true; +} + +void PlatformGLFW::SetRenderer(Renderer* renderer) +{ + m_Renderer = renderer; +} + +void PlatformGLFW::NewFrame() +{ + ImGui_ImplGlfw_NewFrame(); + + if (m_WasMinimized) + { + ImGui::GetIO().DeltaTime = 0.1e-6f; + m_WasMinimized = false; + } +} + +void PlatformGLFW::FinishFrame() +{ + if (m_Renderer) + m_Renderer->Present(); + + glfwSwapBuffers(m_Window); +} + +void PlatformGLFW::Quit() +{ + m_QuitRequested = true; + + glfwPostEmptyEvent(); +} + +void PlatformGLFW::UpdatePixelDensity() +{ + float xscale, yscale; + glfwGetWindowContentScale(m_Window, &xscale, &yscale); + float scale = xscale > yscale ? xscale : yscale; + +# if PLATFORM(WINDOWS) + float windowScale = scale; + float framebufferScale = scale; +# else + float windowScale = 1.0f; + float framebufferScale = scale; +# endif + + SetWindowScale(windowScale); // this is how windows is scaled, not window content + + SetFramebufferScale(framebufferScale); +} + +# endif // BACKEND(IMGUI_GLFW) \ No newline at end of file diff --git a/3rdparty/imgui-node-editor/examples/application/source/platform_win32.cpp b/3rdparty/imgui-node-editor/examples/application/source/platform_win32.cpp new file mode 100644 index 0000000..f8d05f5 --- /dev/null +++ b/3rdparty/imgui-node-editor/examples/application/source/platform_win32.cpp @@ -0,0 +1,313 @@ +# include "platform.h" +# include "setup.h" + +# if BACKEND(IMGUI_WIN32) + +# include "application.h" +# include "renderer.h" + +# define NOMINMAX +# define WIN32_LEAN_AND_MEAN +# include +# include +# include + +# include +# include "imgui_impl_win32.h" + +# if defined(_UNICODE) +std::wstring Utf8ToNative(const std::string& str) +{ + int size = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), nullptr, 0); + std::wstring result(size, 0); + MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), (wchar_t*)result.data(), size); + return result; +} +# else +std::string Utf8ToNative(const std::string& str) +{ + return str; +} +# endif + +IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + +struct PlatformWin32 final + : Platform +{ + static PlatformWin32* s_Instance; + + PlatformWin32(Application& application); + + bool ApplicationStart(int argc, char** argv) override; + void ApplicationStop() override; + bool OpenMainWindow(const char* title, int width, int height) override; + bool CloseMainWindow() override; + void* GetMainWindowHandle() const override; + void SetMainWindowTitle(const char* title) override; + void ShowMainWindow() override; + bool ProcessMainWindowEvents() override; + bool IsMainWindowVisible() const override; + void SetRenderer(Renderer* renderer) override; + void NewFrame() override; + void FinishFrame() override; + void Quit() override; + + void SetDpiScale(float dpiScale); + + LRESULT WinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + + Application& m_Application; + WNDCLASSEX m_WindowClass = {}; + HWND m_MainWindowHandle = nullptr; + bool m_IsMinimized = false; + bool m_WasMinimized = false; + bool m_CanCloseResult = false; + Renderer* m_Renderer = nullptr; +}; + +std::unique_ptr CreatePlatform(Application& application) +{ + return std::make_unique(application); +} + +PlatformWin32* PlatformWin32::s_Instance = nullptr; + +PlatformWin32::PlatformWin32(Application& application) + : m_Application(application) +{ +} + +bool PlatformWin32::ApplicationStart(int argc, char** argv) +{ + if (s_Instance) + return false; + + s_Instance = this; + + auto winProc = [](HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -> LRESULT + { + return s_Instance->WinProc(hWnd, msg, wParam, lParam); + }; + + m_WindowClass = + { + sizeof(WNDCLASSEX), + CS_CLASSDC, + winProc, + 0L, + 0L, + GetModuleHandle(nullptr), + LoadIcon(GetModuleHandle(nullptr), + IDI_APPLICATION), + LoadCursor(nullptr, IDC_ARROW), + nullptr, + nullptr, + _T("imgui-node-editor-application"), + LoadIcon(GetModuleHandle(nullptr), + IDI_APPLICATION) + }; + + if (!RegisterClassEx(&m_WindowClass)) + { + s_Instance = nullptr; + return false; + } + + ImGui_ImplWin32_EnableDpiAwareness(); + + return true; +} + +void PlatformWin32::ApplicationStop() +{ + if (!s_Instance) + return; + + UnregisterClass(m_WindowClass.lpszClassName, m_WindowClass.hInstance); + + s_Instance = nullptr; +} + + +bool PlatformWin32::OpenMainWindow(const char* title, int width, int height) +{ + if (m_MainWindowHandle) + return false; + + m_MainWindowHandle = CreateWindow( + m_WindowClass.lpszClassName, + Utf8ToNative(title).c_str(), + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, + width < 0 ? CW_USEDEFAULT : width, + height < 0 ? CW_USEDEFAULT : height, + nullptr, nullptr, m_WindowClass.hInstance, nullptr); + + if (!m_MainWindowHandle) + return false; + + if (!ImGui_ImplWin32_Init(m_MainWindowHandle)) + { + DestroyWindow(m_MainWindowHandle); + m_MainWindowHandle = nullptr; + return false; + } + + SetDpiScale(ImGui_ImplWin32_GetDpiScaleForHwnd(m_MainWindowHandle)); + + return true; +} + +bool PlatformWin32::CloseMainWindow() +{ + if (m_MainWindowHandle == nullptr) + return true; + + SendMessage(m_MainWindowHandle, WM_CLOSE, 0, 0); + + return m_CanCloseResult; +} + +void* PlatformWin32::GetMainWindowHandle() const +{ + return m_MainWindowHandle; +} + +void PlatformWin32::SetMainWindowTitle(const char* title) +{ + SetWindowText(m_MainWindowHandle, Utf8ToNative(title).c_str()); +} + +void PlatformWin32::ShowMainWindow() +{ + if (m_MainWindowHandle == nullptr) + return; + + //ShowWindow(m_MainWindowHandle, SW_SHOWMAXIMIZED); + ShowWindow(m_MainWindowHandle, SW_SHOW); + UpdateWindow(m_MainWindowHandle); +} + +bool PlatformWin32::ProcessMainWindowEvents() +{ + if (m_MainWindowHandle == nullptr) + return false; + + auto fetchMessage = [this](MSG* msg) -> bool + { + if (!m_IsMinimized) + return PeekMessage(msg, nullptr, 0U, 0U, PM_REMOVE) != 0; + else + return GetMessage(msg, nullptr, 0U, 0U) != 0; + }; + + MSG msg = {}; + while (fetchMessage(&msg)) + { + if (msg.message == WM_KEYDOWN && (msg.wParam == VK_ESCAPE)) + PostQuitMessage(0); + + if (msg.message == WM_QUIT) + return false; + + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + return true; +} + +bool PlatformWin32::IsMainWindowVisible() const +{ + if (m_MainWindowHandle == nullptr) + return false; + + if (m_IsMinimized) + return false; + + return true; +} + +void PlatformWin32::SetRenderer(Renderer* renderer) +{ + m_Renderer = renderer; +} + +void PlatformWin32::NewFrame() +{ + ImGui_ImplWin32_NewFrame(); + + if (m_WasMinimized) + { + ImGui::GetIO().DeltaTime = 0.1e-6f; + m_WasMinimized = false; + } +} + +void PlatformWin32::FinishFrame() +{ + if (m_Renderer) + m_Renderer->Present(); +} + +void PlatformWin32::Quit() +{ + PostQuitMessage(0); +} + +void PlatformWin32::SetDpiScale(float dpiScale) +{ + SetWindowScale(dpiScale); + SetFramebufferScale(dpiScale); +} + +LRESULT PlatformWin32::WinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam)) + return 1; + + switch (msg) + { + case WM_CLOSE: + m_CanCloseResult = m_Application.CanClose(); + if (m_CanCloseResult) + { + ImGui_ImplWin32_Shutdown(); + DestroyWindow(hWnd); + } + return 0; + + case WM_SIZE: + if (wParam == SIZE_MINIMIZED) + { + m_IsMinimized = true; + m_WasMinimized = true; + } + else if (wParam == SIZE_RESTORED && m_IsMinimized) + { + m_IsMinimized = false; + } + + if (m_Renderer != nullptr && wParam != SIZE_MINIMIZED) + m_Renderer->Resize(static_cast(LOWORD(lParam)), static_cast(HIWORD(lParam))); + return 0; + + case WM_SYSCOMMAND: + if ((wParam & 0xfff0) == SC_KEYMENU) // Disable ALT application menu + return 0; + break; + + case WM_DPICHANGED: + SetDpiScale(ImGui_ImplWin32_GetDpiScaleForHwnd(hWnd)); + return 0; + + case WM_DESTROY: + PostQuitMessage(0); + return 0; + } + + return DefWindowProc(hWnd, msg, wParam, lParam); +} + +# endif // BACKEND(IMGUI_WIN32) \ No newline at end of file diff --git a/3rdparty/imgui-node-editor/examples/application/source/renderer.h b/3rdparty/imgui-node-editor/examples/application/source/renderer.h new file mode 100644 index 0000000..3009737 --- /dev/null +++ b/3rdparty/imgui-node-editor/examples/application/source/renderer.h @@ -0,0 +1,32 @@ +# pragma once +# include "setup.h" +# include + +struct Platform; +struct ImDrawData; +struct ImVec4; +using ImTextureID= void*; + +struct Renderer +{ + virtual ~Renderer() {}; + + virtual bool Create(Platform& platform) = 0; + virtual void Destroy() = 0; + + virtual void NewFrame() = 0; + + virtual void RenderDrawData(ImDrawData* drawData) = 0; + + virtual void Clear(const ImVec4& color) = 0; + virtual void Present() = 0; + + virtual void Resize(int width, int height) = 0; + + virtual ImTextureID CreateTexture(const void* data, int width, int height) = 0; + virtual void DestroyTexture(ImTextureID texture) = 0; + virtual int GetTextureWidth(ImTextureID texture) = 0; + virtual int GetTextureHeight(ImTextureID texture) = 0; +}; + +std::unique_ptr CreateRenderer(); diff --git a/3rdparty/imgui-node-editor/examples/application/source/renderer_dx11.cpp b/3rdparty/imgui-node-editor/examples/application/source/renderer_dx11.cpp new file mode 100644 index 0000000..473c5ac --- /dev/null +++ b/3rdparty/imgui-node-editor/examples/application/source/renderer_dx11.cpp @@ -0,0 +1,195 @@ +# include "renderer.h" +# include "setup.h" + +# if RENDERER(IMGUI_DX11) + +# include "platform.h" + +# if PLATFORM(WINDOWS) +# define NOMINMAX +# define WIN32_LEAN_AND_MEAN +# include +# endif + +# include +# include "imgui_impl_dx11.h" +# include + + +struct RendererDX11 final + : Renderer +{ + bool Create(Platform& platform) override; + void Destroy() override; + void NewFrame() override; + void RenderDrawData(ImDrawData* drawData) override; + void Clear(const ImVec4& color) override; + void Present() override; + void Resize(int width, int height) override; + + ImTextureID CreateTexture(const void* data, int width, int height) override; + void DestroyTexture(ImTextureID texture) override; + int GetTextureWidth(ImTextureID texture) override; + int GetTextureHeight(ImTextureID texture) override; + + HRESULT CreateDeviceD3D(HWND hWnd); + void CleanupDeviceD3D(); + + void CreateRenderTarget(); + void CleanupRenderTarget(); + + Platform* m_Platform = nullptr; + ID3D11Device* m_device = nullptr; + ID3D11DeviceContext* m_deviceContext = nullptr; + IDXGISwapChain* m_swapChain = nullptr; + ID3D11RenderTargetView* m_mainRenderTargetView = nullptr; +}; + +std::unique_ptr CreateRenderer() +{ + return std::make_unique(); +} + +bool RendererDX11::Create(Platform& platform) +{ + m_Platform = &platform; + + auto hr = CreateDeviceD3D(reinterpret_cast(platform.GetMainWindowHandle())); + if (FAILED(hr)) + return false; + + if (!ImGui_ImplDX11_Init(m_device, m_deviceContext)) + { + CleanupDeviceD3D(); + return false; + } + + m_Platform->SetRenderer(this); + + return true; +} + +void RendererDX11::Destroy() +{ + if (!m_Platform) + return; + + m_Platform->SetRenderer(nullptr); + + ImGui_ImplDX11_Shutdown(); + + CleanupDeviceD3D(); +} + +void RendererDX11::NewFrame() +{ + ImGui_ImplDX11_NewFrame(); +} + +void RendererDX11::RenderDrawData(ImDrawData* drawData) +{ + ImGui_ImplDX11_RenderDrawData(drawData); +} + +void RendererDX11::Clear(const ImVec4& color) +{ + m_deviceContext->ClearRenderTargetView(m_mainRenderTargetView, (float*)&color.x); +} + +void RendererDX11::Present() +{ + m_swapChain->Present(1, 0); +} + +void RendererDX11::Resize(int width, int height) +{ + ImGui_ImplDX11_InvalidateDeviceObjects(); + CleanupRenderTarget(); + m_swapChain->ResizeBuffers(0, (UINT)width, (UINT)height, DXGI_FORMAT_UNKNOWN, 0); + CreateRenderTarget(); +} + +HRESULT RendererDX11::CreateDeviceD3D(HWND hWnd) +{ + // Setup swap chain + DXGI_SWAP_CHAIN_DESC sd; + { + ZeroMemory(&sd, sizeof(sd)); + sd.BufferCount = 2; + sd.BufferDesc.Width = 0; + sd.BufferDesc.Height = 0; + sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + sd.BufferDesc.RefreshRate.Numerator = 60; + sd.BufferDesc.RefreshRate.Denominator = 1; + sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; + sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + sd.OutputWindow = hWnd; + sd.SampleDesc.Count = 1; + sd.SampleDesc.Quality = 0; + sd.Windowed = TRUE; + sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; + } + + UINT createDeviceFlags = 0; + //createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG; + D3D_FEATURE_LEVEL featureLevel; + const D3D_FEATURE_LEVEL featureLevelArray[1] = { D3D_FEATURE_LEVEL_11_0, }; + if (D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, createDeviceFlags, featureLevelArray, 1, D3D11_SDK_VERSION, &sd, &m_swapChain, &m_device, &featureLevel, &m_deviceContext) != S_OK) + return E_FAIL; + + CreateRenderTarget(); + + return S_OK; +} + +void RendererDX11::CleanupDeviceD3D() +{ + CleanupRenderTarget(); + if (m_swapChain) { m_swapChain->Release(); m_swapChain = nullptr; } + if (m_deviceContext) { m_deviceContext->Release(); m_deviceContext = nullptr; } + if (m_device) { m_device->Release(); m_device = nullptr; } +} + +void RendererDX11::CreateRenderTarget() +{ + DXGI_SWAP_CHAIN_DESC sd; + m_swapChain->GetDesc(&sd); + + // Create the render target + ID3D11Texture2D* pBackBuffer; + D3D11_RENDER_TARGET_VIEW_DESC render_target_view_desc; + ZeroMemory(&render_target_view_desc, sizeof(render_target_view_desc)); + render_target_view_desc.Format = sd.BufferDesc.Format; + render_target_view_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + m_swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer); + m_device->CreateRenderTargetView(pBackBuffer, &render_target_view_desc, &m_mainRenderTargetView); + m_deviceContext->OMSetRenderTargets(1, &m_mainRenderTargetView, nullptr); + pBackBuffer->Release(); +} + +void RendererDX11::CleanupRenderTarget() +{ + if (m_mainRenderTargetView) { m_mainRenderTargetView->Release(); m_mainRenderTargetView = nullptr; } +} + +ImTextureID RendererDX11::CreateTexture(const void* data, int width, int height) +{ + return ImGui_CreateTexture(data, width, height); +} + +void RendererDX11::DestroyTexture(ImTextureID texture) +{ + return ImGui_DestroyTexture(texture); +} + +int RendererDX11::GetTextureWidth(ImTextureID texture) +{ + return ImGui_GetTextureWidth(texture); +} + +int RendererDX11::GetTextureHeight(ImTextureID texture) +{ + return ImGui_GetTextureHeight(texture); +} + +# endif // RENDERER(IMGUI_DX11) \ No newline at end of file diff --git a/3rdparty/imgui-node-editor/examples/application/source/renderer_ogl3.cpp b/3rdparty/imgui-node-editor/examples/application/source/renderer_ogl3.cpp new file mode 100644 index 0000000..72a7dfc --- /dev/null +++ b/3rdparty/imgui-node-editor/examples/application/source/renderer_ogl3.cpp @@ -0,0 +1,205 @@ +# include "renderer.h" + +# if RENDERER(IMGUI_OGL3) + +# include "platform.h" +# include + +# if PLATFORM(WINDOWS) +# define NOMINMAX +# define WIN32_LEAN_AND_MEAN +# include +# endif + +# include "imgui_impl_opengl3.h" + +# if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) +# include // Initialize with gl3wInit() +# elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) +# include // Initialize with glewInit() +# elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) +# include // Initialize with gladLoadGL() +# elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2) +# include // Initialize with gladLoadGL(...) or gladLoaderLoadGL() +# elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2) +# define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors. +# include // Initialize with glbinding::Binding::initialize() +# include +using namespace gl; +# elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3) +# define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors. +# include // Initialize with glbinding::initialize() +# include +using namespace gl; +# else +# include IMGUI_IMPL_OPENGL_LOADER_CUSTOM +# endif + +struct ImTexture +{ + GLuint TextureID = 0; + int Width = 0; + int Height = 0; +}; + +struct RendererOpenGL3 final + : Renderer +{ + bool Create(Platform& platform) override; + void Destroy() override; + void NewFrame() override; + void RenderDrawData(ImDrawData* drawData) override; + void Clear(const ImVec4& color) override; + void Present() override; + void Resize(int width, int height) override; + + ImVector::iterator FindTexture(ImTextureID texture); + ImTextureID CreateTexture(const void* data, int width, int height) override; + void DestroyTexture(ImTextureID texture) override; + int GetTextureWidth(ImTextureID texture) override; + int GetTextureHeight(ImTextureID texture) override; + + Platform* m_Platform = nullptr; + ImVector m_Textures; +}; + +std::unique_ptr CreateRenderer() +{ + return std::make_unique(); +} + +bool RendererOpenGL3::Create(Platform& platform) +{ + m_Platform = &platform; + + // Technically we should initialize OpenGL context here, + // but for now we relay on one created by GLFW3 + +#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) + bool err = gl3wInit() != 0; +#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) + bool err = glewInit() != GLEW_OK; +#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) + bool err = gladLoadGL() == 0; +#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2) + bool err = gladLoadGL(glfwGetProcAddress) == 0; // glad2 recommend using the windowing library loader instead of the (optionally) bundled one. +#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2) + bool err = false; + glbinding::Binding::initialize(); +#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3) + bool err = false; + glbinding::initialize([](const char* name) { return (glbinding::ProcAddress)glfwGetProcAddress(name); }); +#else + bool err = false; // If you use IMGUI_IMPL_OPENGL_LOADER_CUSTOM, your loader is likely to requires some form of initialization. +#endif + if (err) + return false; + +# if PLATFORM(MACOS) + const char* glslVersion = "#version 150"; +# else + const char* glslVersion = "#version 130"; +# endif + + if (!ImGui_ImplOpenGL3_Init(glslVersion)) + return false; + + m_Platform->SetRenderer(this); + + return true; +} + +void RendererOpenGL3::Destroy() +{ + if (!m_Platform) + return; + + m_Platform->SetRenderer(nullptr); + + ImGui_ImplOpenGL3_Shutdown(); +} + +void RendererOpenGL3::NewFrame() +{ + ImGui_ImplOpenGL3_NewFrame(); +} + +void RendererOpenGL3::RenderDrawData(ImDrawData* drawData) +{ + ImGui_ImplOpenGL3_RenderDrawData(drawData); +} + +void RendererOpenGL3::Clear(const ImVec4& color) +{ + glClearColor(color.x, color.y, color.z, color.w); + glClear(GL_COLOR_BUFFER_BIT); +} + +void RendererOpenGL3::Present() +{ +} + +void RendererOpenGL3::Resize(int width, int height) +{ + glViewport(0, 0, width, height); +} + +ImTextureID RendererOpenGL3::CreateTexture(const void* data, int width, int height) +{ + m_Textures.resize(m_Textures.size() + 1); + ImTexture& texture = m_Textures.back(); + + // Upload texture to graphics system + GLint last_texture = 0; + glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); + glGenTextures(1, &texture.TextureID); + glBindTexture(GL_TEXTURE_2D, texture.TextureID); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + glBindTexture(GL_TEXTURE_2D, last_texture); + + texture.Width = width; + texture.Height = height; + + return reinterpret_cast(static_cast(texture.TextureID)); +} + +ImVector::iterator RendererOpenGL3::FindTexture(ImTextureID texture) +{ + auto textureID = static_cast(reinterpret_cast(texture)); + + return std::find_if(m_Textures.begin(), m_Textures.end(), [textureID](ImTexture& texture) + { + return texture.TextureID == textureID; + }); +} + +void RendererOpenGL3::DestroyTexture(ImTextureID texture) +{ + auto textureIt = FindTexture(texture); + if (textureIt == m_Textures.end()) + return; + + glDeleteTextures(1, &textureIt->TextureID); + + m_Textures.erase(textureIt); +} + +int RendererOpenGL3::GetTextureWidth(ImTextureID texture) +{ + auto textureIt = FindTexture(texture); + if (textureIt != m_Textures.end()) + return textureIt->Width; + return 0; +} + +int RendererOpenGL3::GetTextureHeight(ImTextureID texture) +{ + auto textureIt = FindTexture(texture); + if (textureIt != m_Textures.end()) + return textureIt->Height; + return 0; +} + +# endif // RENDERER(IMGUI_OGL3) \ No newline at end of file diff --git a/3rdparty/imgui-node-editor/examples/application/source/setup.h b/3rdparty/imgui-node-editor/examples/application/source/setup.h new file mode 100644 index 0000000..2286ba4 --- /dev/null +++ b/3rdparty/imgui-node-editor/examples/application/source/setup.h @@ -0,0 +1,98 @@ +# pragma once +# include "config.h" + +# define DETAIL_PRIV_EXPAND(x) x +# define EXPAND(x) DETAIL_PRIV_EXPAND(x) +# define DETAIL_PRIV_CONCAT(x, y) x ## y +# define CONCAT(x, y) DETAIL_PRIV_CONCAT(x, y) + + +// Define PLATFORM(x) which evaluate to 0 or 1 when +// 'x' is: WINDOWS, MACOS or LINUX +# if defined(_WIN32) +# define PLATFORM_PRIV_WINDOWS() 1 +# elif defined(__APPLE__) +# define PLATFORM_PRIV_MACOS() 1 +# elif defined(__linux__) +# define PLATFORM_PRIV_LINUX() 1 +# else +# error Unsupported platform +# endif + +# ifndef PLATFORM_PRIV_WINDOWS +# define PLATFORM_PRIV_WINDOWS() 0 +# endif +# ifndef PLATFORM_PRIV_MACOS +# define PLATFORM_PRIV_MACOS() 0 +# endif +# ifndef PLATFORM_PRIV_LINUX +# define PLATFORM_PRIV_LINUX() 0 +# endif + +# define PLATFORM(x) (PLATFORM_PRIV_##x()) + + +// Define BACKEND(x) which evaluate to 0 or 1 when +// 'x' is: IMGUI_WIN32 or IMGUI_GLFW +// +// Use BACKEND_CONFIG to override desired backend +// +# if PLATFORM(WINDOWS) +# define BACKEND_HAVE_IMGUI_WIN32() 1 +# endif +# if HAVE_GLFW3 +# define BACKEND_HAVE_IMGUI_GLFW() 1 +# endif + +# ifndef BACKEND_HAVE_IMGUI_WIN32 +# define BACKEND_HAVE_IMGUI_WIN32() 0 +# endif +# ifndef BACKEND_HAVE_IMGUI_GLFW +# define BACKEND_HAVE_IMGUI_GLFW() 0 +# endif + +# define BACKEND_PRIV_IMGUI_WIN32() 1 +# define BACKEND_PRIV_IMGUI_GLFW() 2 + +# if !defined(BACKEND_CONFIG) +# if PLATFORM(WINDOWS) +# define BACKEND_CONFIG IMGUI_WIN32 +# else +# define BACKEND_CONFIG IMGUI_GLFW +# endif +# endif + +# define BACKEND(x) ((BACKEND_PRIV_##x()) == CONCAT(BACKEND_PRIV_, EXPAND(BACKEND_CONFIG))() && (BACKEND_HAVE_##x())) + + +// Define RENDERER(x) which evaluate to 0 or 1 when +// 'x' is: IMGUI_DX11 or IMGUI_OGL3 +// +// Use RENDERER_CONFIG to override desired renderer +// +# if PLATFORM(WINDOWS) +# define RENDERER_HAVE_IMGUI_DX11() 1 +# endif +# if HAVE_OPENGL +# define RENDERER_HAVE_IMGUI_OGL3() 1 +# endif + +# ifndef RENDERER_HAVE_IMGUI_DX11 +# define RENDERER_HAVE_IMGUI_DX11() 0 +# endif +# ifndef RENDERER_HAVE_IMGUI_OGL3 +# define RENDERER_HAVE_IMGUI_OGL3() 0 +# endif + +# define RENDERER_PRIV_IMGUI_DX11() 1 +# define RENDERER_PRIV_IMGUI_OGL3() 2 + +# if !defined(RENDERER_CONFIG) +# if PLATFORM(WINDOWS) +# define RENDERER_CONFIG IMGUI_DX11 +# else +# define RENDERER_CONFIG IMGUI_OGL3 +# endif +# endif + +# define RENDERER(x) ((RENDERER_PRIV_##x()) == CONCAT(RENDERER_PRIV_, EXPAND(RENDERER_CONFIG))() && (RENDERER_HAVE_##x())) diff --git a/3rdparty/imgui-node-editor/examples/application/support/Icon.icns b/3rdparty/imgui-node-editor/examples/application/support/Icon.icns new file mode 100644 index 0000000000000000000000000000000000000000..18e37c00a3665e0b61d1610921859f82fb716cd6 GIT binary patch literal 172448 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Ð$oI=x-8rBMj$s=Eu#^*Y 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 literal 0 HcmV?d00001 diff --git a/3rdparty/imgui-node-editor/examples/application/support/Icon.ico b/3rdparty/imgui-node-editor/examples/application/support/Icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..0ace9f3ceef6c1b8e72e3a3f9bd841382c981a95 GIT binary patch literal 39257 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 JRHA4V{$Giw3u6EP literal 0 HcmV?d00001 diff --git a/3rdparty/imgui-node-editor/examples/application/support/Icon.png b/3rdparty/imgui-node-editor/examples/application/support/Icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a532a630d4762f79fc218e1e46da5ab8d494d0d0 GIT binary patch literal 52666 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 + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${MACOSX_BUNDLE_EXECUTABLE_NAME} + CFBundleGetInfoString + ${MACOSX_BUNDLE_INFO_STRING} + CFBundleIconFile + ${MACOSX_BUNDLE_ICON_FILE} + CFBundleIdentifier + ${MACOSX_BUNDLE_GUI_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleLongVersionString + ${MACOSX_BUNDLE_LONG_VERSION_STRING} + CFBundleName + ${MACOSX_BUNDLE_BUNDLE_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + ${MACOSX_BUNDLE_SHORT_VERSION_STRING} + CFBundleSignature + ???? + CFBundleVersion + ${MACOSX_BUNDLE_BUNDLE_VERSION} + CSResourcesFileMapped + + LSRequiresCarbon + + NSHumanReadableCopyright + ${MACOSX_BUNDLE_COPYRIGHT} + NSSupportsAutomaticGraphicsSwitching + + NSHighResolutionCapable + + + + diff --git a/3rdparty/imgui-node-editor/examples/application/support/Resource.rc.in b/3rdparty/imgui-node-editor/examples/application/support/Resource.rc.in new file mode 100644 index 0000000..a7809b9 --- /dev/null +++ b/3rdparty/imgui-node-editor/examples/application/support/Resource.rc.in @@ -0,0 +1,3 @@ +#define IDI_APPLICATION 32512 + +IDI_APPLICATION ICON "${ApplicationIcon}" diff --git a/3rdparty/imgui-node-editor/examples/basic-interaction-example/CMakeLists.txt b/3rdparty/imgui-node-editor/examples/basic-interaction-example/CMakeLists.txt new file mode 100644 index 0000000..4c79eba --- /dev/null +++ b/3rdparty/imgui-node-editor/examples/basic-interaction-example/CMakeLists.txt @@ -0,0 +1,3 @@ +add_example_executable(basic-interaction-example + basic-interaction-example.cpp +) \ No newline at end of file diff --git a/3rdparty/imgui-node-editor/examples/basic-interaction-example/basic-interaction-example.cpp b/3rdparty/imgui-node-editor/examples/basic-interaction-example/basic-interaction-example.cpp new file mode 100644 index 0000000..4253533 --- /dev/null +++ b/3rdparty/imgui-node-editor/examples/basic-interaction-example/basic-interaction-example.cpp @@ -0,0 +1,216 @@ +# include +# include +# include + +namespace ed = ax::NodeEditor; + +struct Example: + public Application +{ + // Struct to hold basic information about connection between + // pins. Note that connection (aka. link) has its own ID. + // This is useful later with dealing with selections, deletion + // or other operations. + struct LinkInfo + { + ed::LinkId Id; + ed::PinId InputId; + ed::PinId OutputId; + }; + + using Application::Application; + + void OnStart() override + { + ed::Config config; + config.SettingsFile = "BasicInteraction.json"; + m_Context = ed::CreateEditor(&config); + } + + void OnStop() override + { + ed::DestroyEditor(m_Context); + } + + void ImGuiEx_BeginColumn() + { + ImGui::BeginGroup(); + } + + void ImGuiEx_NextColumn() + { + ImGui::EndGroup(); + ImGui::SameLine(); + ImGui::BeginGroup(); + } + + void ImGuiEx_EndColumn() + { + ImGui::EndGroup(); + } + + void OnFrame(float deltaTime) override + { + auto& io = ImGui::GetIO(); + + ImGui::Text("FPS: %.2f (%.2gms)", io.Framerate, io.Framerate ? 1000.0f / io.Framerate : 0.0f); + + ImGui::Separator(); + + ed::SetCurrentEditor(m_Context); + + // Start interaction with editor. + ed::Begin("My Editor", ImVec2(0.0, 0.0f)); + + int uniqueId = 1; + + // + // 1) Commit known data to editor + // + + // Submit Node A + ed::NodeId nodeA_Id = uniqueId++; + ed::PinId nodeA_InputPinId = uniqueId++; + ed::PinId nodeA_OutputPinId = uniqueId++; + + if (m_FirstFrame) + ed::SetNodePosition(nodeA_Id, ImVec2(10, 10)); + ed::BeginNode(nodeA_Id); + ImGui::Text("Node A"); + ed::BeginPin(nodeA_InputPinId, ed::PinKind::Input); + ImGui::Text("-> In"); + ed::EndPin(); + ImGui::SameLine(); + ed::BeginPin(nodeA_OutputPinId, ed::PinKind::Output); + ImGui::Text("Out ->"); + ed::EndPin(); + ed::EndNode(); + + // Submit Node B + ed::NodeId nodeB_Id = uniqueId++; + ed::PinId nodeB_InputPinId1 = uniqueId++; + ed::PinId nodeB_InputPinId2 = uniqueId++; + ed::PinId nodeB_OutputPinId = uniqueId++; + + if (m_FirstFrame) + ed::SetNodePosition(nodeB_Id, ImVec2(210, 60)); + ed::BeginNode(nodeB_Id); + ImGui::Text("Node B"); + ImGuiEx_BeginColumn(); + ed::BeginPin(nodeB_InputPinId1, ed::PinKind::Input); + ImGui::Text("-> In1"); + ed::EndPin(); + ed::BeginPin(nodeB_InputPinId2, ed::PinKind::Input); + ImGui::Text("-> In2"); + ed::EndPin(); + ImGuiEx_NextColumn(); + ed::BeginPin(nodeB_OutputPinId, ed::PinKind::Output); + ImGui::Text("Out ->"); + ed::EndPin(); + ImGuiEx_EndColumn(); + ed::EndNode(); + + // Submit Links + for (auto& linkInfo : m_Links) + ed::Link(linkInfo.Id, linkInfo.InputId, linkInfo.OutputId); + + // + // 2) Handle interactions + // + + // Handle creation action, returns true if editor want to create new object (node or link) + if (ed::BeginCreate()) + { + ed::PinId inputPinId, outputPinId; + if (ed::QueryNewLink(&inputPinId, &outputPinId)) + { + // QueryNewLink returns true if editor want to create new link between pins. + // + // Link can be created only for two valid pins, it is up to you to + // validate if connection make sense. Editor is happy to make any. + // + // Link always goes from input to output. User may choose to drag + // link from output pin or input pin. This determine which pin ids + // are valid and which are not: + // * input valid, output invalid - user started to drag new ling from input pin + // * input invalid, output valid - user started to drag new ling from output pin + // * input valid, output valid - user dragged link over other pin, can be validated + + if (inputPinId && outputPinId) // both are valid, let's accept link + { + // ed::AcceptNewItem() return true when user release mouse button. + if (ed::AcceptNewItem()) + { + // Since we accepted new link, lets add one to our list of links. + m_Links.push_back({ ed::LinkId(m_NextLinkId++), inputPinId, outputPinId }); + + // Draw new link. + ed::Link(m_Links.back().Id, m_Links.back().InputId, m_Links.back().OutputId); + } + + // You may choose to reject connection between these nodes + // by calling ed::RejectNewItem(). This will allow editor to give + // visual feedback by changing link thickness and color. + } + } + } + ed::EndCreate(); // Wraps up object creation action handling. + + + // Handle deletion action + if (ed::BeginDelete()) + { + // There may be many links marked for deletion, let's loop over them. + ed::LinkId deletedLinkId; + while (ed::QueryDeletedLink(&deletedLinkId)) + { + // If you agree that link can be deleted, accept deletion. + if (ed::AcceptDeletedItem()) + { + // Then remove link from your data. + for (auto& link : m_Links) + { + if (link.Id == deletedLinkId) + { + m_Links.erase(&link); + break; + } + } + } + + // You may reject link deletion by calling: + // ed::RejectDeletedItem(); + } + } + ed::EndDelete(); // Wrap up deletion action + + + + // End of interaction with editor. + ed::End(); + + if (m_FirstFrame) + ed::NavigateToContent(0.0f); + + ed::SetCurrentEditor(nullptr); + + m_FirstFrame = false; + + // ImGui::ShowMetricsWindow(); + } + + ed::EditorContext* m_Context = nullptr; // Editor context, required to trace a editor state. + bool m_FirstFrame = true; // Flag set for first frame only, some action need to be executed once. + ImVector m_Links; // List of live links. It is dynamic unless you want to create read-only view over nodes. + int m_NextLinkId = 100; // Counter to help generate link ids. In real application this will probably based on pointer to user data structure. +}; + +int Main(int argc, char** argv) +{ + Example exampe("Basic Interaction", argc, argv); + + if (exampe.Create()) + return exampe.Run(); + + return 0; +} \ No newline at end of file diff --git a/3rdparty/imgui-node-editor/examples/blueprints-example/CMakeLists.txt b/3rdparty/imgui-node-editor/examples/blueprints-example/CMakeLists.txt new file mode 100644 index 0000000..37ca1ec --- /dev/null +++ b/3rdparty/imgui-node-editor/examples/blueprints-example/CMakeLists.txt @@ -0,0 +1,9 @@ +add_example_executable(blueprints-example + blueprints-example.cpp + utilities/builders.h + utilities/drawing.h + utilities/widgets.h + utilities/builders.cpp + utilities/drawing.cpp + utilities/widgets.cpp +) diff --git a/3rdparty/imgui-node-editor/examples/blueprints-example/blueprints-example.cpp b/3rdparty/imgui-node-editor/examples/blueprints-example/blueprints-example.cpp new file mode 100644 index 0000000..c14c2e3 --- /dev/null +++ b/3rdparty/imgui-node-editor/examples/blueprints-example/blueprints-example.cpp @@ -0,0 +1,1821 @@ +#include +#include "utilities/builders.h" +#include "utilities/widgets.h" + +#include + +#define IMGUI_DEFINE_MATH_OPERATORS +#include + +#include +#include +#include +#include +#include + + +static inline ImRect ImGui_GetItemRect() +{ + return ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax()); +} + +static inline ImRect ImRect_Expanded(const ImRect& rect, float x, float y) +{ + auto result = rect; + result.Min.x -= x; + result.Min.y -= y; + result.Max.x += x; + result.Max.y += y; + return result; +} + +namespace ed = ax::NodeEditor; +namespace util = ax::NodeEditor::Utilities; + +using namespace ax; + +using ax::Widgets::IconType; + +static ed::EditorContext* m_Editor = nullptr; + +//extern "C" __declspec(dllimport) short __stdcall GetAsyncKeyState(int vkey); +//extern "C" bool Debug_KeyPress(int vkey) +//{ +// static std::map state; +// auto lastState = state[vkey]; +// state[vkey] = (GetAsyncKeyState(vkey) & 0x8000) != 0; +// if (state[vkey] && !lastState) +// return true; +// else +// return false; +//} + +enum class PinType +{ + Flow, + Bool, + Int, + Float, + String, + Object, + Function, + Delegate, +}; + +enum class PinKind +{ + Output, + Input +}; + +enum class NodeType +{ + Blueprint, + Simple, + Tree, + Comment, + Houdini +}; + +struct Node; + +struct Pin +{ + ed::PinId ID; + ::Node* Node; + std::string Name; + PinType Type; + PinKind Kind; + + Pin(int id, const char* name, PinType type): + ID(id), Node(nullptr), Name(name), Type(type), Kind(PinKind::Input) + { + } +}; + +struct Node +{ + ed::NodeId ID; + std::string Name; + std::vector Inputs; + std::vector Outputs; + ImColor Color; + NodeType Type; + ImVec2 Size; + + std::string State; + std::string SavedState; + + Node(int id, const char* name, ImColor color = ImColor(255, 255, 255)): + ID(id), Name(name), Color(color), Type(NodeType::Blueprint), Size(0, 0) + { + } +}; + +struct Link +{ + ed::LinkId ID; + + ed::PinId StartPinID; + ed::PinId EndPinID; + + ImColor Color; + + Link(ed::LinkId id, ed::PinId startPinId, ed::PinId endPinId): + ID(id), StartPinID(startPinId), EndPinID(endPinId), Color(255, 255, 255) + { + } +}; + +struct NodeIdLess +{ + bool operator()(const ed::NodeId& lhs, const ed::NodeId& rhs) const + { + return lhs.AsPointer() < rhs.AsPointer(); + } +}; + +static bool Splitter(bool split_vertically, float thickness, float* size1, float* size2, float min_size1, float min_size2, float splitter_long_axis_size = -1.0f) +{ + using namespace ImGui; + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiID id = window->GetID("##Splitter"); + ImRect bb; + bb.Min = window->DC.CursorPos + (split_vertically ? ImVec2(*size1, 0.0f) : ImVec2(0.0f, *size1)); + bb.Max = bb.Min + CalcItemSize(split_vertically ? ImVec2(thickness, splitter_long_axis_size) : ImVec2(splitter_long_axis_size, thickness), 0.0f, 0.0f); + return SplitterBehavior(bb, id, split_vertically ? ImGuiAxis_X : ImGuiAxis_Y, size1, size2, min_size1, min_size2, 0.0f); +} + +struct Example: + public Application +{ + using Application::Application; + + int GetNextId() + { + return m_NextId++; + } + + //ed::NodeId GetNextNodeId() + //{ + // return ed::NodeId(GetNextId()); + //} + + ed::LinkId GetNextLinkId() + { + return ed::LinkId(GetNextId()); + } + + void TouchNode(ed::NodeId id) + { + m_NodeTouchTime[id] = m_TouchTime; + } + + float GetTouchProgress(ed::NodeId id) + { + auto it = m_NodeTouchTime.find(id); + if (it != m_NodeTouchTime.end() && it->second > 0.0f) + return (m_TouchTime - it->second) / m_TouchTime; + else + return 0.0f; + } + + void UpdateTouch() + { + const auto deltaTime = ImGui::GetIO().DeltaTime; + for (auto& entry : m_NodeTouchTime) + { + if (entry.second > 0.0f) + entry.second -= deltaTime; + } + } + + Node* FindNode(ed::NodeId id) + { + for (auto& node : m_Nodes) + if (node.ID == id) + return &node; + + return nullptr; + } + + Link* FindLink(ed::LinkId id) + { + for (auto& link : m_Links) + if (link.ID == id) + return &link; + + return nullptr; + } + + Pin* FindPin(ed::PinId id) + { + if (!id) + return nullptr; + + for (auto& node : m_Nodes) + { + for (auto& pin : node.Inputs) + if (pin.ID == id) + return &pin; + + for (auto& pin : node.Outputs) + if (pin.ID == id) + return &pin; + } + + return nullptr; + } + + bool IsPinLinked(ed::PinId id) + { + if (!id) + return false; + + for (auto& link : m_Links) + if (link.StartPinID == id || link.EndPinID == id) + return true; + + return false; + } + + bool CanCreateLink(Pin* a, Pin* b) + { + if (!a || !b || a == b || a->Kind == b->Kind || a->Type != b->Type || a->Node == b->Node) + return false; + + return true; + } + + //void DrawItemRect(ImColor color, float expand = 0.0f) + //{ + // ImGui::GetWindowDrawList()->AddRect( + // ImGui::GetItemRectMin() - ImVec2(expand, expand), + // ImGui::GetItemRectMax() + ImVec2(expand, expand), + // color); + //}; + + //void FillItemRect(ImColor color, float expand = 0.0f, float rounding = 0.0f) + //{ + // ImGui::GetWindowDrawList()->AddRectFilled( + // ImGui::GetItemRectMin() - ImVec2(expand, expand), + // ImGui::GetItemRectMax() + ImVec2(expand, expand), + // color, rounding); + //}; + + void BuildNode(Node* node) + { + for (auto& input : node->Inputs) + { + input.Node = node; + input.Kind = PinKind::Input; + } + + for (auto& output : node->Outputs) + { + output.Node = node; + output.Kind = PinKind::Output; + } + } + + Node* SpawnInputActionNode() + { + m_Nodes.emplace_back(GetNextId(), "InputAction Fire", ImColor(255, 128, 128)); + m_Nodes.back().Outputs.emplace_back(GetNextId(), "", PinType::Delegate); + m_Nodes.back().Outputs.emplace_back(GetNextId(), "Pressed", PinType::Flow); + m_Nodes.back().Outputs.emplace_back(GetNextId(), "Released", PinType::Flow); + + BuildNode(&m_Nodes.back()); + + return &m_Nodes.back(); + } + + Node* SpawnBranchNode() + { + m_Nodes.emplace_back(GetNextId(), "Branch"); + m_Nodes.back().Inputs.emplace_back(GetNextId(), "", PinType::Flow); + m_Nodes.back().Inputs.emplace_back(GetNextId(), "Condition", PinType::Bool); + m_Nodes.back().Outputs.emplace_back(GetNextId(), "True", PinType::Flow); + m_Nodes.back().Outputs.emplace_back(GetNextId(), "False", PinType::Flow); + + BuildNode(&m_Nodes.back()); + + return &m_Nodes.back(); + } + + Node* SpawnDoNNode() + { + m_Nodes.emplace_back(GetNextId(), "Do N"); + m_Nodes.back().Inputs.emplace_back(GetNextId(), "Enter", PinType::Flow); + m_Nodes.back().Inputs.emplace_back(GetNextId(), "N", PinType::Int); + m_Nodes.back().Inputs.emplace_back(GetNextId(), "Reset", PinType::Flow); + m_Nodes.back().Outputs.emplace_back(GetNextId(), "Exit", PinType::Flow); + m_Nodes.back().Outputs.emplace_back(GetNextId(), "Counter", PinType::Int); + + BuildNode(&m_Nodes.back()); + + return &m_Nodes.back(); + } + + Node* SpawnOutputActionNode() + { + m_Nodes.emplace_back(GetNextId(), "OutputAction"); + m_Nodes.back().Inputs.emplace_back(GetNextId(), "Sample", PinType::Float); + m_Nodes.back().Outputs.emplace_back(GetNextId(), "Condition", PinType::Bool); + m_Nodes.back().Inputs.emplace_back(GetNextId(), "Event", PinType::Delegate); + + BuildNode(&m_Nodes.back()); + + return &m_Nodes.back(); + } + + Node* SpawnPrintStringNode() + { + m_Nodes.emplace_back(GetNextId(), "Print String"); + m_Nodes.back().Inputs.emplace_back(GetNextId(), "", PinType::Flow); + m_Nodes.back().Inputs.emplace_back(GetNextId(), "In String", PinType::String); + m_Nodes.back().Outputs.emplace_back(GetNextId(), "", PinType::Flow); + + BuildNode(&m_Nodes.back()); + + return &m_Nodes.back(); + } + + Node* SpawnMessageNode() + { + m_Nodes.emplace_back(GetNextId(), "", ImColor(128, 195, 248)); + m_Nodes.back().Type = NodeType::Simple; + m_Nodes.back().Outputs.emplace_back(GetNextId(), "Message", PinType::String); + + BuildNode(&m_Nodes.back()); + + return &m_Nodes.back(); + } + + Node* SpawnSetTimerNode() + { + m_Nodes.emplace_back(GetNextId(), "Set Timer", ImColor(128, 195, 248)); + m_Nodes.back().Inputs.emplace_back(GetNextId(), "", PinType::Flow); + m_Nodes.back().Inputs.emplace_back(GetNextId(), "Object", PinType::Object); + m_Nodes.back().Inputs.emplace_back(GetNextId(), "Function Name", PinType::Function); + m_Nodes.back().Inputs.emplace_back(GetNextId(), "Time", PinType::Float); + m_Nodes.back().Inputs.emplace_back(GetNextId(), "Looping", PinType::Bool); + m_Nodes.back().Outputs.emplace_back(GetNextId(), "", PinType::Flow); + + BuildNode(&m_Nodes.back()); + + return &m_Nodes.back(); + } + + Node* SpawnLessNode() + { + m_Nodes.emplace_back(GetNextId(), "<", ImColor(128, 195, 248)); + m_Nodes.back().Type = NodeType::Simple; + m_Nodes.back().Inputs.emplace_back(GetNextId(), "", PinType::Float); + m_Nodes.back().Inputs.emplace_back(GetNextId(), "", PinType::Float); + m_Nodes.back().Outputs.emplace_back(GetNextId(), "", PinType::Float); + + BuildNode(&m_Nodes.back()); + + return &m_Nodes.back(); + } + + Node* SpawnWeirdNode() + { + m_Nodes.emplace_back(GetNextId(), "o.O", ImColor(128, 195, 248)); + m_Nodes.back().Type = NodeType::Simple; + m_Nodes.back().Inputs.emplace_back(GetNextId(), "", PinType::Float); + m_Nodes.back().Outputs.emplace_back(GetNextId(), "", PinType::Float); + m_Nodes.back().Outputs.emplace_back(GetNextId(), "", PinType::Float); + + BuildNode(&m_Nodes.back()); + + return &m_Nodes.back(); + } + + Node* SpawnTraceByChannelNode() + { + m_Nodes.emplace_back(GetNextId(), "Single Line Trace by Channel", ImColor(255, 128, 64)); + m_Nodes.back().Inputs.emplace_back(GetNextId(), "", PinType::Flow); + m_Nodes.back().Inputs.emplace_back(GetNextId(), "Start", PinType::Flow); + m_Nodes.back().Inputs.emplace_back(GetNextId(), "End", PinType::Int); + m_Nodes.back().Inputs.emplace_back(GetNextId(), "Trace Channel", PinType::Float); + m_Nodes.back().Inputs.emplace_back(GetNextId(), "Trace Complex", PinType::Bool); + m_Nodes.back().Inputs.emplace_back(GetNextId(), "Actors to Ignore", PinType::Int); + m_Nodes.back().Inputs.emplace_back(GetNextId(), "Draw Debug Type", PinType::Bool); + m_Nodes.back().Inputs.emplace_back(GetNextId(), "Ignore Self", PinType::Bool); + m_Nodes.back().Outputs.emplace_back(GetNextId(), "", PinType::Flow); + m_Nodes.back().Outputs.emplace_back(GetNextId(), "Out Hit", PinType::Float); + m_Nodes.back().Outputs.emplace_back(GetNextId(), "Return Value", PinType::Bool); + + BuildNode(&m_Nodes.back()); + + return &m_Nodes.back(); + } + + Node* SpawnTreeSequenceNode() + { + m_Nodes.emplace_back(GetNextId(), "Sequence"); + m_Nodes.back().Type = NodeType::Tree; + m_Nodes.back().Inputs.emplace_back(GetNextId(), "", PinType::Flow); + m_Nodes.back().Outputs.emplace_back(GetNextId(), "", PinType::Flow); + + BuildNode(&m_Nodes.back()); + + return &m_Nodes.back(); + } + + Node* SpawnTreeTaskNode() + { + m_Nodes.emplace_back(GetNextId(), "Move To"); + m_Nodes.back().Type = NodeType::Tree; + m_Nodes.back().Inputs.emplace_back(GetNextId(), "", PinType::Flow); + + BuildNode(&m_Nodes.back()); + + return &m_Nodes.back(); + } + + Node* SpawnTreeTask2Node() + { + m_Nodes.emplace_back(GetNextId(), "Random Wait"); + m_Nodes.back().Type = NodeType::Tree; + m_Nodes.back().Inputs.emplace_back(GetNextId(), "", PinType::Flow); + + BuildNode(&m_Nodes.back()); + + return &m_Nodes.back(); + } + + Node* SpawnComment() + { + m_Nodes.emplace_back(GetNextId(), "Test Comment"); + m_Nodes.back().Type = NodeType::Comment; + m_Nodes.back().Size = ImVec2(300, 200); + + return &m_Nodes.back(); + } + + Node* SpawnHoudiniTransformNode() + { + m_Nodes.emplace_back(GetNextId(), "Transform"); + m_Nodes.back().Type = NodeType::Houdini; + m_Nodes.back().Inputs.emplace_back(GetNextId(), "", PinType::Flow); + m_Nodes.back().Outputs.emplace_back(GetNextId(), "", PinType::Flow); + + BuildNode(&m_Nodes.back()); + + return &m_Nodes.back(); + } + + Node* SpawnHoudiniGroupNode() + { + m_Nodes.emplace_back(GetNextId(), "Group"); + m_Nodes.back().Type = NodeType::Houdini; + m_Nodes.back().Inputs.emplace_back(GetNextId(), "", PinType::Flow); + m_Nodes.back().Inputs.emplace_back(GetNextId(), "", PinType::Flow); + m_Nodes.back().Outputs.emplace_back(GetNextId(), "", PinType::Flow); + + BuildNode(&m_Nodes.back()); + + return &m_Nodes.back(); + } + + void BuildNodes() + { + for (auto& node : m_Nodes) + BuildNode(&node); + } + + void OnStart() override + { + ed::Config config; + + config.SettingsFile = "Blueprints.json"; + + config.UserPointer = this; + + config.LoadNodeSettings = [](ed::NodeId nodeId, char* data, void* userPointer) -> size_t + { + auto self = static_cast(userPointer); + + auto node = self->FindNode(nodeId); + if (!node) + return 0; + + if (data != nullptr) + memcpy(data, node->State.data(), node->State.size()); + return node->State.size(); + }; + + config.SaveNodeSettings = [](ed::NodeId nodeId, const char* data, size_t size, ed::SaveReasonFlags reason, void* userPointer) -> bool + { + auto self = static_cast(userPointer); + + auto node = self->FindNode(nodeId); + if (!node) + return false; + + node->State.assign(data, size); + + self->TouchNode(nodeId); + + return true; + }; + + m_Editor = ed::CreateEditor(&config); + ed::SetCurrentEditor(m_Editor); + + Node* node; + node = SpawnInputActionNode(); ed::SetNodePosition(node->ID, ImVec2(-252, 220)); + node = SpawnBranchNode(); ed::SetNodePosition(node->ID, ImVec2(-300, 351)); + node = SpawnDoNNode(); ed::SetNodePosition(node->ID, ImVec2(-238, 504)); + node = SpawnOutputActionNode(); ed::SetNodePosition(node->ID, ImVec2(71, 80)); + node = SpawnSetTimerNode(); ed::SetNodePosition(node->ID, ImVec2(168, 316)); + + node = SpawnTreeSequenceNode(); ed::SetNodePosition(node->ID, ImVec2(1028, 329)); + node = SpawnTreeTaskNode(); ed::SetNodePosition(node->ID, ImVec2(1204, 458)); + node = SpawnTreeTask2Node(); ed::SetNodePosition(node->ID, ImVec2(868, 538)); + + node = SpawnComment(); ed::SetNodePosition(node->ID, ImVec2(112, 576)); ed::SetGroupSize(node->ID, ImVec2(384, 154)); + node = SpawnComment(); ed::SetNodePosition(node->ID, ImVec2(800, 224)); ed::SetGroupSize(node->ID, ImVec2(640, 400)); + + node = SpawnLessNode(); ed::SetNodePosition(node->ID, ImVec2(366, 652)); + node = SpawnWeirdNode(); ed::SetNodePosition(node->ID, ImVec2(144, 652)); + node = SpawnMessageNode(); ed::SetNodePosition(node->ID, ImVec2(-348, 698)); + node = SpawnPrintStringNode(); ed::SetNodePosition(node->ID, ImVec2(-69, 652)); + + node = SpawnHoudiniTransformNode(); ed::SetNodePosition(node->ID, ImVec2(500, -70)); + node = SpawnHoudiniGroupNode(); ed::SetNodePosition(node->ID, ImVec2(500, 42)); + + ed::NavigateToContent(); + + BuildNodes(); + + m_Links.push_back(Link(GetNextLinkId(), m_Nodes[5].Outputs[0].ID, m_Nodes[6].Inputs[0].ID)); + m_Links.push_back(Link(GetNextLinkId(), m_Nodes[5].Outputs[0].ID, m_Nodes[7].Inputs[0].ID)); + + m_Links.push_back(Link(GetNextLinkId(), m_Nodes[14].Outputs[0].ID, m_Nodes[15].Inputs[0].ID)); + + m_HeaderBackground = LoadTexture("data/BlueprintBackground.png"); + m_SaveIcon = LoadTexture("data/ic_save_white_24dp.png"); + m_RestoreIcon = LoadTexture("data/ic_restore_white_24dp.png"); + + + //auto& io = ImGui::GetIO(); + } + + void OnStop() override + { + auto releaseTexture = [this](ImTextureID& id) + { + if (id) + { + DestroyTexture(id); + id = nullptr; + } + }; + + releaseTexture(m_RestoreIcon); + releaseTexture(m_SaveIcon); + releaseTexture(m_HeaderBackground); + + if (m_Editor) + { + ed::DestroyEditor(m_Editor); + m_Editor = nullptr; + } + } + + ImColor GetIconColor(PinType type) + { + switch (type) + { + default: + case PinType::Flow: return ImColor(255, 255, 255); + case PinType::Bool: return ImColor(220, 48, 48); + case PinType::Int: return ImColor( 68, 201, 156); + case PinType::Float: return ImColor(147, 226, 74); + case PinType::String: return ImColor(124, 21, 153); + case PinType::Object: return ImColor( 51, 150, 215); + case PinType::Function: return ImColor(218, 0, 183); + case PinType::Delegate: return ImColor(255, 48, 48); + } + }; + + void DrawPinIcon(const Pin& pin, bool connected, int alpha) + { + IconType iconType; + ImColor color = GetIconColor(pin.Type); + color.Value.w = alpha / 255.0f; + switch (pin.Type) + { + case PinType::Flow: iconType = IconType::Flow; break; + case PinType::Bool: iconType = IconType::Circle; break; + case PinType::Int: iconType = IconType::Circle; break; + case PinType::Float: iconType = IconType::Circle; break; + case PinType::String: iconType = IconType::Circle; break; + case PinType::Object: iconType = IconType::Circle; break; + case PinType::Function: iconType = IconType::Circle; break; + case PinType::Delegate: iconType = IconType::Square; break; + default: + return; + } + + ax::Widgets::Icon(ImVec2(static_cast(m_PinIconSize), static_cast(m_PinIconSize)), iconType, connected, color, ImColor(32, 32, 32, alpha)); + }; + + void ShowStyleEditor(bool* show = nullptr) + { + if (!ImGui::Begin("Style", show)) + { + ImGui::End(); + return; + } + + auto paneWidth = ImGui::GetContentRegionAvail().x; + + auto& editorStyle = ed::GetStyle(); + ImGui::BeginHorizontal("Style buttons", ImVec2(paneWidth, 0), 1.0f); + ImGui::TextUnformatted("Values"); + ImGui::Spring(); + if (ImGui::Button("Reset to defaults")) + editorStyle = ed::Style(); + ImGui::EndHorizontal(); + ImGui::Spacing(); + ImGui::DragFloat4("Node Padding", &editorStyle.NodePadding.x, 0.1f, 0.0f, 40.0f); + ImGui::DragFloat("Node Rounding", &editorStyle.NodeRounding, 0.1f, 0.0f, 40.0f); + ImGui::DragFloat("Node Border Width", &editorStyle.NodeBorderWidth, 0.1f, 0.0f, 15.0f); + ImGui::DragFloat("Hovered Node Border Width", &editorStyle.HoveredNodeBorderWidth, 0.1f, 0.0f, 15.0f); + ImGui::DragFloat("Selected Node Border Width", &editorStyle.SelectedNodeBorderWidth, 0.1f, 0.0f, 15.0f); + ImGui::DragFloat("Pin Rounding", &editorStyle.PinRounding, 0.1f, 0.0f, 40.0f); + ImGui::DragFloat("Pin Border Width", &editorStyle.PinBorderWidth, 0.1f, 0.0f, 15.0f); + ImGui::DragFloat("Link Strength", &editorStyle.LinkStrength, 1.0f, 0.0f, 500.0f); + //ImVec2 SourceDirection; + //ImVec2 TargetDirection; + ImGui::DragFloat("Scroll Duration", &editorStyle.ScrollDuration, 0.001f, 0.0f, 2.0f); + ImGui::DragFloat("Flow Marker Distance", &editorStyle.FlowMarkerDistance, 1.0f, 1.0f, 200.0f); + ImGui::DragFloat("Flow Speed", &editorStyle.FlowSpeed, 1.0f, 1.0f, 2000.0f); + ImGui::DragFloat("Flow Duration", &editorStyle.FlowDuration, 0.001f, 0.0f, 5.0f); + //ImVec2 PivotAlignment; + //ImVec2 PivotSize; + //ImVec2 PivotScale; + //float PinCorners; + //float PinRadius; + //float PinArrowSize; + //float PinArrowWidth; + ImGui::DragFloat("Group Rounding", &editorStyle.GroupRounding, 0.1f, 0.0f, 40.0f); + ImGui::DragFloat("Group Border Width", &editorStyle.GroupBorderWidth, 0.1f, 0.0f, 15.0f); + + ImGui::Separator(); + + static ImGuiColorEditFlags edit_mode = ImGuiColorEditFlags_DisplayRGB; + ImGui::BeginHorizontal("Color Mode", ImVec2(paneWidth, 0), 1.0f); + ImGui::TextUnformatted("Filter Colors"); + ImGui::Spring(); + ImGui::RadioButton("RGB", &edit_mode, ImGuiColorEditFlags_DisplayRGB); + ImGui::Spring(0); + ImGui::RadioButton("HSV", &edit_mode, ImGuiColorEditFlags_DisplayHSV); + ImGui::Spring(0); + ImGui::RadioButton("HEX", &edit_mode, ImGuiColorEditFlags_DisplayHex); + ImGui::EndHorizontal(); + + static ImGuiTextFilter filter; + filter.Draw("", paneWidth); + + ImGui::Spacing(); + + ImGui::PushItemWidth(-160); + for (int i = 0; i < ed::StyleColor_Count; ++i) + { + auto name = ed::GetStyleColorName((ed::StyleColor)i); + if (!filter.PassFilter(name)) + continue; + + ImGui::ColorEdit4(name, &editorStyle.Colors[i].x, edit_mode); + } + ImGui::PopItemWidth(); + + ImGui::End(); + } + + void ShowLeftPane(float paneWidth) + { + auto& io = ImGui::GetIO(); + + ImGui::BeginChild("Selection", ImVec2(paneWidth, 0)); + + paneWidth = ImGui::GetContentRegionAvail().x; + + static bool showStyleEditor = false; + ImGui::BeginHorizontal("Style Editor", ImVec2(paneWidth, 0)); + ImGui::Spring(0.0f, 0.0f); + if (ImGui::Button("Zoom to Content")) + ed::NavigateToContent(); + ImGui::Spring(0.0f); + if (ImGui::Button("Show Flow")) + { + for (auto& link : m_Links) + ed::Flow(link.ID); + } + ImGui::Spring(); + if (ImGui::Button("Edit Style")) + showStyleEditor = true; + ImGui::EndHorizontal(); + ImGui::Checkbox("Show Ordinals", &m_ShowOrdinals); + + if (showStyleEditor) + ShowStyleEditor(&showStyleEditor); + + std::vector selectedNodes; + std::vector selectedLinks; + selectedNodes.resize(ed::GetSelectedObjectCount()); + selectedLinks.resize(ed::GetSelectedObjectCount()); + + int nodeCount = ed::GetSelectedNodes(selectedNodes.data(), static_cast(selectedNodes.size())); + int linkCount = ed::GetSelectedLinks(selectedLinks.data(), static_cast(selectedLinks.size())); + + selectedNodes.resize(nodeCount); + selectedLinks.resize(linkCount); + + int saveIconWidth = GetTextureWidth(m_SaveIcon); + int saveIconHeight = GetTextureWidth(m_SaveIcon); + int restoreIconWidth = GetTextureWidth(m_RestoreIcon); + int restoreIconHeight = GetTextureWidth(m_RestoreIcon); + + ImGui::GetWindowDrawList()->AddRectFilled( + ImGui::GetCursorScreenPos(), + ImGui::GetCursorScreenPos() + ImVec2(paneWidth, ImGui::GetTextLineHeight()), + ImColor(ImGui::GetStyle().Colors[ImGuiCol_HeaderActive]), ImGui::GetTextLineHeight() * 0.25f); + ImGui::Spacing(); ImGui::SameLine(); + ImGui::TextUnformatted("Nodes"); + ImGui::Indent(); + for (auto& node : m_Nodes) + { + ImGui::PushID(node.ID.AsPointer()); + auto start = ImGui::GetCursorScreenPos(); + + if (const auto progress = GetTouchProgress(node.ID)) + { + ImGui::GetWindowDrawList()->AddLine( + start + ImVec2(-8, 0), + start + ImVec2(-8, ImGui::GetTextLineHeight()), + IM_COL32(255, 0, 0, 255 - (int)(255 * progress)), 4.0f); + } + + bool isSelected = std::find(selectedNodes.begin(), selectedNodes.end(), node.ID) != selectedNodes.end(); + if (ImGui::Selectable((node.Name + "##" + std::to_string(reinterpret_cast(node.ID.AsPointer()))).c_str(), &isSelected)) + { + if (io.KeyCtrl) + { + if (isSelected) + ed::SelectNode(node.ID, true); + else + ed::DeselectNode(node.ID); + } + else + ed::SelectNode(node.ID, false); + + ed::NavigateToSelection(); + } + if (ImGui::IsItemHovered() && !node.State.empty()) + ImGui::SetTooltip("State: %s", node.State.c_str()); + + auto id = std::string("(") + std::to_string(reinterpret_cast(node.ID.AsPointer())) + ")"; + auto textSize = ImGui::CalcTextSize(id.c_str(), nullptr); + auto iconPanelPos = start + ImVec2( + paneWidth - ImGui::GetStyle().FramePadding.x - ImGui::GetStyle().IndentSpacing - saveIconWidth - restoreIconWidth - ImGui::GetStyle().ItemInnerSpacing.x * 1, + (ImGui::GetTextLineHeight() - saveIconHeight) / 2); + ImGui::GetWindowDrawList()->AddText( + ImVec2(iconPanelPos.x - textSize.x - ImGui::GetStyle().ItemInnerSpacing.x, start.y), + IM_COL32(255, 255, 255, 255), id.c_str(), nullptr); + + auto drawList = ImGui::GetWindowDrawList(); + ImGui::SetCursorScreenPos(iconPanelPos); + ImGui::SetItemAllowOverlap(); + if (node.SavedState.empty()) + { + if (ImGui::InvisibleButton("save", ImVec2((float)saveIconWidth, (float)saveIconHeight))) + node.SavedState = node.State; + + if (ImGui::IsItemActive()) + drawList->AddImage(m_SaveIcon, ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), ImVec2(0, 0), ImVec2(1, 1), IM_COL32(255, 255, 255, 96)); + else if (ImGui::IsItemHovered()) + drawList->AddImage(m_SaveIcon, ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), ImVec2(0, 0), ImVec2(1, 1), IM_COL32(255, 255, 255, 255)); + else + drawList->AddImage(m_SaveIcon, ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), ImVec2(0, 0), ImVec2(1, 1), IM_COL32(255, 255, 255, 160)); + } + else + { + ImGui::Dummy(ImVec2((float)saveIconWidth, (float)saveIconHeight)); + drawList->AddImage(m_SaveIcon, ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), ImVec2(0, 0), ImVec2(1, 1), IM_COL32(255, 255, 255, 32)); + } + + ImGui::SameLine(0, ImGui::GetStyle().ItemInnerSpacing.x); + ImGui::SetItemAllowOverlap(); + if (!node.SavedState.empty()) + { + if (ImGui::InvisibleButton("restore", ImVec2((float)restoreIconWidth, (float)restoreIconHeight))) + { + node.State = node.SavedState; + ed::RestoreNodeState(node.ID); + node.SavedState.clear(); + } + + if (ImGui::IsItemActive()) + drawList->AddImage(m_RestoreIcon, ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), ImVec2(0, 0), ImVec2(1, 1), IM_COL32(255, 255, 255, 96)); + else if (ImGui::IsItemHovered()) + drawList->AddImage(m_RestoreIcon, ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), ImVec2(0, 0), ImVec2(1, 1), IM_COL32(255, 255, 255, 255)); + else + drawList->AddImage(m_RestoreIcon, ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), ImVec2(0, 0), ImVec2(1, 1), IM_COL32(255, 255, 255, 160)); + } + else + { + ImGui::Dummy(ImVec2((float)restoreIconWidth, (float)restoreIconHeight)); + drawList->AddImage(m_RestoreIcon, ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), ImVec2(0, 0), ImVec2(1, 1), IM_COL32(255, 255, 255, 32)); + } + + ImGui::SameLine(0, 0); + ImGui::SetItemAllowOverlap(); + ImGui::Dummy(ImVec2(0, (float)restoreIconHeight)); + + ImGui::PopID(); + } + ImGui::Unindent(); + + static int changeCount = 0; + + ImGui::GetWindowDrawList()->AddRectFilled( + ImGui::GetCursorScreenPos(), + ImGui::GetCursorScreenPos() + ImVec2(paneWidth, ImGui::GetTextLineHeight()), + ImColor(ImGui::GetStyle().Colors[ImGuiCol_HeaderActive]), ImGui::GetTextLineHeight() * 0.25f); + ImGui::Spacing(); ImGui::SameLine(); + ImGui::TextUnformatted("Selection"); + + ImGui::BeginHorizontal("Selection Stats", ImVec2(paneWidth, 0)); + ImGui::Text("Changed %d time%s", changeCount, changeCount > 1 ? "s" : ""); + ImGui::Spring(); + if (ImGui::Button("Deselect All")) + ed::ClearSelection(); + ImGui::EndHorizontal(); + ImGui::Indent(); + for (int i = 0; i < nodeCount; ++i) ImGui::Text("Node (%p)", selectedNodes[i].AsPointer()); + for (int i = 0; i < linkCount; ++i) ImGui::Text("Link (%p)", selectedLinks[i].AsPointer()); + ImGui::Unindent(); + + if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Z))) + for (auto& link : m_Links) + ed::Flow(link.ID); + + if (ed::HasSelectionChanged()) + ++changeCount; + + ImGui::EndChild(); + } + + void OnFrame(float deltaTime) override + { + UpdateTouch(); + + auto& io = ImGui::GetIO(); + + ImGui::Text("FPS: %.2f (%.2gms)", io.Framerate, io.Framerate ? 1000.0f / io.Framerate : 0.0f); + + ed::SetCurrentEditor(m_Editor); + + //auto& style = ImGui::GetStyle(); + + # if 0 + { + for (auto x = -io.DisplaySize.y; x < io.DisplaySize.x; x += 10.0f) + { + ImGui::GetWindowDrawList()->AddLine(ImVec2(x, 0), ImVec2(x + io.DisplaySize.y, io.DisplaySize.y), + IM_COL32(255, 255, 0, 255)); + } + } + # endif + + static ed::NodeId contextNodeId = 0; + static ed::LinkId contextLinkId = 0; + static ed::PinId contextPinId = 0; + static bool createNewNode = false; + static Pin* newNodeLinkPin = nullptr; + static Pin* newLinkPin = nullptr; + + static float leftPaneWidth = 400.0f; + static float rightPaneWidth = 800.0f; + Splitter(true, 4.0f, &leftPaneWidth, &rightPaneWidth, 50.0f, 50.0f); + + ShowLeftPane(leftPaneWidth - 4.0f); + + ImGui::SameLine(0.0f, 12.0f); + + ed::Begin("Node editor"); + { + auto cursorTopLeft = ImGui::GetCursorScreenPos(); + + util::BlueprintNodeBuilder builder(m_HeaderBackground, GetTextureWidth(m_HeaderBackground), GetTextureHeight(m_HeaderBackground)); + + for (auto& node : m_Nodes) + { + if (node.Type != NodeType::Blueprint && node.Type != NodeType::Simple) + continue; + + const auto isSimple = node.Type == NodeType::Simple; + + bool hasOutputDelegates = false; + for (auto& output : node.Outputs) + if (output.Type == PinType::Delegate) + hasOutputDelegates = true; + + builder.Begin(node.ID); + if (!isSimple) + { + builder.Header(node.Color); + ImGui::Spring(0); + ImGui::TextUnformatted(node.Name.c_str()); + ImGui::Spring(1); + ImGui::Dummy(ImVec2(0, 28)); + if (hasOutputDelegates) + { + ImGui::BeginVertical("delegates", ImVec2(0, 28)); + ImGui::Spring(1, 0); + for (auto& output : node.Outputs) + { + if (output.Type != PinType::Delegate) + continue; + + auto alpha = ImGui::GetStyle().Alpha; + if (newLinkPin && !CanCreateLink(newLinkPin, &output) && &output != newLinkPin) + alpha = alpha * (48.0f / 255.0f); + + ed::BeginPin(output.ID, ed::PinKind::Output); + ed::PinPivotAlignment(ImVec2(1.0f, 0.5f)); + ed::PinPivotSize(ImVec2(0, 0)); + ImGui::BeginHorizontal(output.ID.AsPointer()); + ImGui::PushStyleVar(ImGuiStyleVar_Alpha, alpha); + if (!output.Name.empty()) + { + ImGui::TextUnformatted(output.Name.c_str()); + ImGui::Spring(0); + } + DrawPinIcon(output, IsPinLinked(output.ID), (int)(alpha * 255)); + ImGui::Spring(0, ImGui::GetStyle().ItemSpacing.x / 2); + ImGui::EndHorizontal(); + ImGui::PopStyleVar(); + ed::EndPin(); + + //DrawItemRect(ImColor(255, 0, 0)); + } + ImGui::Spring(1, 0); + ImGui::EndVertical(); + ImGui::Spring(0, ImGui::GetStyle().ItemSpacing.x / 2); + } + else + ImGui::Spring(0); + builder.EndHeader(); + } + + for (auto& input : node.Inputs) + { + auto alpha = ImGui::GetStyle().Alpha; + if (newLinkPin && !CanCreateLink(newLinkPin, &input) && &input != newLinkPin) + alpha = alpha * (48.0f / 255.0f); + + builder.Input(input.ID); + ImGui::PushStyleVar(ImGuiStyleVar_Alpha, alpha); + DrawPinIcon(input, IsPinLinked(input.ID), (int)(alpha * 255)); + ImGui::Spring(0); + if (!input.Name.empty()) + { + ImGui::TextUnformatted(input.Name.c_str()); + ImGui::Spring(0); + } + if (input.Type == PinType::Bool) + { + ImGui::Button("Hello"); + ImGui::Spring(0); + } + ImGui::PopStyleVar(); + builder.EndInput(); + } + + if (isSimple) + { + builder.Middle(); + + ImGui::Spring(1, 0); + ImGui::TextUnformatted(node.Name.c_str()); + ImGui::Spring(1, 0); + } + + for (auto& output : node.Outputs) + { + if (!isSimple && output.Type == PinType::Delegate) + continue; + + auto alpha = ImGui::GetStyle().Alpha; + if (newLinkPin && !CanCreateLink(newLinkPin, &output) && &output != newLinkPin) + alpha = alpha * (48.0f / 255.0f); + + ImGui::PushStyleVar(ImGuiStyleVar_Alpha, alpha); + builder.Output(output.ID); + if (output.Type == PinType::String) + { + static char buffer[128] = "Edit Me\nMultiline!"; + static bool wasActive = false; + + ImGui::PushItemWidth(100.0f); + ImGui::InputText("##edit", buffer, 127); + ImGui::PopItemWidth(); + if (ImGui::IsItemActive() && !wasActive) + { + ed::EnableShortcuts(false); + wasActive = true; + } + else if (!ImGui::IsItemActive() && wasActive) + { + ed::EnableShortcuts(true); + wasActive = false; + } + ImGui::Spring(0); + } + if (!output.Name.empty()) + { + ImGui::Spring(0); + ImGui::TextUnformatted(output.Name.c_str()); + } + ImGui::Spring(0); + DrawPinIcon(output, IsPinLinked(output.ID), (int)(alpha * 255)); + ImGui::PopStyleVar(); + builder.EndOutput(); + } + + builder.End(); + } + + for (auto& node : m_Nodes) + { + if (node.Type != NodeType::Tree) + continue; + + const float rounding = 5.0f; + const float padding = 12.0f; + + const auto pinBackground = ed::GetStyle().Colors[ed::StyleColor_NodeBg]; + + ed::PushStyleColor(ed::StyleColor_NodeBg, ImColor(128, 128, 128, 200)); + ed::PushStyleColor(ed::StyleColor_NodeBorder, ImColor( 32, 32, 32, 200)); + ed::PushStyleColor(ed::StyleColor_PinRect, ImColor( 60, 180, 255, 150)); + ed::PushStyleColor(ed::StyleColor_PinRectBorder, ImColor( 60, 180, 255, 150)); + + ed::PushStyleVar(ed::StyleVar_NodePadding, ImVec4(0, 0, 0, 0)); + ed::PushStyleVar(ed::StyleVar_NodeRounding, rounding); + ed::PushStyleVar(ed::StyleVar_SourceDirection, ImVec2(0.0f, 1.0f)); + ed::PushStyleVar(ed::StyleVar_TargetDirection, ImVec2(0.0f, -1.0f)); + ed::PushStyleVar(ed::StyleVar_LinkStrength, 0.0f); + ed::PushStyleVar(ed::StyleVar_PinBorderWidth, 1.0f); + ed::PushStyleVar(ed::StyleVar_PinRadius, 5.0f); + ed::BeginNode(node.ID); + + ImGui::BeginVertical(node.ID.AsPointer()); + ImGui::BeginHorizontal("inputs"); + ImGui::Spring(0, padding * 2); + + ImRect inputsRect; + int inputAlpha = 200; + if (!node.Inputs.empty()) + { + auto& pin = node.Inputs[0]; + ImGui::Dummy(ImVec2(0, padding)); + ImGui::Spring(1, 0); + inputsRect = ImGui_GetItemRect(); + + ed::PushStyleVar(ed::StyleVar_PinArrowSize, 10.0f); + ed::PushStyleVar(ed::StyleVar_PinArrowWidth, 10.0f); +#if IMGUI_VERSION_NUM > 18101 + ed::PushStyleVar(ed::StyleVar_PinCorners, ImDrawFlags_RoundCornersBottom); +#else + ed::PushStyleVar(ed::StyleVar_PinCorners, 12); +#endif + ed::BeginPin(pin.ID, ed::PinKind::Input); + ed::PinPivotRect(inputsRect.GetTL(), inputsRect.GetBR()); + ed::PinRect(inputsRect.GetTL(), inputsRect.GetBR()); + ed::EndPin(); + ed::PopStyleVar(3); + + if (newLinkPin && !CanCreateLink(newLinkPin, &pin) && &pin != newLinkPin) + inputAlpha = (int)(255 * ImGui::GetStyle().Alpha * (48.0f / 255.0f)); + } + else + ImGui::Dummy(ImVec2(0, padding)); + + ImGui::Spring(0, padding * 2); + ImGui::EndHorizontal(); + + ImGui::BeginHorizontal("content_frame"); + ImGui::Spring(1, padding); + + ImGui::BeginVertical("content", ImVec2(0.0f, 0.0f)); + ImGui::Dummy(ImVec2(160, 0)); + ImGui::Spring(1); + ImGui::TextUnformatted(node.Name.c_str()); + ImGui::Spring(1); + ImGui::EndVertical(); + auto contentRect = ImGui_GetItemRect(); + + ImGui::Spring(1, padding); + ImGui::EndHorizontal(); + + ImGui::BeginHorizontal("outputs"); + ImGui::Spring(0, padding * 2); + + ImRect outputsRect; + int outputAlpha = 200; + if (!node.Outputs.empty()) + { + auto& pin = node.Outputs[0]; + ImGui::Dummy(ImVec2(0, padding)); + ImGui::Spring(1, 0); + outputsRect = ImGui_GetItemRect(); + +#if IMGUI_VERSION_NUM > 18101 + ed::PushStyleVar(ed::StyleVar_PinCorners, ImDrawFlags_RoundCornersTop); +#else + ed::PushStyleVar(ed::StyleVar_PinCorners, 3); +#endif + ed::BeginPin(pin.ID, ed::PinKind::Output); + ed::PinPivotRect(outputsRect.GetTL(), outputsRect.GetBR()); + ed::PinRect(outputsRect.GetTL(), outputsRect.GetBR()); + ed::EndPin(); + ed::PopStyleVar(); + + if (newLinkPin && !CanCreateLink(newLinkPin, &pin) && &pin != newLinkPin) + outputAlpha = (int)(255 * ImGui::GetStyle().Alpha * (48.0f / 255.0f)); + } + else + ImGui::Dummy(ImVec2(0, padding)); + + ImGui::Spring(0, padding * 2); + ImGui::EndHorizontal(); + + ImGui::EndVertical(); + + ed::EndNode(); + ed::PopStyleVar(7); + ed::PopStyleColor(4); + + auto drawList = ed::GetNodeBackgroundDrawList(node.ID); + + //const auto fringeScale = ImGui::GetStyle().AntiAliasFringeScale; + //const auto unitSize = 1.0f / fringeScale; + + //const auto ImDrawList_AddRect = [](ImDrawList* drawList, const ImVec2& a, const ImVec2& b, ImU32 col, float rounding, int rounding_corners, float thickness) + //{ + // if ((col >> 24) == 0) + // return; + // drawList->PathRect(a, b, rounding, rounding_corners); + // drawList->PathStroke(col, true, thickness); + //}; + +#if IMGUI_VERSION_NUM > 18101 + const auto topRoundCornersFlags = ImDrawFlags_RoundCornersTop; + const auto bottomRoundCornersFlags = ImDrawFlags_RoundCornersBottom; +#else + const auto topRoundCornersFlags = 1 | 2; + const auto bottomRoundCornersFlags = 4 | 8; +#endif + + drawList->AddRectFilled(inputsRect.GetTL() + ImVec2(0, 1), inputsRect.GetBR(), + IM_COL32((int)(255 * pinBackground.x), (int)(255 * pinBackground.y), (int)(255 * pinBackground.z), inputAlpha), 4.0f, bottomRoundCornersFlags); + //ImGui::PushStyleVar(ImGuiStyleVar_AntiAliasFringeScale, 1.0f); + drawList->AddRect(inputsRect.GetTL() + ImVec2(0, 1), inputsRect.GetBR(), + IM_COL32((int)(255 * pinBackground.x), (int)(255 * pinBackground.y), (int)(255 * pinBackground.z), inputAlpha), 4.0f, bottomRoundCornersFlags); + //ImGui::PopStyleVar(); + drawList->AddRectFilled(outputsRect.GetTL(), outputsRect.GetBR() - ImVec2(0, 1), + IM_COL32((int)(255 * pinBackground.x), (int)(255 * pinBackground.y), (int)(255 * pinBackground.z), outputAlpha), 4.0f, topRoundCornersFlags); + //ImGui::PushStyleVar(ImGuiStyleVar_AntiAliasFringeScale, 1.0f); + drawList->AddRect(outputsRect.GetTL(), outputsRect.GetBR() - ImVec2(0, 1), + IM_COL32((int)(255 * pinBackground.x), (int)(255 * pinBackground.y), (int)(255 * pinBackground.z), outputAlpha), 4.0f, topRoundCornersFlags); + //ImGui::PopStyleVar(); + drawList->AddRectFilled(contentRect.GetTL(), contentRect.GetBR(), IM_COL32(24, 64, 128, 200), 0.0f); + //ImGui::PushStyleVar(ImGuiStyleVar_AntiAliasFringeScale, 1.0f); + drawList->AddRect( + contentRect.GetTL(), + contentRect.GetBR(), + IM_COL32(48, 128, 255, 100), 0.0f); + //ImGui::PopStyleVar(); + } + + for (auto& node : m_Nodes) + { + if (node.Type != NodeType::Houdini) + continue; + + const float rounding = 10.0f; + const float padding = 12.0f; + + + ed::PushStyleColor(ed::StyleColor_NodeBg, ImColor(229, 229, 229, 200)); + ed::PushStyleColor(ed::StyleColor_NodeBorder, ImColor(125, 125, 125, 200)); + ed::PushStyleColor(ed::StyleColor_PinRect, ImColor(229, 229, 229, 60)); + ed::PushStyleColor(ed::StyleColor_PinRectBorder, ImColor(125, 125, 125, 60)); + + const auto pinBackground = ed::GetStyle().Colors[ed::StyleColor_NodeBg]; + + ed::PushStyleVar(ed::StyleVar_NodePadding, ImVec4(0, 0, 0, 0)); + ed::PushStyleVar(ed::StyleVar_NodeRounding, rounding); + ed::PushStyleVar(ed::StyleVar_SourceDirection, ImVec2(0.0f, 1.0f)); + ed::PushStyleVar(ed::StyleVar_TargetDirection, ImVec2(0.0f, -1.0f)); + ed::PushStyleVar(ed::StyleVar_LinkStrength, 0.0f); + ed::PushStyleVar(ed::StyleVar_PinBorderWidth, 1.0f); + ed::PushStyleVar(ed::StyleVar_PinRadius, 6.0f); + ed::BeginNode(node.ID); + + ImGui::BeginVertical(node.ID.AsPointer()); + if (!node.Inputs.empty()) + { + ImGui::BeginHorizontal("inputs"); + ImGui::Spring(1, 0); + + ImRect inputsRect; + int inputAlpha = 200; + for (auto& pin : node.Inputs) + { + ImGui::Dummy(ImVec2(padding, padding)); + inputsRect = ImGui_GetItemRect(); + ImGui::Spring(1, 0); + inputsRect.Min.y -= padding; + inputsRect.Max.y -= padding; + +#if IMGUI_VERSION_NUM > 18101 + const auto allRoundCornersFlags = ImDrawFlags_RoundCornersAll; +#else + const auto allRoundCornersFlags = 15; +#endif + //ed::PushStyleVar(ed::StyleVar_PinArrowSize, 10.0f); + //ed::PushStyleVar(ed::StyleVar_PinArrowWidth, 10.0f); + ed::PushStyleVar(ed::StyleVar_PinCorners, allRoundCornersFlags); + + ed::BeginPin(pin.ID, ed::PinKind::Input); + ed::PinPivotRect(inputsRect.GetCenter(), inputsRect.GetCenter()); + ed::PinRect(inputsRect.GetTL(), inputsRect.GetBR()); + ed::EndPin(); + //ed::PopStyleVar(3); + ed::PopStyleVar(1); + + auto drawList = ImGui::GetWindowDrawList(); + drawList->AddRectFilled(inputsRect.GetTL(), inputsRect.GetBR(), + IM_COL32((int)(255 * pinBackground.x), (int)(255 * pinBackground.y), (int)(255 * pinBackground.z), inputAlpha), 4.0f, allRoundCornersFlags); + drawList->AddRect(inputsRect.GetTL(), inputsRect.GetBR(), + IM_COL32((int)(255 * pinBackground.x), (int)(255 * pinBackground.y), (int)(255 * pinBackground.z), inputAlpha), 4.0f, allRoundCornersFlags); + + if (newLinkPin && !CanCreateLink(newLinkPin, &pin) && &pin != newLinkPin) + inputAlpha = (int)(255 * ImGui::GetStyle().Alpha * (48.0f / 255.0f)); + } + + //ImGui::Spring(1, 0); + ImGui::EndHorizontal(); + } + + ImGui::BeginHorizontal("content_frame"); + ImGui::Spring(1, padding); + + ImGui::BeginVertical("content", ImVec2(0.0f, 0.0f)); + ImGui::Dummy(ImVec2(160, 0)); + ImGui::Spring(1); + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.0f, 0.0f, 0.0f, 1.0f)); + ImGui::TextUnformatted(node.Name.c_str()); + ImGui::PopStyleColor(); + ImGui::Spring(1); + ImGui::EndVertical(); + auto contentRect = ImGui_GetItemRect(); + + ImGui::Spring(1, padding); + ImGui::EndHorizontal(); + + if (!node.Outputs.empty()) + { + ImGui::BeginHorizontal("outputs"); + ImGui::Spring(1, 0); + + ImRect outputsRect; + int outputAlpha = 200; + for (auto& pin : node.Outputs) + { + ImGui::Dummy(ImVec2(padding, padding)); + outputsRect = ImGui_GetItemRect(); + ImGui::Spring(1, 0); + outputsRect.Min.y += padding; + outputsRect.Max.y += padding; + +#if IMGUI_VERSION_NUM > 18101 + const auto allRoundCornersFlags = ImDrawFlags_RoundCornersAll; + const auto topRoundCornersFlags = ImDrawFlags_RoundCornersTop; +#else + const auto allRoundCornersFlags = 15; + const auto topRoundCornersFlags = 3; +#endif + + ed::PushStyleVar(ed::StyleVar_PinCorners, topRoundCornersFlags); + ed::BeginPin(pin.ID, ed::PinKind::Output); + ed::PinPivotRect(outputsRect.GetCenter(), outputsRect.GetCenter()); + ed::PinRect(outputsRect.GetTL(), outputsRect.GetBR()); + ed::EndPin(); + ed::PopStyleVar(); + + + auto drawList = ImGui::GetWindowDrawList(); + drawList->AddRectFilled(outputsRect.GetTL(), outputsRect.GetBR(), + IM_COL32((int)(255 * pinBackground.x), (int)(255 * pinBackground.y), (int)(255 * pinBackground.z), outputAlpha), 4.0f, allRoundCornersFlags); + drawList->AddRect(outputsRect.GetTL(), outputsRect.GetBR(), + IM_COL32((int)(255 * pinBackground.x), (int)(255 * pinBackground.y), (int)(255 * pinBackground.z), outputAlpha), 4.0f, allRoundCornersFlags); + + + if (newLinkPin && !CanCreateLink(newLinkPin, &pin) && &pin != newLinkPin) + outputAlpha = (int)(255 * ImGui::GetStyle().Alpha * (48.0f / 255.0f)); + } + + ImGui::EndHorizontal(); + } + + ImGui::EndVertical(); + + ed::EndNode(); + ed::PopStyleVar(7); + ed::PopStyleColor(4); + + // auto drawList = ed::GetNodeBackgroundDrawList(node.ID); + + //const auto fringeScale = ImGui::GetStyle().AntiAliasFringeScale; + //const auto unitSize = 1.0f / fringeScale; + + //const auto ImDrawList_AddRect = [](ImDrawList* drawList, const ImVec2& a, const ImVec2& b, ImU32 col, float rounding, int rounding_corners, float thickness) + //{ + // if ((col >> 24) == 0) + // return; + // drawList->PathRect(a, b, rounding, rounding_corners); + // drawList->PathStroke(col, true, thickness); + //}; + + //drawList->AddRectFilled(inputsRect.GetTL() + ImVec2(0, 1), inputsRect.GetBR(), + // IM_COL32((int)(255 * pinBackground.x), (int)(255 * pinBackground.y), (int)(255 * pinBackground.z), inputAlpha), 4.0f, 12); + //ImGui::PushStyleVar(ImGuiStyleVar_AntiAliasFringeScale, 1.0f); + //drawList->AddRect(inputsRect.GetTL() + ImVec2(0, 1), inputsRect.GetBR(), + // IM_COL32((int)(255 * pinBackground.x), (int)(255 * pinBackground.y), (int)(255 * pinBackground.z), inputAlpha), 4.0f, 12); + //ImGui::PopStyleVar(); + //drawList->AddRectFilled(outputsRect.GetTL(), outputsRect.GetBR() - ImVec2(0, 1), + // IM_COL32((int)(255 * pinBackground.x), (int)(255 * pinBackground.y), (int)(255 * pinBackground.z), outputAlpha), 4.0f, 3); + ////ImGui::PushStyleVar(ImGuiStyleVar_AntiAliasFringeScale, 1.0f); + //drawList->AddRect(outputsRect.GetTL(), outputsRect.GetBR() - ImVec2(0, 1), + // IM_COL32((int)(255 * pinBackground.x), (int)(255 * pinBackground.y), (int)(255 * pinBackground.z), outputAlpha), 4.0f, 3); + ////ImGui::PopStyleVar(); + //drawList->AddRectFilled(contentRect.GetTL(), contentRect.GetBR(), IM_COL32(24, 64, 128, 200), 0.0f); + //ImGui::PushStyleVar(ImGuiStyleVar_AntiAliasFringeScale, 1.0f); + //drawList->AddRect( + // contentRect.GetTL(), + // contentRect.GetBR(), + // IM_COL32(48, 128, 255, 100), 0.0f); + //ImGui::PopStyleVar(); + } + + for (auto& node : m_Nodes) + { + if (node.Type != NodeType::Comment) + continue; + + const float commentAlpha = 0.75f; + + ImGui::PushStyleVar(ImGuiStyleVar_Alpha, commentAlpha); + ed::PushStyleColor(ed::StyleColor_NodeBg, ImColor(255, 255, 255, 64)); + ed::PushStyleColor(ed::StyleColor_NodeBorder, ImColor(255, 255, 255, 64)); + ed::BeginNode(node.ID); + ImGui::PushID(node.ID.AsPointer()); + ImGui::BeginVertical("content"); + ImGui::BeginHorizontal("horizontal"); + ImGui::Spring(1); + ImGui::TextUnformatted(node.Name.c_str()); + ImGui::Spring(1); + ImGui::EndHorizontal(); + ed::Group(node.Size); + ImGui::EndVertical(); + ImGui::PopID(); + ed::EndNode(); + ed::PopStyleColor(2); + ImGui::PopStyleVar(); + + if (ed::BeginGroupHint(node.ID)) + { + //auto alpha = static_cast(commentAlpha * ImGui::GetStyle().Alpha * 255); + auto bgAlpha = static_cast(ImGui::GetStyle().Alpha * 255); + + //ImGui::PushStyleVar(ImGuiStyleVar_Alpha, commentAlpha * ImGui::GetStyle().Alpha); + + auto min = ed::GetGroupMin(); + //auto max = ed::GetGroupMax(); + + ImGui::SetCursorScreenPos(min - ImVec2(-8, ImGui::GetTextLineHeightWithSpacing() + 4)); + ImGui::BeginGroup(); + ImGui::TextUnformatted(node.Name.c_str()); + ImGui::EndGroup(); + + auto drawList = ed::GetHintBackgroundDrawList(); + + auto hintBounds = ImGui_GetItemRect(); + auto hintFrameBounds = ImRect_Expanded(hintBounds, 8, 4); + + drawList->AddRectFilled( + hintFrameBounds.GetTL(), + hintFrameBounds.GetBR(), + IM_COL32(255, 255, 255, 64 * bgAlpha / 255), 4.0f); + + drawList->AddRect( + hintFrameBounds.GetTL(), + hintFrameBounds.GetBR(), + IM_COL32(255, 255, 255, 128 * bgAlpha / 255), 4.0f); + + //ImGui::PopStyleVar(); + } + ed::EndGroupHint(); + } + + for (auto& link : m_Links) + ed::Link(link.ID, link.StartPinID, link.EndPinID, link.Color, 2.0f); + + if (!createNewNode) + { + if (ed::BeginCreate(ImColor(255, 255, 255), 2.0f)) + { + auto showLabel = [](const char* label, ImColor color) + { + ImGui::SetCursorPosY(ImGui::GetCursorPosY() - ImGui::GetTextLineHeight()); + auto size = ImGui::CalcTextSize(label); + + auto padding = ImGui::GetStyle().FramePadding; + auto spacing = ImGui::GetStyle().ItemSpacing; + + ImGui::SetCursorPos(ImGui::GetCursorPos() + ImVec2(spacing.x, -spacing.y)); + + auto rectMin = ImGui::GetCursorScreenPos() - padding; + auto rectMax = ImGui::GetCursorScreenPos() + size + padding; + + auto drawList = ImGui::GetWindowDrawList(); + drawList->AddRectFilled(rectMin, rectMax, color, size.y * 0.15f); + ImGui::TextUnformatted(label); + }; + + ed::PinId startPinId = 0, endPinId = 0; + if (ed::QueryNewLink(&startPinId, &endPinId)) + { + auto startPin = FindPin(startPinId); + auto endPin = FindPin(endPinId); + + newLinkPin = startPin ? startPin : endPin; + + if (startPin->Kind == PinKind::Input) + { + std::swap(startPin, endPin); + std::swap(startPinId, endPinId); + } + + if (startPin && endPin) + { + if (endPin == startPin) + { + ed::RejectNewItem(ImColor(255, 0, 0), 2.0f); + } + else if (endPin->Kind == startPin->Kind) + { + showLabel("x Incompatible Pin Kind", ImColor(45, 32, 32, 180)); + ed::RejectNewItem(ImColor(255, 0, 0), 2.0f); + } + //else if (endPin->Node == startPin->Node) + //{ + // showLabel("x Cannot connect to self", ImColor(45, 32, 32, 180)); + // ed::RejectNewItem(ImColor(255, 0, 0), 1.0f); + //} + else if (endPin->Type != startPin->Type) + { + showLabel("x Incompatible Pin Type", ImColor(45, 32, 32, 180)); + ed::RejectNewItem(ImColor(255, 128, 128), 1.0f); + } + else + { + showLabel("+ Create Link", ImColor(32, 45, 32, 180)); + if (ed::AcceptNewItem(ImColor(128, 255, 128), 4.0f)) + { + m_Links.emplace_back(Link(GetNextId(), startPinId, endPinId)); + m_Links.back().Color = GetIconColor(startPin->Type); + } + } + } + } + + ed::PinId pinId = 0; + if (ed::QueryNewNode(&pinId)) + { + newLinkPin = FindPin(pinId); + if (newLinkPin) + showLabel("+ Create Node", ImColor(32, 45, 32, 180)); + + if (ed::AcceptNewItem()) + { + createNewNode = true; + newNodeLinkPin = FindPin(pinId); + newLinkPin = nullptr; + ed::Suspend(); + ImGui::OpenPopup("Create New Node"); + ed::Resume(); + } + } + } + else + newLinkPin = nullptr; + + ed::EndCreate(); + + if (ed::BeginDelete()) + { + ed::LinkId linkId = 0; + while (ed::QueryDeletedLink(&linkId)) + { + if (ed::AcceptDeletedItem()) + { + auto id = std::find_if(m_Links.begin(), m_Links.end(), [linkId](auto& link) { return link.ID == linkId; }); + if (id != m_Links.end()) + m_Links.erase(id); + } + } + + ed::NodeId nodeId = 0; + while (ed::QueryDeletedNode(&nodeId)) + { + if (ed::AcceptDeletedItem()) + { + auto id = std::find_if(m_Nodes.begin(), m_Nodes.end(), [nodeId](auto& node) { return node.ID == nodeId; }); + if (id != m_Nodes.end()) + m_Nodes.erase(id); + } + } + } + ed::EndDelete(); + } + + ImGui::SetCursorScreenPos(cursorTopLeft); + } + + # if 1 + auto openPopupPosition = ImGui::GetMousePos(); + ed::Suspend(); + if (ed::ShowNodeContextMenu(&contextNodeId)) + ImGui::OpenPopup("Node Context Menu"); + else if (ed::ShowPinContextMenu(&contextPinId)) + ImGui::OpenPopup("Pin Context Menu"); + else if (ed::ShowLinkContextMenu(&contextLinkId)) + ImGui::OpenPopup("Link Context Menu"); + else if (ed::ShowBackgroundContextMenu()) + { + ImGui::OpenPopup("Create New Node"); + newNodeLinkPin = nullptr; + } + ed::Resume(); + + ed::Suspend(); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(8, 8)); + if (ImGui::BeginPopup("Node Context Menu")) + { + auto node = FindNode(contextNodeId); + + ImGui::TextUnformatted("Node Context Menu"); + ImGui::Separator(); + if (node) + { + ImGui::Text("ID: %p", node->ID.AsPointer()); + ImGui::Text("Type: %s", node->Type == NodeType::Blueprint ? "Blueprint" : (node->Type == NodeType::Tree ? "Tree" : "Comment")); + ImGui::Text("Inputs: %d", (int)node->Inputs.size()); + ImGui::Text("Outputs: %d", (int)node->Outputs.size()); + } + else + ImGui::Text("Unknown node: %p", contextNodeId.AsPointer()); + ImGui::Separator(); + if (ImGui::MenuItem("Delete")) + ed::DeleteNode(contextNodeId); + ImGui::EndPopup(); + } + + if (ImGui::BeginPopup("Pin Context Menu")) + { + auto pin = FindPin(contextPinId); + + ImGui::TextUnformatted("Pin Context Menu"); + ImGui::Separator(); + if (pin) + { + ImGui::Text("ID: %p", pin->ID.AsPointer()); + if (pin->Node) + ImGui::Text("Node: %p", pin->Node->ID.AsPointer()); + else + ImGui::Text("Node: %s", ""); + } + else + ImGui::Text("Unknown pin: %p", contextPinId.AsPointer()); + + ImGui::EndPopup(); + } + + if (ImGui::BeginPopup("Link Context Menu")) + { + auto link = FindLink(contextLinkId); + + ImGui::TextUnformatted("Link Context Menu"); + ImGui::Separator(); + if (link) + { + ImGui::Text("ID: %p", link->ID.AsPointer()); + ImGui::Text("From: %p", link->StartPinID.AsPointer()); + ImGui::Text("To: %p", link->EndPinID.AsPointer()); + } + else + ImGui::Text("Unknown link: %p", contextLinkId.AsPointer()); + ImGui::Separator(); + if (ImGui::MenuItem("Delete")) + ed::DeleteLink(contextLinkId); + ImGui::EndPopup(); + } + + if (ImGui::BeginPopup("Create New Node")) + { + auto newNodePostion = openPopupPosition; + //ImGui::SetCursorScreenPos(ImGui::GetMousePosOnOpeningCurrentPopup()); + + //auto drawList = ImGui::GetWindowDrawList(); + //drawList->AddCircleFilled(ImGui::GetMousePosOnOpeningCurrentPopup(), 10.0f, 0xFFFF00FF); + + Node* node = nullptr; + if (ImGui::MenuItem("Input Action")) + node = SpawnInputActionNode(); + if (ImGui::MenuItem("Output Action")) + node = SpawnOutputActionNode(); + if (ImGui::MenuItem("Branch")) + node = SpawnBranchNode(); + if (ImGui::MenuItem("Do N")) + node = SpawnDoNNode(); + if (ImGui::MenuItem("Set Timer")) + node = SpawnSetTimerNode(); + if (ImGui::MenuItem("Less")) + node = SpawnLessNode(); + if (ImGui::MenuItem("Weird")) + node = SpawnWeirdNode(); + if (ImGui::MenuItem("Trace by Channel")) + node = SpawnTraceByChannelNode(); + if (ImGui::MenuItem("Print String")) + node = SpawnPrintStringNode(); + ImGui::Separator(); + if (ImGui::MenuItem("Comment")) + node = SpawnComment(); + ImGui::Separator(); + if (ImGui::MenuItem("Sequence")) + node = SpawnTreeSequenceNode(); + if (ImGui::MenuItem("Move To")) + node = SpawnTreeTaskNode(); + if (ImGui::MenuItem("Random Wait")) + node = SpawnTreeTask2Node(); + ImGui::Separator(); + if (ImGui::MenuItem("Message")) + node = SpawnMessageNode(); + ImGui::Separator(); + if (ImGui::MenuItem("Transform")) + node = SpawnHoudiniTransformNode(); + if (ImGui::MenuItem("Group")) + node = SpawnHoudiniGroupNode(); + + if (node) + { + BuildNodes(); + + createNewNode = false; + + ed::SetNodePosition(node->ID, newNodePostion); + + if (auto startPin = newNodeLinkPin) + { + auto& pins = startPin->Kind == PinKind::Input ? node->Outputs : node->Inputs; + + for (auto& pin : pins) + { + if (CanCreateLink(startPin, &pin)) + { + auto endPin = &pin; + if (startPin->Kind == PinKind::Input) + std::swap(startPin, endPin); + + m_Links.emplace_back(Link(GetNextId(), startPin->ID, endPin->ID)); + m_Links.back().Color = GetIconColor(startPin->Type); + + break; + } + } + } + } + + ImGui::EndPopup(); + } + else + createNewNode = false; + ImGui::PopStyleVar(); + ed::Resume(); + # endif + + + /* + cubic_bezier_t c; + c.p0 = pointf(100, 600); + c.p1 = pointf(300, 1200); + c.p2 = pointf(500, 100); + c.p3 = pointf(900, 600); + + auto drawList = ImGui::GetWindowDrawList(); + auto offset_radius = 15.0f; + auto acceptPoint = [drawList, offset_radius](const bezier_subdivide_result_t& r) + { + drawList->AddCircle(to_imvec(r.point), 4.0f, IM_COL32(255, 0, 255, 255)); + + auto nt = r.tangent.normalized(); + nt = pointf(-nt.y, nt.x); + + drawList->AddLine(to_imvec(r.point), to_imvec(r.point + nt * offset_radius), IM_COL32(255, 0, 0, 255), 1.0f); + }; + + drawList->AddBezierCurve(to_imvec(c.p0), to_imvec(c.p1), to_imvec(c.p2), to_imvec(c.p3), IM_COL32(255, 255, 255, 255), 1.0f); + cubic_bezier_subdivide(acceptPoint, c); + */ + + ed::End(); + + auto editorMin = ImGui::GetItemRectMin(); + auto editorMax = ImGui::GetItemRectMax(); + + if (m_ShowOrdinals) + { + int nodeCount = ed::GetNodeCount(); + std::vector orderedNodeIds; + orderedNodeIds.resize(static_cast(nodeCount)); + ed::GetOrderedNodeIds(orderedNodeIds.data(), nodeCount); + + + auto drawList = ImGui::GetWindowDrawList(); + drawList->PushClipRect(editorMin, editorMax); + + int ordinal = 0; + for (auto& nodeId : orderedNodeIds) + { + auto p0 = ed::GetNodePosition(nodeId); + auto p1 = p0 + ed::GetNodeSize(nodeId); + p0 = ed::CanvasToScreen(p0); + p1 = ed::CanvasToScreen(p1); + + + ImGuiTextBuffer builder; + builder.appendf("#%d", ordinal++); + + auto textSize = ImGui::CalcTextSize(builder.c_str()); + auto padding = ImVec2(2.0f, 2.0f); + auto widgetSize = textSize + padding * 2; + + auto widgetPosition = ImVec2(p1.x, p0.y) + ImVec2(0.0f, -widgetSize.y); + + drawList->AddRectFilled(widgetPosition, widgetPosition + widgetSize, IM_COL32(100, 80, 80, 190), 3.0f, ImDrawFlags_RoundCornersAll); + drawList->AddRect(widgetPosition, widgetPosition + widgetSize, IM_COL32(200, 160, 160, 190), 3.0f, ImDrawFlags_RoundCornersAll); + drawList->AddText(widgetPosition + padding, IM_COL32(255, 255, 255, 255), builder.c_str()); + } + + drawList->PopClipRect(); + } + + + //ImGui::ShowTestWindow(); + //ImGui::ShowMetricsWindow(); + } + + int m_NextId = 1; + const int m_PinIconSize = 24; + std::vector m_Nodes; + std::vector m_Links; + ImTextureID m_HeaderBackground = nullptr; + ImTextureID m_SaveIcon = nullptr; + ImTextureID m_RestoreIcon = nullptr; + const float m_TouchTime = 1.0f; + std::map m_NodeTouchTime; + bool m_ShowOrdinals = false; +}; + +int Main(int argc, char** argv) +{ + Example exampe("Blueprints", argc, argv); + + if (exampe.Create()) + return exampe.Run(); + + return 0; +} \ No newline at end of file diff --git a/3rdparty/imgui-node-editor/examples/blueprints-example/data/BlueprintBackground.png b/3rdparty/imgui-node-editor/examples/blueprints-example/data/BlueprintBackground.png new file mode 100644 index 0000000000000000000000000000000000000000..ce7edce3ad7f46987a20a0a814dd1a55b11202e8 GIT binary patch literal 5513 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 eaA@0d?z>-rMJX$#4*z=q0000U8 literal 0 HcmV?d00001 diff --git a/3rdparty/imgui-node-editor/examples/blueprints-example/data/ic_save_white_24dp.png b/3rdparty/imgui-node-editor/examples/blueprints-example/data/ic_save_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..015062ed3b316909362e3bfe43579715a4f2c14e GIT binary patch literal 168 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_+id`}n05R2ZcmmRqp6hvGD%@cNQ zTrf?MD{tY`DCrY!+h+!7)MX@<|M>91UCT6U&6_Q^vKIW^bNn|gNPwG~q2dAY{6@(2Ul)|NDzIgd>D5-Nv3R_&pT)_9!>hC0v RLqMw;JYD@<);T3K0RZw0JMaJi literal 0 HcmV?d00001 diff --git a/3rdparty/imgui-node-editor/examples/blueprints-example/utilities/builders.cpp b/3rdparty/imgui-node-editor/examples/blueprints-example/utilities/builders.cpp new file mode 100644 index 0000000..dd6abf6 --- /dev/null +++ b/3rdparty/imgui-node-editor/examples/blueprints-example/utilities/builders.cpp @@ -0,0 +1,314 @@ +//------------------------------------------------------------------------------ +// LICENSE +// This software is dual-licensed to the public domain and under the following +// license: you are granted a perpetual, irrevocable license to copy, modify, +// publish, and distribute this file as you see fit. +// +// CREDITS +// Written by Michal Cichon +//------------------------------------------------------------------------------ +# include "builders.h" +# define IMGUI_DEFINE_MATH_OPERATORS +# include + + +//------------------------------------------------------------------------------ +namespace ed = ax::NodeEditor; +namespace util = ax::NodeEditor::Utilities; + +util::BlueprintNodeBuilder::BlueprintNodeBuilder(ImTextureID texture, int textureWidth, int textureHeight): + HeaderTextureId(texture), + HeaderTextureWidth(textureWidth), + HeaderTextureHeight(textureHeight), + CurrentNodeId(0), + CurrentStage(Stage::Invalid), + HasHeader(false) +{ +} + +void util::BlueprintNodeBuilder::Begin(ed::NodeId id) +{ + HasHeader = false; + HeaderMin = HeaderMax = ImVec2(); + + ed::PushStyleVar(StyleVar_NodePadding, ImVec4(8, 4, 8, 8)); + + ed::BeginNode(id); + + ImGui::PushID(id.AsPointer()); + CurrentNodeId = id; + + SetStage(Stage::Begin); +} + +void util::BlueprintNodeBuilder::End() +{ + SetStage(Stage::End); + + ed::EndNode(); + + if (ImGui::IsItemVisible()) + { + auto alpha = static_cast(255 * ImGui::GetStyle().Alpha); + + auto drawList = ed::GetNodeBackgroundDrawList(CurrentNodeId); + + const auto halfBorderWidth = ed::GetStyle().NodeBorderWidth * 0.5f; + + auto headerColor = IM_COL32(0, 0, 0, alpha) | (HeaderColor & IM_COL32(255, 255, 255, 0)); + if ((HeaderMax.x > HeaderMin.x) && (HeaderMax.y > HeaderMin.y) && HeaderTextureId) + { + const auto uv = ImVec2( + (HeaderMax.x - HeaderMin.x) / (float)(4.0f * HeaderTextureWidth), + (HeaderMax.y - HeaderMin.y) / (float)(4.0f * HeaderTextureHeight)); + + drawList->AddImageRounded(HeaderTextureId, + HeaderMin - ImVec2(8 - halfBorderWidth, 4 - halfBorderWidth), + HeaderMax + ImVec2(8 - halfBorderWidth, 0), + ImVec2(0.0f, 0.0f), uv, +#if IMGUI_VERSION_NUM > 18101 + headerColor, GetStyle().NodeRounding, ImDrawFlags_RoundCornersTop); +#else + headerColor, GetStyle().NodeRounding, 1 | 2); +#endif + + + auto headerSeparatorMin = ImVec2(HeaderMin.x, HeaderMax.y); + auto headerSeparatorMax = ImVec2(HeaderMax.x, HeaderMin.y); + + if ((headerSeparatorMax.x > headerSeparatorMin.x) && (headerSeparatorMax.y > headerSeparatorMin.y)) + { + drawList->AddLine( + headerSeparatorMin + ImVec2(-(8 - halfBorderWidth), -0.5f), + headerSeparatorMax + ImVec2( (8 - halfBorderWidth), -0.5f), + ImColor(255, 255, 255, 96 * alpha / (3 * 255)), 1.0f); + } + } + } + + CurrentNodeId = 0; + + ImGui::PopID(); + + ed::PopStyleVar(); + + SetStage(Stage::Invalid); +} + +void util::BlueprintNodeBuilder::Header(const ImVec4& color) +{ + HeaderColor = ImColor(color); + SetStage(Stage::Header); +} + +void util::BlueprintNodeBuilder::EndHeader() +{ + SetStage(Stage::Content); +} + +void util::BlueprintNodeBuilder::Input(ed::PinId id) +{ + if (CurrentStage == Stage::Begin) + SetStage(Stage::Content); + + const auto applyPadding = (CurrentStage == Stage::Input); + + SetStage(Stage::Input); + + if (applyPadding) + ImGui::Spring(0); + + Pin(id, PinKind::Input); + + ImGui::BeginHorizontal(id.AsPointer()); +} + +void util::BlueprintNodeBuilder::EndInput() +{ + ImGui::EndHorizontal(); + + EndPin(); +} + +void util::BlueprintNodeBuilder::Middle() +{ + if (CurrentStage == Stage::Begin) + SetStage(Stage::Content); + + SetStage(Stage::Middle); +} + +void util::BlueprintNodeBuilder::Output(ed::PinId id) +{ + if (CurrentStage == Stage::Begin) + SetStage(Stage::Content); + + const auto applyPadding = (CurrentStage == Stage::Output); + + SetStage(Stage::Output); + + if (applyPadding) + ImGui::Spring(0); + + Pin(id, PinKind::Output); + + ImGui::BeginHorizontal(id.AsPointer()); +} + +void util::BlueprintNodeBuilder::EndOutput() +{ + ImGui::EndHorizontal(); + + EndPin(); +} + +bool util::BlueprintNodeBuilder::SetStage(Stage stage) +{ + if (stage == CurrentStage) + return false; + + auto oldStage = CurrentStage; + CurrentStage = stage; + + ImVec2 cursor; + switch (oldStage) + { + case Stage::Begin: + break; + + case Stage::Header: + ImGui::EndHorizontal(); + HeaderMin = ImGui::GetItemRectMin(); + HeaderMax = ImGui::GetItemRectMax(); + + // spacing between header and content + ImGui::Spring(0, ImGui::GetStyle().ItemSpacing.y * 2.0f); + + break; + + case Stage::Content: + break; + + case Stage::Input: + ed::PopStyleVar(2); + + ImGui::Spring(1, 0); + ImGui::EndVertical(); + + // #debug + // ImGui::GetWindowDrawList()->AddRect( + // ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255, 0, 0, 255)); + + break; + + case Stage::Middle: + ImGui::EndVertical(); + + // #debug + // ImGui::GetWindowDrawList()->AddRect( + // ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255, 0, 0, 255)); + + break; + + case Stage::Output: + ed::PopStyleVar(2); + + ImGui::Spring(1, 0); + ImGui::EndVertical(); + + // #debug + // ImGui::GetWindowDrawList()->AddRect( + // ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255, 0, 0, 255)); + + break; + + case Stage::End: + break; + + case Stage::Invalid: + break; + } + + switch (stage) + { + case Stage::Begin: + ImGui::BeginVertical("node"); + break; + + case Stage::Header: + HasHeader = true; + + ImGui::BeginHorizontal("header"); + break; + + case Stage::Content: + if (oldStage == Stage::Begin) + ImGui::Spring(0); + + ImGui::BeginHorizontal("content"); + ImGui::Spring(0, 0); + break; + + case Stage::Input: + ImGui::BeginVertical("inputs", ImVec2(0, 0), 0.0f); + + ed::PushStyleVar(ed::StyleVar_PivotAlignment, ImVec2(0, 0.5f)); + ed::PushStyleVar(ed::StyleVar_PivotSize, ImVec2(0, 0)); + + if (!HasHeader) + ImGui::Spring(1, 0); + break; + + case Stage::Middle: + ImGui::Spring(1); + ImGui::BeginVertical("middle", ImVec2(0, 0), 1.0f); + break; + + case Stage::Output: + if (oldStage == Stage::Middle || oldStage == Stage::Input) + ImGui::Spring(1); + else + ImGui::Spring(1, 0); + ImGui::BeginVertical("outputs", ImVec2(0, 0), 1.0f); + + ed::PushStyleVar(ed::StyleVar_PivotAlignment, ImVec2(1.0f, 0.5f)); + ed::PushStyleVar(ed::StyleVar_PivotSize, ImVec2(0, 0)); + + if (!HasHeader) + ImGui::Spring(1, 0); + break; + + case Stage::End: + if (oldStage == Stage::Input) + ImGui::Spring(1, 0); + if (oldStage != Stage::Begin) + ImGui::EndHorizontal(); + ContentMin = ImGui::GetItemRectMin(); + ContentMax = ImGui::GetItemRectMax(); + + //ImGui::Spring(0); + ImGui::EndVertical(); + NodeMin = ImGui::GetItemRectMin(); + NodeMax = ImGui::GetItemRectMax(); + break; + + case Stage::Invalid: + break; + } + + return true; +} + +void util::BlueprintNodeBuilder::Pin(ed::PinId id, ed::PinKind kind) +{ + ed::BeginPin(id, kind); +} + +void util::BlueprintNodeBuilder::EndPin() +{ + ed::EndPin(); + + // #debug + // ImGui::GetWindowDrawList()->AddRectFilled( + // ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255, 0, 0, 64)); +} diff --git a/3rdparty/imgui-node-editor/examples/blueprints-example/utilities/builders.h b/3rdparty/imgui-node-editor/examples/blueprints-example/utilities/builders.h new file mode 100644 index 0000000..ef5db2c --- /dev/null +++ b/3rdparty/imgui-node-editor/examples/blueprints-example/utilities/builders.h @@ -0,0 +1,81 @@ +//------------------------------------------------------------------------------ +// LICENSE +// This software is dual-licensed to the public domain and under the following +// license: you are granted a perpetual, irrevocable license to copy, modify, +// publish, and distribute this file as you see fit. +// +// CREDITS +// Written by Michal Cichon +//------------------------------------------------------------------------------ +# pragma once + + +//------------------------------------------------------------------------------ +# include + + +//------------------------------------------------------------------------------ +namespace ax { +namespace NodeEditor { +namespace Utilities { + + +//------------------------------------------------------------------------------ +struct BlueprintNodeBuilder +{ + BlueprintNodeBuilder(ImTextureID texture = nullptr, int textureWidth = 0, int textureHeight = 0); + + void Begin(NodeId id); + void End(); + + void Header(const ImVec4& color = ImVec4(1, 1, 1, 1)); + void EndHeader(); + + void Input(PinId id); + void EndInput(); + + void Middle(); + + void Output(PinId id); + void EndOutput(); + + +private: + enum class Stage + { + Invalid, + Begin, + Header, + Content, + Input, + Output, + Middle, + End + }; + + bool SetStage(Stage stage); + + void Pin(PinId id, ax::NodeEditor::PinKind kind); + void EndPin(); + + ImTextureID HeaderTextureId; + int HeaderTextureWidth; + int HeaderTextureHeight; + NodeId CurrentNodeId; + Stage CurrentStage; + ImU32 HeaderColor; + ImVec2 NodeMin; + ImVec2 NodeMax; + ImVec2 HeaderMin; + ImVec2 HeaderMax; + ImVec2 ContentMin; + ImVec2 ContentMax; + bool HasHeader; +}; + + + +//------------------------------------------------------------------------------ +} // namespace Utilities +} // namespace Editor +} // namespace ax \ No newline at end of file diff --git a/3rdparty/imgui-node-editor/examples/blueprints-example/utilities/drawing.cpp b/3rdparty/imgui-node-editor/examples/blueprints-example/utilities/drawing.cpp new file mode 100644 index 0000000..208c9ce --- /dev/null +++ b/3rdparty/imgui-node-editor/examples/blueprints-example/utilities/drawing.cpp @@ -0,0 +1,252 @@ +# include "drawing.h" +# define IMGUI_DEFINE_MATH_OPERATORS +# include + +void ax::Drawing::DrawIcon(ImDrawList* drawList, const ImVec2& a, const ImVec2& b, IconType type, bool filled, ImU32 color, ImU32 innerColor) +{ + auto rect = ImRect(a, b); + auto rect_x = rect.Min.x; + auto rect_y = rect.Min.y; + auto rect_w = rect.Max.x - rect.Min.x; + auto rect_h = rect.Max.y - rect.Min.y; + auto rect_center_x = (rect.Min.x + rect.Max.x) * 0.5f; + auto rect_center_y = (rect.Min.y + rect.Max.y) * 0.5f; + auto rect_center = ImVec2(rect_center_x, rect_center_y); + const auto outline_scale = rect_w / 24.0f; + const auto extra_segments = static_cast(2 * outline_scale); // for full circle + + if (type == IconType::Flow) + { + const auto origin_scale = rect_w / 24.0f; + + const auto offset_x = 1.0f * origin_scale; + const auto offset_y = 0.0f * origin_scale; + const auto margin = (filled ? 2.0f : 2.0f) * origin_scale; + const auto rounding = 0.1f * origin_scale; + const auto tip_round = 0.7f; // percentage of triangle edge (for tip) + //const auto edge_round = 0.7f; // percentage of triangle edge (for corner) + const auto canvas = ImRect( + rect.Min.x + margin + offset_x, + rect.Min.y + margin + offset_y, + rect.Max.x - margin + offset_x, + rect.Max.y - margin + offset_y); + const auto canvas_x = canvas.Min.x; + const auto canvas_y = canvas.Min.y; + const auto canvas_w = canvas.Max.x - canvas.Min.x; + const auto canvas_h = canvas.Max.y - canvas.Min.y; + + const auto left = canvas_x + canvas_w * 0.5f * 0.3f; + const auto right = canvas_x + canvas_w - canvas_w * 0.5f * 0.3f; + const auto top = canvas_y + canvas_h * 0.5f * 0.2f; + const auto bottom = canvas_y + canvas_h - canvas_h * 0.5f * 0.2f; + const auto center_y = (top + bottom) * 0.5f; + //const auto angle = AX_PI * 0.5f * 0.5f * 0.5f; + + const auto tip_top = ImVec2(canvas_x + canvas_w * 0.5f, top); + const auto tip_right = ImVec2(right, center_y); + const auto tip_bottom = ImVec2(canvas_x + canvas_w * 0.5f, bottom); + + drawList->PathLineTo(ImVec2(left, top) + ImVec2(0, rounding)); + drawList->PathBezierCubicCurveTo( + ImVec2(left, top), + ImVec2(left, top), + ImVec2(left, top) + ImVec2(rounding, 0)); + drawList->PathLineTo(tip_top); + drawList->PathLineTo(tip_top + (tip_right - tip_top) * tip_round); + drawList->PathBezierCubicCurveTo( + tip_right, + tip_right, + tip_bottom + (tip_right - tip_bottom) * tip_round); + drawList->PathLineTo(tip_bottom); + drawList->PathLineTo(ImVec2(left, bottom) + ImVec2(rounding, 0)); + drawList->PathBezierCubicCurveTo( + ImVec2(left, bottom), + ImVec2(left, bottom), + ImVec2(left, bottom) - ImVec2(0, rounding)); + + if (!filled) + { + if (innerColor & 0xFF000000) + drawList->AddConvexPolyFilled(drawList->_Path.Data, drawList->_Path.Size, innerColor); + + drawList->PathStroke(color, true, 2.0f * outline_scale); + } + else + drawList->PathFillConvex(color); + } + else + { + auto triangleStart = rect_center_x + 0.32f * rect_w; + + auto rect_offset = -static_cast(rect_w * 0.25f * 0.25f); + + rect.Min.x += rect_offset; + rect.Max.x += rect_offset; + rect_x += rect_offset; + rect_center_x += rect_offset * 0.5f; + rect_center.x += rect_offset * 0.5f; + + if (type == IconType::Circle) + { + const auto c = rect_center; + + if (!filled) + { + const auto r = 0.5f * rect_w / 2.0f - 0.5f; + + if (innerColor & 0xFF000000) + drawList->AddCircleFilled(c, r, innerColor, 12 + extra_segments); + drawList->AddCircle(c, r, color, 12 + extra_segments, 2.0f * outline_scale); + } + else + { + drawList->AddCircleFilled(c, 0.5f * rect_w / 2.0f, color, 12 + extra_segments); + } + } + + if (type == IconType::Square) + { + if (filled) + { + const auto r = 0.5f * rect_w / 2.0f; + const auto p0 = rect_center - ImVec2(r, r); + const auto p1 = rect_center + ImVec2(r, r); + +#if IMGUI_VERSION_NUM > 18101 + drawList->AddRectFilled(p0, p1, color, 0, ImDrawFlags_RoundCornersAll); +#else + drawList->AddRectFilled(p0, p1, color, 0, 15); +#endif + } + else + { + const auto r = 0.5f * rect_w / 2.0f - 0.5f; + const auto p0 = rect_center - ImVec2(r, r); + const auto p1 = rect_center + ImVec2(r, r); + + if (innerColor & 0xFF000000) + { +#if IMGUI_VERSION_NUM > 18101 + drawList->AddRectFilled(p0, p1, innerColor, 0, ImDrawFlags_RoundCornersAll); +#else + drawList->AddRectFilled(p0, p1, innerColor, 0, 15); +#endif + } + +#if IMGUI_VERSION_NUM > 18101 + drawList->AddRect(p0, p1, color, 0, ImDrawFlags_RoundCornersAll, 2.0f * outline_scale); +#else + drawList->AddRect(p0, p1, color, 0, 15, 2.0f * outline_scale); +#endif + } + } + + if (type == IconType::Grid) + { + const auto r = 0.5f * rect_w / 2.0f; + const auto w = ceilf(r / 3.0f); + + const auto baseTl = ImVec2(floorf(rect_center_x - w * 2.5f), floorf(rect_center_y - w * 2.5f)); + const auto baseBr = ImVec2(floorf(baseTl.x + w), floorf(baseTl.y + w)); + + auto tl = baseTl; + auto br = baseBr; + for (int i = 0; i < 3; ++i) + { + tl.x = baseTl.x; + br.x = baseBr.x; + drawList->AddRectFilled(tl, br, color); + tl.x += w * 2; + br.x += w * 2; + if (i != 1 || filled) + drawList->AddRectFilled(tl, br, color); + tl.x += w * 2; + br.x += w * 2; + drawList->AddRectFilled(tl, br, color); + + tl.y += w * 2; + br.y += w * 2; + } + + triangleStart = br.x + w + 1.0f / 24.0f * rect_w; + } + + if (type == IconType::RoundSquare) + { + if (filled) + { + const auto r = 0.5f * rect_w / 2.0f; + const auto cr = r * 0.5f; + const auto p0 = rect_center - ImVec2(r, r); + const auto p1 = rect_center + ImVec2(r, r); + +#if IMGUI_VERSION_NUM > 18101 + drawList->AddRectFilled(p0, p1, color, cr, ImDrawFlags_RoundCornersAll); +#else + drawList->AddRectFilled(p0, p1, color, cr, 15); +#endif + } + else + { + const auto r = 0.5f * rect_w / 2.0f - 0.5f; + const auto cr = r * 0.5f; + const auto p0 = rect_center - ImVec2(r, r); + const auto p1 = rect_center + ImVec2(r, r); + + if (innerColor & 0xFF000000) + { +#if IMGUI_VERSION_NUM > 18101 + drawList->AddRectFilled(p0, p1, innerColor, cr, ImDrawFlags_RoundCornersAll); +#else + drawList->AddRectFilled(p0, p1, innerColor, cr, 15); +#endif + } + +#if IMGUI_VERSION_NUM > 18101 + drawList->AddRect(p0, p1, color, cr, ImDrawFlags_RoundCornersAll, 2.0f * outline_scale); +#else + drawList->AddRect(p0, p1, color, cr, 15, 2.0f * outline_scale); +#endif + } + } + else if (type == IconType::Diamond) + { + if (filled) + { + const auto r = 0.607f * rect_w / 2.0f; + const auto c = rect_center; + + drawList->PathLineTo(c + ImVec2( 0, -r)); + drawList->PathLineTo(c + ImVec2( r, 0)); + drawList->PathLineTo(c + ImVec2( 0, r)); + drawList->PathLineTo(c + ImVec2(-r, 0)); + drawList->PathFillConvex(color); + } + else + { + const auto r = 0.607f * rect_w / 2.0f - 0.5f; + const auto c = rect_center; + + drawList->PathLineTo(c + ImVec2( 0, -r)); + drawList->PathLineTo(c + ImVec2( r, 0)); + drawList->PathLineTo(c + ImVec2( 0, r)); + drawList->PathLineTo(c + ImVec2(-r, 0)); + + if (innerColor & 0xFF000000) + drawList->AddConvexPolyFilled(drawList->_Path.Data, drawList->_Path.Size, innerColor); + + drawList->PathStroke(color, true, 2.0f * outline_scale); + } + } + else + { + const auto triangleTip = triangleStart + rect_w * (0.45f - 0.32f); + + drawList->AddTriangleFilled( + ImVec2(ceilf(triangleTip), rect_y + rect_h * 0.5f), + ImVec2(triangleStart, rect_center_y + 0.15f * rect_h), + ImVec2(triangleStart, rect_center_y - 0.15f * rect_h), + color); + } + } +} diff --git a/3rdparty/imgui-node-editor/examples/blueprints-example/utilities/drawing.h b/3rdparty/imgui-node-editor/examples/blueprints-example/utilities/drawing.h new file mode 100644 index 0000000..4387c58 --- /dev/null +++ b/3rdparty/imgui-node-editor/examples/blueprints-example/utilities/drawing.h @@ -0,0 +1,12 @@ +# pragma once +# include + +namespace ax { +namespace Drawing { + +enum class IconType: ImU32 { Flow, Circle, Square, Grid, RoundSquare, Diamond }; + +void DrawIcon(ImDrawList* drawList, const ImVec2& a, const ImVec2& b, IconType type, bool filled, ImU32 color, ImU32 innerColor); + +} // namespace Drawing +} // namespace ax \ No newline at end of file diff --git a/3rdparty/imgui-node-editor/examples/blueprints-example/utilities/widgets.cpp b/3rdparty/imgui-node-editor/examples/blueprints-example/utilities/widgets.cpp new file mode 100644 index 0000000..9faa5e0 --- /dev/null +++ b/3rdparty/imgui-node-editor/examples/blueprints-example/utilities/widgets.cpp @@ -0,0 +1,16 @@ +# include "widgets.h" +# define IMGUI_DEFINE_MATH_OPERATORS +# include + +void ax::Widgets::Icon(const ImVec2& size, IconType type, bool filled, const ImVec4& color/* = ImVec4(1, 1, 1, 1)*/, const ImVec4& innerColor/* = ImVec4(0, 0, 0, 0)*/) +{ + if (ImGui::IsRectVisible(size)) + { + auto cursorPos = ImGui::GetCursorScreenPos(); + auto drawList = ImGui::GetWindowDrawList(); + ax::Drawing::DrawIcon(drawList, cursorPos, cursorPos + size, type, filled, ImColor(color), ImColor(innerColor)); + } + + ImGui::Dummy(size); +} + diff --git a/3rdparty/imgui-node-editor/examples/blueprints-example/utilities/widgets.h b/3rdparty/imgui-node-editor/examples/blueprints-example/utilities/widgets.h new file mode 100644 index 0000000..09b3946 --- /dev/null +++ b/3rdparty/imgui-node-editor/examples/blueprints-example/utilities/widgets.h @@ -0,0 +1,13 @@ +#pragma once +#include +#include "drawing.h" + +namespace ax { +namespace Widgets { + +using Drawing::IconType; + +void Icon(const ImVec2& size, IconType type, bool filled, const ImVec4& color = ImVec4(1, 1, 1, 1), const ImVec4& innerColor = ImVec4(0, 0, 0, 0)); + +} // namespace Widgets +} // namespace ax \ No newline at end of file diff --git a/3rdparty/imgui-node-editor/examples/canvas-example/CMakeLists.txt b/3rdparty/imgui-node-editor/examples/canvas-example/CMakeLists.txt new file mode 100644 index 0000000..11f1c89 --- /dev/null +++ b/3rdparty/imgui-node-editor/examples/canvas-example/CMakeLists.txt @@ -0,0 +1,5 @@ +add_example_executable(canvas-example + canvas-example.cpp +) + +#target_link_libraries(Canvas PRIVATE imgui_canvas) \ No newline at end of file diff --git a/3rdparty/imgui-node-editor/examples/canvas-example/canvas-example.cpp b/3rdparty/imgui-node-editor/examples/canvas-example/canvas-example.cpp new file mode 100644 index 0000000..370f97b --- /dev/null +++ b/3rdparty/imgui-node-editor/examples/canvas-example/canvas-example.cpp @@ -0,0 +1,251 @@ +# include +# define IMGUI_DEFINE_MATH_OPERATORS +# include +# include +# include + +static void DrawScale(const ImVec2& from, const ImVec2& to, float majorUnit, float minorUnit, float labelAlignment, float sign = 1.0f) +{ + auto drawList = ImGui::GetWindowDrawList(); + auto direction = (to - from) * ImInvLength(to - from, 0.0f); + auto normal = ImVec2(-direction.y, direction.x); + auto distance = sqrtf(ImLengthSqr(to - from)); + + if (ImDot(direction, direction) < FLT_EPSILON) + return; + + auto minorSize = 5.0f; + auto majorSize = 10.0f; + auto labelDistance = 8.0f; + + drawList->AddLine(from, to, IM_COL32(255, 255, 255, 255)); + + auto p = from; + for (auto d = 0.0f; d <= distance; d += minorUnit, p += direction * minorUnit) + drawList->AddLine(p - normal * minorSize, p + normal * minorSize, IM_COL32(255, 255, 255, 255)); + + for (auto d = 0.0f; d <= distance + majorUnit; d += majorUnit) + { + p = from + direction * d; + + drawList->AddLine(p - normal * majorSize, p + normal * majorSize, IM_COL32(255, 255, 255, 255)); + + if (d == 0.0f) + continue; + + char label[16]; + snprintf(label, 15, "%g", d * sign); + auto labelSize = ImGui::CalcTextSize(label); + + auto labelPosition = p + ImVec2(fabsf(normal.x), fabsf(normal.y)) * labelDistance; + auto labelAlignedSize = ImDot(labelSize, direction); + labelPosition += direction * (-labelAlignedSize + labelAlignment * labelAlignedSize * 2.0f); + labelPosition = ImFloor(labelPosition + ImVec2(0.5f, 0.5f)); + + drawList->AddText(labelPosition, IM_COL32(255, 255, 255, 255), label); + } +} + +static bool Splitter(bool split_vertically, float thickness, float* size1, float* size2, float min_size1, float min_size2, float splitter_long_axis_size = -1.0f) +{ + using namespace ImGui; + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiID id = window->GetID("##Splitter"); + ImRect bb; + bb.Min = window->DC.CursorPos + (split_vertically ? ImVec2(*size1, 0.0f) : ImVec2(0.0f, *size1)); + bb.Max = bb.Min + CalcItemSize(split_vertically ? ImVec2(thickness, splitter_long_axis_size) : ImVec2(splitter_long_axis_size, thickness), 0.0f, 0.0f); + return SplitterBehavior(bb, id, split_vertically ? ImGuiAxis_X : ImGuiAxis_Y, size1, size2, min_size1, min_size2, 0.0f); +} + +struct Example: + public Application +{ + using Application::Application; + + void OnFrame(float deltaTime) override + { + auto& io = ImGui::GetIO(); + + ImGui::Text("FPS: %.2f (%.2gms)", io.Framerate, io.Framerate ? 1000.0f / io.Framerate : 0.0f); + + ImGui::Separator(); + + auto availableRegion = ImGui::GetContentRegionAvail(); + + static float s_SplitterSize = 6.0f; + static float s_SplitterArea = 0.0f; + static float s_LeftPaneSize = 0.0f; + static float s_RightPaneSize = 0.0f; + + if (s_SplitterArea != availableRegion.x) + { + if (s_SplitterArea == 0.0f) + { + s_SplitterArea = availableRegion.x; + s_LeftPaneSize = ImFloor(availableRegion.x * 0.25f); + s_RightPaneSize = availableRegion.x - s_LeftPaneSize - s_SplitterSize; + } + else + { + auto ratio = availableRegion.x / s_SplitterArea; + s_SplitterArea = availableRegion.x; + s_LeftPaneSize = s_LeftPaneSize * ratio; + s_RightPaneSize = availableRegion.x - s_LeftPaneSize - s_SplitterSize; + } + } + + static ImGuiEx::Canvas canvas; + static ImVec2 drawStartPoint; + static bool isDragging = false; + static ImRect panelRect; + + Splitter(true, s_SplitterSize, &s_LeftPaneSize, &s_RightPaneSize, 100.0f, 100.0f); + + auto canvasRect = canvas.Rect(); + auto viewRect = canvas.ViewRect(); + auto viewOrigin = canvas.ViewOrigin(); + auto viewScale = canvas.ViewScale(); + + ImGui::BeginChild("##top", ImVec2(s_LeftPaneSize, -1), false, ImGuiWindowFlags_NoScrollWithMouse); + + ImGui::TextUnformatted("Rect:"); + ImGui::BeginColumns("rect", 2, ImGuiOldColumnFlags_NoBorder); + ImGui::SetColumnWidth(0, ImGui::CalcTextSize("\t\tL: 0000.00\t").x); + ImGui::Text("\tL: %.2f", canvasRect.Min.x); ImGui::NextColumn(); + ImGui::Text("\tT: %.2f", canvasRect.Min.y); ImGui::NextColumn(); + ImGui::Text("\tR: %.2f", canvasRect.Max.x); ImGui::NextColumn(); + ImGui::Text("\tB: %.2f", canvasRect.Max.y); ImGui::NextColumn(); + ImGui::Text("\tW: %.2f", canvasRect.GetWidth()); ImGui::NextColumn(); + ImGui::Text("\tH: %.2f", canvasRect.GetHeight()); ImGui::NextColumn(); + ImGui::EndColumns(); + + ImGui::TextUnformatted("View Rect:"); + ImGui::BeginColumns("viewrect", 2, ImGuiOldColumnFlags_NoBorder); + ImGui::SetColumnWidth(0, ImGui::CalcTextSize("\t\tL: 0000.00\t").x); + ImGui::Text("\tL: %.2f", viewRect.Min.x); ImGui::NextColumn(); + ImGui::Text("\tT: %.2f", viewRect.Min.y); ImGui::NextColumn(); + ImGui::Text("\tR: %.2f", viewRect.Max.x); ImGui::NextColumn(); + ImGui::Text("\tB: %.2f", viewRect.Max.y); ImGui::NextColumn(); + ImGui::Text("\tW: %.2f", viewRect.GetWidth()); ImGui::NextColumn(); + ImGui::Text("\tH: %.2f", viewRect.GetHeight()); ImGui::NextColumn(); + ImGui::EndColumns(); + + ImGui::TextUnformatted("Origin:"); + ImGui::Indent(); + auto originChanged = false; + ImGui::PushItemWidth(-ImGui::GetStyle().IndentSpacing); + originChanged |= ImGui::DragFloat("##originx", &viewOrigin.x, 1.0f); + originChanged |= ImGui::DragFloat("##originy", &viewOrigin.y, 1.0f); + if (originChanged) canvas.SetView(viewOrigin, viewScale); + ImGui::PopItemWidth(); + ImGui::Unindent(); + + ImGui::TextUnformatted("Scale:"); + ImGui::Indent(); + ImGui::PushItemWidth(-ImGui::GetStyle().IndentSpacing); + if (ImGui::DragFloat("##scale", &viewScale, 0.01f, 0.01f, 15.0f)) + canvas.SetView(viewOrigin, viewScale); + ImGui::PopItemWidth(); + ImGui::Unindent(); + + ImGui::Separator(); + + if (ImGui::Button("Center over Panel", ImVec2(s_LeftPaneSize, 0))) + canvas.CenterView(panelRect.GetCenter()); + + if (ImGui::Button("Center and zoom to Panel", ImVec2(s_LeftPaneSize, 0))) + canvas.CenterView(panelRect); + + ImGui::TextUnformatted("Panel Rect:"); + ImGui::BeginColumns("panelrect", 2, ImGuiOldColumnFlags_NoBorder); + ImGui::SetColumnWidth(0, ImGui::CalcTextSize("\t\tL: 0000.00\t").x); + ImGui::Text("\tL: %.2f", panelRect.Min.x); ImGui::NextColumn(); + ImGui::Text("\tT: %.2f", panelRect.Min.y); ImGui::NextColumn(); + ImGui::Text("\tR: %.2f", panelRect.Max.x); ImGui::NextColumn(); + ImGui::Text("\tB: %.2f", panelRect.Max.y); ImGui::NextColumn(); + ImGui::Text("\tW: %.2f", panelRect.GetWidth()); ImGui::NextColumn(); + ImGui::Text("\tH: %.2f", panelRect.GetHeight()); ImGui::NextColumn(); + ImGui::EndColumns(); + + ImGui::EndChild(); + + ImGui::SameLine(0.0f, s_SplitterSize); + + + if (canvas.Begin("##mycanvas", ImVec2(s_RightPaneSize, 0.0f))) + { + //auto drawList = ImGui::GetWindowDrawList(); + + if ((isDragging || ImGui::IsItemHovered()) && ImGui::IsMouseDragging(1, 0.0f)) + { + if (!isDragging) + { + isDragging = true; + drawStartPoint = viewOrigin; + } + + canvas.SetView(drawStartPoint + ImGui::GetMouseDragDelta(1, 0.0f) * viewScale, viewScale); + } + else if (isDragging) + isDragging = false; + + viewRect = canvas.ViewRect(); + + if (viewRect.Max.x > 0.0f) + DrawScale(ImVec2(0.0f, 0.0f), ImVec2(viewRect.Max.x, 0.0f), 100.0f, 10.0f, 0.6f); + if (viewRect.Min.x < 0.0f) + DrawScale(ImVec2(0.0f, 0.0f), ImVec2(viewRect.Min.x, 0.0f), 100.0f, 10.0f, 0.6f, -1.0f); + if (viewRect.Max.y > 0.0f) + DrawScale(ImVec2(0.0f, 0.0f), ImVec2(0.0f, viewRect.Max.y), 100.0f, 10.0f, 0.6f); + if (viewRect.Min.y < 0.0f) + DrawScale(ImVec2(0.0f, 0.0f), ImVec2(0.0f, viewRect.Min.y), 100.0f, 10.0f, 0.6f, -1.0f); + + ImGui::Text("Hovered: %d", ImGui::IsItemHovered() ? 1 : 0); + + ImGui::TextUnformatted("Hello World!"); + + ImGui::Bullet(); + + ImGui::Button("Panel", ImVec2(s_RightPaneSize * 0.75f, availableRegion.y * 0.5f) * 0.5f); + panelRect.Min = ImGui::GetItemRectMin(); + panelRect.Max = ImGui::GetItemRectMax(); + + canvas.End(); + } + + + + + + + //ed::SetCurrentEditor(g_Context); + //ed::Begin("My Editor", ImVec2(0.0, 0.0f)); + //int uniqueId = 1; + //// Start drawing nodes. + //ed::BeginNode(uniqueId++); + // ImGui::Text("Node A"); + // ed::BeginPin(uniqueId++, ed::PinKind::Input); + // ImGui::Text("-> In"); + // ed::EndPin(); + // ImGui::SameLine(); + // ed::BeginPin(uniqueId++, ed::PinKind::Output); + // ImGui::Text("Out ->"); + // ed::EndPin(); + //ed::EndNode(); + //ed::End(); + //ed::SetCurrentEditor(nullptr); + + //ImGui::ShowMetricsWindow(); + } +}; + +int Main(int argc, char** argv) +{ + Example exampe("Canvas", argc, argv); + + if (exampe.Create()) + return exampe.Run(); + + return 0; +} \ No newline at end of file diff --git a/3rdparty/imgui-node-editor/examples/data/Cuprum-Bold.ttf b/3rdparty/imgui-node-editor/examples/data/Cuprum-Bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..d56cd44e3c2486cf96d65c0d17e4fe6123567208 GIT binary patch literal 96364 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 r_L}Eb^V}(OyrDK|=|! literal 0 HcmV?d00001 diff --git a/3rdparty/imgui-node-editor/examples/data/Cuprum-OFL.txt b/3rdparty/imgui-node-editor/examples/data/Cuprum-OFL.txt new file mode 100644 index 0000000..6acddd0 --- /dev/null +++ b/3rdparty/imgui-node-editor/examples/data/Cuprum-OFL.txt @@ -0,0 +1,93 @@ +Copyright 2010 The Cuprum Project Authors (lemonad@jovanny.ru), with Reserved Font Name "Cuprum". + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/3rdparty/imgui-node-editor/examples/data/Oswald-OFL.txt b/3rdparty/imgui-node-editor/examples/data/Oswald-OFL.txt new file mode 100644 index 0000000..7e2c152 --- /dev/null +++ b/3rdparty/imgui-node-editor/examples/data/Oswald-OFL.txt @@ -0,0 +1,93 @@ +Copyright 2016 The Oswald Project Authors (https://github.com/googlefonts/OswaldFont) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/3rdparty/imgui-node-editor/examples/data/Oswald-Regular.ttf b/3rdparty/imgui-node-editor/examples/data/Oswald-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..2492c44a2de20b40ee64b10d8da1f8129227c78f GIT binary patch literal 91400 zcmc$H33yybm2TC&y-RAT)tg$qsnwg*+IMSjNtR^Uk}Y|a?08W&FR~rm*%LxcNJ7{l zo?#fsKp2<@2}>M?44J%4h!e1##UYS|fdK*`5Flh>O$MUY`%l&FtJap}eeb>RInh>q zZq=z%r%s(Z+hv?FR*Y{3RyMqPaOlvV54AI1`!UA&4a4IbHhuDj+s`px?_#X>(cw*7 z`ror|rjYSnKV!`J*A1KM8t=-#@*|A>?N8`s&!)|No3Fn0K#=hZe~iCV7aW>Ca+~#a zeD>yM#w<5naK&Y11@X{7GVZ(|pWkrtk-djL)9QMXal?NyW_RzMzVry%i!lBz_-WaD z@al_M&lkTBT&fxS_1E@YG<{()H-D0`S6{&At^3em`I_;cG5(YIJGSr8WmoYR_dLMZ zYXQdczJBnM3#J3Bp8qvtzj+h*{_4>5RYwf{g`N1D@GCn!edwYKzWL!<#$9Q~)Xb4f zF1_qiYnu{`m*8*D(2-*o9VzNMc!u%f*8u+*Q`mOKlyNo1RAy$WbP}zq!qmM?;au6q z6ov0L;5WX3F|)~N0GR49n!Ht)IwFpE#1Yxf|B^Y%D>DD7rrvyZyK)73bYgZtM2}`> zW7X+O8#gdMiq%lKLD`4?YsQQ!davc{8M9gdW_CCnCabUNQfHGhnv9yAO{()NhrT)! z|CeOz`&LuOk3Y_X{LtK-?AuUg!i+GAS$UZKh5edY?pFB8U!QEL%0j5W*CEcb*O!AZ z+@wSNCJUkHeawwx23j91seBKk&}iAd)PUX$6Q+=n%il&S@SW z(MPckaV86~2#Z857EW{5Dx9bqEtpG7Ur*m%$@!(PjF{hL^Cv7fSF3I7ehq6yDqG&?L@9`BN=J9)C zc?k7cy^qJ1Ld^O2uhe<`p5b3(Ovlf!Klw=Z$@$eHo-jJJnI#ngfz`r};6G%JyA=s} zw}Icwe~7Iy-)o89>!aCT<*b=9cMj5EC-!b3D`x%a-eT;0>|F>1ivpQoVJ3scw3l(t zc8iV73&VF^eC`FB8{=&py^1L+WTf#p zGa6K*;oVGC`825BGzNmRX%l2$Gh5GDv^*4WI}7bL3rq5(+3KkpEKej_9L=q*O^qIp z+Z`2iDL0wi4wuIxX4KL|^X0a!yW{cQTSupoGuDc_`sxB#ZL+q)HWQn)uDNC%4{f|= zVAZ~nbbHNUqHlLd>Eq-3&H0b7tUdFZfs4jia}Q zmRsFz;i_7zVta){!GPaaOq& zWjXaZv2K_JcHbFpS+M&Q=0N+;gpBxqhj(9n{oUL5RaalMWw=*Ty{oJ1?eP{oA@M%7 z5O28$)lKv3!%ya{Pj36y#rkl;L)Qu(s!Las3^b4oTqyfYToZlZqC6q?%vL`sN4nVS z*PGuo<*(GO9r!vi2o2@3r zbJy*mrB4d{NNbQYczgv2l5P^>iRB@L)*vAsTM7ZK0i3Dh_YCjKN*Yjy&Ug9bqYIzJ zDHFme^A+%Pf{ms}0^DHqa+4v*Rg*f(xT>gJInGQ>I7Jj?lJfOT?|>Ooe!YRDGd;vid;0Ef{lI z{QVtUzWhBt^`FkZ@$IpSNo(V-wBKMgwvD(e+9E^StNVX7(U5s6-hb7`H8Y*GX9VVA zUHd^}$R+kd?vB9RXyvcM+^noJomjeGjoe_UHLS;iTA7u$s>xcKvr~I{``J%Jd{1Ql zFrK+7yGySUe6m`Mc#3^{(TMePf8o#L%uca)-%|l%^3ioCz2lR(MJb@DVj@}^4JPB> zMF+Uqf|Cv>xIbO>7LaChtvv57lJrw)FK5X_JeG6pr+CWx&W?RLC!$H5{A_ebWqkLR z(VeLS_Nv;(nmk8+b#;C5-gCowMXPOn@7l%-r>^U7+CLuhwG2dRH#BCR?pU8lZR}n( zp1EXaO@}!BF>fKih6H6E=J~ml$wCPEB_Yo8g5@B@dP;~h%lDB3ae664=I2Cz@H_gz zK79%hv~qG?NI#H$pIZ1NcmoiM4=bl)r~Jb`)f|Vfws!T*V6+$wmgCTN&CFun%b1Nr zTjO*rtJ7FXXkjLkGHuOM6s1|gA~wI1N32$?COwzO#bZXm4E| z#-(phKB>%f+=PD}vwu&c^T$66o*?P)d%;cUndAreE#k<<5T_SHfDVJ;vTtAxD)Xg1 z_`PNf*CVM(id9pk7U>wggp3x%iGy=5^Ir;`V zEQVmPim@MyvrvpYiom={$U1!1CP=gSDh;TMHe9*cEi6Fvn|s zwj-g@A?Jjxv>~A!o&E68l(>~+B;GG(ISs7L%4v2_?n(m};!MINk0sJko7DtO6ecxj zqToP-3Ncix(76T`w7A$|6xV_#2U*dgsu|nyzWuk~clguI*pWBzcV|AG>E!R)m3dy< z6EBOAFAyW20e6x$Ek~<^gvH2M0YH$1CH~bgx*ixASvXB=0K&jZxQ7TMaWOKZLl6OX zY+OWokA7E8%_gPxJNL43jo1?xQ=e>_e^}REt`{7GcCja}T8s_aj|*%h#CLcx^GSSt z()!m6e1RA66@3HW=jQv)wxjR!*o&-FKG~@~Id@p;na7HE5LS%O{T1J6rUi^_nO2J# z1m`%BVQyGv+6An@?WVQA)M0LE!_?c{W}5!s;L-j2zss*qY)kO%nP0YV?a2J&1nAfe zcG`yC^XZnFXHj8$%`Pmi{#aT`&3u+$>?oER3yh>>CskGa-(7ggM?ZGBaEJB%>07KI z@FmK}-+WdXo&5%Vk^GVU)9yViXnKmT&84Zfk`UHViel-A1taPRgOgd*dNzSW| z-mzcpTJswW`YWXrgI3P|fH(?kJ1eMoM6Rs@xvz2BlVWYrPHU^(&T=>n?N16`ln~i_ zXAT6`7MNl#qHmn`7Fr>UIYR9?DK>mF-)sU8(pg@PE$bzI6s(D}7Y>1G(g7O{II>-^ zp2IF}xM&`Nwr>HToD7@DBWOL?LN=fl6-P`H&6@Tx&ugm5|LOLz-%XaT?)&DLyQwO| z=VpJ9r9;<5O3WABbZVXsykh|!NJE#id~_ilgl6(Oe+in2gGE_Q8fQ(`^kc+a*fi_| zq&Yg_;0Tl!N1ajFejFUwF1Gy;vPnW;7%{RYAa37yeyVDE&-rReR=sdPbhncdM`g->*MIv?HCFXs6L^nYDc=i=lqb%hBk(ma}|( zc?k6~9pcw;@htSt%ySU@VZiiZt&e$+idcgqe;M>_b=I|at%&+wmS%`&n5;}>b6IO5u6?_ZU;2GYExvJpne?$8b{N{!o zxFy}Fa=sSF{KyJY!0Ry@%0ix`H;Jo*+vp}Kur2BIstaxn%S(dWlW$ghbOm9sHedak z?ahzBtwrHooW(K2b*lUKA zz2@z9aU62G)GQ+l@WosB72mo2_A{AVTUT|rVb{}!|jt@;otDpU0c>efu%e5dHi=c*@CQ&)u(HG93J7(-~#TZ z8zAmT;)n}}DiWc(a9uKC1X%`am87XWsxMU5;tj`*cbQ}EU;Qn0PJ_*;G5B;~dvi~KFJSV{>A~W{NWl8(#fKl^Pg*$n6bhkpHl^!rT#-H}@@tcE zKwDQBezZHG&nv0tD1o<$Z1vfdHA8)yUtG}d^AiV}T-C8l4;`4Ss_zOkk2R{Ps@-FC zV=eia1N>c?8~M4Cj^^QBZH1o``|Z=(elz5*uns{IN@@6%u$@4jWwjX2 zB4Mu^`>=-B7)f?vd6R7+MeB?RfRGZg7B?Qq`LY!F!!cB9R5TNVRfSB)l{>jrz zpTvsfKKWGclVU&1F;6Xg67*gLde4I1F?KXvgi?NFb~Nj+<$-N!oJ!>F6>LF!KjYm z@RVVJpeak|qZfAHMzZ=wGv)28R<)PhDQbt5iQETcY4H54S;b@R6b#5*5c% z)0=dK`3F*0{^IAQYCKf8NN3)=7rHVq1hM!>AT7)+k`9sWOgojZ9i%r8pHSe7ysnd> zJnH!5`}y@ZDbH@+Je$JovpuM|*f*yeuoPHR*da+ss=KkHYR1gc{e&}x8S)HybUnpv zDMrTvQ`9E1zQaLCU03p+?^5sled%=OYB>hDUW_4plXn6`vZ|k5#Px-9Zkh+Ymw*sF zeOB;vAviX-{V6<2ye_fMNO<&kYGIEW$CCHnO*c+xIAm4Hx!Q1q5r{=|b2kYE>C(pK zOLJh$dl)a8+*N+iURPINYo96KX&t(Li{hJozIkh7xY01?T#14u0AQ| z_b@M7G(Q0$ZY&bwEO#siA!MF}IJ0~oIS{Ac7UEnMLYJ%(Q<4#Kln0lA7{_iPsSOCB z85aqPFP`H=*(Y_4R6>wuEc@Jd#So-JN{C0b87zRnN|WX;XYlRp99N|96IqCbbP}4o?BlUz zAbbnf;2FLuXALM`M?U#T_Q^$~(+ng;b_Uw{f_>oyU7yFkFpTV%n!W!D z5GPBB)BNoq9?U}M)LJ~sLs8#+6 z|FQqtBm3|C`u-b_@h|ZkGSBl+=JL!mZ^(QXG=vvP^lf3$bQ!wNvC7S_g@sv)i>0Yg zcI^0{ckO@IH3z=NLrQ+;YW}|2KV_aLiizF?#m-5JvEMJEn1mpTNr=;L3-MqULZ?_h zY$BkC?1Oe6AeI~bq3n}7*UQmq_sP*8Umim23kmVq@(|*VCm|kP2mzWVF!v8(y{x4B z!wU(A8^x8bgQ(C>MjQevf=#m=3Y#Nro?_)%oWhaZ&t zgo34TT<4BqQYv`}TgAZ)H5U#p)&@WCx|1P*mEpnzFyrwR;nKJ{E(U?VR;%?#fnVru z3ZCF(0wirrHkO5PsdeH48Rv1`6W`pUw9P9yNulD12rzFH3bwQhwzb$*XgZ%MZw|$J zH`Q8vK94{DfUl&z!=c`u5)@~^ZcnrSkh_lp^>@IIbAaQYJwASm2`+|l&J9bTF z-tae8Ig1)x<(=mhd(B_42f|5Tv;sUY=%ua#&3`1$f`{3E32v0_R=xc!L)@|s|4(}R zZ}j$Y{$4c;p9EJwBl=tEx!>x~VZGGH_5NO3(Ec^O{dWuSqTM6$J+ngl>74f8satjU zm-TkS*Q2%1sNr!(# zhsU^vO0AuuTERDBSN|6ziUrZECx0*fHIkF+^&TE2NT|MOSN341cCa;UGoMZujHF{0 zgIQ_gCbNPIkrf-Ui75scijFZeB0rCa-Drf|X&pnXx;>Im=_5?qmj= zVw2C<y~h1ZwWmevG(B^?`Uf-Q*h4Q_H* zmF+6D1d^qmh?83jEU{#1ytF2)NhSC+X?Kt}o2=Co0ifVk@dp1poMkR(Lm!f|y%1MW zwLGH02ubl0qyBVm3rEY81PtPs!-YqSC83joLV9`jq)0~=eGU#I@t=+RCGnp|U<7C3 zpgZP?C&jlv+x9 zHUvscmePPbZnq~bVP^_%;@^78>V`*3Kh%9_U~}bA>O-;aSaDwF!+C{}7;^69d-;pl znWx}c%&{)vq^|;Xj$sET-XfB@bv}|AGvcf~67*}4%m^u?NM;#Qmc5?mL^3aArl*HT ze5E5py@RFGw$hT)fHe^F`^?k+K}-9-!J9_*wpC7al}8iRu9EhKe_Pw=s}0swbZoAs z)fIS()qO**E_*`ACfQChPPU)X+ubxTz5Qvu9rG2kSi+xP&`xK8Y(GWq;2!G#MsQCt zi|E{whg09{0rwPTxhJPZU50!3G#DexJ?c{K(LRSVvXpyVPR{&3XT%jDJGj-1Y^h>R zcWBWJB3|QrK}Qlo^(I2(x@lz82wg28d@0 zpQ9}x^eEV=j7Bk&`kXBw0_VbDG%{S1O-qBF-z0#*CP~COYpjp2O01$lB3Kz?Jf^Ei z*?B?~!BLOzZ61#o&idR<)1|hEsgvE&^K#Foijsl;XuaLwuwS{|Ju+;ZJ{Gxb${nzm zZ|Dz(^9o|#P5D>nA7-dU${qf##HEE%z{zQeyEVjFP7rPv0IZ@vY-DTOucOPbWl<5nIHDHdx9 zXBHuKa$3x2(WFiiCxi*-hYCxz!2tPVwQ3xa$1N6^&TQH#m#$h7l2JgS1V_}CP(;(= zfFEfH5r1W%l8Efod@JCoQeK*`9S>Prw;)t48@2ToymjQrOlRi`{Pls(HETL&rxvrA zwwrGfI=rOcDWt6B$R!D(WU>@yW`2^xmat6w*Qs5j_cf4XK~}*IOT{71=mu>#26HL) zDrkv#O1TlS(b)MEBTMRjIzezqML`0`TLDg`A;;sw zt_J_I-ad~0AsIzGX~`HD=j)65=Wp<@<~;XGPWxHXlC}O`&1t`ev}CRQHLcwaNsCA$ zz5Uz*`1$q+7qn;bBHLw_9>A9*zt+FNcNzLUq{Gv=(4IB;#}~BEkNZS!J891v{9}51 zbbefD!OyV&W{8y}zrIas!E}~fqe2VTo_v&^6ukR7Jt=tiGReCMX+Fm#b)ogVb!>t4 z+@DUaWM^LlIhFQ>Lohf+Llxl)k4v-Kf`iG_u0@3Fj4Dj+!v8g|lL)r{?wTRb3)a$r zuhhD4-6XN|+J12FwU$yVaqf{|eZZRn=We~QdGETLNB1^w0PlvIqm4d@NkoNr@vkWT z&^3nBs{>wa%Ag0a*UHjpc4*C@%SDiWBC5UK0IfrYvb&uthq4Q;l(NCvypiQ%*^?D^ zS4-nX|6Y-KlMmci);+o{UOD+~J(xYdy1IQs<=~&A;~jI%-*~z|e4`E#Z<(@7rQJjiFh!|xW$6ei+5pqW4<#IX~O{Q8CWR4%x zgLO*Xzs#r7cT>Vj9L{*m0p~zKi=)jtYqTSt0%|7*2cbT?!cMEl8g@)h@;`0}wT`7! z!+J%nEU({?DZmUQrauPXA^J~P`M=Fh%XqrebXuv*H8;k;rHtXcA7(q)d(ysOiDKjt z9P?Fn_-*=-P^cJ20|;}VmCf4j2+0j1SFq`>uK%hJnDUXk|)U_8HtAj=Uf~vUDoEIAG zE(qnD3cSAUtNW{`y4qU{%FA}-x$>)9ynegUSm5`1f_9U!Fz~OQ`eYy#wppUivRc1y z{ov{yb!BCiWPy25DJ(QP(!S2^O$OCkl9yMYSWH8Gb$w-<{h{I#yK2ev`0S;ne1{`a z9||=@i;E)-W&XNy7oBZl6@-Kj2~K;M>>GMJNqE_QR=a;oc#=@E{mcUR`S#Nb+V|-2 z-(Ap7l2rC{irSfB?)N%Zbg^}Cn15REg&BNdG812z1{d>1Wga(Cl7zCKsa9|gVmzRT zXbfT#em{!v5Db!73JVB)Yy_udA2NeeqGO{y-RO%hK|80(mLr|Fi?{N+MY-e8hzsot7H#J4xj(Iq1$IkwsxaGo=ufmJ(gmi&q6=APh zSYj*r6tdn47js2jQR!3A?x5IIYKTzY$FuDK?-rYf4nNBKHZ473&rl)8ey?rWOEd0D?n2w~6*QBKzsL%?#XJ%%U{@DkVPac6mOOA(gF`KDSze1)$ zw|Iyo0%15SBn85&5XJxSrD&!60QS1j1ZC^l%c%8Nm@gCOmux*PV7~^~r*m4*iPjg< zI+xS>Ahn9o?hqQF?BSGbMJB-=ss(gR2^_vBdUy%He<=sEhXiaCt-laDmh9ni0sAUi zU(Xrs39aA5{1d9hAp14*4mxjv1x_*cl+e3mACHMXev6EOFXv$KjA;D{=4=(3mV|xu zQs`N8FV7ujcVk_PU<Wv6v*{)qFp)u#eDzpkMX49jFXz(%P4Y_efsf(( z3wmC>2$nL7ybR|Yt`d-W8W8oOkO#o+aKKaUa^TKYkZ&=uB3`7KO_D9So^oQ2SV1_? zSZwr`=FO}tJ9w*V7~@KDnM>)Oy?6B*HANgFW^xi7Q^bar&ciW}Jfx-HBpe2*}ZD!wj;OPICHRpL*4}c`h4bgUa|HkSbN#?bKo^_zSz|P zk(fbly)sioN%E8v5`FLxH7&Y4dhyz$1F=~YU9 zCi9cbr+HxWS@fAk&tHbr%kI~eGK-!%49WUr zm*h&!Cre?i+%j2eK1*WD>eVyIO}{;|xs11E{uB%}&AJ|ujEFzOr(`SBKb%Sz;ll(=L_JYgEQ&<> zAO+{iLjwAsxTfgG7Lr=^-yN+N1c%~fO?lywia>4PeCTiWF8W^QR{Gl_Wo4C#sK2v5 z)4{)$3i><-i!u9arV^ADa}iQ+4G_Tnl5fUOF-LwAZfh}oB-6q) z$F{524_lH9^fx}zG@ zt-$qR&4XqG!jG#P4M}DF-1EwF$edg|jFj5D8NXL~j#PjBS<)8evuCttTd|`sPrdyq zYRCMm=hpCR#clNiX`2Igo_v_9vhxqX(5WI~P*pKsY<4;~YYi6+Ph*(c5*K@;Q`eN&u4;0e%~Zt#*; zj|!Sl?AsgsI?!ZM9tadJ5hF`^ATTv8mj|-Qa=yp~V1iS?<9Q~%HXL4?PLG7cBk8cu zX!M1{rAA|^rFl=^m-_ZJYdEJ zrvZt4gr}t(twziS)>x-a)+@W1#t$vPf$T~W=f`u~l@ICdPm;e%r#;#C&ezsT+VSML z1TWjar`h-B$Cd35Eoi54W&7g`+KG2%`=dGSpBE>m#Pi#^c;?XjiQIOfhe>#%sl-1r zPajb58IFu>P!RSn3yB&PT=zLZ+=ky)$e38PUzX39;4))Evs1(1y6m3WQ^sxaPpzGb8yj$5H}JfB?TVUDM0OHXQ6gvMo_!PORq>?dPP#A9e(f2 zATLrltB2Xg(zXI*DONy5AUR4-ZzOA~Fn%3F1deL7s(WoP{AZ8Ge6xa6^n6p+*NwUa z07mJd|(ZsO`H&Q|yLbhk8BbyasIVv({S4#nakI9*VoKywqLLWJhd^9tW^j$vDR zhNbN#*Iy}xm2=+S{XEDYTGLZj7qR8Vo5Owm-d~$TWuelUwPQ{F4tslTxYT4Sg+U$P z&t7LL4F&ubOVjSYuk`I|c7$D?P*MBg4Gpo{@rEjdmrrd>l!cR%(N$$%DQk~L+wo&n zlv~50_88j8j@mlc&rgVxImZ4eU8v#&5l&tl&~VC0B|nIJX!d|6ACxfCwTUE(Mrb1P z6i0;hNQ&PGT^=`T0SWIfGzM2i6!tt{)i&*b(i~VsOSe;` zFV4GuTW6fD((BvX9sR zw-z*N1C6rY@XG~__!1gL04coQ%g>JJl#U?nL{V>E5fZ2L%5%^4crQEmwncOI`%D%; zdA(`wzs_}eFP%KivKq4_9gV!U_h{a?!mQU8+L`qEqeT&ZT-gHe8(jm5L$X^Q22%@|7{9`3 z_C_+>Az{f{(=R0K<>-g>lY8Y^f_BuBgd~;iXS8;@=y7hj11<>+#t9X@`^+Mj~ z1xYW$GM$t3f?bU>>HguZrYTDz9t?SW7lbO2q%=5UTw^E-cuT_tMHjo{B^7HdQzQPi zwn)HN;oef3ZmR8#O!fLhHNI#`VbH$IS-mRW&>sPv1jd3+xM&MH{ZBzB*-kT;?PplF z-Ayyp+n?6kF>^r?34c1<4!Y*TKb37KN(m_<;ZIRJDAUCo7%Vcl+g^aCxv&%#da+9?)Wi1MS6FL9F)O`>mE)Mlq~Y6 zeV8J4mAZe)XZn4Q{5rCt5qa4c`gIohbQXGaWOAlg;?@m; ze3KEkX9a<|!hS^|ahjW(GnYf;QOc~75?-RauBj@W=IN(`P_1ollj+HtHeYx5%+8&j zu*Ge2m0QYtQvB-SJMI|He55>x3bVN8Vw!|WIWSRS&fSn6^+Ah4w1@?`7!AgoaMR>S zndke+HDo|(M}q+}#9~pVk&dUdDeI}GPKjGj@w6HO#sK`9LWQgYsz`DE&C~_sJ6oN}j?|3ILMUPZ}Tn z0egHl>cgpG>4c1B=ObJ}3r;{)1koz?2n4gRM?x-5rOBd*+}J!T49tiq6Y0c)T$Fu7 z%cw;Ky}vv`MtpJm4GddgI^a)dM#E8eA^-mD1286lJ_1)EUp^papS2&zcDg6Z_OlF@ zRUMw>j%?4`3?%$~`)SRV;3ZlJxg+7vY3+;QAJp5&iFSJb-_zTvAG#ySejZxTPIn&J z{&-INz2dGV+n?lhI{x>He*SLJe8*uKp}UrB&mA`xK6l)Ego42x(T|K98aBrD-nhMl{g$+{@HSuDZ`mdz1ZDU0Rm zos(T-8^^jP_iW#=9{q0RcV;H}mu4T}pUmu|S&9C|YJEs;QDn3KVYq2*Yfd=W~am26Xn0ljPsMTpGh@%h)Mzr zLA@_Z>Y*~;d^=H3wx3?1{XxB*>>sozCH(hzPfkBXRoVWK4v*Q3y&>Bl&utexE!!W< zZ5KQ$+aINNP_Yc(R%3OnlmU-G0?>|>Rr*XGyb!2wmx@w$_h)(W*T1%g-#Olq8JPf8 zM6ZG>C(#pWp74n2?L-yXer7>C`N(DaDXkrP0xG2y;A8=p!nz(1u|1-$y7C1?ht#nq z_EQ-&ksr*5njI=o>@XMm)8fwp?N8i2C~TyGlKGYC0wWwHbz?=`ZrA_Fv*JkLyAhI3 zyi=HOQ!SQS3*A^LAfplw+7)$*p2TBZvF}~!fpiK+NeRB66%cU2iom$Qmetq8c->Ur z)YyQ@)YaBhqY55HrikDahhF4up%R0NZ;KnCtjYg4lnpIzrMyVQt=vp8ED`zpYX@#V za5KMRW})6wpBvQz$?(Ta0euMvDpt)ocUb+nScQAUDs(76!%v~bDNm>o*1-NQT^I%1 z*i1Z6iE%ZL>;Xh^#A@QU18*3E(=RX2HjNy6BBN>~zu?U`lyiy_XpEF0{zsB(K~zwv zY@j11sixef=7V?tT~dvc_g20W;G~+5*wqkXfwb5rtMGA<{T`+~@TdhRL>(ebt=8=C z*qdNbcvZolHm%IKKaFzEpyCw3DcDu9?p+RSDqZ6D;}#t9qiQn7Ep<4Yv1W%OUpRY~ zqlVxmr{pAGS93wI$mX~a#T@1fB*7Tq6)~{m(2~h{ zy&pN{24egPALH!kG}(GgkDozAVmdIT&qYHp}1C?r)m?-4_b1XNcE7p zA`~N{#RIp9D66kmx0kmM$BX<0sr?VDZs{U=pE(nEwDzqZ({0^3kzZ)3w;Ss2)JUagce+6nJ7a389dFv)RwnHJex6 zxaGpV8*gmgT(>^b7CuIwSp}CyqA2Fm$rv`clU?O8vDY% zTZ5>yKUaD2&fcjG|AcpS|E3{2n`nH>DK~*n@T>UyQs5)&`srAZ?p7jd41!ls*UwA^ z?x?IlFK>PrrLAXET3?q6kMx7+iq5}NxgKe)_si5zAO>c5-APKE^b#5P5fXj7F}@cu zFk+@;9m27E(~=LQ3Zqp{5EP($Ch&M=_}gmg;Dacf02=1a9TIOba4@6{?sqigPCm75;f0Rx`N@n|cf| zy1)b*O-9W4C2F=C^5Tw2u*7LB;G5QOvt|xkk%IPKi^1UyMozq7ujt!*+a<5fCSN#l z;sxcVZyr3cTl&{%MX0v32}O&tDO*YVTHzx4NJ2cAg^;Qus&i}aNOO`$6JNRe#hbZA$d|j3~pZ|SkhQ2Ve4_2LfQNg2&ZAov8BVnxtZ)$+1 zg#F5tbDC=L!M6|lhRI}^#(h3OE?hQk1$zW3Kd275XHnz`m7*e%h}P}mT{g2G zX6$mIER4qesHR&ElTKr6liUo*dV&ObUA5kjmuJM6I@Vd$ z)>3PjsXwoOU}r;bORPDdm8UirnwtCL1J%8ojeILN4yW4&23k!8W`Ey#jZHiIM$RkD zZ=PsdGt+^2(<=TP6kl9b5gbktD{?PsRTU*0qh2QtAhq|xmnSZG35oaLRT_|V-!Xey z+gU%S8WsEz!2@TxKX+$kA;jL35D)RvTnG)L*MLzzLsdZ-p(%`ptkzm(U*ZDn0U>1o zgW>?-Zove(>)(4c_3@*(f8*#Est`@{Nxm<0eP$c~VCHfSgVzKGj|&_hW|>78D06Qr zMquD1E`$w<45VBc!IcF&PQm%3Y8wpKZmjqx`mDL$9A z3LEhERl4k>=oL}1B}ej5J*N^>vV$%zE4E0eDZ><^+zc{)rcEbK}$pDQ;*_M##Ljfx7$E-#7PZ7rVG z)@E^AYr~GT8(Ny%y{6k|R#(Ql4}RQM;H}+s?KYz=+!9xw%zQC3H^+C();6qd4%vX2 z9Eo@cetF1|v+NfO)`zOk{aCqJy_7|9zZhUU)7zbRAw^%hLN%Fz3{{9%xN;K$YMJq7 zn2@a4&D^{{-;$@AU}>EaznH|KYGME2SE+R$bXn2*{*d5E=7t*t96b9~rR zWUv-nB8eh<#gAeMyFHP>pJrF=7Oo_AZG3cMS0(4S-Nt$4?s5E)RQN5AKwbMC=cVb6 zM?2CbCE`aZ=NT90pk4uJM%5Ke;=KnP+JE*9G`K-JV0QzB=mtqAi^BGUJUD2`d|P6m zC4`&K8FN7rl~zqVXm)r>OSYm78P)jZ{Vjt#YL0mtE8PwLWBiK3%FVspocZrW6LbrH z2&Fx!&gmg#Gk7JBZIovkiiFTGqG;M4j8YYQAMy5VH;1PvI zXPDULgDCMPL_N+hK5NaaJNm1mV<%2P5G9GVUyu?+xl4>6PnW~WNarfltR=tSIv}|BAl$?PulO(26~M{38^QESU8CLxHBIW zxKJ!6zynrNP7wc!N*p-4^aT=Um>Sm=^_VAI6LOk-{Nh4QUBCI`9%E_4DF23AESr<_ z&5Eb%&}RM}9ci3$AKiJ&RBE$S$*Dke=tj&OoHRnR0=MHFH*yG`)EwdyoFdu_BF|-uEB8PGGjhrB-FW$~R@crZE-i zfAV4hd8t(aguMJ5IC%c;R#j|GdXOqjBKhYyGaF4tvk7-fW;7e--;x344-di|pecX! zeuMy4UCWV#+mxug;;XLcw!AQ5a+%j%ojtqk3$KD6`NFGx>pv*pcom7z8?P{f2AqCB zP`lxuynfxu6eL3}(&!9E6Q)673mgiJ)M2RJO!kUQ0;vy?UrjZO_o&Uk^I-m+0{lgEU{)5rQviJ~TU#Hy9m42*x@ra~ z_8ljb(1fVAzIS15eW44zeQkY2wa=kTGq5kAH*8@?s9s?K!EETwYGQwAf=>98Ulvs)CSOc8uV_MX<2H`u(NETcuV0s^TKl!Il17ANSFXN^GkZ5&)0~ z*?=waQZx~mwXmA__t$TapLgKEdGYP**H0x9Q|qg$i;AkNs%nagYOH-%jbEDiFof-A zFPgZlr}wh)%=b53)xV^!I4DHg6;(cSz)rU+-2!(rDy!m-f-Pr2-WLo}yTKa}yP7JF z>o@bbic6iPbPaECBrT+pJFzXuLQMB4s8~^zZd9UZXu+MWef39nec@T(Yh2q7J;FWSnR2;-BNI`bW2J26x(k4RT0WgmtGokY1^laij2sWB;nAT%G}D zhG`4M&Pm3Jut>szqaN>OgXVE5tXgCv(ZYs>UMph_pu~!x;&)%hFMLmNOQ>R9W7Vdv z;#8%*qN*t25sdWnqT=%5j_Gx~swd*z<-4M7w!F+OOr6VU*r}MhUt$OWqjI(nOf3)u ze}Dym8cH7v%qVTh?{gI!9EKumHhIX3ecR`bv^aC+{=ELcFVDRHq9uo?@-JJr&hA)p zeqwy^A5*BlS3WXGJZxKfv%46#J?voIE4jgBLx~E5VH8X*g(jtP!p`_^;Hgr6jCafo z^PG^Bc+U$M0=GXDwkjwpfJ2%tq)wNOj(VrJO}9ii)rg8}*O4}-;g?gBe>nUZ7$ZLW ziN_Sj>2)W{GG7V(qf$`OHTzuF9KrA7M=~F4seCWL|UbCog~>zZv<>%fL`#YbmXu!DsM!5ZM6# zyv>YvbV2sou!e)lCU<;ULydC4x@UG^iM8g$3oo2l(PBf=>X1?(=26I|(^h+d%}o1H zn}v_WvzUZo4}2J4FQE&GIryLz891(niy+8q<`FX}G!*9NSuNQTrCIF3fzrTacJP0* z?#VP}-&jJZg4uH4S|a4>A*CJ|=0R({Si3i1+ZqrIB3@Di^h_pokFe>H@YC)M5&Wi_ zZ(b1+v6X30K0KuPh54w9qF-ffWC^29g8xV?8bNURiX&cW-2?RW*Bk*|vMZnq?XGwZ zJf&p+#){>Wbc4)R@~|hE0*51FYaqDyNt#hK3j~QERlWhbq_)gv5K7i^)d~&P@LT?> z)f(huW0|=H6$ddvQds^B3c1L?32BNqL|{=c92Sx(uz?#4^6Dm!adA6!M(K9CNlL5S zb1v$*JJMCU|H5OQh7?^+G2;&`I^;0a|NnJ?_uMSk<@L%vjmxZyR!tbE>>Z#4**j2| z9_O-*9fz!k6+k(da9`{~lB8mJ#I;`fDCKKJm!6pW z_{5i2D7w#&VJUA~P>y`L*KiPriP~p~#WRVlYO1dD1~PTmv2wf`q$AztLF{2Yd^yUf zy+A=)$-L_W`Xyar!)$#l%2`cSv^m!7_px#g(}ZSBrTWcnxV2D9JQCsE*--7pA@Nky z%kzWAwMlPdMXJBM%o7;s4+hH$5F!xkiq%e3dHe-7kJIM!7ZwC9HB6KIV>ktD3{HRIF0zPxi*DR@==rJ(0%I)I>o=qNdU|7OSl+1Cj#MFfd)< zGx3Rd7ja+52fELMd=;&~dAHI(mdT@)q*=C$n1NaFB>7D4!cUIW9>&X*+hK8pr-bUx zE%KE3R`QhSAFSjlY5Q6yhTrvNjE_C5%pKxC2JZAWfSI%n#x86DNFz<$N9iI)x|a{e zEPOyGb&2>@p|Al(@sp+=q+hwRX*pn$st(vNafi_iGhPei%(fQTbmtu=kgR5eFoYTt z9@x^1L+h=Xr>&*mS*LJkr0T?vyy^2lcJXM&_S}gR&+$9l2R=O24BCm>C$tM-ktABm zS}2Gbp<6F#xv&}w;xDvzQSAjZCXJ;Rb9a+eCZ7l#p?s8Ly4PXJa6?d!V^%bGcq?)p zBo5&r5toBy4_?E^Z@Ktd%cSL+i*Nb(1vgtJtvB-|_h){~J>u(^nIG~%<^}o!7D2p2 zavLIt@rsJ{x(dnTi|>h9=ZJQ(3`ysRem{<&3X{Ah+URVp<+Z~4P+qIxm7H0(hzN6) zil;l86;jyLBFNSBKt)HQct?5IUt)4M)eP0e{Gr&6&+BaJJLwKK8cJ$jY`U+kS-&=S&+)X0<3SO?( znb4ubS6_SNP)OqS~X-(2%Dq%guwqyp7C^ZuEc_bdH>{3AN$nK@cdk$EQeGUYkR5pKo^ z3w$wxg;w^(wDR$pYp4bS|9yrk6>7OVkPk<7`9SsiOxio_AOQJ>>=+~)ge5>1pui*7 z-y`pGS03c65Ai>Yk7w){L5s%22wxN<$hbJ-R`~e^x1PaI6_Tl6X@ZgzLUvXw`=kun zi=wiq8K<$)%qaFp8UXk-*_(YRL@G`A^3{V;>2!IE2dDs0B*!%amyK!vB6yMIS{e>B z*4kWC6;6dyQ3_fKRYV+>k$h;m+ghR|Gblo%NrZ2cS=sG^T{-Gjv3B%29AR~u_ryeJ zZIPj_c(`r2qTm8Y%VbNeb1-5*V77&8OH1lMWQx}NO6$t35B$_oJ2|v()p%3MAO29a zbKSn7$y&!xd5YicYHhl*qu1x_?YOe3)diYjXNj0V6DrUXC&cj$t15Nb74D2AqYbrO=shRjo_(Jzd(67t;S#rUa^91C$Bi#I>*38M756%poIDt)OkCwU){?6kYGeil+D za6c4|owxS0wC=qa|7CmQf6-^8P&DcyKMQv2JM^L|n3p!umX9;R* zmHyUe`_3?2mrMX=xG#{8g}d@ev^fzJhbT+n4%p&s)Cb1!0kC?jYABGJpP z`h_D0iFQK5h7hq=i*is%)FOFMXxB=+Muqaleiw}py5EIFMz}m&j;v0dB%0r4C6bWu zWks^^8XPK1D3kde$!-Rp)ZE{ctASg9CE0E3PP(A|mZ8}UOD;_128~D*^QTVBOFja3 z`z#x`r6)#V$Og6z`pBxU8|jS6*1x%I&YO}r5_gL6x*}zWD*n!E_Cu>$#R`M{&YFK z5=Io;R>>2jS-KYiO{H;4RmQ`m=-20{n1I@$IfLk^o?ls-m7}dgX^`)APo@-b{53O* z(ZpA6sP}jpH+CMq=9kc(s~X&x4}RfT-dFzw)=xLorjwXZUgpoe+*w-@t9Fx3Udxul zxk))-RR7@(ekpX|6nh8WA!xri!iAp%_gMJe;-vrT-XVG;diE}>o3C@r2TSjeJiSsg=;lcE3zg9x{BOmd{sfci3wO&McysM~477?x=N{ceWeplzFYT!v25U+(m-C~gf&6?WbE&dFou=J^%=aR25BXOvm3dK1{VTp){|aco&}AZahLH-2 zi51FqnE>{kc}#G#CmlC?wOT%ElwZ@)Upl^P*LZ1vM@OIE-`5fF8jaq7_)f()8ZwZA z^($B4z3 z793`zZ{vn8THfkewERn8GcX{kY3H7$|h{j+!T=!q=&TsW7Z-U|AgP}d}Da@2~h;oYh2HVpe zNU}Y)f=SdEmFMVgvL0d=yu~T%SV6H!0^QXsDHs3Fhk;+^Vg=*54I6O2lWoHe9?8d& zd)T`4n&Lt@-R;<|MwMJKcsCqHf3G8#D9S;w<5&<85(~D;`eB^l8>h#Kvd*yG2oH>9 zi3cW$x~Oel_+bop?AUq71xJmO#-k@oukvR8;;H=tfAn*FM{RB9U$`mrSMfEdKATMb zp1U(IfsgTz9|Vpo_+LOhK{p&rOZ+drnN#=AaQ{iZXG7*yrGEo@Bmc_|(VLGQPut1+ zg10{KQ3_&PC)qHHD;bmsc3fB@&_9m&JusOFR}2_jx?*%Fv}9c}3t`D66Ue$`C=X+S zQzkF#)>zgyq!ifCo4sR+f#}3@&z)G&NQBvuzI?x!T@gEq%r6syC$p{(xcyKjZZF+Q zG(4@8Dv{$|ib(GgD7`%7ypO5KAl{9d^CCIj$3)UCYa!u>?dN5#(aj`;eXgkl%qKAZ zFM)9(JMjMkRXCG!vX2+I!*Yxb{KLR>hp;$EEOn~`_H6##7P@PqrVRXlxQpxWd6L#! z7&pNpC^&=nJc*D4>3(tFdb3E7`|=Y?IP)HU{p>HlkNIZ%A}`O*bY6~^M`i^fkW5=2 zj!-UGG2l2e82pso?OEUl!VZ)lpxVWdef+!fgoJFhYG;boQtI9I_ZLzT8o+y|VgzK^VewX%;Ul;fibzm1Qk z$*qdmnYTWpcfEYY3PpZ+-oQZS<+rTy1FjwzM5s!S7H}Q@NvVWQJzMa3Y zN2tP*a`F+G#ZI$%Swy~GAh@UlxIG51*`m5+O|ZdG_!7C7{!iXduMSRCrKX04CR0_D zgNbCJJ()y!eqp7x=ingUIXu(VH8Y&~{LsPf$?Cy4-<=#xr3RCk&&3Bx7e}pO?g8cP ztPD;GcoN9;Nrh)9J{Q?`_}$Lz0a*Y8{-()#F5uX)FmUQqbv1MkrKkKr4)D-k7UGlw)XdiffZJ zo@KRnQVz{(#9jG>H|dMjBvM5)$!%-S-{Y$&xsS6^-WTf`tXY*#txoy_Bl|lpIlp=R z>R9H5?U-W)=>KoPr<42z&F{!x0Q|C%Wmp={YO5=0TkAfGX*m4u;^{D@# z`VdxDkDC}p>uXV#28ug0k;=`dL9eET_5R~Aas}#hR$~#7ZrW z3hVIIYq?{?4eM(sdl8}6*%Ke_y4Dx&*grgS)$mm1>Wcb}4Mjft)s;iE0inY(z8$M% zBAY0c%M}}2n1X7Ar&WJHCbHA$E$Z@(fje*gAz%Fo#8WlT+OTIEL9bJwR~Tu>-E1)3 z??oOdZYdOuM6c`6OV2lOrrQ$ouiP2d01a(%4yW1 z&qOFTylSu$YVTgs$U~NMT^7(Ee;t`j+Wm1)MPtR5zP?Qr4V9j_zc9INB$+C7q~dV| z=T#-kqxM)`UBVu>cFe4)?5T^|{o4lc*7v4e>D62P_Gn#CB{Gh-RIE-V2C7m6$<*o! z{xM$BTi!S{)L7n2CN7G5xL7$op05;vN+qTsN+{q>yhrEHy;HS(CeaqEa20k| z<9w=^T0<e{;Gc@R zuSyM8rUr;fh&#sl-R!UGRp5^HZ<6_e#ojWCntLmGDr@!vyXR``>%o9HyapHpev zr16Z&rP>g|;Xo@X89RG|ByFBortuapATitW9|7x>Zkg)vQf~ zDa=ixdOcQ5+M6f|7AT7sB>cFsH@Kk;nRvc3SagD=!AM}kSYOXb((kVx<6n$+R}>lI zvGQwS|roA$f`A1F~ldyCG+Ug9YwEs zw~+22t4Ik|II0n8vL9LB1_M42@3zR1{DSDZ?l4WOJ^XK-URU6E5IQ{C0lnc@)PAeL!l}>UyeutPK9<>ny2^Pz_&b zPDA{snGLL%>fp|O9jX(GRNkA}Aa$topvs2jGx_qFE5$Qw_?H(wqv+4z_*2)Y4H#$m z<-5c@7)N^sJc7-@Zev&KGvd4F6`$;kE`@2gVdhFg0J_9=$Wyx%E8$JU zUc*K}a1ri-U<8LtfgIh2mxtmQB|B-m!yj%xT>IWyYfbplqb)B_NtHio& zkS=7n5wH~6I|XD(g+`KyNR`*yG43|tB0hy{eEAm+Y(tm;(W(*Vw}S`2uDomZM&*7n zYAYUn0Ow4QMaU)=D6}Jb8S%h_MoU+t=y|zhJ6I&S&a9ykD(fi z%0dX#pv@rZfn5Z85I<>RftWXTkoRNWoUP_XFx~tO-c`Eq(LHL49-XG^2b>r6l{&gnuB;NWvm6s_|VGuGspz5#6Ae5eVVBQSqlo! z$414ihOPH-Dr%N&gB32>WN!1Cz2@YJ-VIlj9?hR9IOe-zyf4k4NnBF1y6XcU=vrNS zIB^~ETNye(3x4xM55ilM5XP$(!dHony3cM!?|2m)N(%|`S~FHupycJ%=HXToraBrp z*|Mca=;|r|QNb4ITTN~FLLjgBaz}B(Mb#*RwVn8&yt1mzKCnJ9lh~d(kf>}fOs`AL zq^2sHx7(+9`S|oi)B-UR(K*xgMSmj`z|E0Z06Q5u~1Ea^$NyN|A?t$r2|(5(0q)DwbR#7sjkTBLBh3R#ZZ!Aa0?MQWy0LS}ie%s=z|FF^iBwbI39 z!^fP_++Ahk%kTer4K%R5PE_Kj736nCXY!UOn{X}NF9O+Ik^~(_U4jY zBW8j)>QIB(CwY+sVaMrz4tTUoxZuUcFHTaJ31?Q(g!FXLgawVeuU(U9&%e0EqtSX= zF3PhfYTJ1WPbn^rZjN%7oXT6s$3QhaM{H(yHp$H*LCIv9IKZQ%X=qa-fl)owBeDwh99pD-p)FIGbHALmGv= z3@O1O%HY~w2+5l^y>WYqV!HGPuAOEFOFfb<1(<&YhPA&%Rh^yqs+>MgjV$xmeO3NG zeO`Q}B~Q^0D2`40rLwkxp{k{CJtcib!xZ<@<-hzDSNYZ|Zlz&uZJaKYTZSXwIiCy@ zH?V{D2cASe*)!_lx}RT9X4Isv7x~ft-KYd|s|XxHX2|gx4V%D`8q1{f74|RV>y-2s zIOceq!7z%Gh(HzL%Acn*FRfR!fM(pl`y0P_%hNLx^$GeDx#9VQ_zFh|GcP#@dgGx4 zr>k%yf4-~61__K02HgR4?jRT-ly%@M2!LYa_}01`8$Jy81Z?M=ap~5QnDhiU^CsF8 zm-Mq7g}ZDc&jKalTpVrNcL`7ArI5 zvf|QB$hi&6FvDt<2M^3y*s+BX?Jar@XbOjAB*%?YTe0qm3*B|qRb5>VUU_9#SKhm> zcXuDYeV26M-|uN?XDz;0d~vyuJR^`I_L7Q+_L47!**}qcEY=E)FhTU zASdUmnucV0VDt_Yh1m>(0gL{jC_T^{8W4|~SYJ-3FNZn4#UDyTK4go?C&?4fNqs@Q zBMZQG9;w1VK|@>evoj_C@!BF?(L7o@Odwoo-yk^o z+*m=_R?k!LfU8njZ-Vby)ceh593HtUD{Ix#)&bbU=E4>>Y|i#~$&w|CZOzR;Jl(jX zg{F1w@WLk6QzqE}&)z4Q09RIW6JQRz8Jz!o2Co~;3Uc1Wq1S33_=qLY*KG0gGvPV^V(vTD&R_GPr-+X<_(tMIE%*f1 zO)`^jK~Yd&io}Sp5^HR1c4lmpfggC&=N77-P+;Q3JXiDtb2?~59Mn7!5H!c_Ev<-+ zuPDi=t~>aY?M3ZPn#$GHyS%H*)r}4L9fvw=d-1&Sk%O63M9z@fZX?*WF_m&>s4hgI z0b<$&(K+@bYPL4m4h#=$eBj(yaH0%o`hrh1yMN&e9Q9|l=H`MVD6+!QV6G(>t_IB+ zX(_TTc@E9trxPq-b}l3glPI~ z!hNrRFKLFNT~vq`#=xLmVxqC3B+WQ!SwT7B4=JT$6w+Rx=K(JC<>V%#omrV+}k?g%#j9Bs_aGkAlfw$zii+9_rC*HL9N>ui zfg@bxWKT3d0o<6bf;t}Kb;2r zc%fo1XQAA^AP4T_Skkd~5m!`7w(ytThcmu&N`%M*<3A^dtHp>pk)}w119ol$#Sa6O z9I$KRzF9l08dk*FEY<=?_KC^nsMS5@{Ax>*a!?Unke^?alyXv<+mzqpSW?f9U2Cv( zIPHZc-i*T&UDdgLK84q-NOiS1l5^|x6^eXoR#Ecd25*`5s( zn}6=T@VNj!L>f1i<{NJK=szIM$&q~Y!~7UKU7=LO853ZVa$YVxQ!#H$YOGe9pf$!R zZM7{*RdRW8Y)Y(F7pF~6fa!Cu4NtZy6zx=*Z=%n(XS!N)6|93Q#i6=YxC0)*u!q+| zP8oy|Zjp%U!s8-VO;BfQ&RGLvO`^!TmJyD<6l|d|B`P~lXG6#5Ki3ivKKf9*C?!qZ z2YclUFTA0n;|3Tk&wkM{yGzE)`{Z@oL2kUoMzuP=>*J?Zlww@L(pbNf;2dIU@z!HG z*XvN7P>jzXE#e{JFbKvfZtzt8H=lyPAQ1uJ7xB*rJlPT*AbEzJqXir~$2?jf;=iK> z_*TRWw8zN-W9#y~tW~|Ohvlyiw-h=GLZWO|t1Wu%(~CnQ>w*-)Q#D8S(TIVgYMrAU zX-RIcsj%HK`$BnJc79h?X~*p3VFl&T1p5ZaI|}`!B0BUK^dW)IFfJiNgir;Vuh;iFCHgQuI!vuogE+#cs%YL}K8WTh<<5$@mKy!t?DJHyJwRyQZ1Va` z=>7CQIyQUGYz^mf(DOP#l5?9L0!}*jEWvqhu(=1V&Ud?551{&_*-11Z6dXz|^iTCr z8B(diA!UO823qAJYaFP{C8t2&I4)0O!f~E{ih-*H<1p8pP_Qqi-6c_6Q&1ujg2Fy* zANfJIJg^FVMqQa}QA&q48Ow#1J~ewfO`ZKaO)XBQ_g1XyDzvsaO=-pE+)CsA?>lEZ zI!=-5uS5Oc0`wxFhmb(r9tU)(;9D^&5>7DC3jBcUyA!w{8&Fsu!U0pz@pl9Xk2M9) z2Z4nr)-jMVAorl+mxW4Y!9?4$$Q3eGFw*-Oy>!+`FXgVRY%6LCYL{-UqJtgBcIXlK z+FOcRe27}aq0z9JLUHIcwjTJS0DgMa5D@a7i-!m@J}DleUhX?5Gd7d+kEiDdQ0QF* zsVDTHGpaOWW&glo8N-owr_&M9+(X}Jo~WvtXr49GeU`esygJKlnqXKdz)!}O9p#4r z1}5@bkKRa$)gofd-`dWm3)Sx74$vyE%%CH;P`>p z7>fC50#<1VpXXJbuSF1JbLSV_=Hr0ti)@o_UX?M%%~4!4beo zBE!QZX%%u)z%RDs#ek1`KKiLpFpR;5$E;9fvNQWbW{Y*p*_r#lJbq>0hK`Be6~}gM znxYT2w4Bn?G7EXa{yUi$p$SvGfB!XrDA!Zx9_``@q(RvJV_AeW4x^k)8laI1=dRe- zt>tP{s3Y{QfW-hwmV4&@)(Ia+@UAY9&>4utm z`myjq8&_Y`FpV1gI(d$oH+)W>qac{L6enr`+8oNlZxqCd5_g7gM=4y3$jkZ9$o#le z0*ECp2BG_{6>n}HJAX`J`Qb%&^R{jKTP6AH0qF+huP9YgP1p(`2<{CkcCc(CiM&8} zvoX{Ql0vLgDtI{MiuQ0MB2GqE!B-z#K5|*rocS&I?%M2M1o*Hrt8Vm9!f z5Oum`8yB^S0KT9kYSXMsX&W*eeU{-cgLfc#`oz?kHJyW9LqlDIooje~%P|`UWDe#5 z&ZH`?{F!HHdgj=WfN2_nvOLHa&_Q#FBg!-S`nvl1uBGHge(mbJv8#)>B9nYiFJ>NKX$Kkh_+l}P z;~-tdvQI!xYScv;Or$ZnE*rjp>`Exj5iKR~v|ccVEHsg5;M_;8v3RB$=?Q<@i(lamGKxG~w` z7Hd?J%Ml-u8Jh$5V=)U}#DFspDZimJ@OGXM;f%;ggt=0rJt8yt*68?X=?PvXM%p7Y zlQDwKbc|j^zXLT}DQM06KL5AmY?LS4$LH!wN1ckBSHjfk8?F zP2dOPaj8fRMCLzk70pd@JL1Fgc=ZdSl0XMUWW{EOSmQSFfo7lmhI+ug z?Rzf4tLGY>>P*VEeox&%sy>twL4lYmKKM- z)zVa)msiXK>J~?~vmxl-C4l@XBJdck!{Sq5U{KP)a*v+o-VNY}6nzZ?Y0W4GG32WQ z*o)$0wSwP+xr;%sBw$}AC4$GEmsylml$M%kPBMc84$-LiUBs?ueV`RtR_#ANE#mEL{7Az@nmyl9Y0>RQOlt8%0T9DQ_2SbI%KyebjVY!&X zE$<-Z(=COg#jaQ|lE6obiY|5|s*BU5M@PHwRj^Jli%iTv$2c?IIkxUP80O}8kit~Qp6;DP^!^lZK8wu=X zE)>KzYvHmiWXwEEtYGjUqT*S?A77jqR!?!sS6o3GA3yQrXYQrn(9e5jhh~@YH8Zdu zKVKkkEwOnDxY`llpG9!u~%{gSwZEvEYc;?gCdpbEa`trv0e{Mfw^agPLJhRK# zX_A({BhX2YVceGwv@}5mlW;K0K@y7{v0^9IC4$qjz&#MIA{;_Xle@r$KR>Re-v-z z5!b+$T8N5ZBcUAS>S#cIxB%;cW&_r<G98oW{Re)ajrRnq|!y?ktGeC@o)I6>Dl~s>}q>Q?1bE zlzP()c?L~ldPzb`cAO&85}MQL(S~bgI+n*K>(r5v;p&F&JXL*IX6@(_MOJx3Q%2u9 zS5$jUWz}0TF^NUy8&!H$0TzB0$qan2=u_Cxf+(!mMX-8-UlV?AlohhP5bPPb=T40f z{|OJCK1>np&%?1}qP{S-UgC!tJg!3|7YrXbhV-GwobZJL28{SnjZ>9`@NB@7Z?~B< zVxqZ2wz3jiwY@q&H>1d0WJroO#h60%$|x0AOH_b=0nQpH#ifI9fj_veiEzv&qd%^S zO@IEa3H19t-OY`?y^T#h$w|7noSax)5{vF`THL#IF&-srrAM5=r$???T0JnhqJMGU z>dsV~VR2r0Mc!gVQR-~rNMCio@38)ceji>WHwIq-Oj&{Nm5(lf<`S}k+$=%V5lNL1 z5=29&CX8~C>U@~ShDPJ$F6xWXN2$XlWkiFg{E#0lglxEgtn|5>f3A?BTi)JQ<2eA~ zzTUPK?JF7^JWFbp{4BKN{vUw0>gW1`X8crFpm#)91bc^`$UAJ_qxk==b2>-*77YYD zt;irctuc2I<~{b}^akd|T+k7dCk?%#1kX3P;sb9|zTk8AE+>4ap$8YEzz#|Cg8y2( z|JvkjM{J`euIV=WR^zMBKhJ5#iog!VO5n#9vW)yq;>^V4Qk}9Rk*Rf!a46CQ&Y%(p zz4522gPy{LehQ{v4i;8$FVtXQYO%f6LK*_jjt?{rn5a6P5?Dv6EY@*ZS{jmP;g;ys zN(`u<{EmCww}KYcDOC{Y|BB??$1o*5UG?7bQd?nuUY6OA92XO!BQ3NgM2M7R<8!D= zX}DcBw<7=+Q*-r5iG1Z}A%b)f=G?`cu;m9sr71Wkh^w9`4&Xj9e_!f5cjF@O_TLXJ z-?cQ4W_bFGQ>@8UW3@WGrVLM?Dh2-m&Jkohuw^WgSChsTI}f zF(vC4Cs_4xv!%&hY>hDPcC5X4{RxjA>+wvU+)}$`z!{&Pl3uD%+I#J#(}U%jP<7Po znK8!LoQ4&y>ZyK5)%2Ak^&2|e$?8yDTVy1yRN7r1F@<+yU1|~B)+@NJ4$B6wz7TpS z4P=?8FG0hY+UYRiuxMrlp~P1TwL;AlJFy879VVFcWHro~A^nuCcBC89W-Fqk)>Bkw zE6aoIE;R*50&u@?04_Jm;37;R$m9eQr=bNT{ zRMMVTZ;#GP&2MwtmlWC?Oglm%LKN#0GGoH>6JZOLT9_4O=&Q_j#T=QK8kz=p_WExjq!)AioPGN8xy)E1sv$IvkJkk4 zCNN;##YiuSlV5Vw=j%H)3Ff5KEXK4kQPUZATUMIO(&}*3T%EqDH}OOe;wT85KL0m0-f~ttSLW z+%f;r=n$QP0yW6)(uo=iJ5bALC?(G2IEol6>8Q%A#6lhcf$5k{Q-ryEUc^{&{pG(Ugot`#eGFU`wa zx;vzK$9b)-=k923-f?bg>v=nxPspeqC?0DaFU#+#HW+e?Vv{PJm$*vfl8e%fNmYG? z%RS>KE^a(wyt;b)gvP}uj(fO-qA>8KqFGS_2P{(_zU240GagegTFD z!6rwRZeZ3!SQE$PW1QGA)4SK7H&{?Gc;0$(U3K2rz|QX6-0qzN1IO^|G1V7Uw3rKX z27SF%rbT(?!jiD2?dP<#p1r-PY5Uo&{OVY={CqIYm6 z-Rxo-Ir}dfG5a~)3VZE6ygudh9oWL#!S^wcGBMVF=|n(m*bLB=l1>Da$L_)U`#_&_ zd+2@6*1Wt{r>iADzr~eTSeS=E-^p!tyPI=!o89i#+{R*y)$O)giZLS6SS>jX@DY0L zoK!fJ<{k{^(;|GutoFkXc^lH$Qko^c`L$Yu$N(-IL?(yvjF!HDKa^e{7$?_?oNSV3 z2FL(qD`{aA5{eoTzJcUM29lYaU`T_ygZW2PJsmn*aqkbcs8e-dEi_0aO-5+&@FNQn z4rRb1)P`e)tqD^M9Z13ThNBN*+S1L%;0V=Amo9}p;{~&8_P-2~I5ZF7aS1;i3NyHP zIiAesGB|hVEN#>E8by&#yl4CFH+X5hIE6 zgd3xy6vDh>Ycd7ZHWJRVvrDixrZFs?@HW2)_lT(DASSMP z@vE7Ct@nh-Wg1m$bkTXmhDNhRW9q17$K;i!C^DNiUNAiSbOyBzpSGevm6pDLdufR_ zBZJq$jGyI-OyCkBZ{XS~5RY(i6K|7jNQHA_!7bRI>0ZVwkkOWhMv-x>AWfXsF z_|N{Pn;ZA-YrMG$TW|%b34E=9X9&=(3D~vn@aUnas8Ue1hTGtAiL(*?&xP*tITFPv zSFL8NbV@Bw?_&^B;tt|yHZl+NJ&ZzfgmWun3$K82Mg(hkOa;$;L}>j z&x2y*LsR`?b1QsK)^zS$-u@2rfVxRY8;?xT3{RQQz{9>(us0G&KfiKt+Rt`CT2C4JZWTe1oEIuv*xJj@IAnF9K3TnY< zBm}g4qYkP-SOE*}q%qBq91{hP_*#O)GWafC=nV#SBTR9Eqr>^D3KO)-Kn7@N#j+jM zwvN^IwjdlI^BOO|J5B`xZIow{N=OIvX988+#7?ClC!{Ob{FBNE^t|jL*TU>@H)^neYn7qOQ;sZ zcIgmPOfVoZSh!)DaeVf}ady`v{_s`c33e$dR>ULMU#Yw9MIOcD>{5ueXy91)=XlJVT}@k2Ge&kH z&SV~Qw6KB?!Wb=c_jQ$*clEQQuHUlddY;pf>=<&Kf@>}H@Lp>1M`GUd)6T&0gBmlY z3t03FyAPf&R{)cqrwSXp71Ny<*-nkza15t5S9SGa0rD4l|)l^iVXng?FiP+ z+?woIw8+6jveB4qNKa=yRZeGRrPEneoNh=-OG`1poQek4v%AT;;JqY}^Cd{|eX#)+ zE?`v)CMB4<-13R6X8aHn07G)Ym;v4;=Zj)XJeL$)NhvAx1$atN9@jU7s^ZRti7`32 z?&AEk*fhsLr5`RB!a}q_$DHx4nMZi=T}9AwHz(-$X0A2Gk{urvRTW`QOUlcQi;Aoa zHL|;t5~CB+?5T-~(TQmeSlt9JW7m^G_UV5&p9k+}*VokGYd<>@eY6Oa9475>oyQ34 zKrn@&TPjZniPH^GlFrO*ZZ#}W3!f4~z@Tx@?LuirYNk0kG&w9MKi!d*>R?Cah9$?u zMJtrW`skdr)La9`L(3p4Eh2m_}YNg^_0%-k?VOd(nMP4a)CIiALqx!q;))#>mEO4&K^Ly+sux8>#) z0b>UqN9{`#gTT=5BO@C4n(4_&>=Z0|Z3pIAf=2{V0+0<&J9me}1;!}O(DS)#|D2z0>z)&sx3zZVPq?ccPCw_tOii<}a8 z0JcZ>6Y|4(-1dmw{=<2)=JDgR@4$}s0boR%fMOP41{49AJzpy&qiey>=WvuPt>@q< zV@Zu#jj5MZvVlTN@EtcxPu;NAT?<$}5r`uo*D({N{b&e|dzEA>oG{U2TEY}u!JxQG zse(Iik)E3Upli+&;fdX+w>OpVO z1f@Ku`}oEe0=W{WIP)A+x&(k>21iaphBLW1I>+Ej(MD;awXq+lqcc)Wl~!$}r6?gC zXSuj3Lq8oEh#|)XE<`^)hJO03WFz*&ZzUVCz-0js84MhQw@>2jS@PSn zx{Dz?up;<*?7<~P?7j}HDe4>CWpVPV5?98~k>?<0BWjq&j-oD<^Xu2iZlDZQcJtEC z^776;d7T6W))9!Ku$}?m?FF(M{miZACU9oQyu5!|&MU3v>GEnmarfQ3krn(Wu)Aot zfaCv!>A2Psr`|popZ#cTj(Q_Tb}BiQ?f>qMo`-Z5~FZL}UcJ&0P zH{Q2^R59BLA3YX8>LGH9fRs$F{&zJgyq|qkQzIasM56@cUnH+0KSoTf2h5cJyVL^4 zkt9hzh*~&PkPB5+4*1CbDRP05MeJ@m3Qj`e{~xG@I5=|&4~5`C!L>kw)Pm5NfI!@g zok;@tzcBL=)B=r9wB<*Jg;r@}O-YFk3v|#c!!z04iAgjjAt5I%iY6vdK{Fg!$KWf0 zizaIBhoqPLHeod~29apmc+4=!KBO6dZ4~e@pCm=%;OaSDhl8ov3ojfQ;kfe?7F-)E zCHgZO1CYSoj^K$QA7Qi+g@;rSx5OtsJ7_h;?n7#!IW~5|O2|OvPJqh27$Y!>j7nwj ztv1;OMKc9=CZm9<`bM}CW6A-p+qoL*iAuf>i(UD=R9H|BP6Ri!T>Kaj&RrtS2^_W9 z+n~J~%>n}00V?G`H|4}_LgBR8_dTh*7^t1KkyN0L0eK3&`PY9<3 zK?j0KkM)^Lp9Eop6%T|h*cM8*1`t*h!9TkvgOk$GU{~(seJmxJgStrDg_DBfV$->g zqJ&tSwU?F6U4e+LRgjM4gd}F|!a6H5;*(Qj^+_SonK70Mcfq{s>*vTzl`6j=*Kxrd z%rU~(V+VAu;s$j#Uq7juJ%Q5*wKJ6ZkLE+1@m(8@QY^&?*As`Q2xA-?tSXFgC0{t< zy##{?R1Y8Q8Vz(SpyH+jZ1j+Vu`hg0E}{1p zsQ~%7CsB@)!gh2)K_CzhT?1?$ey$SeXt@$Eb{ytDPzk9H|5lui9!)0DosfGJ3=U9I zidKkTa1p8*nA=d~VMVMhHa0dnHaRLjE1T<19IAs<(t>y1!k(GENnQY-UeGPp!XXY5 z(IZEoM{Y-te1IO&phpNfQRQk*#ZCCA4 zovXT9b-U_u)oZHvRo|$4)FbLs)t6|JH5N^!W{GB{X1(SJtzPTWZr1M7o~yl4dzbbp z?Hk%pwEppBa5c^i9zZMZXyRPV^Ts zikR4#tQdPtZA^E}aLksN-7)9ITp4q7%)>Ds#wNz*#g@mm#IA_l6FU?8=h)|C-;MoO z90d_=j&sEg#%+o_Htwu=OMFSZH@-c7Rs2}|w)o@XPmjMa{_6PK;vbBEHvVt%AH;td z9{}GlA;Fwblu(hdIAKM?y2R5GFGxyE%1b&b>7=A{k}glWKIx8RXYxbIFB*moTMWk- zPBqM?=u_fTGExdt%2S$CmZq#unMm1@vODFsDVL=DG3C~jKc_sC@>a^nsjE`&OnoHH zkY-K$EbaSrO?pgvdb%aO#2995G@fa^!g!PMW0TSpVM;b-nQW#CQ-i6~w8FI3G-W#4 zbdu?8)1?{8jJk~Wj3YBn&G=o$gBh=9{4-$_}qc64@Hc7Aqo zc5QZB_NwgLvLDQTHv8S2({tl;O}S_1ne*1=ZO+@7cXHl&c~|EBkgv^;%{S&-^GoyV z@^7&yERB|nEZ1A^usm#e$!fKhTI;MG))m%u*3H(P)>EwKTd%VEt#?}=v%X+`+xm(1 z+X7`lWI;+nZb3`I5d|j{oKm83d{^EGY@rAR<`6uUd&c8dq!a;*> z*9O-X*HNxruB%-)x^8pb=laU6a-ZeC(EVa@T=Amf6N(=y4wO`voKUi_)Kcm!J-aNj zEU&D*Y_e>oyte$L@>eP{D~_tTs#04yP_SQDmcGR9! z`*`ga-U{#G-aEYC*EQ8WS6^OVTYp*o{svV;WJ6+uui@3jS&J`N{BdJd<8b5iP1dHP zo33j5XVbr%7dN*zU)%gdbD$-%C9!2q%NZ@Nw6?eIY<+V{_mZtkK5tvyc1GI^?Pcvp zwV&U#yDF?)BZz z_o#YGdb)Zx^qkmpRnK)jPxidl^M214J+r+Qu)eqSp4EGG@14DG_I|T8e5qOfcTS(P z@4)>_1Jl~Y>_r51rr>#DJ_1}lIL&ZZwLzfSy3_mz> z@yH`pwyKd}Co^$)K9Zfxt=vtuuhy)~{M&l_(T z9~wV>eDC<-pyol!{)xteZcZq z2XG+n1>LV+TD>Zw^4}yv0TCG?FaF~)5SE0z@~QTrK*j7k%15CF#+7ctwd8;7k7ODB z1mfub1A!e8cv^%|Qq6dPmyAP(2vV)^OM$6LIKw@|vDW;mST6;79;yD7!SJinJx0^8=ga_kr(V2VW&ZB;Zknw7AZN7{tGp?+s|j|A~-- za(D=q^(SJZZ=W{y4lEt-|6d67KO}*@ zN-_@)bRT&7@4$}qm%`;Fo6Zk^B>D7z5AnbDTXr(Z=YifwN=3MkSm>d`op}B-aj|e* zA3?yqB2EhQ_qhLcA^caSv(P6nw|GbguHoS(68qC3@HxGQl+k+v-^tf~#A@?PK{xPODZANXf5(CY!4V7LK(!`~ww9;jPf zt7!`2Pa=c>=Uf9W4g$SR4*!OUUNC+HY6?PTmSZ|XgX2Lr;&>xTb1n{N0T!A9ozT zECcN1zG5qJ&--tNWZ|1)SQQns^X0TWpSJ@)ut_{S3vJ(udp<5t#kjo)yH{x*f57J| zeH^l)D!lh&&LK{($9**F2gyI{#r0OaL;m!5wD}|ijx+c@Zx7}OD+CN8NR;SrtgB1~ zt*29fgWiNq!5grF`a8nwqzLdX$2f?mUt)}Zje7LJfA$~X=lYNE%)A$jyW0YTiWyRd zumbc)1-YBp$z8BWdKj95FOzbX2X94xfmIs<{Q%{E07XeZ$)sbXj-Cc<()TewHvy&y zhdYkDjp_U)-Ub}@~xmdMM&pY+^36YkHY2p zJ7{wZ+M7u#sU8x^-vFp(rjIesINtvpa6K{*0L`Nm z^iDtg=$wYJ9YJ&qr)hzv2vPO}cKsxU{u|*3w1vON+KBO?7wvo>W%Kr3ihkUM_WlO- zUWW0{`}%T(Eojpgygv@(Z5J`oji~ee`2Id(#nmuH%N}+2$HG%1mo#BlBqZm-t<-?&reX7KaqUJN|LHLoD{ORkpIKbWxWo4>?LXB zGtgWwAg{x*9)3mY=~2Y2xR=zhEhuvWa7uyhF$r)z67W?5ha`Au24IA`P#@lz0H15fB7FCFU^?&#WLo^+dc^rZ)B%5>^_ADozJ=dUK+}Jwd{j{X z;+6CRZjln4oHM`?B5V)(j*u4VN>>7&P%J+1cNy4j9%5_>KA9NVwwc^d$oEVtLsdYx z8wv0t{uqv(!^J50N_+>w`Af0*<-3nqSS?TB`U2$tYSM!kPN;xx_tEq>^mO`LdO7ve z+vqd&1^O}l4BmzfES(iFCr)-9V83N|vq#zE>}geoEw(cn8}DstiG*{*OaE>qmE zOjeqe2BYrKi=T^`-gJ#?p4BU6S@6 zW27Eyg>I_n2Z#@um!u#Z;KV zGE^B68POSW8Oa%G8J3L3jKPeNtS53l`W_NSw28OMNNgBomx)$gMsGx`9)ds4cj>3} zbNU?=ohap;cx@_PkaRoOhI|tWee|S1Z>m&rqJLyg+${@&@qL z9#_7i{4kBB>C@8EJZVeQ2GiE3?L@0CL#twpiN+M8QMAfoESqc9mBv4yRev(hpjCGm z@0MGYKi8@#v?^(?Rl{i2hu?FJp3m7h`j*>sl0Y(M4gO|N=D!R70?OI@XHVoiM?U8H zU*O)rJ%L*SHw3N^Tod?1;L6$aW-*KQ--PfNDa9}U?$Z;puWuhrg!$h-%f2J_9k;J^ zpK4$AJ1@NRH$vXo_YTKlYg5!I8WcT>rLZcwOmT(c8vc&|DgMBN!mqepx?lLK zz?@g?!+Z->)}pT(l(Wrwm$*{@utT%la497O*OE7vI3p%=%Mm<39%c0|Av%~e?! z=7pz5@h(l3fp~^0Q+h8w6>ngot3r^U#|C3;8|z}zm@P-MKe8LxW_B1`$@j7QJE!WfGAFPnn!M>u6bP*pJB5TM5oH8B`A2Sz_3(4i=kHk+N zA&-)$$kXH{=EI3`tJ&pj9ebO+hLexJg+~JwO`&Nto95GUT19JUBWdYtCAk+ra9*z@*+_s&msOoogqkr+q@aAgtJ*D|skcx5T+$J)CM zvghsO2y!+#mYqX>OKyjE*qh0%7 zHWHwnbdYw_UOGWnuyg4+@YBikG$__yL#MIs$72>K$m>``|ApE9AM7c9Aem%8WIW%2 zb|6?!pp_2XZKE2jLs8f(Bw)?cl4j6WjnoL*Arq!OW{BBgGBnpTn#T1`D<9jztnvHFc-?YVB3*$X=m)u_m8LSCc#G*(3+6xe{8piy@KOV)AS*;#i?NSLB42>N@o#b#-2gv7ACWln zDb~OUvIuKoABAN!b(3ST4xJ8#uS@B6;L;uB7J52)0JP*E=uUD2Xvq$mOOB(5k#p!I zIUeiQ3$QJFgZ+)Y#@=G@vcI$U*gNdc>_PSjdxAa59%B!%``J^#whysK>BIC9`cL`* zeGgdq1NtHTi0-3*r~jZ&V^w^azDe()_d?cjKYb9G`%(HBeVjf)pQ5kOSLxsAYmk7v zLEnac{9E*WtW}@T@96jR2f82nNL+%ag3_CY=~x_#$0?QxEQuwvRABuSW@fo84?4dJ zmQQC{1~aitmc_EM&KX$_)5CdXEHltgnT37^1E)XJ0R0y$pr5ls`UNYZUosp0irKL; zf(nJx?{Aoke#_kSKdczE%r~GP7-*POGD(}r`S471H9dyh2)g%4(7TV(E65Y{Dx7Wk zG1lRKLVNICtW)p9YUl%KmV8J;K?f?y8(5d$f~4qeSX{gV+Tcyll+mP$#*!ME2)bTR z+%y!lNEqm-aO@RA$O`HLf6zg8;b5T?K%X25Pt`|*M*R(pxuM%Yjsh)n5*;EZ(-CqC zT|-WV*3%w3Om3rRk~`>G{wRc+f1zu~XP?b^<$@mE(NwKd`ge8SH9y5xbB8aaoOi z(%WA@U^KSePQp7|{Oayy{eG9hpF1$P#<-`q-_Npqcfe+v3=NrA8%!oY8SoRYxo$78 zqj#{jz)!7ybGBaoFg;zr(N0UbZ)vhI#9U>iz2aev@C3HPE%ZABhcn`i=gM4m|P< z7>xc>9xELfFwRJ+QKMWulJAUu8-H)(Dev#-Hv$@ad`7M@Hi#!i{!Y(h#XMF#Xc&aQ zAOoP~5A_cDNmsw02=y`(?j^fOlRvG+cY7om;wf%dk<|kO!@dDOwG0f%Ef_Ekqdn%@ zfdaqEYOFW+`eKYy5Nw74d8G3;a5`KtOH7(JW}RA_?m2864nA2J1v^_13+* zaN@16%{R>roDl26ffOp`LM^BQ>Yg=dtlwky@lF-MCI;Riexm`E4Av4|YxdPiMTGst z=l)E5g^%Z&Hvgk=KK{+MH{k>qMLjywU^WfpV-QDJaa>`&f7n-7;E%MT2}Ywo!rRPS zh6sAdAIa~!a2F~1D+(D!3ZNJPgCSJhALSi1?in=tqX4!7f3&rwr+-E{TsM&E4;wKb zUf_?hwsiKlbW0BnCOnT3&tt7KB--2CKNB78^;2K1KgzGwyQYmN2(a16gNGlm?7Vl18vq7Jtu!u>`RNRiswS`LX=R0Qv4 zVzn0k$reKf#(6v%8)qr-Cs=1Fza|3k{F-E)QSfWBbw~G z%{rsy*L3TQj$bWSfJN#Ezj_cLHyaE6^e{ec3jEf2FXQK4ZjxRW%zK$V_i{>lX|xi5 zgyp9i%-ed4)K=cm`Ry~IeMZzP1MTBiGup?mnP?xsW}$ujnvM4HYYy7SueoR+zviKR z{F;yU@oS;gSSe;ykrg0L95e#^(Lp{qe7O1x`QWu#{Y4gk5hkV`b7C=u?jdKU*;i`j z82)EdU|bgX9l^ey30K$iq35^f&!}izeLt`x??vZ4@cdL7m(}PNHFqO7DWCcu;|rjn zL)Ml*C-FBE{#UoiTsq^TalEa?fCn0I$ZrNQYkZ{z{t|0pLS=!!^p}!igbyKk8M=tX zXBi8Pi#cupXq)!zS!`YmT-1*h5a<_6Qz@l!v4C(nkXXDw0m+oWt63u1Oem@Khj=X` zdkW1)W91&?S+Ovgu~5p-uf}YUQycw*9JzQp`)^VjRYt>2%4}8gKrKhPdSGvqj~bX8 z2K{RE_QH9KsYNZ)@}%?*4x9ZdtggU%O0Um=_}~B##lheBP&F(B<_2G>!Hg0b&`w-L zDah{-g`grFH>)v;(HSZXI4mUx)dV^E__D<-p}?<cFrNRalEp8i5(C02G`dnP?ZrgL54S7+g_39sge7^xF~ zJn{z3a&KV?DDYPYOB2wSyK9hBItMp7*u@^;k3tT`27iLLzr%pV)mS-DIAf!+n71_x z-gX%}7QC%p@HY7E{QM67!fW-HTjnPSeiSUQ&g!qQ?7{HkV{8v*`cKsj9a`wOp^EjQ z$$S`ROOW@0Qmd7k&WE!ZGp!IaPijzubw-axhmU?S^8dRbz4%ZA?0*@>9Nrv{Rhml; zrg`JVG$7Y=F%WRMB?y&9+*Mdiyw5mXAhg=7d_en`0L<;yy@WI%(t!x&kxuJgDxP#9BA#^f zG>h@7ho|9@UY>?Wmhv<_(q{#ehr0;^SrV$ZB3Dj|}lNjff2MG(0lG)9}a|o`y%(ih9){wocTG z$3{iHcx=6>7mtmJdhyt}s27iI5cT4*2~jT|n*@w2=Q?nsxbu7PVv`iDL3D}(ohS3x z;%*viEuuWlW+}?kY!PYr3!Y{xKCYU}b(^>oUmPw)`4`)zC{Mlv`BX_+9w9|}f+M9U zPjD2{E}F~lXmKa<`;8Rk$#+Uop8Obmxk$?ISSiXA94AG2g5#04dM>|R;!fnZTZ;1J zCrDAA{6u_NE#-HT6y*u_NKu~PWb57#LE`$=hP_b0tjF#NYuP}p#jhRlD>6F{4=(5h ze2K+o@UbqCmh?0%chdH6;|$T%-a?9V(v&2h$36NArA2F2#%Yv#`9U>vs&iP1N<0Xu zy(a?OXdO}Q#LhVcNg`_RAs+c3e{u)BonKTplSxnP#D?L-e)&F^-`}n!!3P6|nH>J; zPVG)O=J%X9)FY?FjtdrU`YKkS&SD8FWqAJWG_cFBJQWLg-A$@tn1j~w*8G~kF)~Kl zNjvAxvs&8yElwP5fiEc!GeGb7>U@k-DF!Mx3Yb52jZfOJ@+S7R5(` zM+h#zQir=gB1m!Aq~K19Gw>R2mE$;9m^>uMx!>xq<+zG01;0T`uZApXogCLfS0CO? zME<&Y@es%=E|Q;z&WndpBYj4G4n76rc6|JV2Y9DcWXN&Ff%cbtojIqArE_$_cLst5K&RaA+6S{@~h3B~HlY)d0pmz-M|6iV_UB zpg|BS2=0O~<^45^cSaI~n~`)QtQ_umv!8|4(^xDJW0r}4}C zbqjJDMtll!-dj9vH;gx1acxI$@{;D~+`1qKE8ZOpI}Q;Zq>&`mY+<><+V}uJAM)cp zx>}3~BWf&-8Y7FHlnrc;SzN$umQ8XIz>LKtPZvZzt4iepX@QwGA0657B;6momB$`Yt!1u4OI;9Eb-Iq#5Y)KV|_+;xz^)`QPoL>EKG(F7?+3vC6r+eVjw zx8FwFX$PbRU9=lx46=UO11@GST}u1lD|!ID(6w|q&i^_Le9e_~6{HJ3x|$BrVLC$B z(6zvIXM)##Bl!1za9YQ}qjiDXI!-r00x=0relaBI??O^B1^EM)tZW4jb{jpMZl^ow z5twT)&?CXqe-XU>b>Q*8M0e6-=&|%T$X|BR-Sh-{B0UL`n3KWZFM~wlRLC+;r)K~+ zRFaSBnc&0zmYzk=rsshFS_OXW`{2iNS;Oz>1@uCC5p@4AfrMa8NOG>ASJJD%Qyzy7 z#Ck||uA$dLA~FGv?FR7auLBSIdW^7HO2CP}0ltG5lYc<6i?gI5Ik<^5l8y9cdJAM1 zw?Zy@JH3P63Hkmsy&Dq#O)}U00r0*#=lx+w5FUZdR7#y zv^Bz_qZ#tGR!9olgru+&(!_2^3VR`c>w_F|020LIY=w|2u7VWL2T9-%oJ-I7^^=g*ZDLc9Ms8+X*j7j;4`=T>WspK%!LDRivEPI1 ze>LQU*Fx&~Cw3jXp4~t$gw)Uv)?6$kOYxA>B|_qq3`t=Mn}K}sCU!G)biRW8>1#0X zA|MA%BYy%FcO@i=SC9wE36PDbAuFk7w}8Y8B`e7wG%h?OlHE%7lAG9Vq!#qc!;mN5 z0-EMFaxJKwd&zx}nCKzR1f9q3gq-4Tay+|-+(R_%UUnb(1NjE>rw4>Y>LK;UInd`XCTGA2vXVKk>5kp z>wE|;9wB!SGf2=AA?rMu?12sGaqKV9Xj=t|&avz{@@Muudx5>kUScn^S0GD$4brjK zAtQSe60)};9oq*f*}IUFz0W>iAF_|wKiJ3Y6ZTK`Df^6^3JK{ukN~|xPJ^7&3%Ss1 zkPE#*US!@gzzVc)Uu)itZ9Mz)Suc(zYi+T7waHh9 ze0A}w&F-y}?rX$7zVpiW@^>|*@_mg+@36`F)C8|0Kbynm(9~@34NXl>Xlf?cPEL%B z>1(D&C)WCgwrn2J)YMB?Q8k+*#5*)PHMC{Jn(>jt_1@vh&Ay?bk%`Ts1bc&Bx_Vve zx*;Dj#ARyIC*IoYZBjk#4N|#wuUlO&nys!EiKW`s%B}axt?AP2 z#oOy^Bnm$GrSZ%Vv(*y}?Y4}8O#n$=BnJqt+774(V<+UvdI9?xquO>#w>q>8GWHjj=E zkAyTI$V{%Q^oiXmz=J_hqHYx(q;8!9qRsBCRkos<(kD_WsHcD=KB-Z+NuRXM`^4o| z)K9FHzo=EW&sE!AUnh4#om~Aoxhv{KSKz%=7l%!PtHU9~-x=&Wd0=|$Rqg90rzUtI z_(}#seK0pURh`@$^|r9~bz3kDr?zYu_id3Hzo3#4!aDq`rx%#)q4OY^>Tp?a)I?h7|AWFuMg|}F-+{mnqChwgW5OOU|^#L=|gFfVR8!GfU5umu5JMkyI1b+8gY;Bf>=#VPTZGC z`P9^k^bVVxPfhSD1J>r$_+%jXWGv=8fW>?xqOwv}HfPAtf#&Lm4m4nRu0w&Yqyp^? zQUP{vv3f+bPdzd(Rju4iuUuWPTrIEMOs~{Ths~`YnJY)CMy=ek+F;8{G$V2gMi!te z0TG+SEz;W@WztBq*ULrQ#T97FtzIi?7P9t0>jcp34yS(Yg3^Ju+{$$a&{jjpx&z;+ zN9XzxxT#DxS~xyAG~UzIBGua~>I>{8*T+`NM%Qab<*JX$2y9f0JyE>FSrW4TK=x9V z>ZPyk&XUlvwNoP_6XU*#;n5-WxacVL_#BLZ&AiHS)L!~dDizqwuAY#_^@MNZf|nvW+$G@gRo9o85}kl^bWa;oWb6e2dTF~ zHF;q6*2#dWm;1g>PE{v&RJ}cH^2f8+)}Wb`VJBg<+K|Z~VKg}>cZqsRg3r{vhPvh2 z+C}Yvf}HAU2{h9OLET}O8(eHxjZaRjomOt~$%!;Mq?y$>^DXvv-nS&hgn7~^o zLxxm+@LHnUasU!i=VFA)@Tw0&Ms7!aL)exdL&A=B1R){gu`L3RZISTUHmOnD4m3)) zZ4QrZlknK~123h~idnIJJ|2@{<&^uVp-jC)WUJpXH$fC@R;^JXtQu8|-}T~VT!{zk z#UOOaYllmQxXUh0Ntay$o(sr`_ob^$T4P)i*0;GNsM%Z+DTb@mV=iEDk)A_O9pa|dS=ArEoa*U&lv5}$eQcg0> z=#r6|OQLmbE@?%!xg=T!R~drRI*5B2f;cW+>ha)vxrI)-#csI=+`;#94V`j}oib#d zGQ`|6WSnvf+;R^)Wr#R~_rY{Bgq$*jWMa?dlFM_+5OW3VE2nqK^>oSgbjkH`$@O!| z^>PL470h2Q-zC@2CD%({q+IS`y@Tx!mLu0!rovn@?sB>1a@=x0u3-J-^4!55m+N0F zrz;D>U9NYT{Jh4g+cMYVa_pcUms3i_xXmT41?cfI)-lRE6O^Gyf~(XRo3vuvY_(El zY!WTwu$8#tH;zn=P7d>}5a_C5v0!>@dc>HpNhA#@7cmALCDNF}Rf4Il#>Tu|qC{J* zJ8WnYn0W)XVViwZ+m*w>(#rZRQtcw=)&^{_eQx#W~*v(r|h6PS2ta>Ht!K)O68%5d6hLwH$Eo43$6 zE|u$)XE~n9X{0gfwAJXuf-vuESJ=AA$uZyR$*rj2T%OX{amrZQDPw7;y*3oMe)Y)s zT}8{&ncrIr;GrcPPbHHM=`H(s8o4J;gD~7M7pupiW|9E#b}y+ zUfeb>UN$f8l;e(h>3KYup2vgfdEBXN>uqfXj~G&0*ib~^%B4l(4_sFU`2o&CN65oJ zoOlFXbqdMLIDWaDgo0mwK7KC%r-XtNGYc^=BKT$C7gL%{v+4vf~~;s4z>fo;G5wW95ei$#!kcU{qP{B08i-^{C>dx z#bsQAD<29VrXa3ne`U`JZV-4uc%u?u5Pb10;vX<*0dxKjI9#9L>uAvz+!_t<(nJ)EG(LFt%X~JT(4>|1r51NQLiIBsA7# z`P%wgK|kJT5%i(wqVBakPnx1=#lPYO{}$f!yZHfk%6w)1{6D2F_)oD${2N#NmZv%J zPjQjr&-nM0;#$K0!|EB}P`q%!`zP>P}R2Mwc z!bcDP7p=4Em+Bn4N?n8euT}ql)pj<}RaI9WKj*%e50aSo9UxMTN~u+r<5(BtQdFQy zDFQl_qKzL7h!~Nt1(Y&?7Euu$2B~8$i)AULl(8-csYS{F<0zywW0?#{g02uTr4bQ> z1xhhu%$wid_uS;=@u0SL-dq2(&)H|6eLnBG_nxmiyyzBA>6u*gMA35o8;f@GZ!9`d z>=h^Z_bcwN|0{|I@*i6~xp*P}<;5F|cNOm~ZYn-l+*;gG5-uq!iSl1aJCgGYWk1Xp z*v(Ro>rzHVFXR6uW;X`n9>o94%x8>X|ETP6`3kdNlh}hfg*mLN8TtPKd%=H5A9B0) zA$KyK`yzATJ4^#JW{u1}Eo9EBH~S9yu%}@QGdwfdFYz6AB)rG`%ERUevm*ayK4gw# zy*a79$49b%fH|gD={HW%OYAZ2GAm&|Wskw{*<11na|a~b<6F5hH(+~6pJ0ob4M^G& z8Tq#nM(VGzF~;hzwQ)x4Z?Fl**6+8yWpthSuROCN-C=g5TkNWIn>RUK>rGA9GG=`t zCr9M+v9_9h?mgJ|!p6PyVcFqltI~Vn?zQ)U2h)eVk?A+QQR#Z)b=rEErRgU0wVT#- zhrJzCa~j2ygk6#Tkli81uF|U<3AGg>d&<1Z?t4jDb@~J;+d;}|yqTOxF$+IWe8q>f ziY#(DWOkr+XPQ}iJByvbBhxRCt_{?&@I5tms;!k&%wn$@{Ws=z?j9{{R%~J2MT-f8 zJdh6xKq2S>ia;?a0q1~H5CKsT196Z5Nst0%peN`BdV_LsKBZg%E&x*E7lFQDDEJx} z2EGnhFJW#1Bfv;7j#Q5aGH1%M;bsoJe*$yCJTM?AG`ya!SBEU@O#h#-USE2d*Bdw9~=fBfL3q>dePM_j7H`gU<~*s7z=I%w}EegN^m>41KbJj0^bHzU>q0^ z?gkUUJzyfZ7gU4$z$9=#m<*tHyLy}t51HWIL3leHDb%mwoR zyOs?*DmnSju$SDJ1>hmD5IhVX0gr-3;4!cmJPw`!vS)M&kn`u30(ug&46t95xh=z7 zmtn@s&>tJa&P{q_bM`ihzvQ!(d>$s(hv^Ac!Skel^G0E_zG>H{TiItuFGjm+ryaE0 zuYdvcXkT?bTb1^19n?pMeG>eL^Akq$^@CBA=VY`^W&H~MCnt_bKUf8=2KRyKM8h6Z z?HB12iQREb9xdyXy_&BbUIPY#wdv!eQLZsh`eNMe;>PsQ*)DqM8QV0S9X!bzdmfM& z#fN@QLb_V*AWTnEISOg=iFv)|unn1y!71CU^Ms!7z4fu#sW^BvbTY6fl46v zojbst;4biOPzA<;@!)PS0o(&7f_p(VxDQMM_XBE!U4zEbi&}co&eFEj#tE`VX;Jdj z?P>K_U>mr9?WHu|1dZ66kqYjfA-flCZ-PczQURySwA$_I8e5BOU7Fp0+|v%E8*MAT zdH9~dx1O~L2H*YoG|?9S6W4ZR>X6ANwiaS*CAL;{ZX>q6_AvL45XH}aYVL`0Rfc&_ z@LiN-z`@UO|D=w*Qmx-oX*rzgAuWae5$;K1kdV|7?-GX784N20j3-xip2iTS?G~dY zPQM^A<#`sp9tZ*I87-&C%PIT~SCPb4%$0OLcklu)j4Pgg%S%v3Nl*rQ;`@d4Tf9&B zz6bF=f$s_Dvx_tiA!XLPUb4ukC&n9sO`h_}sk*QAdEO1mzh0$>q>pLHR(V_DNyY;q z5C(Z59~6K>&;t~KVo(Ck0i_@Uq96w1AOVsf11`(25OPGY$$!mhSP`m z*v?RS7s;#7uj5&g^8DNVxSO8#qb@stv={xQn|ZrBn(5OilGBn)Z%)B1CRfVe=qD); zQh&Ni`dyPgt}@aekvDM2m!syhe%bk^b$;gGUn2XNm40r)>>Pcw+# zU)FT>V{Cx$f08m*(VH7t9VTmHdyu|+Nc}|q2~A}}Q<)%@Q{c$Dhr z$vO8?&s1p6!8yPFMwK7(0Uzf3B`&$_+wmW5%*w)D?vHf2eCAPa|l$cSd3S)ZBI16~P zK8wG_&+ECe8$#+{t~?1VGNza4$*IfMC*#JXmZw&hzUAn1j;`)t161KzMQsqiCS2A`*R@lVwQdgTaEn)GS%a`X*M4oMF1X{5ZnyOZDF`9mXDWXMzZ z5Dze<@FS0yIyAgL}mQMqBHjT`6{t|vcMz}?12R={`Brt_|ZvSe09&pJ>Qp0K0*0kf!)#Q!Y+4ovCoe#MgD1@AKesvJ-REp zm#+u-bVZgs;Ac|_w<;stS{E)`-|QzsrW}f1cCpF?s5!psGeB9F|l5tB#XvL2Cwjd8Tn(JJyqKM8`80Wyu%de6|49Zuru7H&sw`5-;9olfr?gxe1&XQ5@UfEw&AK8<^n ze<5!4D?Oa$4*29x{o8#SgiB4OTxY>6bu{TyDWOz#sybfo)6{t9uITO#_yLXg^Zg}! zygwR(aP$?TFK~;0E_eJYpC7-D@Wa6kj@|(s3vO{#+~|(aiqDNNfL1#ixP_9pPXBKw z8y$aZmVBURo8#B|RO0CtzTWwFz;8`0NrZhG7k6WZyV>y%I(j^Je4Y6qyyQppDJ^m| z>S!75k@lC8`lY=j`Z#(a_KU$~U=X-EiwghB)A^~fgr^P@Bf3-JCx&+M)jb;bZBA}N zVs>Ia?p*XP$Dah9?&MY_UP^3AypmYq=)x>_z|W=Dc=BDDGIMn5z_^`WN;)L%`oT8pffXSly z&K*aN_nP4OKiL;Sk-fyx%duxXzX#9j$zjfal%r!Dt#q`?(TRkg3}%2iz&+mu&pW|; zM$q3Um$`7yIJ$u_o58bSHF(bP*Jb$!a)JK0$QSp&WQ&tK?C4Q+gwE_AgMK==UQ_g8QV*#$(C5K=un|c8 zZv(ZU4%CB2)z+-$LENp_tT`FpB4+5Q+8-|*p=T~CFiT=`KoQcYI{Jn%~x&nRnG%zzAULVFKehDDyL2D zZKBi6QTsc-UGo)JbGXJ;D89B(V=vUamujj?)wfjgWlJSrn6fgiG<;A@Nso<4dhA`{ zgz`mCsjq=4DQmy4vCspOhNG%2q8w%>@eQjztnr354Pli$BIRt3Xqt~`nvZA+)GDV| zeQT9pt2(2a+Nh={rs=8D^h8x>RAY&Tsb3q_w5|0yng&`eaeXQroolsripFwGOZ&K% z_A#HMWxiV_cPnSNrfRop*caM^hJ7I!@!A*qk($q`S*GTbYHq@8;``Df!#Y8;Pf~^b za?*CAH$+TL+l{Jos>U@{V`)}So#wqRgib4Gf`}2$6`tv z_GpgkHTFFcqj^_iH1BGtcU6B)s0mJ^YG_n`W2j0wqM=dc<=V6Mf>0xzX<805l|NHM z&D6MNYFx84u9+IwJe8TJI_IS&r+q^2py5r`*2j}^)i%B!g{qg_;yV#eGIXDF?1<9 z8#MNMO@F=G8&sx2+tRJde@ElmuXdg(2(?M=(=uD%~LS76z#FIUZbS{LuB zZ;NtT)c%gz>wHr~?NIv;k>_LziE+DfwyS-M+PA2ErfQg}_G!L0wKu5D2{jvpV+(X- z{bYzWD9lL+$FGq#4b`R`PwcW@1eqG;*C@Y4`6X&ERJ+{yt@m<>mS(3YhgBNPg-A$$ z1pjK|nL+HB_ZZ&~M(}0*@oul4!BAP5oY1w%DP4F5sWp$@n(5;k{u%M65^G#=#?0ahkZ0+N$un(P18x{$R>`S@F;P{TY$31%No2*_S_ z&6A>xz;}Z@6;uyVuSf*3Q%)}S z%M2s(lxt=gpT5Rh);CNz3wUcdtG|R5ncQ;n-2f>AS^v?KnU{%RGHa;B9KfpFA<$v! z8in5&Q)#MHW(KoTtnQZ{DV^5RmhV@iNBa<~{fP-xsW10RWaKVsIH_MuxxW}~rAB*f zqv!R*;|nqJjgQQ=?EQ3hN!GHn0*Y|{8ue1<WFvHpYQempTIvR8KO@k{d z%#x8ekEk%KN8dcM!fYBNzIE&=t>9!9(W6%YCEul~i|g~Gc6n;)l=Zm~%-D~DfWY4BqfOVW%Bs*!%5;dPv zbGe!;)m)?I^J=bFbK|rb6Q-K2Gru!^CZ}f5Ahfil#Cu^2;m&g<=l9X_#^BE%TelN| zm1%Hf2+)#BG0#y`dmkxJI8jWG(>|nCTV@XVE*xtPS8=w^M7ucjNazv!3M;EC`A_A) ztn*U_Cfnt=NT(wnW5Z84tI(`uIq&Kq)^dFfAzlmAWm$vrJ?(iV%H0M zN08ahnQk6usr&(RCo{hur>JyEysr|6RpJAcXjKW(zQdDs@_w57Y6{qaqrJ6IDGj;b z4DR%~7`N{u{~~D9NX_+*dO+^&p>? zmLu!tx^mxNb6g>=GL8Eh?*?^yW)5pPgS2UmQ5tg?ti$KU_$V2p!xCB#&CtEhjkI(y|;RnBuz_0L_${X=;r?bu_)W$ literal 0 HcmV?d00001 diff --git a/3rdparty/imgui-node-editor/examples/data/Play-OFL.txt b/3rdparty/imgui-node-editor/examples/data/Play-OFL.txt new file mode 100644 index 0000000..cb9baa9 --- /dev/null +++ b/3rdparty/imgui-node-editor/examples/data/Play-OFL.txt @@ -0,0 +1,93 @@ +Copyright (c) 2011, Jonas Hecksher, Playtypes, e-types AS (lasse@e-types.com), with Reserved Font Name 'Play', 'Playtype', 'Playtype Sans'. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/3rdparty/imgui-node-editor/examples/data/Play-Regular.ttf b/3rdparty/imgui-node-editor/examples/data/Play-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..25a72a746cf4061c7a19b22aa9d0039e4a801ac7 GIT binary patch literal 183852 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
i`FVMT8^_<$mwxpJ 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 Bic +# include +# include + +namespace ed = ax::NodeEditor; + +struct Example: + public Application +{ + using Application::Application; + + void OnStart() override + { + ed::Config config; + config.SettingsFile = "Simple.json"; + m_Context = ed::CreateEditor(&config); + } + + void OnStop() override + { + ed::DestroyEditor(m_Context); + } + + void OnFrame(float deltaTime) override + { + auto& io = ImGui::GetIO(); + + ImGui::Text("FPS: %.2f (%.2gms)", io.Framerate, io.Framerate ? 1000.0f / io.Framerate : 0.0f); + + ImGui::Separator(); + + ed::SetCurrentEditor(m_Context); + ed::Begin("My Editor", ImVec2(0.0, 0.0f)); + int uniqueId = 1; + // Start drawing nodes. + ed::BeginNode(uniqueId++); + ImGui::Text("Node A"); + ed::BeginPin(uniqueId++, ed::PinKind::Input); + ImGui::Text("-> In"); + ed::EndPin(); + ImGui::SameLine(); + ed::BeginPin(uniqueId++, ed::PinKind::Output); + ImGui::Text("Out ->"); + ed::EndPin(); + ed::EndNode(); + ed::End(); + ed::SetCurrentEditor(nullptr); + + //ImGui::ShowMetricsWindow(); + } + + ed::EditorContext* m_Context = nullptr; +}; + +int Main(int argc, char** argv) +{ + Example exampe("Simple", argc, argv); + + if (exampe.Create()) + return exampe.Run(); + + return 0; +} \ No newline at end of file diff --git a/3rdparty/imgui-node-editor/examples/widgets-example/CMakeLists.txt b/3rdparty/imgui-node-editor/examples/widgets-example/CMakeLists.txt new file mode 100644 index 0000000..1f1080a --- /dev/null +++ b/3rdparty/imgui-node-editor/examples/widgets-example/CMakeLists.txt @@ -0,0 +1,3 @@ +add_example_executable(widgets-example + widgets-example.cpp +) \ No newline at end of file diff --git a/3rdparty/imgui-node-editor/examples/widgets-example/widgets-example.cpp b/3rdparty/imgui-node-editor/examples/widgets-example/widgets-example.cpp new file mode 100644 index 0000000..6431426 --- /dev/null +++ b/3rdparty/imgui-node-editor/examples/widgets-example/widgets-example.cpp @@ -0,0 +1,432 @@ +// =================================================================================================================== +// Widget Example +// Drawing standard ImGui widgets inside the node body +// +// First, some unsorted notes about which widgets do and don't draw well inside nodes. Run the examples to see all the allowed widgets. +// +// - Child windows with scrolling doesn't work in the node. The child window appears in a normal node, +// and scrolls, but its contents are floating around in the wrong location, and they are not scaled. +// Note that you can put scrolling child windows into "deferred popups" (see next item). +// - Listboxes and combo-boxes only work in nodes with a work-around: deferring the popup calls until after the node drawing is +// completed. Look to the popup-demo for an example. +// - Headers and trees work inside the nodes only with hacks. This is because they attempt to span the "avaialbe width" +// and the nodes can't tell these widgets how wide it is. The work-around is to set up a fake +// table with a static column width, then draw your header and tree widgets in that column. +// - Clickable tabs don't work in nodes. Tabs appear, but you cannot actually change the tab, so they're functionally useless. +// - Editable text areas work, but you have to manually manage disabling the editor shorcuts while typing is detected. +// Look around for the call to ed::EnableShortcuts() for an example. +// - Most of the cool graph widgets can't be used because they are hard-coded in ImGui to spawn tooltips, which don't work. + +# include +# include +# include +# include + +namespace ed = ax::NodeEditor; + +# ifdef _MSC_VER +# define portable_strcpy strcpy_s +# define portable_sprintf sprintf_s +# else +# define portable_strcpy strcpy +# define portable_sprintf sprintf +# endif + +struct Example: + public Application +{ + using Application::Application; + + struct LinkInfo + { + ed::LinkId Id; + ed::PinId InputId; + ed::PinId OutputId; + }; + + void OnStart() override + { + ed::Config config; + config.SettingsFile = "Widgets.json"; + m_Context = ed::CreateEditor(&config); + } + + void OnStop() override + { + ed::DestroyEditor(m_Context); + } + + void OnFrame(float deltaTime) override + { + static bool firstframe = true; // Used to position the nodes on startup + auto& io = ImGui::GetIO(); + + // FPS Counter Ribbon + ImGui::Text("FPS: %.2f (%.2gms)", io.Framerate, io.Framerate ? 1000.0f / io.Framerate : 0.0f); + ImGui::Separator(); + + // Node Editor Widget + ed::SetCurrentEditor(m_Context); + ed::Begin("My Editor", ImVec2(0.0, 0.0f)); + int uniqueId = 1; + + + // Basic Widgets Demo ============================================================================================== + auto basic_id = uniqueId++; + ed::BeginNode(basic_id); + ImGui::Text("Basic Widget Demo"); + ed::BeginPin(uniqueId++, ed::PinKind::Input); + ImGui::Text("-> In"); + ed::EndPin(); + ImGui::SameLine(); + ImGui::Dummy(ImVec2(250, 0)); // Hacky magic number to space out the output pin. + ImGui::SameLine(); + ed::BeginPin(uniqueId++, ed::PinKind::Output); + ImGui::Text("Out ->"); + ed::EndPin(); + + // Widget Demo from imgui_demo.cpp... + // Normal Button + static int clicked = 0; + if (ImGui::Button("Button")) + clicked++; + if (clicked & 1) + { + ImGui::SameLine(); + ImGui::Text("Thanks for clicking me!"); + } + + // Checkbox + static bool check = true; + ImGui::Checkbox("checkbox", &check); + + // Radio buttons + static int e = 0; + ImGui::RadioButton("radio a", &e, 0); ImGui::SameLine(); + ImGui::RadioButton("radio b", &e, 1); ImGui::SameLine(); + ImGui::RadioButton("radio c", &e, 2); + + // Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style. + for (int i = 0; i < 7; i++) + { + if (i > 0) + ImGui::SameLine(); + ImGui::PushID(i); + ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.6f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.7f, 0.7f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.8f, 0.8f)); + ImGui::Button("Click"); + ImGui::PopStyleColor(3); + ImGui::PopID(); + } + + // Use AlignTextToFramePadding() to align text baseline to the baseline of framed elements (otherwise a Text+SameLine+Button sequence will have the text a little too high by default) + ImGui::AlignTextToFramePadding(); + ImGui::Text("Hold to repeat:"); + ImGui::SameLine(); + + // Arrow buttons with Repeater + static int counter = 0; + float spacing = ImGui::GetStyle().ItemInnerSpacing.x; + ImGui::PushButtonRepeat(true); + if (ImGui::ArrowButton("##left", ImGuiDir_Left)) { counter--; } + ImGui::SameLine(0.0f, spacing); + if (ImGui::ArrowButton("##right", ImGuiDir_Right)) { counter++; } + ImGui::PopButtonRepeat(); + ImGui::SameLine(); + ImGui::Text("%d", counter); + + // The input widgets also require you to manually disable the editor shortcuts so the view doesn't fly around. + // (note that this is a per-frame setting, so it disables it for all text boxes. I left it here so you could find it!) + ed::EnableShortcuts(!io.WantTextInput); + // The input widgets require some guidance on their widths, or else they're very large. (note matching pop at the end). + ImGui::PushItemWidth(200); + static char str1[128] = ""; + ImGui::InputTextWithHint("input text (w/ hint)", "enter text here", str1, IM_ARRAYSIZE(str1)); + + static float f0 = 0.001f; + ImGui::InputFloat("input float", &f0, 0.01f, 1.0f, "%.3f"); + + static float f1 = 1.00f, f2 = 0.0067f; + ImGui::DragFloat("drag float", &f1, 0.005f); + ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns"); + ImGui::PopItemWidth(); + + ed::EndNode(); + if (firstframe) + { + ed::SetNodePosition(basic_id, ImVec2(20, 20)); + } + + // Headers and Trees Demo ======================================================================================================= + // TreeNodes and Headers streatch to the entire remaining work area. To put them in nodes what we need to do is to tell + // ImGui out work area is shorter. We can achieve that right now only by using columns API. + // + // Relevent bugs: https://github.com/thedmd/imgui-node-editor/issues/30 + auto header_id = uniqueId++; + ed::BeginNode(header_id); + ImGui::Text("Tree Widget Demo"); + + // Pins Row + ed::BeginPin(uniqueId++, ed::PinKind::Input); + ImGui::Text("-> In"); + ed::EndPin(); + ImGui::SameLine(); + ImGui::Dummy(ImVec2(35, 0)); // magic number - Crude & simple way to nudge over the output pin. Consider using layout and springs + ImGui::SameLine(); + ed::BeginPin(uniqueId++, ed::PinKind::Output); + ImGui::Text("Out ->"); + ed::EndPin(); + + // Tree column startup ------------------------------------------------------------------- + // Push dummy widget to extend node size. Columns do not do that. + float width = 135; // bad magic numbers. used to define width of tree widget + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f)); + ImGui::Dummy(ImVec2(width, 0)); + ImGui::PopStyleVar(); + + // Start columns, but use only first one. + ImGui::BeginColumns("##TreeColumns", 2, + ImGuiOldColumnFlags_NoBorder | + ImGuiOldColumnFlags_NoResize | + ImGuiOldColumnFlags_NoPreserveWidths | + ImGuiOldColumnFlags_NoForceWithinWindow); + + // Adjust column width to match requested one. + ImGui::SetColumnWidth(0, width + + ImGui::GetStyle().WindowPadding.x + + ImGui::GetStyle().ItemSpacing.x); + // End of tree column startup -------------------------------------------------------------- + + // Back to normal ImGui drawing, in our column. + if (ImGui::CollapsingHeader("Open Header")) + { + ImGui::Text("Hello There"); + if (ImGui::TreeNode("Open Tree")) { + static bool OP1_Bool = false; + ImGui::Text("Checked: %s", OP1_Bool ? "true" : "false"); + ImGui::Checkbox("Option 1", &OP1_Bool); + ImGui::TreePop(); + } + } + // Tree Column Shutdown + ImGui::EndColumns(); + ed::EndNode(); // End of Tree Node Demo + + if (firstframe) + { + ed::SetNodePosition(header_id, ImVec2(420, 20)); + } + + // Tool Tip & Pop-up Demo ===================================================================================== + // Tooltips, combo-boxes, drop-down menus need to use a work-around to place the "overlay window" in the canvas. + // To do this, we must defer the popup calls until after we're done drawing the node material. + // + // Relevent bugs: https://github.com/thedmd/imgui-node-editor/issues/48 + auto popup_id = uniqueId++; + ed::BeginNode(popup_id); + ImGui::Text("Tool Tip & Pop-up Demo"); + ed::BeginPin(uniqueId++, ed::PinKind::Input); + ImGui::Text("-> In"); + ed::EndPin(); + ImGui::SameLine(); + ImGui::Dummy(ImVec2(85, 0)); // Hacky magic number to space out the output pin. + ImGui::SameLine(); + ed::BeginPin(uniqueId++, ed::PinKind::Output); + ImGui::Text("Out ->"); + ed::EndPin(); + + // Tooltip example + ImGui::Text("Hover over me"); + static bool do_tooltip = false; + do_tooltip = ImGui::IsItemHovered() ? true : false; + ImGui::SameLine(); + ImGui::Text("- or me"); + static bool do_adv_tooltip = false; + do_adv_tooltip = ImGui::IsItemHovered() ? true : false; + + // Use AlignTextToFramePadding() to align text baseline to the baseline of framed elements + // (otherwise a Text+SameLine+Button sequence will have the text a little too high by default) + ImGui::AlignTextToFramePadding(); + ImGui::Text("Option:"); + ImGui::SameLine(); + static char popup_text[128] = "Pick one!"; + static bool do_popup = false; + if (ImGui::Button(popup_text)) { + do_popup = true; // Instead of saying OpenPopup() here, we set this bool, which is used later in the Deferred Pop-up Section + } + ed::EndNode(); + if (firstframe) { + ed::SetNodePosition(popup_id, ImVec2(610, 20)); + } + + // -------------------------------------------------------------------------------------------------- + // Deferred Pop-up Section + + // This entire section needs to be bounded by Suspend/Resume! These calls pop us out of "node canvas coordinates" + // and draw the popups in a reasonable screen location. + ed::Suspend(); + // There is some stately stuff happening here. You call "open popup" exactly once, and this + // causes it to stick open for many frames until the user makes a selection in the popup, or clicks off to dismiss. + // More importantly, this is done inside Suspend(), so it loads the popup with the correct screen coordinates! + if (do_popup) { + ImGui::OpenPopup("popup_button"); // Cause openpopup to stick open. + do_popup = false; // disable bool so that if we click off the popup, it doesn't open the next frame. + } + + // This is the actual popup Gui drawing section. + if (ImGui::BeginPopup("popup_button")) { + // Note: if it weren't for the child window, we would have to PushItemWidth() here to avoid a crash! + ImGui::TextDisabled("Pick One:"); + ImGui::BeginChild("popup_scroller", ImVec2(100, 100), true, ImGuiWindowFlags_AlwaysVerticalScrollbar); + if (ImGui::Button("Option 1")) { + portable_strcpy(popup_text, "Option 1"); + ImGui::CloseCurrentPopup(); // These calls revoke the popup open state, which was set by OpenPopup above. + } + if (ImGui::Button("Option 2")) { + portable_strcpy(popup_text, "Option 2"); + ImGui::CloseCurrentPopup(); + } + if (ImGui::Button("Option 3")) { + portable_strcpy(popup_text, "Option 3"); + ImGui::CloseCurrentPopup(); + } + if (ImGui::Button("Option 4")) { + portable_strcpy(popup_text, "Option 4"); + ImGui::CloseCurrentPopup(); + } + ImGui::EndChild(); + ImGui::EndPopup(); // Note this does not do anything to the popup open/close state. It just terminates the content declaration. + } + + // Handle the simple tooltip + if (do_tooltip) + ImGui::SetTooltip("I am a tooltip"); + + // Handle the advanced tooltip + if (do_adv_tooltip) { + ImGui::BeginTooltip(); + ImGui::Text("I am a fancy tooltip"); + static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f }; + ImGui::PlotLines("Curve", arr, IM_ARRAYSIZE(arr)); + ImGui::EndTooltip(); + } + + ed::Resume(); + // End of "Deferred Pop-up section" + + + + // Plot Widgets ========================================================================================= + // Note: most of these plots can't be used in nodes missing, because they spawn tooltips automatically, + // so we can't trap them in our deferred pop-up mechanism. This causes them to fly into a random screen + // location. + auto plot_id = uniqueId++; + ed::BeginNode(plot_id); + ImGui::Text("Plot Demo"); + ed::BeginPin(uniqueId++, ed::PinKind::Input); + ImGui::Text("-> In"); + ed::EndPin(); + ImGui::SameLine(); + ImGui::Dummy(ImVec2(250, 0)); // Hacky magic number to space out the output pin. + ImGui::SameLine(); + ed::BeginPin(uniqueId++, ed::PinKind::Output); + ImGui::Text("Out ->"); + ed::EndPin(); + + ImGui::PushItemWidth(300); + + // Animate a simple progress bar + static float progress = 0.0f, progress_dir = 1.0f; + progress += progress_dir * 0.4f * ImGui::GetIO().DeltaTime; + if (progress >= +1.1f) { progress = +1.1f; progress_dir *= -1.0f; } + if (progress <= -0.1f) { progress = -0.1f; progress_dir *= -1.0f; } + + + // Typically we would use ImVec2(-1.0f,0.0f) or ImVec2(-FLT_MIN,0.0f) to use all available width, + // or ImVec2(width,0.0f) for a specified width. ImVec2(0.0f,0.0f) uses ItemWidth. + ImGui::ProgressBar(progress, ImVec2(0.0f, 0.0f)); + ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); + ImGui::Text("Progress Bar"); + + float progress_saturated = (progress < 0.0f) ? 0.0f : (progress > 1.0f) ? 1.0f : progress; + char buf[32]; + portable_sprintf(buf, "%d/%d", (int)(progress_saturated * 1753), 1753); + ImGui::ProgressBar(progress, ImVec2(0.f, 0.f), buf); + + ImGui::PopItemWidth(); + ed::EndNode(); + if (firstframe) { + ed::SetNodePosition(plot_id, ImVec2(850, 20)); + } + // ================================================================================================== + // Link Drawing Section + + for (auto& linkInfo : m_Links) + ed::Link(linkInfo.Id, linkInfo.InputId, linkInfo.OutputId); + + // ================================================================================================== + // Interaction Handling Section + // This was coppied from BasicInteration.cpp. See that file for commented code. + + // Handle creation action --------------------------------------------------------------------------- + if (ed::BeginCreate()) + { + ed::PinId inputPinId, outputPinId; + if (ed::QueryNewLink(&inputPinId, &outputPinId)) + { + if (inputPinId && outputPinId) + { + if (ed::AcceptNewItem()) + { + m_Links.push_back({ ed::LinkId(m_NextLinkId++), inputPinId, outputPinId }); + ed::Link(m_Links.back().Id, m_Links.back().InputId, m_Links.back().OutputId); + } + } + } + } + ed::EndCreate(); + + // Handle deletion action --------------------------------------------------------------------------- + if (ed::BeginDelete()) + { + ed::LinkId deletedLinkId; + while (ed::QueryDeletedLink(&deletedLinkId)) + { + if (ed::AcceptDeletedItem()) + { + for (auto& link : m_Links) + { + if (link.Id == deletedLinkId) + { + m_Links.erase(&link); + break; + } + } + } + } + } + ed::EndDelete(); + + ed::End(); + ed::SetCurrentEditor(nullptr); + firstframe = false; + //ImGui::ShowMetricsWindow(); + //ImGui::ShowDemoWindow(); + } + + ed::EditorContext* m_Context = nullptr; + + ImVector m_Links; // List of live links. It is dynamic unless you want to create read-only view over nodes. + int m_NextLinkId = 100; // Counter to help generate link ids. In real application this will probably based on pointer to user data structure. +}; + +int Main(int argc, char** argv) +{ + Example exampe("Widgets", argc, argv); + + if (exampe.Create()) + return exampe.Run(); + + return 0; +} \ No newline at end of file diff --git a/3rdparty/imgui-node-editor/external/ScopeGuard/CMakeLists.txt b/3rdparty/imgui-node-editor/external/ScopeGuard/CMakeLists.txt new file mode 100644 index 0000000..4464a8a --- /dev/null +++ b/3rdparty/imgui-node-editor/external/ScopeGuard/CMakeLists.txt @@ -0,0 +1,12 @@ +project(ScopeGuard) + +add_library(ScopeGuard INTERFACE) + +set(_ScopeGuard_Sources + ${CMAKE_CURRENT_SOURCE_DIR}/ScopeGuard.h +) + +target_include_directories(ScopeGuard INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) +target_sources(ScopeGuard INTERFACE ${_ScopeGuard_Sources}) + +source_group("ThirdParty\\ScopeGuard" FILES ${_ScopeGuard_Sources}) \ No newline at end of file diff --git a/3rdparty/imgui-node-editor/external/ScopeGuard/ScopeGuard.h b/3rdparty/imgui-node-editor/external/ScopeGuard/ScopeGuard.h new file mode 100644 index 0000000..b5b5f9d --- /dev/null +++ b/3rdparty/imgui-node-editor/external/ScopeGuard/ScopeGuard.h @@ -0,0 +1,42 @@ +# pragma once + +# include + +# define AX_CONCATENATE_IMPL(s1, s2) s1##s2 +# define AX_CONCATENATE(s1, s2) AX_CONCATENATE_IMPL(s1, s2) +# ifdef __COUNTER__ +# define AX_ANONYMOUS_VARIABLE(str) AX_CONCATENATE(str, __COUNTER__) +# else +# define AX_ANONYMOUS_VARIABLE(str) AX_CONCATENATE(str, __LINE__) +# endif + +namespace ax { +namespace scopeguard_detail { + +enum class ScopeGuardOnExit {}; +template +class ScopeGuard +{ + F f_; + bool active_; +public: + ScopeGuard() = delete; + ScopeGuard(const ScopeGuard&) = delete; + ScopeGuard& operator=(const ScopeGuard&) = delete; + ScopeGuard(ScopeGuard&& rhs): f_(std::move(rhs.f_)), active_(rhs.active_) { rhs.dismiss(); } + ScopeGuard(F f): f_(std::move(f)), active_(true) {} + ~ScopeGuard() { if (active_) f_(); } + void dismiss() { active_ = false; } +}; +template +inline ScopeGuard operator+(ScopeGuardOnExit, F&& f) +{ + return ScopeGuard(std::forward(f)); +} + +} // namespace scopeguard_detail +} // namespace ax + +# define AX_SCOPE_EXIT \ + auto AX_ANONYMOUS_VARIABLE(AX_SCOPE_EXIT_STATE) \ + = ::ax::scopeguard_detail::ScopeGuardOnExit() + [&]() diff --git a/3rdparty/imgui-node-editor/external/gl3w/CMakeLists.txt b/3rdparty/imgui-node-editor/external/gl3w/CMakeLists.txt new file mode 100644 index 0000000..848649b --- /dev/null +++ b/3rdparty/imgui-node-editor/external/gl3w/CMakeLists.txt @@ -0,0 +1,19 @@ + +set(_gl3w_Sources + Include/GL/gl3w.h + Include/GL/glcorearb.h + Source/gl3w.c +) + +source_group("" FILES ${_gl3w_Sources}) + +add_library(gl3w STATIC ${_gl3w_Sources}) + +target_include_directories(gl3w PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/Include) + +if (UNIX AND (NOT APPLE)) + # Linux: GL is required to pull glXGetProcAddress + target_link_libraries(gl3w PRIVATE GL dl) +endif() + +set_property(TARGET gl3w PROPERTY FOLDER "external") diff --git a/3rdparty/imgui-node-editor/external/gl3w/Include/GL/gl3w.h b/3rdparty/imgui-node-editor/external/gl3w/Include/GL/gl3w.h new file mode 100755 index 0000000..ee563f8 --- /dev/null +++ b/3rdparty/imgui-node-editor/external/gl3w/Include/GL/gl3w.h @@ -0,0 +1,1234 @@ +#ifndef __gl3w_h_ +#define __gl3w_h_ + +#include + +#ifndef __gl_h_ +#define __gl_h_ +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* gl3w api */ +int gl3wInit(void); +int gl3wIsSupported(int major, int minor); +void *gl3wGetProcAddress(const char *proc); + +/* OpenGL functions */ +extern PFNGLCULLFACEPROC gl3wCullFace; +extern PFNGLFRONTFACEPROC gl3wFrontFace; +extern PFNGLHINTPROC gl3wHint; +extern PFNGLLINEWIDTHPROC gl3wLineWidth; +extern PFNGLPOINTSIZEPROC gl3wPointSize; +extern PFNGLPOLYGONMODEPROC gl3wPolygonMode; +extern PFNGLSCISSORPROC gl3wScissor; +extern PFNGLTEXPARAMETERFPROC gl3wTexParameterf; +extern PFNGLTEXPARAMETERFVPROC gl3wTexParameterfv; +extern PFNGLTEXPARAMETERIPROC gl3wTexParameteri; +extern PFNGLTEXPARAMETERIVPROC gl3wTexParameteriv; +extern PFNGLTEXIMAGE1DPROC gl3wTexImage1D; +extern PFNGLTEXIMAGE2DPROC gl3wTexImage2D; +extern PFNGLDRAWBUFFERPROC gl3wDrawBuffer; +extern PFNGLCLEARPROC gl3wClear; +extern PFNGLCLEARCOLORPROC gl3wClearColor; +extern PFNGLCLEARSTENCILPROC gl3wClearStencil; +extern PFNGLCLEARDEPTHPROC gl3wClearDepth; +extern PFNGLSTENCILMASKPROC gl3wStencilMask; +extern PFNGLCOLORMASKPROC gl3wColorMask; +extern PFNGLDEPTHMASKPROC gl3wDepthMask; +extern PFNGLDISABLEPROC gl3wDisable; +extern PFNGLENABLEPROC gl3wEnable; +extern PFNGLFINISHPROC gl3wFinish; +extern PFNGLFLUSHPROC gl3wFlush; +extern PFNGLBLENDFUNCPROC gl3wBlendFunc; +extern PFNGLLOGICOPPROC gl3wLogicOp; +extern PFNGLSTENCILFUNCPROC gl3wStencilFunc; +extern PFNGLSTENCILOPPROC gl3wStencilOp; +extern PFNGLDEPTHFUNCPROC gl3wDepthFunc; +extern PFNGLPIXELSTOREFPROC gl3wPixelStoref; +extern PFNGLPIXELSTOREIPROC gl3wPixelStorei; +extern PFNGLREADBUFFERPROC gl3wReadBuffer; +extern PFNGLREADPIXELSPROC gl3wReadPixels; +extern PFNGLGETBOOLEANVPROC gl3wGetBooleanv; +extern PFNGLGETDOUBLEVPROC gl3wGetDoublev; +extern PFNGLGETERRORPROC gl3wGetError; +extern PFNGLGETFLOATVPROC gl3wGetFloatv; +extern PFNGLGETINTEGERVPROC gl3wGetIntegerv; +extern PFNGLGETSTRINGPROC gl3wGetString; +extern PFNGLGETTEXIMAGEPROC gl3wGetTexImage; +extern PFNGLGETTEXPARAMETERFVPROC gl3wGetTexParameterfv; +extern PFNGLGETTEXPARAMETERIVPROC gl3wGetTexParameteriv; +extern PFNGLGETTEXLEVELPARAMETERFVPROC gl3wGetTexLevelParameterfv; +extern PFNGLGETTEXLEVELPARAMETERIVPROC gl3wGetTexLevelParameteriv; +extern PFNGLISENABLEDPROC gl3wIsEnabled; +extern PFNGLDEPTHRANGEPROC gl3wDepthRange; +extern PFNGLVIEWPORTPROC gl3wViewport; +extern PFNGLDRAWARRAYSPROC gl3wDrawArrays; +extern PFNGLDRAWELEMENTSPROC gl3wDrawElements; +extern PFNGLGETPOINTERVPROC gl3wGetPointerv; +extern PFNGLPOLYGONOFFSETPROC gl3wPolygonOffset; +extern PFNGLCOPYTEXIMAGE1DPROC gl3wCopyTexImage1D; +extern PFNGLCOPYTEXIMAGE2DPROC gl3wCopyTexImage2D; +extern PFNGLCOPYTEXSUBIMAGE1DPROC gl3wCopyTexSubImage1D; +extern PFNGLCOPYTEXSUBIMAGE2DPROC gl3wCopyTexSubImage2D; +extern PFNGLTEXSUBIMAGE1DPROC gl3wTexSubImage1D; +extern PFNGLTEXSUBIMAGE2DPROC gl3wTexSubImage2D; +extern PFNGLBINDTEXTUREPROC gl3wBindTexture; +extern PFNGLDELETETEXTURESPROC gl3wDeleteTextures; +extern PFNGLGENTEXTURESPROC gl3wGenTextures; +extern PFNGLISTEXTUREPROC gl3wIsTexture; +extern PFNGLBLENDCOLORPROC gl3wBlendColor; +extern PFNGLBLENDEQUATIONPROC gl3wBlendEquation; +extern PFNGLDRAWRANGEELEMENTSPROC gl3wDrawRangeElements; +extern PFNGLTEXIMAGE3DPROC gl3wTexImage3D; +extern PFNGLTEXSUBIMAGE3DPROC gl3wTexSubImage3D; +extern PFNGLCOPYTEXSUBIMAGE3DPROC gl3wCopyTexSubImage3D; +extern PFNGLACTIVETEXTUREPROC gl3wActiveTexture; +extern PFNGLSAMPLECOVERAGEPROC gl3wSampleCoverage; +extern PFNGLCOMPRESSEDTEXIMAGE3DPROC gl3wCompressedTexImage3D; +extern PFNGLCOMPRESSEDTEXIMAGE2DPROC gl3wCompressedTexImage2D; +extern PFNGLCOMPRESSEDTEXIMAGE1DPROC gl3wCompressedTexImage1D; +extern PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC gl3wCompressedTexSubImage3D; +extern PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC gl3wCompressedTexSubImage2D; +extern PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC gl3wCompressedTexSubImage1D; +extern PFNGLGETCOMPRESSEDTEXIMAGEPROC gl3wGetCompressedTexImage; +extern PFNGLBLENDFUNCSEPARATEPROC gl3wBlendFuncSeparate; +extern PFNGLMULTIDRAWARRAYSPROC gl3wMultiDrawArrays; +extern PFNGLMULTIDRAWELEMENTSPROC gl3wMultiDrawElements; +extern PFNGLPOINTPARAMETERFPROC gl3wPointParameterf; +extern PFNGLPOINTPARAMETERFVPROC gl3wPointParameterfv; +extern PFNGLPOINTPARAMETERIPROC gl3wPointParameteri; +extern PFNGLPOINTPARAMETERIVPROC gl3wPointParameteriv; +extern PFNGLGENQUERIESPROC gl3wGenQueries; +extern PFNGLDELETEQUERIESPROC gl3wDeleteQueries; +extern PFNGLISQUERYPROC gl3wIsQuery; +extern PFNGLBEGINQUERYPROC gl3wBeginQuery; +extern PFNGLENDQUERYPROC gl3wEndQuery; +extern PFNGLGETQUERYIVPROC gl3wGetQueryiv; +extern PFNGLGETQUERYOBJECTIVPROC gl3wGetQueryObjectiv; +extern PFNGLGETQUERYOBJECTUIVPROC gl3wGetQueryObjectuiv; +extern PFNGLBINDBUFFERPROC gl3wBindBuffer; +extern PFNGLDELETEBUFFERSPROC gl3wDeleteBuffers; +extern PFNGLGENBUFFERSPROC gl3wGenBuffers; +extern PFNGLISBUFFERPROC gl3wIsBuffer; +extern PFNGLBUFFERDATAPROC gl3wBufferData; +extern PFNGLBUFFERSUBDATAPROC gl3wBufferSubData; +extern PFNGLGETBUFFERSUBDATAPROC gl3wGetBufferSubData; +extern PFNGLMAPBUFFERPROC gl3wMapBuffer; +extern PFNGLUNMAPBUFFERPROC gl3wUnmapBuffer; +extern PFNGLGETBUFFERPARAMETERIVPROC gl3wGetBufferParameteriv; +extern PFNGLGETBUFFERPOINTERVPROC gl3wGetBufferPointerv; +extern PFNGLBLENDEQUATIONSEPARATEPROC gl3wBlendEquationSeparate; +extern PFNGLDRAWBUFFERSPROC gl3wDrawBuffers; +extern PFNGLSTENCILOPSEPARATEPROC gl3wStencilOpSeparate; +extern PFNGLSTENCILFUNCSEPARATEPROC gl3wStencilFuncSeparate; +extern PFNGLSTENCILMASKSEPARATEPROC gl3wStencilMaskSeparate; +extern PFNGLATTACHSHADERPROC gl3wAttachShader; +extern PFNGLBINDATTRIBLOCATIONPROC gl3wBindAttribLocation; +extern PFNGLCOMPILESHADERPROC gl3wCompileShader; +extern PFNGLCREATEPROGRAMPROC gl3wCreateProgram; +extern PFNGLCREATESHADERPROC gl3wCreateShader; +extern PFNGLDELETEPROGRAMPROC gl3wDeleteProgram; +extern PFNGLDELETESHADERPROC gl3wDeleteShader; +extern PFNGLDETACHSHADERPROC gl3wDetachShader; +extern PFNGLDISABLEVERTEXATTRIBARRAYPROC gl3wDisableVertexAttribArray; +extern PFNGLENABLEVERTEXATTRIBARRAYPROC gl3wEnableVertexAttribArray; +extern PFNGLGETACTIVEATTRIBPROC gl3wGetActiveAttrib; +extern PFNGLGETACTIVEUNIFORMPROC gl3wGetActiveUniform; +extern PFNGLGETATTACHEDSHADERSPROC gl3wGetAttachedShaders; +extern PFNGLGETATTRIBLOCATIONPROC gl3wGetAttribLocation; +extern PFNGLGETPROGRAMIVPROC gl3wGetProgramiv; +extern PFNGLGETPROGRAMINFOLOGPROC gl3wGetProgramInfoLog; +extern PFNGLGETSHADERIVPROC gl3wGetShaderiv; +extern PFNGLGETSHADERINFOLOGPROC gl3wGetShaderInfoLog; +extern PFNGLGETSHADERSOURCEPROC gl3wGetShaderSource; +extern PFNGLGETUNIFORMLOCATIONPROC gl3wGetUniformLocation; +extern PFNGLGETUNIFORMFVPROC gl3wGetUniformfv; +extern PFNGLGETUNIFORMIVPROC gl3wGetUniformiv; +extern PFNGLGETVERTEXATTRIBDVPROC gl3wGetVertexAttribdv; +extern PFNGLGETVERTEXATTRIBFVPROC gl3wGetVertexAttribfv; +extern PFNGLGETVERTEXATTRIBIVPROC gl3wGetVertexAttribiv; +extern PFNGLGETVERTEXATTRIBPOINTERVPROC gl3wGetVertexAttribPointerv; +extern PFNGLISPROGRAMPROC gl3wIsProgram; +extern PFNGLISSHADERPROC gl3wIsShader; +extern PFNGLLINKPROGRAMPROC gl3wLinkProgram; +extern PFNGLSHADERSOURCEPROC gl3wShaderSource; +extern PFNGLUSEPROGRAMPROC gl3wUseProgram; +extern PFNGLUNIFORM1FPROC gl3wUniform1f; +extern PFNGLUNIFORM2FPROC gl3wUniform2f; +extern PFNGLUNIFORM3FPROC gl3wUniform3f; +extern PFNGLUNIFORM4FPROC gl3wUniform4f; +extern PFNGLUNIFORM1IPROC gl3wUniform1i; +extern PFNGLUNIFORM2IPROC gl3wUniform2i; +extern PFNGLUNIFORM3IPROC gl3wUniform3i; +extern PFNGLUNIFORM4IPROC gl3wUniform4i; +extern PFNGLUNIFORM1FVPROC gl3wUniform1fv; +extern PFNGLUNIFORM2FVPROC gl3wUniform2fv; +extern PFNGLUNIFORM3FVPROC gl3wUniform3fv; +extern PFNGLUNIFORM4FVPROC gl3wUniform4fv; +extern PFNGLUNIFORM1IVPROC gl3wUniform1iv; +extern PFNGLUNIFORM2IVPROC gl3wUniform2iv; +extern PFNGLUNIFORM3IVPROC gl3wUniform3iv; +extern PFNGLUNIFORM4IVPROC gl3wUniform4iv; +extern PFNGLUNIFORMMATRIX2FVPROC gl3wUniformMatrix2fv; +extern PFNGLUNIFORMMATRIX3FVPROC gl3wUniformMatrix3fv; +extern PFNGLUNIFORMMATRIX4FVPROC gl3wUniformMatrix4fv; +extern PFNGLVALIDATEPROGRAMPROC gl3wValidateProgram; +extern PFNGLVERTEXATTRIB1DPROC gl3wVertexAttrib1d; +extern PFNGLVERTEXATTRIB1DVPROC gl3wVertexAttrib1dv; +extern PFNGLVERTEXATTRIB1FPROC gl3wVertexAttrib1f; +extern PFNGLVERTEXATTRIB1FVPROC gl3wVertexAttrib1fv; +extern PFNGLVERTEXATTRIB1SPROC gl3wVertexAttrib1s; +extern PFNGLVERTEXATTRIB1SVPROC gl3wVertexAttrib1sv; +extern PFNGLVERTEXATTRIB2DPROC gl3wVertexAttrib2d; +extern PFNGLVERTEXATTRIB2DVPROC gl3wVertexAttrib2dv; +extern PFNGLVERTEXATTRIB2FPROC gl3wVertexAttrib2f; +extern PFNGLVERTEXATTRIB2FVPROC gl3wVertexAttrib2fv; +extern PFNGLVERTEXATTRIB2SPROC gl3wVertexAttrib2s; +extern PFNGLVERTEXATTRIB2SVPROC gl3wVertexAttrib2sv; +extern PFNGLVERTEXATTRIB3DPROC gl3wVertexAttrib3d; +extern PFNGLVERTEXATTRIB3DVPROC gl3wVertexAttrib3dv; +extern PFNGLVERTEXATTRIB3FPROC gl3wVertexAttrib3f; +extern PFNGLVERTEXATTRIB3FVPROC gl3wVertexAttrib3fv; +extern PFNGLVERTEXATTRIB3SPROC gl3wVertexAttrib3s; +extern PFNGLVERTEXATTRIB3SVPROC gl3wVertexAttrib3sv; +extern PFNGLVERTEXATTRIB4NBVPROC gl3wVertexAttrib4Nbv; +extern PFNGLVERTEXATTRIB4NIVPROC gl3wVertexAttrib4Niv; +extern PFNGLVERTEXATTRIB4NSVPROC gl3wVertexAttrib4Nsv; +extern PFNGLVERTEXATTRIB4NUBPROC gl3wVertexAttrib4Nub; +extern PFNGLVERTEXATTRIB4NUBVPROC gl3wVertexAttrib4Nubv; +extern PFNGLVERTEXATTRIB4NUIVPROC gl3wVertexAttrib4Nuiv; +extern PFNGLVERTEXATTRIB4NUSVPROC gl3wVertexAttrib4Nusv; +extern PFNGLVERTEXATTRIB4BVPROC gl3wVertexAttrib4bv; +extern PFNGLVERTEXATTRIB4DPROC gl3wVertexAttrib4d; +extern PFNGLVERTEXATTRIB4DVPROC gl3wVertexAttrib4dv; +extern PFNGLVERTEXATTRIB4FPROC gl3wVertexAttrib4f; +extern PFNGLVERTEXATTRIB4FVPROC gl3wVertexAttrib4fv; +extern PFNGLVERTEXATTRIB4IVPROC gl3wVertexAttrib4iv; +extern PFNGLVERTEXATTRIB4SPROC gl3wVertexAttrib4s; +extern PFNGLVERTEXATTRIB4SVPROC gl3wVertexAttrib4sv; +extern PFNGLVERTEXATTRIB4UBVPROC gl3wVertexAttrib4ubv; +extern PFNGLVERTEXATTRIB4UIVPROC gl3wVertexAttrib4uiv; +extern PFNGLVERTEXATTRIB4USVPROC gl3wVertexAttrib4usv; +extern PFNGLVERTEXATTRIBPOINTERPROC gl3wVertexAttribPointer; +extern PFNGLUNIFORMMATRIX2X3FVPROC gl3wUniformMatrix2x3fv; +extern PFNGLUNIFORMMATRIX3X2FVPROC gl3wUniformMatrix3x2fv; +extern PFNGLUNIFORMMATRIX2X4FVPROC gl3wUniformMatrix2x4fv; +extern PFNGLUNIFORMMATRIX4X2FVPROC gl3wUniformMatrix4x2fv; +extern PFNGLUNIFORMMATRIX3X4FVPROC gl3wUniformMatrix3x4fv; +extern PFNGLUNIFORMMATRIX4X3FVPROC gl3wUniformMatrix4x3fv; +extern PFNGLCOLORMASKIPROC gl3wColorMaski; +extern PFNGLGETBOOLEANI_VPROC gl3wGetBooleani_v; +extern PFNGLGETINTEGERI_VPROC gl3wGetIntegeri_v; +extern PFNGLENABLEIPROC gl3wEnablei; +extern PFNGLDISABLEIPROC gl3wDisablei; +extern PFNGLISENABLEDIPROC gl3wIsEnabledi; +extern PFNGLBEGINTRANSFORMFEEDBACKPROC gl3wBeginTransformFeedback; +extern PFNGLENDTRANSFORMFEEDBACKPROC gl3wEndTransformFeedback; +extern PFNGLBINDBUFFERRANGEPROC gl3wBindBufferRange; +extern PFNGLBINDBUFFERBASEPROC gl3wBindBufferBase; +extern PFNGLTRANSFORMFEEDBACKVARYINGSPROC gl3wTransformFeedbackVaryings; +extern PFNGLGETTRANSFORMFEEDBACKVARYINGPROC gl3wGetTransformFeedbackVarying; +extern PFNGLCLAMPCOLORPROC gl3wClampColor; +extern PFNGLBEGINCONDITIONALRENDERPROC gl3wBeginConditionalRender; +extern PFNGLENDCONDITIONALRENDERPROC gl3wEndConditionalRender; +extern PFNGLVERTEXATTRIBIPOINTERPROC gl3wVertexAttribIPointer; +extern PFNGLGETVERTEXATTRIBIIVPROC gl3wGetVertexAttribIiv; +extern PFNGLGETVERTEXATTRIBIUIVPROC gl3wGetVertexAttribIuiv; +extern PFNGLVERTEXATTRIBI1IPROC gl3wVertexAttribI1i; +extern PFNGLVERTEXATTRIBI2IPROC gl3wVertexAttribI2i; +extern PFNGLVERTEXATTRIBI3IPROC gl3wVertexAttribI3i; +extern PFNGLVERTEXATTRIBI4IPROC gl3wVertexAttribI4i; +extern PFNGLVERTEXATTRIBI1UIPROC gl3wVertexAttribI1ui; +extern PFNGLVERTEXATTRIBI2UIPROC gl3wVertexAttribI2ui; +extern PFNGLVERTEXATTRIBI3UIPROC gl3wVertexAttribI3ui; +extern PFNGLVERTEXATTRIBI4UIPROC gl3wVertexAttribI4ui; +extern PFNGLVERTEXATTRIBI1IVPROC gl3wVertexAttribI1iv; +extern PFNGLVERTEXATTRIBI2IVPROC gl3wVertexAttribI2iv; +extern PFNGLVERTEXATTRIBI3IVPROC gl3wVertexAttribI3iv; +extern PFNGLVERTEXATTRIBI4IVPROC gl3wVertexAttribI4iv; +extern PFNGLVERTEXATTRIBI1UIVPROC gl3wVertexAttribI1uiv; +extern PFNGLVERTEXATTRIBI2UIVPROC gl3wVertexAttribI2uiv; +extern PFNGLVERTEXATTRIBI3UIVPROC gl3wVertexAttribI3uiv; +extern PFNGLVERTEXATTRIBI4UIVPROC gl3wVertexAttribI4uiv; +extern PFNGLVERTEXATTRIBI4BVPROC gl3wVertexAttribI4bv; +extern PFNGLVERTEXATTRIBI4SVPROC gl3wVertexAttribI4sv; +extern PFNGLVERTEXATTRIBI4UBVPROC gl3wVertexAttribI4ubv; +extern PFNGLVERTEXATTRIBI4USVPROC gl3wVertexAttribI4usv; +extern PFNGLGETUNIFORMUIVPROC gl3wGetUniformuiv; +extern PFNGLBINDFRAGDATALOCATIONPROC gl3wBindFragDataLocation; +extern PFNGLGETFRAGDATALOCATIONPROC gl3wGetFragDataLocation; +extern PFNGLUNIFORM1UIPROC gl3wUniform1ui; +extern PFNGLUNIFORM2UIPROC gl3wUniform2ui; +extern PFNGLUNIFORM3UIPROC gl3wUniform3ui; +extern PFNGLUNIFORM4UIPROC gl3wUniform4ui; +extern PFNGLUNIFORM1UIVPROC gl3wUniform1uiv; +extern PFNGLUNIFORM2UIVPROC gl3wUniform2uiv; +extern PFNGLUNIFORM3UIVPROC gl3wUniform3uiv; +extern PFNGLUNIFORM4UIVPROC gl3wUniform4uiv; +extern PFNGLTEXPARAMETERIIVPROC gl3wTexParameterIiv; +extern PFNGLTEXPARAMETERIUIVPROC gl3wTexParameterIuiv; +extern PFNGLGETTEXPARAMETERIIVPROC gl3wGetTexParameterIiv; +extern PFNGLGETTEXPARAMETERIUIVPROC gl3wGetTexParameterIuiv; +extern PFNGLCLEARBUFFERIVPROC gl3wClearBufferiv; +extern PFNGLCLEARBUFFERUIVPROC gl3wClearBufferuiv; +extern PFNGLCLEARBUFFERFVPROC gl3wClearBufferfv; +extern PFNGLCLEARBUFFERFIPROC gl3wClearBufferfi; +extern PFNGLGETSTRINGIPROC gl3wGetStringi; +extern PFNGLDRAWARRAYSINSTANCEDPROC gl3wDrawArraysInstanced; +extern PFNGLDRAWELEMENTSINSTANCEDPROC gl3wDrawElementsInstanced; +extern PFNGLTEXBUFFERPROC gl3wTexBuffer; +extern PFNGLPRIMITIVERESTARTINDEXPROC gl3wPrimitiveRestartIndex; +extern PFNGLGETINTEGER64I_VPROC gl3wGetInteger64i_v; +extern PFNGLGETBUFFERPARAMETERI64VPROC gl3wGetBufferParameteri64v; +extern PFNGLFRAMEBUFFERTEXTUREPROC gl3wFramebufferTexture; +extern PFNGLVERTEXATTRIBDIVISORPROC gl3wVertexAttribDivisor; +extern PFNGLMINSAMPLESHADINGPROC gl3wMinSampleShading; +extern PFNGLBLENDEQUATIONIPROC gl3wBlendEquationi; +extern PFNGLBLENDEQUATIONSEPARATEIPROC gl3wBlendEquationSeparatei; +extern PFNGLBLENDFUNCIPROC gl3wBlendFunci; +extern PFNGLBLENDFUNCSEPARATEIPROC gl3wBlendFuncSeparatei; +extern PFNGLISRENDERBUFFERPROC gl3wIsRenderbuffer; +extern PFNGLBINDRENDERBUFFERPROC gl3wBindRenderbuffer; +extern PFNGLDELETERENDERBUFFERSPROC gl3wDeleteRenderbuffers; +extern PFNGLGENRENDERBUFFERSPROC gl3wGenRenderbuffers; +extern PFNGLRENDERBUFFERSTORAGEPROC gl3wRenderbufferStorage; +extern PFNGLGETRENDERBUFFERPARAMETERIVPROC gl3wGetRenderbufferParameteriv; +extern PFNGLISFRAMEBUFFERPROC gl3wIsFramebuffer; +extern PFNGLBINDFRAMEBUFFERPROC gl3wBindFramebuffer; +extern PFNGLDELETEFRAMEBUFFERSPROC gl3wDeleteFramebuffers; +extern PFNGLGENFRAMEBUFFERSPROC gl3wGenFramebuffers; +extern PFNGLCHECKFRAMEBUFFERSTATUSPROC gl3wCheckFramebufferStatus; +extern PFNGLFRAMEBUFFERTEXTURE1DPROC gl3wFramebufferTexture1D; +extern PFNGLFRAMEBUFFERTEXTURE2DPROC gl3wFramebufferTexture2D; +extern PFNGLFRAMEBUFFERTEXTURE3DPROC gl3wFramebufferTexture3D; +extern PFNGLFRAMEBUFFERRENDERBUFFERPROC gl3wFramebufferRenderbuffer; +extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC gl3wGetFramebufferAttachmentParameteriv; +extern PFNGLGENERATEMIPMAPPROC gl3wGenerateMipmap; +extern PFNGLBLITFRAMEBUFFERPROC gl3wBlitFramebuffer; +extern PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC gl3wRenderbufferStorageMultisample; +extern PFNGLFRAMEBUFFERTEXTURELAYERPROC gl3wFramebufferTextureLayer; +extern PFNGLMAPBUFFERRANGEPROC gl3wMapBufferRange; +extern PFNGLFLUSHMAPPEDBUFFERRANGEPROC gl3wFlushMappedBufferRange; +extern PFNGLBINDVERTEXARRAYPROC gl3wBindVertexArray; +extern PFNGLDELETEVERTEXARRAYSPROC gl3wDeleteVertexArrays; +extern PFNGLGENVERTEXARRAYSPROC gl3wGenVertexArrays; +extern PFNGLISVERTEXARRAYPROC gl3wIsVertexArray; +extern PFNGLGETUNIFORMINDICESPROC gl3wGetUniformIndices; +extern PFNGLGETACTIVEUNIFORMSIVPROC gl3wGetActiveUniformsiv; +extern PFNGLGETACTIVEUNIFORMNAMEPROC gl3wGetActiveUniformName; +extern PFNGLGETUNIFORMBLOCKINDEXPROC gl3wGetUniformBlockIndex; +extern PFNGLGETACTIVEUNIFORMBLOCKIVPROC gl3wGetActiveUniformBlockiv; +extern PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC gl3wGetActiveUniformBlockName; +extern PFNGLUNIFORMBLOCKBINDINGPROC gl3wUniformBlockBinding; +extern PFNGLCOPYBUFFERSUBDATAPROC gl3wCopyBufferSubData; +extern PFNGLDRAWELEMENTSBASEVERTEXPROC gl3wDrawElementsBaseVertex; +extern PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC gl3wDrawRangeElementsBaseVertex; +extern PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC gl3wDrawElementsInstancedBaseVertex; +extern PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC gl3wMultiDrawElementsBaseVertex; +extern PFNGLPROVOKINGVERTEXPROC gl3wProvokingVertex; +extern PFNGLFENCESYNCPROC gl3wFenceSync; +extern PFNGLISSYNCPROC gl3wIsSync; +extern PFNGLDELETESYNCPROC gl3wDeleteSync; +extern PFNGLCLIENTWAITSYNCPROC gl3wClientWaitSync; +extern PFNGLWAITSYNCPROC gl3wWaitSync; +extern PFNGLGETINTEGER64VPROC gl3wGetInteger64v; +extern PFNGLGETSYNCIVPROC gl3wGetSynciv; +extern PFNGLTEXIMAGE2DMULTISAMPLEPROC gl3wTexImage2DMultisample; +extern PFNGLTEXIMAGE3DMULTISAMPLEPROC gl3wTexImage3DMultisample; +extern PFNGLGETMULTISAMPLEFVPROC gl3wGetMultisamplefv; +extern PFNGLSAMPLEMASKIPROC gl3wSampleMaski; +extern PFNGLBLENDEQUATIONIARBPROC gl3wBlendEquationiARB; +extern PFNGLBLENDEQUATIONSEPARATEIARBPROC gl3wBlendEquationSeparateiARB; +extern PFNGLBLENDFUNCIARBPROC gl3wBlendFunciARB; +extern PFNGLBLENDFUNCSEPARATEIARBPROC gl3wBlendFuncSeparateiARB; +extern PFNGLMINSAMPLESHADINGARBPROC gl3wMinSampleShadingARB; +extern PFNGLNAMEDSTRINGARBPROC gl3wNamedStringARB; +extern PFNGLDELETENAMEDSTRINGARBPROC gl3wDeleteNamedStringARB; +extern PFNGLCOMPILESHADERINCLUDEARBPROC gl3wCompileShaderIncludeARB; +extern PFNGLISNAMEDSTRINGARBPROC gl3wIsNamedStringARB; +extern PFNGLGETNAMEDSTRINGARBPROC gl3wGetNamedStringARB; +extern PFNGLGETNAMEDSTRINGIVARBPROC gl3wGetNamedStringivARB; +extern PFNGLBINDFRAGDATALOCATIONINDEXEDPROC gl3wBindFragDataLocationIndexed; +extern PFNGLGETFRAGDATAINDEXPROC gl3wGetFragDataIndex; +extern PFNGLGENSAMPLERSPROC gl3wGenSamplers; +extern PFNGLDELETESAMPLERSPROC gl3wDeleteSamplers; +extern PFNGLISSAMPLERPROC gl3wIsSampler; +extern PFNGLBINDSAMPLERPROC gl3wBindSampler; +extern PFNGLSAMPLERPARAMETERIPROC gl3wSamplerParameteri; +extern PFNGLSAMPLERPARAMETERIVPROC gl3wSamplerParameteriv; +extern PFNGLSAMPLERPARAMETERFPROC gl3wSamplerParameterf; +extern PFNGLSAMPLERPARAMETERFVPROC gl3wSamplerParameterfv; +extern PFNGLSAMPLERPARAMETERIIVPROC gl3wSamplerParameterIiv; +extern PFNGLSAMPLERPARAMETERIUIVPROC gl3wSamplerParameterIuiv; +extern PFNGLGETSAMPLERPARAMETERIVPROC gl3wGetSamplerParameteriv; +extern PFNGLGETSAMPLERPARAMETERIIVPROC gl3wGetSamplerParameterIiv; +extern PFNGLGETSAMPLERPARAMETERFVPROC gl3wGetSamplerParameterfv; +extern PFNGLGETSAMPLERPARAMETERIUIVPROC gl3wGetSamplerParameterIuiv; +extern PFNGLQUERYCOUNTERPROC gl3wQueryCounter; +extern PFNGLGETQUERYOBJECTI64VPROC gl3wGetQueryObjecti64v; +extern PFNGLGETQUERYOBJECTUI64VPROC gl3wGetQueryObjectui64v; +extern PFNGLVERTEXP2UIPROC gl3wVertexP2ui; +extern PFNGLVERTEXP2UIVPROC gl3wVertexP2uiv; +extern PFNGLVERTEXP3UIPROC gl3wVertexP3ui; +extern PFNGLVERTEXP3UIVPROC gl3wVertexP3uiv; +extern PFNGLVERTEXP4UIPROC gl3wVertexP4ui; +extern PFNGLVERTEXP4UIVPROC gl3wVertexP4uiv; +extern PFNGLTEXCOORDP1UIPROC gl3wTexCoordP1ui; +extern PFNGLTEXCOORDP1UIVPROC gl3wTexCoordP1uiv; +extern PFNGLTEXCOORDP2UIPROC gl3wTexCoordP2ui; +extern PFNGLTEXCOORDP2UIVPROC gl3wTexCoordP2uiv; +extern PFNGLTEXCOORDP3UIPROC gl3wTexCoordP3ui; +extern PFNGLTEXCOORDP3UIVPROC gl3wTexCoordP3uiv; +extern PFNGLTEXCOORDP4UIPROC gl3wTexCoordP4ui; +extern PFNGLTEXCOORDP4UIVPROC gl3wTexCoordP4uiv; +extern PFNGLMULTITEXCOORDP1UIPROC gl3wMultiTexCoordP1ui; +extern PFNGLMULTITEXCOORDP1UIVPROC gl3wMultiTexCoordP1uiv; +extern PFNGLMULTITEXCOORDP2UIPROC gl3wMultiTexCoordP2ui; +extern PFNGLMULTITEXCOORDP2UIVPROC gl3wMultiTexCoordP2uiv; +extern PFNGLMULTITEXCOORDP3UIPROC gl3wMultiTexCoordP3ui; +extern PFNGLMULTITEXCOORDP3UIVPROC gl3wMultiTexCoordP3uiv; +extern PFNGLMULTITEXCOORDP4UIPROC gl3wMultiTexCoordP4ui; +extern PFNGLMULTITEXCOORDP4UIVPROC gl3wMultiTexCoordP4uiv; +extern PFNGLNORMALP3UIPROC gl3wNormalP3ui; +extern PFNGLNORMALP3UIVPROC gl3wNormalP3uiv; +extern PFNGLCOLORP3UIPROC gl3wColorP3ui; +extern PFNGLCOLORP3UIVPROC gl3wColorP3uiv; +extern PFNGLCOLORP4UIPROC gl3wColorP4ui; +extern PFNGLCOLORP4UIVPROC gl3wColorP4uiv; +extern PFNGLSECONDARYCOLORP3UIPROC gl3wSecondaryColorP3ui; +extern PFNGLSECONDARYCOLORP3UIVPROC gl3wSecondaryColorP3uiv; +extern PFNGLVERTEXATTRIBP1UIPROC gl3wVertexAttribP1ui; +extern PFNGLVERTEXATTRIBP1UIVPROC gl3wVertexAttribP1uiv; +extern PFNGLVERTEXATTRIBP2UIPROC gl3wVertexAttribP2ui; +extern PFNGLVERTEXATTRIBP2UIVPROC gl3wVertexAttribP2uiv; +extern PFNGLVERTEXATTRIBP3UIPROC gl3wVertexAttribP3ui; +extern PFNGLVERTEXATTRIBP3UIVPROC gl3wVertexAttribP3uiv; +extern PFNGLVERTEXATTRIBP4UIPROC gl3wVertexAttribP4ui; +extern PFNGLVERTEXATTRIBP4UIVPROC gl3wVertexAttribP4uiv; +extern PFNGLDRAWARRAYSINDIRECTPROC gl3wDrawArraysIndirect; +extern PFNGLDRAWELEMENTSINDIRECTPROC gl3wDrawElementsIndirect; +extern PFNGLUNIFORM1DPROC gl3wUniform1d; +extern PFNGLUNIFORM2DPROC gl3wUniform2d; +extern PFNGLUNIFORM3DPROC gl3wUniform3d; +extern PFNGLUNIFORM4DPROC gl3wUniform4d; +extern PFNGLUNIFORM1DVPROC gl3wUniform1dv; +extern PFNGLUNIFORM2DVPROC gl3wUniform2dv; +extern PFNGLUNIFORM3DVPROC gl3wUniform3dv; +extern PFNGLUNIFORM4DVPROC gl3wUniform4dv; +extern PFNGLUNIFORMMATRIX2DVPROC gl3wUniformMatrix2dv; +extern PFNGLUNIFORMMATRIX3DVPROC gl3wUniformMatrix3dv; +extern PFNGLUNIFORMMATRIX4DVPROC gl3wUniformMatrix4dv; +extern PFNGLUNIFORMMATRIX2X3DVPROC gl3wUniformMatrix2x3dv; +extern PFNGLUNIFORMMATRIX2X4DVPROC gl3wUniformMatrix2x4dv; +extern PFNGLUNIFORMMATRIX3X2DVPROC gl3wUniformMatrix3x2dv; +extern PFNGLUNIFORMMATRIX3X4DVPROC gl3wUniformMatrix3x4dv; +extern PFNGLUNIFORMMATRIX4X2DVPROC gl3wUniformMatrix4x2dv; +extern PFNGLUNIFORMMATRIX4X3DVPROC gl3wUniformMatrix4x3dv; +extern PFNGLGETUNIFORMDVPROC gl3wGetUniformdv; +extern PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC gl3wGetSubroutineUniformLocation; +extern PFNGLGETSUBROUTINEINDEXPROC gl3wGetSubroutineIndex; +extern PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC gl3wGetActiveSubroutineUniformiv; +extern PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC gl3wGetActiveSubroutineUniformName; +extern PFNGLGETACTIVESUBROUTINENAMEPROC gl3wGetActiveSubroutineName; +extern PFNGLUNIFORMSUBROUTINESUIVPROC gl3wUniformSubroutinesuiv; +extern PFNGLGETUNIFORMSUBROUTINEUIVPROC gl3wGetUniformSubroutineuiv; +extern PFNGLGETPROGRAMSTAGEIVPROC gl3wGetProgramStageiv; +extern PFNGLPATCHPARAMETERIPROC gl3wPatchParameteri; +extern PFNGLPATCHPARAMETERFVPROC gl3wPatchParameterfv; +extern PFNGLBINDTRANSFORMFEEDBACKPROC gl3wBindTransformFeedback; +extern PFNGLDELETETRANSFORMFEEDBACKSPROC gl3wDeleteTransformFeedbacks; +extern PFNGLGENTRANSFORMFEEDBACKSPROC gl3wGenTransformFeedbacks; +extern PFNGLISTRANSFORMFEEDBACKPROC gl3wIsTransformFeedback; +extern PFNGLPAUSETRANSFORMFEEDBACKPROC gl3wPauseTransformFeedback; +extern PFNGLRESUMETRANSFORMFEEDBACKPROC gl3wResumeTransformFeedback; +extern PFNGLDRAWTRANSFORMFEEDBACKPROC gl3wDrawTransformFeedback; +extern PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC gl3wDrawTransformFeedbackStream; +extern PFNGLBEGINQUERYINDEXEDPROC gl3wBeginQueryIndexed; +extern PFNGLENDQUERYINDEXEDPROC gl3wEndQueryIndexed; +extern PFNGLGETQUERYINDEXEDIVPROC gl3wGetQueryIndexediv; +extern PFNGLRELEASESHADERCOMPILERPROC gl3wReleaseShaderCompiler; +extern PFNGLSHADERBINARYPROC gl3wShaderBinary; +extern PFNGLGETSHADERPRECISIONFORMATPROC gl3wGetShaderPrecisionFormat; +extern PFNGLDEPTHRANGEFPROC gl3wDepthRangef; +extern PFNGLCLEARDEPTHFPROC gl3wClearDepthf; +extern PFNGLGETPROGRAMBINARYPROC gl3wGetProgramBinary; +extern PFNGLPROGRAMBINARYPROC gl3wProgramBinary; +extern PFNGLPROGRAMPARAMETERIPROC gl3wProgramParameteri; +extern PFNGLUSEPROGRAMSTAGESPROC gl3wUseProgramStages; +extern PFNGLACTIVESHADERPROGRAMPROC gl3wActiveShaderProgram; +extern PFNGLCREATESHADERPROGRAMVPROC gl3wCreateShaderProgramv; +extern PFNGLBINDPROGRAMPIPELINEPROC gl3wBindProgramPipeline; +extern PFNGLDELETEPROGRAMPIPELINESPROC gl3wDeleteProgramPipelines; +extern PFNGLGENPROGRAMPIPELINESPROC gl3wGenProgramPipelines; +extern PFNGLISPROGRAMPIPELINEPROC gl3wIsProgramPipeline; +extern PFNGLGETPROGRAMPIPELINEIVPROC gl3wGetProgramPipelineiv; +extern PFNGLPROGRAMUNIFORM1IPROC gl3wProgramUniform1i; +extern PFNGLPROGRAMUNIFORM1IVPROC gl3wProgramUniform1iv; +extern PFNGLPROGRAMUNIFORM1FPROC gl3wProgramUniform1f; +extern PFNGLPROGRAMUNIFORM1FVPROC gl3wProgramUniform1fv; +extern PFNGLPROGRAMUNIFORM1DPROC gl3wProgramUniform1d; +extern PFNGLPROGRAMUNIFORM1DVPROC gl3wProgramUniform1dv; +extern PFNGLPROGRAMUNIFORM1UIPROC gl3wProgramUniform1ui; +extern PFNGLPROGRAMUNIFORM1UIVPROC gl3wProgramUniform1uiv; +extern PFNGLPROGRAMUNIFORM2IPROC gl3wProgramUniform2i; +extern PFNGLPROGRAMUNIFORM2IVPROC gl3wProgramUniform2iv; +extern PFNGLPROGRAMUNIFORM2FPROC gl3wProgramUniform2f; +extern PFNGLPROGRAMUNIFORM2FVPROC gl3wProgramUniform2fv; +extern PFNGLPROGRAMUNIFORM2DPROC gl3wProgramUniform2d; +extern PFNGLPROGRAMUNIFORM2DVPROC gl3wProgramUniform2dv; +extern PFNGLPROGRAMUNIFORM2UIPROC gl3wProgramUniform2ui; +extern PFNGLPROGRAMUNIFORM2UIVPROC gl3wProgramUniform2uiv; +extern PFNGLPROGRAMUNIFORM3IPROC gl3wProgramUniform3i; +extern PFNGLPROGRAMUNIFORM3IVPROC gl3wProgramUniform3iv; +extern PFNGLPROGRAMUNIFORM3FPROC gl3wProgramUniform3f; +extern PFNGLPROGRAMUNIFORM3FVPROC gl3wProgramUniform3fv; +extern PFNGLPROGRAMUNIFORM3DPROC gl3wProgramUniform3d; +extern PFNGLPROGRAMUNIFORM3DVPROC gl3wProgramUniform3dv; +extern PFNGLPROGRAMUNIFORM3UIPROC gl3wProgramUniform3ui; +extern PFNGLPROGRAMUNIFORM3UIVPROC gl3wProgramUniform3uiv; +extern PFNGLPROGRAMUNIFORM4IPROC gl3wProgramUniform4i; +extern PFNGLPROGRAMUNIFORM4IVPROC gl3wProgramUniform4iv; +extern PFNGLPROGRAMUNIFORM4FPROC gl3wProgramUniform4f; +extern PFNGLPROGRAMUNIFORM4FVPROC gl3wProgramUniform4fv; +extern PFNGLPROGRAMUNIFORM4DPROC gl3wProgramUniform4d; +extern PFNGLPROGRAMUNIFORM4DVPROC gl3wProgramUniform4dv; +extern PFNGLPROGRAMUNIFORM4UIPROC gl3wProgramUniform4ui; +extern PFNGLPROGRAMUNIFORM4UIVPROC gl3wProgramUniform4uiv; +extern PFNGLPROGRAMUNIFORMMATRIX2FVPROC gl3wProgramUniformMatrix2fv; +extern PFNGLPROGRAMUNIFORMMATRIX3FVPROC gl3wProgramUniformMatrix3fv; +extern PFNGLPROGRAMUNIFORMMATRIX4FVPROC gl3wProgramUniformMatrix4fv; +extern PFNGLPROGRAMUNIFORMMATRIX2DVPROC gl3wProgramUniformMatrix2dv; +extern PFNGLPROGRAMUNIFORMMATRIX3DVPROC gl3wProgramUniformMatrix3dv; +extern PFNGLPROGRAMUNIFORMMATRIX4DVPROC gl3wProgramUniformMatrix4dv; +extern PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC gl3wProgramUniformMatrix2x3fv; +extern PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC gl3wProgramUniformMatrix3x2fv; +extern PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC gl3wProgramUniformMatrix2x4fv; +extern PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC gl3wProgramUniformMatrix4x2fv; +extern PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC gl3wProgramUniformMatrix3x4fv; +extern PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC gl3wProgramUniformMatrix4x3fv; +extern PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC gl3wProgramUniformMatrix2x3dv; +extern PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC gl3wProgramUniformMatrix3x2dv; +extern PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC gl3wProgramUniformMatrix2x4dv; +extern PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC gl3wProgramUniformMatrix4x2dv; +extern PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC gl3wProgramUniformMatrix3x4dv; +extern PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC gl3wProgramUniformMatrix4x3dv; +extern PFNGLVALIDATEPROGRAMPIPELINEPROC gl3wValidateProgramPipeline; +extern PFNGLGETPROGRAMPIPELINEINFOLOGPROC gl3wGetProgramPipelineInfoLog; +extern PFNGLVERTEXATTRIBL1DPROC gl3wVertexAttribL1d; +extern PFNGLVERTEXATTRIBL2DPROC gl3wVertexAttribL2d; +extern PFNGLVERTEXATTRIBL3DPROC gl3wVertexAttribL3d; +extern PFNGLVERTEXATTRIBL4DPROC gl3wVertexAttribL4d; +extern PFNGLVERTEXATTRIBL1DVPROC gl3wVertexAttribL1dv; +extern PFNGLVERTEXATTRIBL2DVPROC gl3wVertexAttribL2dv; +extern PFNGLVERTEXATTRIBL3DVPROC gl3wVertexAttribL3dv; +extern PFNGLVERTEXATTRIBL4DVPROC gl3wVertexAttribL4dv; +extern PFNGLVERTEXATTRIBLPOINTERPROC gl3wVertexAttribLPointer; +extern PFNGLGETVERTEXATTRIBLDVPROC gl3wGetVertexAttribLdv; +extern PFNGLVIEWPORTARRAYVPROC gl3wViewportArrayv; +extern PFNGLVIEWPORTINDEXEDFPROC gl3wViewportIndexedf; +extern PFNGLVIEWPORTINDEXEDFVPROC gl3wViewportIndexedfv; +extern PFNGLSCISSORARRAYVPROC gl3wScissorArrayv; +extern PFNGLSCISSORINDEXEDPROC gl3wScissorIndexed; +extern PFNGLSCISSORINDEXEDVPROC gl3wScissorIndexedv; +extern PFNGLDEPTHRANGEARRAYVPROC gl3wDepthRangeArrayv; +extern PFNGLDEPTHRANGEINDEXEDPROC gl3wDepthRangeIndexed; +extern PFNGLGETFLOATI_VPROC gl3wGetFloati_v; +extern PFNGLGETDOUBLEI_VPROC gl3wGetDoublei_v; +extern PFNGLCREATESYNCFROMCLEVENTARBPROC gl3wCreateSyncFromCLeventARB; +extern PFNGLDEBUGMESSAGECONTROLARBPROC gl3wDebugMessageControlARB; +extern PFNGLDEBUGMESSAGEINSERTARBPROC gl3wDebugMessageInsertARB; +extern PFNGLDEBUGMESSAGECALLBACKARBPROC gl3wDebugMessageCallbackARB; +extern PFNGLGETDEBUGMESSAGELOGARBPROC gl3wGetDebugMessageLogARB; +extern PFNGLGETGRAPHICSRESETSTATUSARBPROC gl3wGetGraphicsResetStatusARB; +extern PFNGLGETNTEXIMAGEARBPROC gl3wGetnTexImageARB; +extern PFNGLREADNPIXELSARBPROC gl3wReadnPixelsARB; +extern PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC gl3wGetnCompressedTexImageARB; +extern PFNGLGETNUNIFORMFVARBPROC gl3wGetnUniformfvARB; +extern PFNGLGETNUNIFORMIVARBPROC gl3wGetnUniformivARB; +extern PFNGLGETNUNIFORMUIVARBPROC gl3wGetnUniformuivARB; +extern PFNGLGETNUNIFORMDVARBPROC gl3wGetnUniformdvARB; +extern PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC gl3wDrawArraysInstancedBaseInstance; +extern PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC gl3wDrawElementsInstancedBaseInstance; +extern PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC gl3wDrawElementsInstancedBaseVertexBaseInstance; +extern PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC gl3wDrawTransformFeedbackInstanced; +extern PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC gl3wDrawTransformFeedbackStreamInstanced; +extern PFNGLGETINTERNALFORMATIVPROC gl3wGetInternalformativ; +extern PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC gl3wGetActiveAtomicCounterBufferiv; +extern PFNGLBINDIMAGETEXTUREPROC gl3wBindImageTexture; +extern PFNGLMEMORYBARRIERPROC gl3wMemoryBarrier; +extern PFNGLTEXSTORAGE1DPROC gl3wTexStorage1D; +extern PFNGLTEXSTORAGE2DPROC gl3wTexStorage2D; +extern PFNGLTEXSTORAGE3DPROC gl3wTexStorage3D; +extern PFNGLTEXTURESTORAGE1DEXTPROC gl3wTextureStorage1DEXT; +extern PFNGLTEXTURESTORAGE2DEXTPROC gl3wTextureStorage2DEXT; +extern PFNGLTEXTURESTORAGE3DEXTPROC gl3wTextureStorage3DEXT; +extern PFNGLDEBUGMESSAGECONTROLPROC gl3wDebugMessageControl; +extern PFNGLDEBUGMESSAGEINSERTPROC gl3wDebugMessageInsert; +extern PFNGLDEBUGMESSAGECALLBACKPROC gl3wDebugMessageCallback; +extern PFNGLGETDEBUGMESSAGELOGPROC gl3wGetDebugMessageLog; +extern PFNGLPUSHDEBUGGROUPPROC gl3wPushDebugGroup; +extern PFNGLPOPDEBUGGROUPPROC gl3wPopDebugGroup; +extern PFNGLOBJECTLABELPROC gl3wObjectLabel; +extern PFNGLGETOBJECTLABELPROC gl3wGetObjectLabel; +extern PFNGLOBJECTPTRLABELPROC gl3wObjectPtrLabel; +extern PFNGLGETOBJECTPTRLABELPROC gl3wGetObjectPtrLabel; +extern PFNGLCLEARBUFFERDATAPROC gl3wClearBufferData; +extern PFNGLCLEARBUFFERSUBDATAPROC gl3wClearBufferSubData; +extern PFNGLCLEARNAMEDBUFFERDATAEXTPROC gl3wClearNamedBufferDataEXT; +extern PFNGLCLEARNAMEDBUFFERSUBDATAEXTPROC gl3wClearNamedBufferSubDataEXT; +extern PFNGLDISPATCHCOMPUTEPROC gl3wDispatchCompute; +extern PFNGLDISPATCHCOMPUTEINDIRECTPROC gl3wDispatchComputeIndirect; +extern PFNGLCOPYIMAGESUBDATAPROC gl3wCopyImageSubData; +extern PFNGLTEXTUREVIEWPROC gl3wTextureView; +extern PFNGLBINDVERTEXBUFFERPROC gl3wBindVertexBuffer; +extern PFNGLVERTEXATTRIBFORMATPROC gl3wVertexAttribFormat; +extern PFNGLVERTEXATTRIBIFORMATPROC gl3wVertexAttribIFormat; +extern PFNGLVERTEXATTRIBLFORMATPROC gl3wVertexAttribLFormat; +extern PFNGLVERTEXATTRIBBINDINGPROC gl3wVertexAttribBinding; +extern PFNGLVERTEXBINDINGDIVISORPROC gl3wVertexBindingDivisor; +extern PFNGLVERTEXARRAYBINDVERTEXBUFFEREXTPROC gl3wVertexArrayBindVertexBufferEXT; +extern PFNGLVERTEXARRAYVERTEXATTRIBFORMATEXTPROC gl3wVertexArrayVertexAttribFormatEXT; +extern PFNGLVERTEXARRAYVERTEXATTRIBIFORMATEXTPROC gl3wVertexArrayVertexAttribIFormatEXT; +extern PFNGLVERTEXARRAYVERTEXATTRIBLFORMATEXTPROC gl3wVertexArrayVertexAttribLFormatEXT; +extern PFNGLVERTEXARRAYVERTEXATTRIBBINDINGEXTPROC gl3wVertexArrayVertexAttribBindingEXT; +extern PFNGLVERTEXARRAYVERTEXBINDINGDIVISOREXTPROC gl3wVertexArrayVertexBindingDivisorEXT; +extern PFNGLFRAMEBUFFERPARAMETERIPROC gl3wFramebufferParameteri; +extern PFNGLGETFRAMEBUFFERPARAMETERIVPROC gl3wGetFramebufferParameteriv; +extern PFNGLNAMEDFRAMEBUFFERPARAMETERIEXTPROC gl3wNamedFramebufferParameteriEXT; +extern PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVEXTPROC gl3wGetNamedFramebufferParameterivEXT; +extern PFNGLGETINTERNALFORMATI64VPROC gl3wGetInternalformati64v; +extern PFNGLINVALIDATETEXSUBIMAGEPROC gl3wInvalidateTexSubImage; +extern PFNGLINVALIDATETEXIMAGEPROC gl3wInvalidateTexImage; +extern PFNGLINVALIDATEBUFFERSUBDATAPROC gl3wInvalidateBufferSubData; +extern PFNGLINVALIDATEBUFFERDATAPROC gl3wInvalidateBufferData; +extern PFNGLINVALIDATEFRAMEBUFFERPROC gl3wInvalidateFramebuffer; +extern PFNGLINVALIDATESUBFRAMEBUFFERPROC gl3wInvalidateSubFramebuffer; +extern PFNGLMULTIDRAWARRAYSINDIRECTPROC gl3wMultiDrawArraysIndirect; +extern PFNGLMULTIDRAWELEMENTSINDIRECTPROC gl3wMultiDrawElementsIndirect; +extern PFNGLGETPROGRAMINTERFACEIVPROC gl3wGetProgramInterfaceiv; +extern PFNGLGETPROGRAMRESOURCEINDEXPROC gl3wGetProgramResourceIndex; +extern PFNGLGETPROGRAMRESOURCENAMEPROC gl3wGetProgramResourceName; +extern PFNGLGETPROGRAMRESOURCEIVPROC gl3wGetProgramResourceiv; +extern PFNGLGETPROGRAMRESOURCELOCATIONPROC gl3wGetProgramResourceLocation; +extern PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC gl3wGetProgramResourceLocationIndex; +extern PFNGLSHADERSTORAGEBLOCKBINDINGPROC gl3wShaderStorageBlockBinding; +extern PFNGLTEXBUFFERRANGEPROC gl3wTexBufferRange; +extern PFNGLTEXTUREBUFFERRANGEEXTPROC gl3wTextureBufferRangeEXT; +extern PFNGLTEXSTORAGE2DMULTISAMPLEPROC gl3wTexStorage2DMultisample; +extern PFNGLTEXSTORAGE3DMULTISAMPLEPROC gl3wTexStorage3DMultisample; +extern PFNGLTEXTURESTORAGE2DMULTISAMPLEEXTPROC gl3wTextureStorage2DMultisampleEXT; +extern PFNGLTEXTURESTORAGE3DMULTISAMPLEEXTPROC gl3wTextureStorage3DMultisampleEXT; + +#define glCullFace gl3wCullFace +#define glFrontFace gl3wFrontFace +#define glHint gl3wHint +#define glLineWidth gl3wLineWidth +#define glPointSize gl3wPointSize +#define glPolygonMode gl3wPolygonMode +#define glScissor gl3wScissor +#define glTexParameterf gl3wTexParameterf +#define glTexParameterfv gl3wTexParameterfv +#define glTexParameteri gl3wTexParameteri +#define glTexParameteriv gl3wTexParameteriv +#define glTexImage1D gl3wTexImage1D +#define glTexImage2D gl3wTexImage2D +#define glDrawBuffer gl3wDrawBuffer +#define glClear gl3wClear +#define glClearColor gl3wClearColor +#define glClearStencil gl3wClearStencil +#define glClearDepth gl3wClearDepth +#define glStencilMask gl3wStencilMask +#define glColorMask gl3wColorMask +#define glDepthMask gl3wDepthMask +#define glDisable gl3wDisable +#define glEnable gl3wEnable +#define glFinish gl3wFinish +#define glFlush gl3wFlush +#define glBlendFunc gl3wBlendFunc +#define glLogicOp gl3wLogicOp +#define glStencilFunc gl3wStencilFunc +#define glStencilOp gl3wStencilOp +#define glDepthFunc gl3wDepthFunc +#define glPixelStoref gl3wPixelStoref +#define glPixelStorei gl3wPixelStorei +#define glReadBuffer gl3wReadBuffer +#define glReadPixels gl3wReadPixels +#define glGetBooleanv gl3wGetBooleanv +#define glGetDoublev gl3wGetDoublev +#define glGetError gl3wGetError +#define glGetFloatv gl3wGetFloatv +#define glGetIntegerv gl3wGetIntegerv +#define glGetString gl3wGetString +#define glGetTexImage gl3wGetTexImage +#define glGetTexParameterfv gl3wGetTexParameterfv +#define glGetTexParameteriv gl3wGetTexParameteriv +#define glGetTexLevelParameterfv gl3wGetTexLevelParameterfv +#define glGetTexLevelParameteriv gl3wGetTexLevelParameteriv +#define glIsEnabled gl3wIsEnabled +#define glDepthRange gl3wDepthRange +#define glViewport gl3wViewport +#define glDrawArrays gl3wDrawArrays +#define glDrawElements gl3wDrawElements +#define glGetPointerv gl3wGetPointerv +#define glPolygonOffset gl3wPolygonOffset +#define glCopyTexImage1D gl3wCopyTexImage1D +#define glCopyTexImage2D gl3wCopyTexImage2D +#define glCopyTexSubImage1D gl3wCopyTexSubImage1D +#define glCopyTexSubImage2D gl3wCopyTexSubImage2D +#define glTexSubImage1D gl3wTexSubImage1D +#define glTexSubImage2D gl3wTexSubImage2D +#define glBindTexture gl3wBindTexture +#define glDeleteTextures gl3wDeleteTextures +#define glGenTextures gl3wGenTextures +#define glIsTexture gl3wIsTexture +#define glBlendColor gl3wBlendColor +#define glBlendEquation gl3wBlendEquation +#define glDrawRangeElements gl3wDrawRangeElements +#define glTexImage3D gl3wTexImage3D +#define glTexSubImage3D gl3wTexSubImage3D +#define glCopyTexSubImage3D gl3wCopyTexSubImage3D +#define glActiveTexture gl3wActiveTexture +#define glSampleCoverage gl3wSampleCoverage +#define glCompressedTexImage3D gl3wCompressedTexImage3D +#define glCompressedTexImage2D gl3wCompressedTexImage2D +#define glCompressedTexImage1D gl3wCompressedTexImage1D +#define glCompressedTexSubImage3D gl3wCompressedTexSubImage3D +#define glCompressedTexSubImage2D gl3wCompressedTexSubImage2D +#define glCompressedTexSubImage1D gl3wCompressedTexSubImage1D +#define glGetCompressedTexImage gl3wGetCompressedTexImage +#define glBlendFuncSeparate gl3wBlendFuncSeparate +#define glMultiDrawArrays gl3wMultiDrawArrays +#define glMultiDrawElements gl3wMultiDrawElements +#define glPointParameterf gl3wPointParameterf +#define glPointParameterfv gl3wPointParameterfv +#define glPointParameteri gl3wPointParameteri +#define glPointParameteriv gl3wPointParameteriv +#define glGenQueries gl3wGenQueries +#define glDeleteQueries gl3wDeleteQueries +#define glIsQuery gl3wIsQuery +#define glBeginQuery gl3wBeginQuery +#define glEndQuery gl3wEndQuery +#define glGetQueryiv gl3wGetQueryiv +#define glGetQueryObjectiv gl3wGetQueryObjectiv +#define glGetQueryObjectuiv gl3wGetQueryObjectuiv +#define glBindBuffer gl3wBindBuffer +#define glDeleteBuffers gl3wDeleteBuffers +#define glGenBuffers gl3wGenBuffers +#define glIsBuffer gl3wIsBuffer +#define glBufferData gl3wBufferData +#define glBufferSubData gl3wBufferSubData +#define glGetBufferSubData gl3wGetBufferSubData +#define glMapBuffer gl3wMapBuffer +#define glUnmapBuffer gl3wUnmapBuffer +#define glGetBufferParameteriv gl3wGetBufferParameteriv +#define glGetBufferPointerv gl3wGetBufferPointerv +#define glBlendEquationSeparate gl3wBlendEquationSeparate +#define glDrawBuffers gl3wDrawBuffers +#define glStencilOpSeparate gl3wStencilOpSeparate +#define glStencilFuncSeparate gl3wStencilFuncSeparate +#define glStencilMaskSeparate gl3wStencilMaskSeparate +#define glAttachShader gl3wAttachShader +#define glBindAttribLocation gl3wBindAttribLocation +#define glCompileShader gl3wCompileShader +#define glCreateProgram gl3wCreateProgram +#define glCreateShader gl3wCreateShader +#define glDeleteProgram gl3wDeleteProgram +#define glDeleteShader gl3wDeleteShader +#define glDetachShader gl3wDetachShader +#define glDisableVertexAttribArray gl3wDisableVertexAttribArray +#define glEnableVertexAttribArray gl3wEnableVertexAttribArray +#define glGetActiveAttrib gl3wGetActiveAttrib +#define glGetActiveUniform gl3wGetActiveUniform +#define glGetAttachedShaders gl3wGetAttachedShaders +#define glGetAttribLocation gl3wGetAttribLocation +#define glGetProgramiv gl3wGetProgramiv +#define glGetProgramInfoLog gl3wGetProgramInfoLog +#define glGetShaderiv gl3wGetShaderiv +#define glGetShaderInfoLog gl3wGetShaderInfoLog +#define glGetShaderSource gl3wGetShaderSource +#define glGetUniformLocation gl3wGetUniformLocation +#define glGetUniformfv gl3wGetUniformfv +#define glGetUniformiv gl3wGetUniformiv +#define glGetVertexAttribdv gl3wGetVertexAttribdv +#define glGetVertexAttribfv gl3wGetVertexAttribfv +#define glGetVertexAttribiv gl3wGetVertexAttribiv +#define glGetVertexAttribPointerv gl3wGetVertexAttribPointerv +#define glIsProgram gl3wIsProgram +#define glIsShader gl3wIsShader +#define glLinkProgram gl3wLinkProgram +#define glShaderSource gl3wShaderSource +#define glUseProgram gl3wUseProgram +#define glUniform1f gl3wUniform1f +#define glUniform2f gl3wUniform2f +#define glUniform3f gl3wUniform3f +#define glUniform4f gl3wUniform4f +#define glUniform1i gl3wUniform1i +#define glUniform2i gl3wUniform2i +#define glUniform3i gl3wUniform3i +#define glUniform4i gl3wUniform4i +#define glUniform1fv gl3wUniform1fv +#define glUniform2fv gl3wUniform2fv +#define glUniform3fv gl3wUniform3fv +#define glUniform4fv gl3wUniform4fv +#define glUniform1iv gl3wUniform1iv +#define glUniform2iv gl3wUniform2iv +#define glUniform3iv gl3wUniform3iv +#define glUniform4iv gl3wUniform4iv +#define glUniformMatrix2fv gl3wUniformMatrix2fv +#define glUniformMatrix3fv gl3wUniformMatrix3fv +#define glUniformMatrix4fv gl3wUniformMatrix4fv +#define glValidateProgram gl3wValidateProgram +#define glVertexAttrib1d gl3wVertexAttrib1d +#define glVertexAttrib1dv gl3wVertexAttrib1dv +#define glVertexAttrib1f gl3wVertexAttrib1f +#define glVertexAttrib1fv gl3wVertexAttrib1fv +#define glVertexAttrib1s gl3wVertexAttrib1s +#define glVertexAttrib1sv gl3wVertexAttrib1sv +#define glVertexAttrib2d gl3wVertexAttrib2d +#define glVertexAttrib2dv gl3wVertexAttrib2dv +#define glVertexAttrib2f gl3wVertexAttrib2f +#define glVertexAttrib2fv gl3wVertexAttrib2fv +#define glVertexAttrib2s gl3wVertexAttrib2s +#define glVertexAttrib2sv gl3wVertexAttrib2sv +#define glVertexAttrib3d gl3wVertexAttrib3d +#define glVertexAttrib3dv gl3wVertexAttrib3dv +#define glVertexAttrib3f gl3wVertexAttrib3f +#define glVertexAttrib3fv gl3wVertexAttrib3fv +#define glVertexAttrib3s gl3wVertexAttrib3s +#define glVertexAttrib3sv gl3wVertexAttrib3sv +#define glVertexAttrib4Nbv gl3wVertexAttrib4Nbv +#define glVertexAttrib4Niv gl3wVertexAttrib4Niv +#define glVertexAttrib4Nsv gl3wVertexAttrib4Nsv +#define glVertexAttrib4Nub gl3wVertexAttrib4Nub +#define glVertexAttrib4Nubv gl3wVertexAttrib4Nubv +#define glVertexAttrib4Nuiv gl3wVertexAttrib4Nuiv +#define glVertexAttrib4Nusv gl3wVertexAttrib4Nusv +#define glVertexAttrib4bv gl3wVertexAttrib4bv +#define glVertexAttrib4d gl3wVertexAttrib4d +#define glVertexAttrib4dv gl3wVertexAttrib4dv +#define glVertexAttrib4f gl3wVertexAttrib4f +#define glVertexAttrib4fv gl3wVertexAttrib4fv +#define glVertexAttrib4iv gl3wVertexAttrib4iv +#define glVertexAttrib4s gl3wVertexAttrib4s +#define glVertexAttrib4sv gl3wVertexAttrib4sv +#define glVertexAttrib4ubv gl3wVertexAttrib4ubv +#define glVertexAttrib4uiv gl3wVertexAttrib4uiv +#define glVertexAttrib4usv gl3wVertexAttrib4usv +#define glVertexAttribPointer gl3wVertexAttribPointer +#define glUniformMatrix2x3fv gl3wUniformMatrix2x3fv +#define glUniformMatrix3x2fv gl3wUniformMatrix3x2fv +#define glUniformMatrix2x4fv gl3wUniformMatrix2x4fv +#define glUniformMatrix4x2fv gl3wUniformMatrix4x2fv +#define glUniformMatrix3x4fv gl3wUniformMatrix3x4fv +#define glUniformMatrix4x3fv gl3wUniformMatrix4x3fv +#define glColorMaski gl3wColorMaski +#define glGetBooleani_v gl3wGetBooleani_v +#define glGetIntegeri_v gl3wGetIntegeri_v +#define glEnablei gl3wEnablei +#define glDisablei gl3wDisablei +#define glIsEnabledi gl3wIsEnabledi +#define glBeginTransformFeedback gl3wBeginTransformFeedback +#define glEndTransformFeedback gl3wEndTransformFeedback +#define glBindBufferRange gl3wBindBufferRange +#define glBindBufferBase gl3wBindBufferBase +#define glTransformFeedbackVaryings gl3wTransformFeedbackVaryings +#define glGetTransformFeedbackVarying gl3wGetTransformFeedbackVarying +#define glClampColor gl3wClampColor +#define glBeginConditionalRender gl3wBeginConditionalRender +#define glEndConditionalRender gl3wEndConditionalRender +#define glVertexAttribIPointer gl3wVertexAttribIPointer +#define glGetVertexAttribIiv gl3wGetVertexAttribIiv +#define glGetVertexAttribIuiv gl3wGetVertexAttribIuiv +#define glVertexAttribI1i gl3wVertexAttribI1i +#define glVertexAttribI2i gl3wVertexAttribI2i +#define glVertexAttribI3i gl3wVertexAttribI3i +#define glVertexAttribI4i gl3wVertexAttribI4i +#define glVertexAttribI1ui gl3wVertexAttribI1ui +#define glVertexAttribI2ui gl3wVertexAttribI2ui +#define glVertexAttribI3ui gl3wVertexAttribI3ui +#define glVertexAttribI4ui gl3wVertexAttribI4ui +#define glVertexAttribI1iv gl3wVertexAttribI1iv +#define glVertexAttribI2iv gl3wVertexAttribI2iv +#define glVertexAttribI3iv gl3wVertexAttribI3iv +#define glVertexAttribI4iv gl3wVertexAttribI4iv +#define glVertexAttribI1uiv gl3wVertexAttribI1uiv +#define glVertexAttribI2uiv gl3wVertexAttribI2uiv +#define glVertexAttribI3uiv gl3wVertexAttribI3uiv +#define glVertexAttribI4uiv gl3wVertexAttribI4uiv +#define glVertexAttribI4bv gl3wVertexAttribI4bv +#define glVertexAttribI4sv gl3wVertexAttribI4sv +#define glVertexAttribI4ubv gl3wVertexAttribI4ubv +#define glVertexAttribI4usv gl3wVertexAttribI4usv +#define glGetUniformuiv gl3wGetUniformuiv +#define glBindFragDataLocation gl3wBindFragDataLocation +#define glGetFragDataLocation gl3wGetFragDataLocation +#define glUniform1ui gl3wUniform1ui +#define glUniform2ui gl3wUniform2ui +#define glUniform3ui gl3wUniform3ui +#define glUniform4ui gl3wUniform4ui +#define glUniform1uiv gl3wUniform1uiv +#define glUniform2uiv gl3wUniform2uiv +#define glUniform3uiv gl3wUniform3uiv +#define glUniform4uiv gl3wUniform4uiv +#define glTexParameterIiv gl3wTexParameterIiv +#define glTexParameterIuiv gl3wTexParameterIuiv +#define glGetTexParameterIiv gl3wGetTexParameterIiv +#define glGetTexParameterIuiv gl3wGetTexParameterIuiv +#define glClearBufferiv gl3wClearBufferiv +#define glClearBufferuiv gl3wClearBufferuiv +#define glClearBufferfv gl3wClearBufferfv +#define glClearBufferfi gl3wClearBufferfi +#define glGetStringi gl3wGetStringi +#define glDrawArraysInstanced gl3wDrawArraysInstanced +#define glDrawElementsInstanced gl3wDrawElementsInstanced +#define glTexBuffer gl3wTexBuffer +#define glPrimitiveRestartIndex gl3wPrimitiveRestartIndex +#define glGetInteger64i_v gl3wGetInteger64i_v +#define glGetBufferParameteri64v gl3wGetBufferParameteri64v +#define glFramebufferTexture gl3wFramebufferTexture +#define glVertexAttribDivisor gl3wVertexAttribDivisor +#define glMinSampleShading gl3wMinSampleShading +#define glBlendEquationi gl3wBlendEquationi +#define glBlendEquationSeparatei gl3wBlendEquationSeparatei +#define glBlendFunci gl3wBlendFunci +#define glBlendFuncSeparatei gl3wBlendFuncSeparatei +#define glIsRenderbuffer gl3wIsRenderbuffer +#define glBindRenderbuffer gl3wBindRenderbuffer +#define glDeleteRenderbuffers gl3wDeleteRenderbuffers +#define glGenRenderbuffers gl3wGenRenderbuffers +#define glRenderbufferStorage gl3wRenderbufferStorage +#define glGetRenderbufferParameteriv gl3wGetRenderbufferParameteriv +#define glIsFramebuffer gl3wIsFramebuffer +#define glBindFramebuffer gl3wBindFramebuffer +#define glDeleteFramebuffers gl3wDeleteFramebuffers +#define glGenFramebuffers gl3wGenFramebuffers +#define glCheckFramebufferStatus gl3wCheckFramebufferStatus +#define glFramebufferTexture1D gl3wFramebufferTexture1D +#define glFramebufferTexture2D gl3wFramebufferTexture2D +#define glFramebufferTexture3D gl3wFramebufferTexture3D +#define glFramebufferRenderbuffer gl3wFramebufferRenderbuffer +#define glGetFramebufferAttachmentParameteriv gl3wGetFramebufferAttachmentParameteriv +#define glGenerateMipmap gl3wGenerateMipmap +#define glBlitFramebuffer gl3wBlitFramebuffer +#define glRenderbufferStorageMultisample gl3wRenderbufferStorageMultisample +#define glFramebufferTextureLayer gl3wFramebufferTextureLayer +#define glMapBufferRange gl3wMapBufferRange +#define glFlushMappedBufferRange gl3wFlushMappedBufferRange +#define glBindVertexArray gl3wBindVertexArray +#define glDeleteVertexArrays gl3wDeleteVertexArrays +#define glGenVertexArrays gl3wGenVertexArrays +#define glIsVertexArray gl3wIsVertexArray +#define glGetUniformIndices gl3wGetUniformIndices +#define glGetActiveUniformsiv gl3wGetActiveUniformsiv +#define glGetActiveUniformName gl3wGetActiveUniformName +#define glGetUniformBlockIndex gl3wGetUniformBlockIndex +#define glGetActiveUniformBlockiv gl3wGetActiveUniformBlockiv +#define glGetActiveUniformBlockName gl3wGetActiveUniformBlockName +#define glUniformBlockBinding gl3wUniformBlockBinding +#define glCopyBufferSubData gl3wCopyBufferSubData +#define glDrawElementsBaseVertex gl3wDrawElementsBaseVertex +#define glDrawRangeElementsBaseVertex gl3wDrawRangeElementsBaseVertex +#define glDrawElementsInstancedBaseVertex gl3wDrawElementsInstancedBaseVertex +#define glMultiDrawElementsBaseVertex gl3wMultiDrawElementsBaseVertex +#define glProvokingVertex gl3wProvokingVertex +#define glFenceSync gl3wFenceSync +#define glIsSync gl3wIsSync +#define glDeleteSync gl3wDeleteSync +#define glClientWaitSync gl3wClientWaitSync +#define glWaitSync gl3wWaitSync +#define glGetInteger64v gl3wGetInteger64v +#define glGetSynciv gl3wGetSynciv +#define glTexImage2DMultisample gl3wTexImage2DMultisample +#define glTexImage3DMultisample gl3wTexImage3DMultisample +#define glGetMultisamplefv gl3wGetMultisamplefv +#define glSampleMaski gl3wSampleMaski +#define glBlendEquationiARB gl3wBlendEquationiARB +#define glBlendEquationSeparateiARB gl3wBlendEquationSeparateiARB +#define glBlendFunciARB gl3wBlendFunciARB +#define glBlendFuncSeparateiARB gl3wBlendFuncSeparateiARB +#define glMinSampleShadingARB gl3wMinSampleShadingARB +#define glNamedStringARB gl3wNamedStringARB +#define glDeleteNamedStringARB gl3wDeleteNamedStringARB +#define glCompileShaderIncludeARB gl3wCompileShaderIncludeARB +#define glIsNamedStringARB gl3wIsNamedStringARB +#define glGetNamedStringARB gl3wGetNamedStringARB +#define glGetNamedStringivARB gl3wGetNamedStringivARB +#define glBindFragDataLocationIndexed gl3wBindFragDataLocationIndexed +#define glGetFragDataIndex gl3wGetFragDataIndex +#define glGenSamplers gl3wGenSamplers +#define glDeleteSamplers gl3wDeleteSamplers +#define glIsSampler gl3wIsSampler +#define glBindSampler gl3wBindSampler +#define glSamplerParameteri gl3wSamplerParameteri +#define glSamplerParameteriv gl3wSamplerParameteriv +#define glSamplerParameterf gl3wSamplerParameterf +#define glSamplerParameterfv gl3wSamplerParameterfv +#define glSamplerParameterIiv gl3wSamplerParameterIiv +#define glSamplerParameterIuiv gl3wSamplerParameterIuiv +#define glGetSamplerParameteriv gl3wGetSamplerParameteriv +#define glGetSamplerParameterIiv gl3wGetSamplerParameterIiv +#define glGetSamplerParameterfv gl3wGetSamplerParameterfv +#define glGetSamplerParameterIuiv gl3wGetSamplerParameterIuiv +#define glQueryCounter gl3wQueryCounter +#define glGetQueryObjecti64v gl3wGetQueryObjecti64v +#define glGetQueryObjectui64v gl3wGetQueryObjectui64v +#define glVertexP2ui gl3wVertexP2ui +#define glVertexP2uiv gl3wVertexP2uiv +#define glVertexP3ui gl3wVertexP3ui +#define glVertexP3uiv gl3wVertexP3uiv +#define glVertexP4ui gl3wVertexP4ui +#define glVertexP4uiv gl3wVertexP4uiv +#define glTexCoordP1ui gl3wTexCoordP1ui +#define glTexCoordP1uiv gl3wTexCoordP1uiv +#define glTexCoordP2ui gl3wTexCoordP2ui +#define glTexCoordP2uiv gl3wTexCoordP2uiv +#define glTexCoordP3ui gl3wTexCoordP3ui +#define glTexCoordP3uiv gl3wTexCoordP3uiv +#define glTexCoordP4ui gl3wTexCoordP4ui +#define glTexCoordP4uiv gl3wTexCoordP4uiv +#define glMultiTexCoordP1ui gl3wMultiTexCoordP1ui +#define glMultiTexCoordP1uiv gl3wMultiTexCoordP1uiv +#define glMultiTexCoordP2ui gl3wMultiTexCoordP2ui +#define glMultiTexCoordP2uiv gl3wMultiTexCoordP2uiv +#define glMultiTexCoordP3ui gl3wMultiTexCoordP3ui +#define glMultiTexCoordP3uiv gl3wMultiTexCoordP3uiv +#define glMultiTexCoordP4ui gl3wMultiTexCoordP4ui +#define glMultiTexCoordP4uiv gl3wMultiTexCoordP4uiv +#define glNormalP3ui gl3wNormalP3ui +#define glNormalP3uiv gl3wNormalP3uiv +#define glColorP3ui gl3wColorP3ui +#define glColorP3uiv gl3wColorP3uiv +#define glColorP4ui gl3wColorP4ui +#define glColorP4uiv gl3wColorP4uiv +#define glSecondaryColorP3ui gl3wSecondaryColorP3ui +#define glSecondaryColorP3uiv gl3wSecondaryColorP3uiv +#define glVertexAttribP1ui gl3wVertexAttribP1ui +#define glVertexAttribP1uiv gl3wVertexAttribP1uiv +#define glVertexAttribP2ui gl3wVertexAttribP2ui +#define glVertexAttribP2uiv gl3wVertexAttribP2uiv +#define glVertexAttribP3ui gl3wVertexAttribP3ui +#define glVertexAttribP3uiv gl3wVertexAttribP3uiv +#define glVertexAttribP4ui gl3wVertexAttribP4ui +#define glVertexAttribP4uiv gl3wVertexAttribP4uiv +#define glDrawArraysIndirect gl3wDrawArraysIndirect +#define glDrawElementsIndirect gl3wDrawElementsIndirect +#define glUniform1d gl3wUniform1d +#define glUniform2d gl3wUniform2d +#define glUniform3d gl3wUniform3d +#define glUniform4d gl3wUniform4d +#define glUniform1dv gl3wUniform1dv +#define glUniform2dv gl3wUniform2dv +#define glUniform3dv gl3wUniform3dv +#define glUniform4dv gl3wUniform4dv +#define glUniformMatrix2dv gl3wUniformMatrix2dv +#define glUniformMatrix3dv gl3wUniformMatrix3dv +#define glUniformMatrix4dv gl3wUniformMatrix4dv +#define glUniformMatrix2x3dv gl3wUniformMatrix2x3dv +#define glUniformMatrix2x4dv gl3wUniformMatrix2x4dv +#define glUniformMatrix3x2dv gl3wUniformMatrix3x2dv +#define glUniformMatrix3x4dv gl3wUniformMatrix3x4dv +#define glUniformMatrix4x2dv gl3wUniformMatrix4x2dv +#define glUniformMatrix4x3dv gl3wUniformMatrix4x3dv +#define glGetUniformdv gl3wGetUniformdv +#define glGetSubroutineUniformLocation gl3wGetSubroutineUniformLocation +#define glGetSubroutineIndex gl3wGetSubroutineIndex +#define glGetActiveSubroutineUniformiv gl3wGetActiveSubroutineUniformiv +#define glGetActiveSubroutineUniformName gl3wGetActiveSubroutineUniformName +#define glGetActiveSubroutineName gl3wGetActiveSubroutineName +#define glUniformSubroutinesuiv gl3wUniformSubroutinesuiv +#define glGetUniformSubroutineuiv gl3wGetUniformSubroutineuiv +#define glGetProgramStageiv gl3wGetProgramStageiv +#define glPatchParameteri gl3wPatchParameteri +#define glPatchParameterfv gl3wPatchParameterfv +#define glBindTransformFeedback gl3wBindTransformFeedback +#define glDeleteTransformFeedbacks gl3wDeleteTransformFeedbacks +#define glGenTransformFeedbacks gl3wGenTransformFeedbacks +#define glIsTransformFeedback gl3wIsTransformFeedback +#define glPauseTransformFeedback gl3wPauseTransformFeedback +#define glResumeTransformFeedback gl3wResumeTransformFeedback +#define glDrawTransformFeedback gl3wDrawTransformFeedback +#define glDrawTransformFeedbackStream gl3wDrawTransformFeedbackStream +#define glBeginQueryIndexed gl3wBeginQueryIndexed +#define glEndQueryIndexed gl3wEndQueryIndexed +#define glGetQueryIndexediv gl3wGetQueryIndexediv +#define glReleaseShaderCompiler gl3wReleaseShaderCompiler +#define glShaderBinary gl3wShaderBinary +#define glGetShaderPrecisionFormat gl3wGetShaderPrecisionFormat +#define glDepthRangef gl3wDepthRangef +#define glClearDepthf gl3wClearDepthf +#define glGetProgramBinary gl3wGetProgramBinary +#define glProgramBinary gl3wProgramBinary +#define glProgramParameteri gl3wProgramParameteri +#define glUseProgramStages gl3wUseProgramStages +#define glActiveShaderProgram gl3wActiveShaderProgram +#define glCreateShaderProgramv gl3wCreateShaderProgramv +#define glBindProgramPipeline gl3wBindProgramPipeline +#define glDeleteProgramPipelines gl3wDeleteProgramPipelines +#define glGenProgramPipelines gl3wGenProgramPipelines +#define glIsProgramPipeline gl3wIsProgramPipeline +#define glGetProgramPipelineiv gl3wGetProgramPipelineiv +#define glProgramUniform1i gl3wProgramUniform1i +#define glProgramUniform1iv gl3wProgramUniform1iv +#define glProgramUniform1f gl3wProgramUniform1f +#define glProgramUniform1fv gl3wProgramUniform1fv +#define glProgramUniform1d gl3wProgramUniform1d +#define glProgramUniform1dv gl3wProgramUniform1dv +#define glProgramUniform1ui gl3wProgramUniform1ui +#define glProgramUniform1uiv gl3wProgramUniform1uiv +#define glProgramUniform2i gl3wProgramUniform2i +#define glProgramUniform2iv gl3wProgramUniform2iv +#define glProgramUniform2f gl3wProgramUniform2f +#define glProgramUniform2fv gl3wProgramUniform2fv +#define glProgramUniform2d gl3wProgramUniform2d +#define glProgramUniform2dv gl3wProgramUniform2dv +#define glProgramUniform2ui gl3wProgramUniform2ui +#define glProgramUniform2uiv gl3wProgramUniform2uiv +#define glProgramUniform3i gl3wProgramUniform3i +#define glProgramUniform3iv gl3wProgramUniform3iv +#define glProgramUniform3f gl3wProgramUniform3f +#define glProgramUniform3fv gl3wProgramUniform3fv +#define glProgramUniform3d gl3wProgramUniform3d +#define glProgramUniform3dv gl3wProgramUniform3dv +#define glProgramUniform3ui gl3wProgramUniform3ui +#define glProgramUniform3uiv gl3wProgramUniform3uiv +#define glProgramUniform4i gl3wProgramUniform4i +#define glProgramUniform4iv gl3wProgramUniform4iv +#define glProgramUniform4f gl3wProgramUniform4f +#define glProgramUniform4fv gl3wProgramUniform4fv +#define glProgramUniform4d gl3wProgramUniform4d +#define glProgramUniform4dv gl3wProgramUniform4dv +#define glProgramUniform4ui gl3wProgramUniform4ui +#define glProgramUniform4uiv gl3wProgramUniform4uiv +#define glProgramUniformMatrix2fv gl3wProgramUniformMatrix2fv +#define glProgramUniformMatrix3fv gl3wProgramUniformMatrix3fv +#define glProgramUniformMatrix4fv gl3wProgramUniformMatrix4fv +#define glProgramUniformMatrix2dv gl3wProgramUniformMatrix2dv +#define glProgramUniformMatrix3dv gl3wProgramUniformMatrix3dv +#define glProgramUniformMatrix4dv gl3wProgramUniformMatrix4dv +#define glProgramUniformMatrix2x3fv gl3wProgramUniformMatrix2x3fv +#define glProgramUniformMatrix3x2fv gl3wProgramUniformMatrix3x2fv +#define glProgramUniformMatrix2x4fv gl3wProgramUniformMatrix2x4fv +#define glProgramUniformMatrix4x2fv gl3wProgramUniformMatrix4x2fv +#define glProgramUniformMatrix3x4fv gl3wProgramUniformMatrix3x4fv +#define glProgramUniformMatrix4x3fv gl3wProgramUniformMatrix4x3fv +#define glProgramUniformMatrix2x3dv gl3wProgramUniformMatrix2x3dv +#define glProgramUniformMatrix3x2dv gl3wProgramUniformMatrix3x2dv +#define glProgramUniformMatrix2x4dv gl3wProgramUniformMatrix2x4dv +#define glProgramUniformMatrix4x2dv gl3wProgramUniformMatrix4x2dv +#define glProgramUniformMatrix3x4dv gl3wProgramUniformMatrix3x4dv +#define glProgramUniformMatrix4x3dv gl3wProgramUniformMatrix4x3dv +#define glValidateProgramPipeline gl3wValidateProgramPipeline +#define glGetProgramPipelineInfoLog gl3wGetProgramPipelineInfoLog +#define glVertexAttribL1d gl3wVertexAttribL1d +#define glVertexAttribL2d gl3wVertexAttribL2d +#define glVertexAttribL3d gl3wVertexAttribL3d +#define glVertexAttribL4d gl3wVertexAttribL4d +#define glVertexAttribL1dv gl3wVertexAttribL1dv +#define glVertexAttribL2dv gl3wVertexAttribL2dv +#define glVertexAttribL3dv gl3wVertexAttribL3dv +#define glVertexAttribL4dv gl3wVertexAttribL4dv +#define glVertexAttribLPointer gl3wVertexAttribLPointer +#define glGetVertexAttribLdv gl3wGetVertexAttribLdv +#define glViewportArrayv gl3wViewportArrayv +#define glViewportIndexedf gl3wViewportIndexedf +#define glViewportIndexedfv gl3wViewportIndexedfv +#define glScissorArrayv gl3wScissorArrayv +#define glScissorIndexed gl3wScissorIndexed +#define glScissorIndexedv gl3wScissorIndexedv +#define glDepthRangeArrayv gl3wDepthRangeArrayv +#define glDepthRangeIndexed gl3wDepthRangeIndexed +#define glGetFloati_v gl3wGetFloati_v +#define glGetDoublei_v gl3wGetDoublei_v +#define glCreateSyncFromCLeventARB gl3wCreateSyncFromCLeventARB +#define glDebugMessageControlARB gl3wDebugMessageControlARB +#define glDebugMessageInsertARB gl3wDebugMessageInsertARB +#define glDebugMessageCallbackARB gl3wDebugMessageCallbackARB +#define glGetDebugMessageLogARB gl3wGetDebugMessageLogARB +#define glGetGraphicsResetStatusARB gl3wGetGraphicsResetStatusARB +#define glGetnTexImageARB gl3wGetnTexImageARB +#define glReadnPixelsARB gl3wReadnPixelsARB +#define glGetnCompressedTexImageARB gl3wGetnCompressedTexImageARB +#define glGetnUniformfvARB gl3wGetnUniformfvARB +#define glGetnUniformivARB gl3wGetnUniformivARB +#define glGetnUniformuivARB gl3wGetnUniformuivARB +#define glGetnUniformdvARB gl3wGetnUniformdvARB +#define glDrawArraysInstancedBaseInstance gl3wDrawArraysInstancedBaseInstance +#define glDrawElementsInstancedBaseInstance gl3wDrawElementsInstancedBaseInstance +#define glDrawElementsInstancedBaseVertexBaseInstance gl3wDrawElementsInstancedBaseVertexBaseInstance +#define glDrawTransformFeedbackInstanced gl3wDrawTransformFeedbackInstanced +#define glDrawTransformFeedbackStreamInstanced gl3wDrawTransformFeedbackStreamInstanced +#define glGetInternalformativ gl3wGetInternalformativ +#define glGetActiveAtomicCounterBufferiv gl3wGetActiveAtomicCounterBufferiv +#define glBindImageTexture gl3wBindImageTexture +#define glMemoryBarrier gl3wMemoryBarrier +#define glTexStorage1D gl3wTexStorage1D +#define glTexStorage2D gl3wTexStorage2D +#define glTexStorage3D gl3wTexStorage3D +#define glTextureStorage1DEXT gl3wTextureStorage1DEXT +#define glTextureStorage2DEXT gl3wTextureStorage2DEXT +#define glTextureStorage3DEXT gl3wTextureStorage3DEXT +#define glDebugMessageControl gl3wDebugMessageControl +#define glDebugMessageInsert gl3wDebugMessageInsert +#define glDebugMessageCallback gl3wDebugMessageCallback +#define glGetDebugMessageLog gl3wGetDebugMessageLog +#define glPushDebugGroup gl3wPushDebugGroup +#define glPopDebugGroup gl3wPopDebugGroup +#define glObjectLabel gl3wObjectLabel +#define glGetObjectLabel gl3wGetObjectLabel +#define glObjectPtrLabel gl3wObjectPtrLabel +#define glGetObjectPtrLabel gl3wGetObjectPtrLabel +#define glClearBufferData gl3wClearBufferData +#define glClearBufferSubData gl3wClearBufferSubData +#define glClearNamedBufferDataEXT gl3wClearNamedBufferDataEXT +#define glClearNamedBufferSubDataEXT gl3wClearNamedBufferSubDataEXT +#define glDispatchCompute gl3wDispatchCompute +#define glDispatchComputeIndirect gl3wDispatchComputeIndirect +#define glCopyImageSubData gl3wCopyImageSubData +#define glTextureView gl3wTextureView +#define glBindVertexBuffer gl3wBindVertexBuffer +#define glVertexAttribFormat gl3wVertexAttribFormat +#define glVertexAttribIFormat gl3wVertexAttribIFormat +#define glVertexAttribLFormat gl3wVertexAttribLFormat +#define glVertexAttribBinding gl3wVertexAttribBinding +#define glVertexBindingDivisor gl3wVertexBindingDivisor +#define glVertexArrayBindVertexBufferEXT gl3wVertexArrayBindVertexBufferEXT +#define glVertexArrayVertexAttribFormatEXT gl3wVertexArrayVertexAttribFormatEXT +#define glVertexArrayVertexAttribIFormatEXT gl3wVertexArrayVertexAttribIFormatEXT +#define glVertexArrayVertexAttribLFormatEXT gl3wVertexArrayVertexAttribLFormatEXT +#define glVertexArrayVertexAttribBindingEXT gl3wVertexArrayVertexAttribBindingEXT +#define glVertexArrayVertexBindingDivisorEXT gl3wVertexArrayVertexBindingDivisorEXT +#define glFramebufferParameteri gl3wFramebufferParameteri +#define glGetFramebufferParameteriv gl3wGetFramebufferParameteriv +#define glNamedFramebufferParameteriEXT gl3wNamedFramebufferParameteriEXT +#define glGetNamedFramebufferParameterivEXT gl3wGetNamedFramebufferParameterivEXT +#define glGetInternalformati64v gl3wGetInternalformati64v +#define glInvalidateTexSubImage gl3wInvalidateTexSubImage +#define glInvalidateTexImage gl3wInvalidateTexImage +#define glInvalidateBufferSubData gl3wInvalidateBufferSubData +#define glInvalidateBufferData gl3wInvalidateBufferData +#define glInvalidateFramebuffer gl3wInvalidateFramebuffer +#define glInvalidateSubFramebuffer gl3wInvalidateSubFramebuffer +#define glMultiDrawArraysIndirect gl3wMultiDrawArraysIndirect +#define glMultiDrawElementsIndirect gl3wMultiDrawElementsIndirect +#define glGetProgramInterfaceiv gl3wGetProgramInterfaceiv +#define glGetProgramResourceIndex gl3wGetProgramResourceIndex +#define glGetProgramResourceName gl3wGetProgramResourceName +#define glGetProgramResourceiv gl3wGetProgramResourceiv +#define glGetProgramResourceLocation gl3wGetProgramResourceLocation +#define glGetProgramResourceLocationIndex gl3wGetProgramResourceLocationIndex +#define glShaderStorageBlockBinding gl3wShaderStorageBlockBinding +#define glTexBufferRange gl3wTexBufferRange +#define glTextureBufferRangeEXT gl3wTextureBufferRangeEXT +#define glTexStorage2DMultisample gl3wTexStorage2DMultisample +#define glTexStorage3DMultisample gl3wTexStorage3DMultisample +#define glTextureStorage2DMultisampleEXT gl3wTextureStorage2DMultisampleEXT +#define glTextureStorage3DMultisampleEXT gl3wTextureStorage3DMultisampleEXT + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/3rdparty/imgui-node-editor/external/gl3w/Include/GL/glcorearb.h b/3rdparty/imgui-node-editor/external/gl3w/Include/GL/glcorearb.h new file mode 100755 index 0000000..07cb03e --- /dev/null +++ b/3rdparty/imgui-node-editor/external/gl3w/Include/GL/glcorearb.h @@ -0,0 +1,4533 @@ +#ifndef __glcorearb_h_ +#define __glcorearb_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** Copyright (c) 2007-2012 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +/* glcorearb.h replaces gl3.h. It is for use with OpenGL core + * profile implementations. + * + * glcorearb.h last updated on $Date: 2012-09-19 19:02:24 -0700 (Wed, 19 Sep 2012) $ + * + * RELEASE NOTES - 2012/09/19 + * + * glcorearb.h should be placed in the same directory as gl.h and + * included as + * ''. + * + * glcorearb.h includes only APIs in the latest OpenGL core profile + * implementation together with APIs in newer ARB extensions which can be + * can be supported by the core profile. It does not, and never will + * include functionality removed from the core profile, such as + * fixed-function vertex and fragment processing. + * + * It is not possible to #include both and either of + * or in the same source file. + * + * Feedback can be given by registering for the Khronos Bugzilla + * (www.khronos.org/bugzilla) and filing issues there under product + * "OpenGL", category "Registry". + */ + +/* Function declaration macros - to move into glplatform.h */ + +#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) +#define WIN32_LEAN_AND_MEAN 1 +#include +#endif + +#ifndef APIENTRY +#define APIENTRY +#endif +#ifndef APIENTRYP +#define APIENTRYP APIENTRY * +#endif +#ifndef GLAPI +#define GLAPI extern +#endif + +/* Base GL types */ + +typedef unsigned int GLenum; +typedef unsigned char GLboolean; +typedef unsigned int GLbitfield; +typedef signed char GLbyte; +typedef short GLshort; +typedef int GLint; +typedef int GLsizei; +typedef unsigned char GLubyte; +typedef unsigned short GLushort; +typedef unsigned int GLuint; +typedef unsigned short GLhalf; +typedef float GLfloat; +typedef float GLclampf; +typedef double GLdouble; +typedef double GLclampd; +typedef void GLvoid; + +/*************************************************************/ + +#ifndef GL_VERSION_1_1 +/* AttribMask */ +#define GL_DEPTH_BUFFER_BIT 0x00000100 +#define GL_STENCIL_BUFFER_BIT 0x00000400 +#define GL_COLOR_BUFFER_BIT 0x00004000 +/* Boolean */ +#define GL_FALSE 0 +#define GL_TRUE 1 +/* BeginMode */ +#define GL_POINTS 0x0000 +#define GL_LINES 0x0001 +#define GL_LINE_LOOP 0x0002 +#define GL_LINE_STRIP 0x0003 +#define GL_TRIANGLES 0x0004 +#define GL_TRIANGLE_STRIP 0x0005 +#define GL_TRIANGLE_FAN 0x0006 +#define GL_QUADS 0x0007 +/* AlphaFunction */ +#define GL_NEVER 0x0200 +#define GL_LESS 0x0201 +#define GL_EQUAL 0x0202 +#define GL_LEQUAL 0x0203 +#define GL_GREATER 0x0204 +#define GL_NOTEQUAL 0x0205 +#define GL_GEQUAL 0x0206 +#define GL_ALWAYS 0x0207 +/* BlendingFactorDest */ +#define GL_ZERO 0 +#define GL_ONE 1 +#define GL_SRC_COLOR 0x0300 +#define GL_ONE_MINUS_SRC_COLOR 0x0301 +#define GL_SRC_ALPHA 0x0302 +#define GL_ONE_MINUS_SRC_ALPHA 0x0303 +#define GL_DST_ALPHA 0x0304 +#define GL_ONE_MINUS_DST_ALPHA 0x0305 +/* BlendingFactorSrc */ +#define GL_DST_COLOR 0x0306 +#define GL_ONE_MINUS_DST_COLOR 0x0307 +#define GL_SRC_ALPHA_SATURATE 0x0308 +/* DrawBufferMode */ +#define GL_NONE 0 +#define GL_FRONT_LEFT 0x0400 +#define GL_FRONT_RIGHT 0x0401 +#define GL_BACK_LEFT 0x0402 +#define GL_BACK_RIGHT 0x0403 +#define GL_FRONT 0x0404 +#define GL_BACK 0x0405 +#define GL_LEFT 0x0406 +#define GL_RIGHT 0x0407 +#define GL_FRONT_AND_BACK 0x0408 +/* ErrorCode */ +#define GL_NO_ERROR 0 +#define GL_INVALID_ENUM 0x0500 +#define GL_INVALID_VALUE 0x0501 +#define GL_INVALID_OPERATION 0x0502 +#define GL_OUT_OF_MEMORY 0x0505 +/* FrontFaceDirection */ +#define GL_CW 0x0900 +#define GL_CCW 0x0901 +/* GetPName */ +#define GL_POINT_SIZE 0x0B11 +#define GL_POINT_SIZE_RANGE 0x0B12 +#define GL_POINT_SIZE_GRANULARITY 0x0B13 +#define GL_LINE_SMOOTH 0x0B20 +#define GL_LINE_WIDTH 0x0B21 +#define GL_LINE_WIDTH_RANGE 0x0B22 +#define GL_LINE_WIDTH_GRANULARITY 0x0B23 +#define GL_POLYGON_MODE 0x0B40 +#define GL_POLYGON_SMOOTH 0x0B41 +#define GL_CULL_FACE 0x0B44 +#define GL_CULL_FACE_MODE 0x0B45 +#define GL_FRONT_FACE 0x0B46 +#define GL_DEPTH_RANGE 0x0B70 +#define GL_DEPTH_TEST 0x0B71 +#define GL_DEPTH_WRITEMASK 0x0B72 +#define GL_DEPTH_CLEAR_VALUE 0x0B73 +#define GL_DEPTH_FUNC 0x0B74 +#define GL_STENCIL_TEST 0x0B90 +#define GL_STENCIL_CLEAR_VALUE 0x0B91 +#define GL_STENCIL_FUNC 0x0B92 +#define GL_STENCIL_VALUE_MASK 0x0B93 +#define GL_STENCIL_FAIL 0x0B94 +#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 +#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 +#define GL_STENCIL_REF 0x0B97 +#define GL_STENCIL_WRITEMASK 0x0B98 +#define GL_VIEWPORT 0x0BA2 +#define GL_DITHER 0x0BD0 +#define GL_BLEND_DST 0x0BE0 +#define GL_BLEND_SRC 0x0BE1 +#define GL_BLEND 0x0BE2 +#define GL_LOGIC_OP_MODE 0x0BF0 +#define GL_COLOR_LOGIC_OP 0x0BF2 +#define GL_DRAW_BUFFER 0x0C01 +#define GL_READ_BUFFER 0x0C02 +#define GL_SCISSOR_BOX 0x0C10 +#define GL_SCISSOR_TEST 0x0C11 +#define GL_COLOR_CLEAR_VALUE 0x0C22 +#define GL_COLOR_WRITEMASK 0x0C23 +#define GL_DOUBLEBUFFER 0x0C32 +#define GL_STEREO 0x0C33 +#define GL_LINE_SMOOTH_HINT 0x0C52 +#define GL_POLYGON_SMOOTH_HINT 0x0C53 +#define GL_UNPACK_SWAP_BYTES 0x0CF0 +#define GL_UNPACK_LSB_FIRST 0x0CF1 +#define GL_UNPACK_ROW_LENGTH 0x0CF2 +#define GL_UNPACK_SKIP_ROWS 0x0CF3 +#define GL_UNPACK_SKIP_PIXELS 0x0CF4 +#define GL_UNPACK_ALIGNMENT 0x0CF5 +#define GL_PACK_SWAP_BYTES 0x0D00 +#define GL_PACK_LSB_FIRST 0x0D01 +#define GL_PACK_ROW_LENGTH 0x0D02 +#define GL_PACK_SKIP_ROWS 0x0D03 +#define GL_PACK_SKIP_PIXELS 0x0D04 +#define GL_PACK_ALIGNMENT 0x0D05 +#define GL_MAX_TEXTURE_SIZE 0x0D33 +#define GL_MAX_VIEWPORT_DIMS 0x0D3A +#define GL_SUBPIXEL_BITS 0x0D50 +#define GL_TEXTURE_1D 0x0DE0 +#define GL_TEXTURE_2D 0x0DE1 +#define GL_POLYGON_OFFSET_UNITS 0x2A00 +#define GL_POLYGON_OFFSET_POINT 0x2A01 +#define GL_POLYGON_OFFSET_LINE 0x2A02 +#define GL_POLYGON_OFFSET_FILL 0x8037 +#define GL_POLYGON_OFFSET_FACTOR 0x8038 +#define GL_TEXTURE_BINDING_1D 0x8068 +#define GL_TEXTURE_BINDING_2D 0x8069 +/* GetTextureParameter */ +#define GL_TEXTURE_WIDTH 0x1000 +#define GL_TEXTURE_HEIGHT 0x1001 +#define GL_TEXTURE_INTERNAL_FORMAT 0x1003 +#define GL_TEXTURE_BORDER_COLOR 0x1004 +#define GL_TEXTURE_RED_SIZE 0x805C +#define GL_TEXTURE_GREEN_SIZE 0x805D +#define GL_TEXTURE_BLUE_SIZE 0x805E +#define GL_TEXTURE_ALPHA_SIZE 0x805F +/* HintMode */ +#define GL_DONT_CARE 0x1100 +#define GL_FASTEST 0x1101 +#define GL_NICEST 0x1102 +/* DataType */ +#define GL_BYTE 0x1400 +#define GL_UNSIGNED_BYTE 0x1401 +#define GL_SHORT 0x1402 +#define GL_UNSIGNED_SHORT 0x1403 +#define GL_INT 0x1404 +#define GL_UNSIGNED_INT 0x1405 +#define GL_FLOAT 0x1406 +#define GL_DOUBLE 0x140A +/* ErrorCode */ +#define GL_STACK_OVERFLOW 0x0503 +#define GL_STACK_UNDERFLOW 0x0504 +/* LogicOp */ +#define GL_CLEAR 0x1500 +#define GL_AND 0x1501 +#define GL_AND_REVERSE 0x1502 +#define GL_COPY 0x1503 +#define GL_AND_INVERTED 0x1504 +#define GL_NOOP 0x1505 +#define GL_XOR 0x1506 +#define GL_OR 0x1507 +#define GL_NOR 0x1508 +#define GL_EQUIV 0x1509 +#define GL_INVERT 0x150A +#define GL_OR_REVERSE 0x150B +#define GL_COPY_INVERTED 0x150C +#define GL_OR_INVERTED 0x150D +#define GL_NAND 0x150E +#define GL_SET 0x150F +/* MatrixMode (for gl3.h, FBO attachment type) */ +#define GL_TEXTURE 0x1702 +/* PixelCopyType */ +#define GL_COLOR 0x1800 +#define GL_DEPTH 0x1801 +#define GL_STENCIL 0x1802 +/* PixelFormat */ +#define GL_STENCIL_INDEX 0x1901 +#define GL_DEPTH_COMPONENT 0x1902 +#define GL_RED 0x1903 +#define GL_GREEN 0x1904 +#define GL_BLUE 0x1905 +#define GL_ALPHA 0x1906 +#define GL_RGB 0x1907 +#define GL_RGBA 0x1908 +/* PolygonMode */ +#define GL_POINT 0x1B00 +#define GL_LINE 0x1B01 +#define GL_FILL 0x1B02 +/* StencilOp */ +#define GL_KEEP 0x1E00 +#define GL_REPLACE 0x1E01 +#define GL_INCR 0x1E02 +#define GL_DECR 0x1E03 +/* StringName */ +#define GL_VENDOR 0x1F00 +#define GL_RENDERER 0x1F01 +#define GL_VERSION 0x1F02 +#define GL_EXTENSIONS 0x1F03 +/* TextureMagFilter */ +#define GL_NEAREST 0x2600 +#define GL_LINEAR 0x2601 +/* TextureMinFilter */ +#define GL_NEAREST_MIPMAP_NEAREST 0x2700 +#define GL_LINEAR_MIPMAP_NEAREST 0x2701 +#define GL_NEAREST_MIPMAP_LINEAR 0x2702 +#define GL_LINEAR_MIPMAP_LINEAR 0x2703 +/* TextureParameterName */ +#define GL_TEXTURE_MAG_FILTER 0x2800 +#define GL_TEXTURE_MIN_FILTER 0x2801 +#define GL_TEXTURE_WRAP_S 0x2802 +#define GL_TEXTURE_WRAP_T 0x2803 +/* TextureTarget */ +#define GL_PROXY_TEXTURE_1D 0x8063 +#define GL_PROXY_TEXTURE_2D 0x8064 +/* TextureWrapMode */ +#define GL_REPEAT 0x2901 +/* PixelInternalFormat */ +#define GL_R3_G3_B2 0x2A10 +#define GL_RGB4 0x804F +#define GL_RGB5 0x8050 +#define GL_RGB8 0x8051 +#define GL_RGB10 0x8052 +#define GL_RGB12 0x8053 +#define GL_RGB16 0x8054 +#define GL_RGBA2 0x8055 +#define GL_RGBA4 0x8056 +#define GL_RGB5_A1 0x8057 +#define GL_RGBA8 0x8058 +#define GL_RGB10_A2 0x8059 +#define GL_RGBA12 0x805A +#define GL_RGBA16 0x805B +#endif + +#ifndef GL_VERSION_1_2 +#define GL_UNSIGNED_BYTE_3_3_2 0x8032 +#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 +#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 +#define GL_UNSIGNED_INT_8_8_8_8 0x8035 +#define GL_UNSIGNED_INT_10_10_10_2 0x8036 +#define GL_TEXTURE_BINDING_3D 0x806A +#define GL_PACK_SKIP_IMAGES 0x806B +#define GL_PACK_IMAGE_HEIGHT 0x806C +#define GL_UNPACK_SKIP_IMAGES 0x806D +#define GL_UNPACK_IMAGE_HEIGHT 0x806E +#define GL_TEXTURE_3D 0x806F +#define GL_PROXY_TEXTURE_3D 0x8070 +#define GL_TEXTURE_DEPTH 0x8071 +#define GL_TEXTURE_WRAP_R 0x8072 +#define GL_MAX_3D_TEXTURE_SIZE 0x8073 +#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 +#define GL_UNSIGNED_SHORT_5_6_5 0x8363 +#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 +#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 +#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 +#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 +#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 +#define GL_BGR 0x80E0 +#define GL_BGRA 0x80E1 +#define GL_MAX_ELEMENTS_VERTICES 0x80E8 +#define GL_MAX_ELEMENTS_INDICES 0x80E9 +#define GL_CLAMP_TO_EDGE 0x812F +#define GL_TEXTURE_MIN_LOD 0x813A +#define GL_TEXTURE_MAX_LOD 0x813B +#define GL_TEXTURE_BASE_LEVEL 0x813C +#define GL_TEXTURE_MAX_LEVEL 0x813D +#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12 +#define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13 +#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22 +#define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23 +#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E +#endif + +#ifndef GL_ARB_imaging +#define GL_CONSTANT_COLOR 0x8001 +#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 +#define GL_CONSTANT_ALPHA 0x8003 +#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 +#define GL_BLEND_COLOR 0x8005 +#define GL_FUNC_ADD 0x8006 +#define GL_MIN 0x8007 +#define GL_MAX 0x8008 +#define GL_BLEND_EQUATION 0x8009 +#define GL_FUNC_SUBTRACT 0x800A +#define GL_FUNC_REVERSE_SUBTRACT 0x800B +#endif + +#ifndef GL_VERSION_1_3 +#define GL_TEXTURE0 0x84C0 +#define GL_TEXTURE1 0x84C1 +#define GL_TEXTURE2 0x84C2 +#define GL_TEXTURE3 0x84C3 +#define GL_TEXTURE4 0x84C4 +#define GL_TEXTURE5 0x84C5 +#define GL_TEXTURE6 0x84C6 +#define GL_TEXTURE7 0x84C7 +#define GL_TEXTURE8 0x84C8 +#define GL_TEXTURE9 0x84C9 +#define GL_TEXTURE10 0x84CA +#define GL_TEXTURE11 0x84CB +#define GL_TEXTURE12 0x84CC +#define GL_TEXTURE13 0x84CD +#define GL_TEXTURE14 0x84CE +#define GL_TEXTURE15 0x84CF +#define GL_TEXTURE16 0x84D0 +#define GL_TEXTURE17 0x84D1 +#define GL_TEXTURE18 0x84D2 +#define GL_TEXTURE19 0x84D3 +#define GL_TEXTURE20 0x84D4 +#define GL_TEXTURE21 0x84D5 +#define GL_TEXTURE22 0x84D6 +#define GL_TEXTURE23 0x84D7 +#define GL_TEXTURE24 0x84D8 +#define GL_TEXTURE25 0x84D9 +#define GL_TEXTURE26 0x84DA +#define GL_TEXTURE27 0x84DB +#define GL_TEXTURE28 0x84DC +#define GL_TEXTURE29 0x84DD +#define GL_TEXTURE30 0x84DE +#define GL_TEXTURE31 0x84DF +#define GL_ACTIVE_TEXTURE 0x84E0 +#define GL_MULTISAMPLE 0x809D +#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E +#define GL_SAMPLE_ALPHA_TO_ONE 0x809F +#define GL_SAMPLE_COVERAGE 0x80A0 +#define GL_SAMPLE_BUFFERS 0x80A8 +#define GL_SAMPLES 0x80A9 +#define GL_SAMPLE_COVERAGE_VALUE 0x80AA +#define GL_SAMPLE_COVERAGE_INVERT 0x80AB +#define GL_TEXTURE_CUBE_MAP 0x8513 +#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A +#define GL_PROXY_TEXTURE_CUBE_MAP 0x851B +#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C +#define GL_COMPRESSED_RGB 0x84ED +#define GL_COMPRESSED_RGBA 0x84EE +#define GL_TEXTURE_COMPRESSION_HINT 0x84EF +#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0 +#define GL_TEXTURE_COMPRESSED 0x86A1 +#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 +#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 +#define GL_CLAMP_TO_BORDER 0x812D +#endif + +#ifndef GL_VERSION_1_4 +#define GL_BLEND_DST_RGB 0x80C8 +#define GL_BLEND_SRC_RGB 0x80C9 +#define GL_BLEND_DST_ALPHA 0x80CA +#define GL_BLEND_SRC_ALPHA 0x80CB +#define GL_POINT_FADE_THRESHOLD_SIZE 0x8128 +#define GL_DEPTH_COMPONENT16 0x81A5 +#define GL_DEPTH_COMPONENT24 0x81A6 +#define GL_DEPTH_COMPONENT32 0x81A7 +#define GL_MIRRORED_REPEAT 0x8370 +#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD +#define GL_TEXTURE_LOD_BIAS 0x8501 +#define GL_INCR_WRAP 0x8507 +#define GL_DECR_WRAP 0x8508 +#define GL_TEXTURE_DEPTH_SIZE 0x884A +#define GL_TEXTURE_COMPARE_MODE 0x884C +#define GL_TEXTURE_COMPARE_FUNC 0x884D +#endif + +#ifndef GL_VERSION_1_5 +#define GL_BUFFER_SIZE 0x8764 +#define GL_BUFFER_USAGE 0x8765 +#define GL_QUERY_COUNTER_BITS 0x8864 +#define GL_CURRENT_QUERY 0x8865 +#define GL_QUERY_RESULT 0x8866 +#define GL_QUERY_RESULT_AVAILABLE 0x8867 +#define GL_ARRAY_BUFFER 0x8892 +#define GL_ELEMENT_ARRAY_BUFFER 0x8893 +#define GL_ARRAY_BUFFER_BINDING 0x8894 +#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 +#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F +#define GL_READ_ONLY 0x88B8 +#define GL_WRITE_ONLY 0x88B9 +#define GL_READ_WRITE 0x88BA +#define GL_BUFFER_ACCESS 0x88BB +#define GL_BUFFER_MAPPED 0x88BC +#define GL_BUFFER_MAP_POINTER 0x88BD +#define GL_STREAM_DRAW 0x88E0 +#define GL_STREAM_READ 0x88E1 +#define GL_STREAM_COPY 0x88E2 +#define GL_STATIC_DRAW 0x88E4 +#define GL_STATIC_READ 0x88E5 +#define GL_STATIC_COPY 0x88E6 +#define GL_DYNAMIC_DRAW 0x88E8 +#define GL_DYNAMIC_READ 0x88E9 +#define GL_DYNAMIC_COPY 0x88EA +#define GL_SAMPLES_PASSED 0x8914 +#define GL_SRC1_ALPHA 0x8589 +#endif + +#ifndef GL_VERSION_2_0 +#define GL_BLEND_EQUATION_RGB 0x8009 +#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 +#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 +#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 +#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 +#define GL_CURRENT_VERTEX_ATTRIB 0x8626 +#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 +#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 +#define GL_STENCIL_BACK_FUNC 0x8800 +#define GL_STENCIL_BACK_FAIL 0x8801 +#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 +#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 +#define GL_MAX_DRAW_BUFFERS 0x8824 +#define GL_DRAW_BUFFER0 0x8825 +#define GL_DRAW_BUFFER1 0x8826 +#define GL_DRAW_BUFFER2 0x8827 +#define GL_DRAW_BUFFER3 0x8828 +#define GL_DRAW_BUFFER4 0x8829 +#define GL_DRAW_BUFFER5 0x882A +#define GL_DRAW_BUFFER6 0x882B +#define GL_DRAW_BUFFER7 0x882C +#define GL_DRAW_BUFFER8 0x882D +#define GL_DRAW_BUFFER9 0x882E +#define GL_DRAW_BUFFER10 0x882F +#define GL_DRAW_BUFFER11 0x8830 +#define GL_DRAW_BUFFER12 0x8831 +#define GL_DRAW_BUFFER13 0x8832 +#define GL_DRAW_BUFFER14 0x8833 +#define GL_DRAW_BUFFER15 0x8834 +#define GL_BLEND_EQUATION_ALPHA 0x883D +#define GL_MAX_VERTEX_ATTRIBS 0x8869 +#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A +#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_VERTEX_SHADER 0x8B31 +#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 +#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A +#define GL_MAX_VARYING_FLOATS 0x8B4B +#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C +#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D +#define GL_SHADER_TYPE 0x8B4F +#define GL_FLOAT_VEC2 0x8B50 +#define GL_FLOAT_VEC3 0x8B51 +#define GL_FLOAT_VEC4 0x8B52 +#define GL_INT_VEC2 0x8B53 +#define GL_INT_VEC3 0x8B54 +#define GL_INT_VEC4 0x8B55 +#define GL_BOOL 0x8B56 +#define GL_BOOL_VEC2 0x8B57 +#define GL_BOOL_VEC3 0x8B58 +#define GL_BOOL_VEC4 0x8B59 +#define GL_FLOAT_MAT2 0x8B5A +#define GL_FLOAT_MAT3 0x8B5B +#define GL_FLOAT_MAT4 0x8B5C +#define GL_SAMPLER_1D 0x8B5D +#define GL_SAMPLER_2D 0x8B5E +#define GL_SAMPLER_3D 0x8B5F +#define GL_SAMPLER_CUBE 0x8B60 +#define GL_SAMPLER_1D_SHADOW 0x8B61 +#define GL_SAMPLER_2D_SHADOW 0x8B62 +#define GL_DELETE_STATUS 0x8B80 +#define GL_COMPILE_STATUS 0x8B81 +#define GL_LINK_STATUS 0x8B82 +#define GL_VALIDATE_STATUS 0x8B83 +#define GL_INFO_LOG_LENGTH 0x8B84 +#define GL_ATTACHED_SHADERS 0x8B85 +#define GL_ACTIVE_UNIFORMS 0x8B86 +#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 +#define GL_SHADER_SOURCE_LENGTH 0x8B88 +#define GL_ACTIVE_ATTRIBUTES 0x8B89 +#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A +#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B +#define GL_SHADING_LANGUAGE_VERSION 0x8B8C +#define GL_CURRENT_PROGRAM 0x8B8D +#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 +#define GL_LOWER_LEFT 0x8CA1 +#define GL_UPPER_LEFT 0x8CA2 +#define GL_STENCIL_BACK_REF 0x8CA3 +#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 +#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 +#endif + +#ifndef GL_VERSION_2_1 +#define GL_PIXEL_PACK_BUFFER 0x88EB +#define GL_PIXEL_UNPACK_BUFFER 0x88EC +#define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED +#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF +#define GL_FLOAT_MAT2x3 0x8B65 +#define GL_FLOAT_MAT2x4 0x8B66 +#define GL_FLOAT_MAT3x2 0x8B67 +#define GL_FLOAT_MAT3x4 0x8B68 +#define GL_FLOAT_MAT4x2 0x8B69 +#define GL_FLOAT_MAT4x3 0x8B6A +#define GL_SRGB 0x8C40 +#define GL_SRGB8 0x8C41 +#define GL_SRGB_ALPHA 0x8C42 +#define GL_SRGB8_ALPHA8 0x8C43 +#define GL_COMPRESSED_SRGB 0x8C48 +#define GL_COMPRESSED_SRGB_ALPHA 0x8C49 +#endif + +#ifndef GL_VERSION_3_0 +#define GL_COMPARE_REF_TO_TEXTURE 0x884E +#define GL_CLIP_DISTANCE0 0x3000 +#define GL_CLIP_DISTANCE1 0x3001 +#define GL_CLIP_DISTANCE2 0x3002 +#define GL_CLIP_DISTANCE3 0x3003 +#define GL_CLIP_DISTANCE4 0x3004 +#define GL_CLIP_DISTANCE5 0x3005 +#define GL_CLIP_DISTANCE6 0x3006 +#define GL_CLIP_DISTANCE7 0x3007 +#define GL_MAX_CLIP_DISTANCES 0x0D32 +#define GL_MAJOR_VERSION 0x821B +#define GL_MINOR_VERSION 0x821C +#define GL_NUM_EXTENSIONS 0x821D +#define GL_CONTEXT_FLAGS 0x821E +#define GL_COMPRESSED_RED 0x8225 +#define GL_COMPRESSED_RG 0x8226 +#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x0001 +#define GL_RGBA32F 0x8814 +#define GL_RGB32F 0x8815 +#define GL_RGBA16F 0x881A +#define GL_RGB16F 0x881B +#define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD +#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF +#define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904 +#define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905 +#define GL_CLAMP_READ_COLOR 0x891C +#define GL_FIXED_ONLY 0x891D +#define GL_MAX_VARYING_COMPONENTS 0x8B4B +#define GL_TEXTURE_1D_ARRAY 0x8C18 +#define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19 +#define GL_TEXTURE_2D_ARRAY 0x8C1A +#define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B +#define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C +#define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D +#define GL_R11F_G11F_B10F 0x8C3A +#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B +#define GL_RGB9_E5 0x8C3D +#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E +#define GL_TEXTURE_SHARED_SIZE 0x8C3F +#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76 +#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80 +#define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83 +#define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84 +#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85 +#define GL_PRIMITIVES_GENERATED 0x8C87 +#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88 +#define GL_RASTERIZER_DISCARD 0x8C89 +#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B +#define GL_INTERLEAVED_ATTRIBS 0x8C8C +#define GL_SEPARATE_ATTRIBS 0x8C8D +#define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E +#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F +#define GL_RGBA32UI 0x8D70 +#define GL_RGB32UI 0x8D71 +#define GL_RGBA16UI 0x8D76 +#define GL_RGB16UI 0x8D77 +#define GL_RGBA8UI 0x8D7C +#define GL_RGB8UI 0x8D7D +#define GL_RGBA32I 0x8D82 +#define GL_RGB32I 0x8D83 +#define GL_RGBA16I 0x8D88 +#define GL_RGB16I 0x8D89 +#define GL_RGBA8I 0x8D8E +#define GL_RGB8I 0x8D8F +#define GL_RED_INTEGER 0x8D94 +#define GL_GREEN_INTEGER 0x8D95 +#define GL_BLUE_INTEGER 0x8D96 +#define GL_RGB_INTEGER 0x8D98 +#define GL_RGBA_INTEGER 0x8D99 +#define GL_BGR_INTEGER 0x8D9A +#define GL_BGRA_INTEGER 0x8D9B +#define GL_SAMPLER_1D_ARRAY 0x8DC0 +#define GL_SAMPLER_2D_ARRAY 0x8DC1 +#define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3 +#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4 +#define GL_SAMPLER_CUBE_SHADOW 0x8DC5 +#define GL_UNSIGNED_INT_VEC2 0x8DC6 +#define GL_UNSIGNED_INT_VEC3 0x8DC7 +#define GL_UNSIGNED_INT_VEC4 0x8DC8 +#define GL_INT_SAMPLER_1D 0x8DC9 +#define GL_INT_SAMPLER_2D 0x8DCA +#define GL_INT_SAMPLER_3D 0x8DCB +#define GL_INT_SAMPLER_CUBE 0x8DCC +#define GL_INT_SAMPLER_1D_ARRAY 0x8DCE +#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF +#define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1 +#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2 +#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3 +#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4 +#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6 +#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7 +#define GL_QUERY_WAIT 0x8E13 +#define GL_QUERY_NO_WAIT 0x8E14 +#define GL_QUERY_BY_REGION_WAIT 0x8E15 +#define GL_QUERY_BY_REGION_NO_WAIT 0x8E16 +#define GL_BUFFER_ACCESS_FLAGS 0x911F +#define GL_BUFFER_MAP_LENGTH 0x9120 +#define GL_BUFFER_MAP_OFFSET 0x9121 +/* Reuse tokens from ARB_depth_buffer_float */ +/* reuse GL_DEPTH_COMPONENT32F */ +/* reuse GL_DEPTH32F_STENCIL8 */ +/* reuse GL_FLOAT_32_UNSIGNED_INT_24_8_REV */ +/* Reuse tokens from ARB_framebuffer_object */ +/* reuse GL_INVALID_FRAMEBUFFER_OPERATION */ +/* reuse GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING */ +/* reuse GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE */ +/* reuse GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE */ +/* reuse GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE */ +/* reuse GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE */ +/* reuse GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE */ +/* reuse GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE */ +/* reuse GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE */ +/* reuse GL_FRAMEBUFFER_DEFAULT */ +/* reuse GL_FRAMEBUFFER_UNDEFINED */ +/* reuse GL_DEPTH_STENCIL_ATTACHMENT */ +/* reuse GL_INDEX */ +/* reuse GL_MAX_RENDERBUFFER_SIZE */ +/* reuse GL_DEPTH_STENCIL */ +/* reuse GL_UNSIGNED_INT_24_8 */ +/* reuse GL_DEPTH24_STENCIL8 */ +/* reuse GL_TEXTURE_STENCIL_SIZE */ +/* reuse GL_TEXTURE_RED_TYPE */ +/* reuse GL_TEXTURE_GREEN_TYPE */ +/* reuse GL_TEXTURE_BLUE_TYPE */ +/* reuse GL_TEXTURE_ALPHA_TYPE */ +/* reuse GL_TEXTURE_DEPTH_TYPE */ +/* reuse GL_UNSIGNED_NORMALIZED */ +/* reuse GL_FRAMEBUFFER_BINDING */ +/* reuse GL_DRAW_FRAMEBUFFER_BINDING */ +/* reuse GL_RENDERBUFFER_BINDING */ +/* reuse GL_READ_FRAMEBUFFER */ +/* reuse GL_DRAW_FRAMEBUFFER */ +/* reuse GL_READ_FRAMEBUFFER_BINDING */ +/* reuse GL_RENDERBUFFER_SAMPLES */ +/* reuse GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE */ +/* reuse GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME */ +/* reuse GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL */ +/* reuse GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE */ +/* reuse GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER */ +/* reuse GL_FRAMEBUFFER_COMPLETE */ +/* reuse GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT */ +/* reuse GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT */ +/* reuse GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER */ +/* reuse GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER */ +/* reuse GL_FRAMEBUFFER_UNSUPPORTED */ +/* reuse GL_MAX_COLOR_ATTACHMENTS */ +/* reuse GL_COLOR_ATTACHMENT0 */ +/* reuse GL_COLOR_ATTACHMENT1 */ +/* reuse GL_COLOR_ATTACHMENT2 */ +/* reuse GL_COLOR_ATTACHMENT3 */ +/* reuse GL_COLOR_ATTACHMENT4 */ +/* reuse GL_COLOR_ATTACHMENT5 */ +/* reuse GL_COLOR_ATTACHMENT6 */ +/* reuse GL_COLOR_ATTACHMENT7 */ +/* reuse GL_COLOR_ATTACHMENT8 */ +/* reuse GL_COLOR_ATTACHMENT9 */ +/* reuse GL_COLOR_ATTACHMENT10 */ +/* reuse GL_COLOR_ATTACHMENT11 */ +/* reuse GL_COLOR_ATTACHMENT12 */ +/* reuse GL_COLOR_ATTACHMENT13 */ +/* reuse GL_COLOR_ATTACHMENT14 */ +/* reuse GL_COLOR_ATTACHMENT15 */ +/* reuse GL_DEPTH_ATTACHMENT */ +/* reuse GL_STENCIL_ATTACHMENT */ +/* reuse GL_FRAMEBUFFER */ +/* reuse GL_RENDERBUFFER */ +/* reuse GL_RENDERBUFFER_WIDTH */ +/* reuse GL_RENDERBUFFER_HEIGHT */ +/* reuse GL_RENDERBUFFER_INTERNAL_FORMAT */ +/* reuse GL_STENCIL_INDEX1 */ +/* reuse GL_STENCIL_INDEX4 */ +/* reuse GL_STENCIL_INDEX8 */ +/* reuse GL_STENCIL_INDEX16 */ +/* reuse GL_RENDERBUFFER_RED_SIZE */ +/* reuse GL_RENDERBUFFER_GREEN_SIZE */ +/* reuse GL_RENDERBUFFER_BLUE_SIZE */ +/* reuse GL_RENDERBUFFER_ALPHA_SIZE */ +/* reuse GL_RENDERBUFFER_DEPTH_SIZE */ +/* reuse GL_RENDERBUFFER_STENCIL_SIZE */ +/* reuse GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE */ +/* reuse GL_MAX_SAMPLES */ +/* Reuse tokens from ARB_framebuffer_sRGB */ +/* reuse GL_FRAMEBUFFER_SRGB */ +/* Reuse tokens from ARB_half_float_vertex */ +/* reuse GL_HALF_FLOAT */ +/* Reuse tokens from ARB_map_buffer_range */ +/* reuse GL_MAP_READ_BIT */ +/* reuse GL_MAP_WRITE_BIT */ +/* reuse GL_MAP_INVALIDATE_RANGE_BIT */ +/* reuse GL_MAP_INVALIDATE_BUFFER_BIT */ +/* reuse GL_MAP_FLUSH_EXPLICIT_BIT */ +/* reuse GL_MAP_UNSYNCHRONIZED_BIT */ +/* Reuse tokens from ARB_texture_compression_rgtc */ +/* reuse GL_COMPRESSED_RED_RGTC1 */ +/* reuse GL_COMPRESSED_SIGNED_RED_RGTC1 */ +/* reuse GL_COMPRESSED_RG_RGTC2 */ +/* reuse GL_COMPRESSED_SIGNED_RG_RGTC2 */ +/* Reuse tokens from ARB_texture_rg */ +/* reuse GL_RG */ +/* reuse GL_RG_INTEGER */ +/* reuse GL_R8 */ +/* reuse GL_R16 */ +/* reuse GL_RG8 */ +/* reuse GL_RG16 */ +/* reuse GL_R16F */ +/* reuse GL_R32F */ +/* reuse GL_RG16F */ +/* reuse GL_RG32F */ +/* reuse GL_R8I */ +/* reuse GL_R8UI */ +/* reuse GL_R16I */ +/* reuse GL_R16UI */ +/* reuse GL_R32I */ +/* reuse GL_R32UI */ +/* reuse GL_RG8I */ +/* reuse GL_RG8UI */ +/* reuse GL_RG16I */ +/* reuse GL_RG16UI */ +/* reuse GL_RG32I */ +/* reuse GL_RG32UI */ +/* Reuse tokens from ARB_vertex_array_object */ +/* reuse GL_VERTEX_ARRAY_BINDING */ +#endif + +#ifndef GL_VERSION_3_1 +#define GL_SAMPLER_2D_RECT 0x8B63 +#define GL_SAMPLER_2D_RECT_SHADOW 0x8B64 +#define GL_SAMPLER_BUFFER 0x8DC2 +#define GL_INT_SAMPLER_2D_RECT 0x8DCD +#define GL_INT_SAMPLER_BUFFER 0x8DD0 +#define GL_UNSIGNED_INT_SAMPLER_2D_RECT 0x8DD5 +#define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8 +#define GL_TEXTURE_BUFFER 0x8C2A +#define GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B +#define GL_TEXTURE_BINDING_BUFFER 0x8C2C +#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING 0x8C2D +#define GL_TEXTURE_RECTANGLE 0x84F5 +#define GL_TEXTURE_BINDING_RECTANGLE 0x84F6 +#define GL_PROXY_TEXTURE_RECTANGLE 0x84F7 +#define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8 +#define GL_RED_SNORM 0x8F90 +#define GL_RG_SNORM 0x8F91 +#define GL_RGB_SNORM 0x8F92 +#define GL_RGBA_SNORM 0x8F93 +#define GL_R8_SNORM 0x8F94 +#define GL_RG8_SNORM 0x8F95 +#define GL_RGB8_SNORM 0x8F96 +#define GL_RGBA8_SNORM 0x8F97 +#define GL_R16_SNORM 0x8F98 +#define GL_RG16_SNORM 0x8F99 +#define GL_RGB16_SNORM 0x8F9A +#define GL_RGBA16_SNORM 0x8F9B +#define GL_SIGNED_NORMALIZED 0x8F9C +#define GL_PRIMITIVE_RESTART 0x8F9D +#define GL_PRIMITIVE_RESTART_INDEX 0x8F9E +/* Reuse tokens from ARB_copy_buffer */ +/* reuse GL_COPY_READ_BUFFER */ +/* reuse GL_COPY_WRITE_BUFFER */ +/* Reuse tokens from ARB_draw_instanced (none) */ +/* Reuse tokens from ARB_uniform_buffer_object */ +/* reuse GL_UNIFORM_BUFFER */ +/* reuse GL_UNIFORM_BUFFER_BINDING */ +/* reuse GL_UNIFORM_BUFFER_START */ +/* reuse GL_UNIFORM_BUFFER_SIZE */ +/* reuse GL_MAX_VERTEX_UNIFORM_BLOCKS */ +/* reuse GL_MAX_FRAGMENT_UNIFORM_BLOCKS */ +/* reuse GL_MAX_COMBINED_UNIFORM_BLOCKS */ +/* reuse GL_MAX_UNIFORM_BUFFER_BINDINGS */ +/* reuse GL_MAX_UNIFORM_BLOCK_SIZE */ +/* reuse GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS */ +/* reuse GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS */ +/* reuse GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT */ +/* reuse GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH */ +/* reuse GL_ACTIVE_UNIFORM_BLOCKS */ +/* reuse GL_UNIFORM_TYPE */ +/* reuse GL_UNIFORM_SIZE */ +/* reuse GL_UNIFORM_NAME_LENGTH */ +/* reuse GL_UNIFORM_BLOCK_INDEX */ +/* reuse GL_UNIFORM_OFFSET */ +/* reuse GL_UNIFORM_ARRAY_STRIDE */ +/* reuse GL_UNIFORM_MATRIX_STRIDE */ +/* reuse GL_UNIFORM_IS_ROW_MAJOR */ +/* reuse GL_UNIFORM_BLOCK_BINDING */ +/* reuse GL_UNIFORM_BLOCK_DATA_SIZE */ +/* reuse GL_UNIFORM_BLOCK_NAME_LENGTH */ +/* reuse GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS */ +/* reuse GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES */ +/* reuse GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER */ +/* reuse GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER */ +/* reuse GL_INVALID_INDEX */ +#endif + +#ifndef GL_VERSION_3_2 +#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001 +#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002 +#define GL_LINES_ADJACENCY 0x000A +#define GL_LINE_STRIP_ADJACENCY 0x000B +#define GL_TRIANGLES_ADJACENCY 0x000C +#define GL_TRIANGLE_STRIP_ADJACENCY 0x000D +#define GL_PROGRAM_POINT_SIZE 0x8642 +#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29 +#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7 +#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8 +#define GL_GEOMETRY_SHADER 0x8DD9 +#define GL_GEOMETRY_VERTICES_OUT 0x8916 +#define GL_GEOMETRY_INPUT_TYPE 0x8917 +#define GL_GEOMETRY_OUTPUT_TYPE 0x8918 +#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF +#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0 +#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1 +#define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122 +#define GL_MAX_GEOMETRY_INPUT_COMPONENTS 0x9123 +#define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS 0x9124 +#define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125 +#define GL_CONTEXT_PROFILE_MASK 0x9126 +/* reuse GL_MAX_VARYING_COMPONENTS */ +/* reuse GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER */ +/* Reuse tokens from ARB_depth_clamp */ +/* reuse GL_DEPTH_CLAMP */ +/* Reuse tokens from ARB_draw_elements_base_vertex (none) */ +/* Reuse tokens from ARB_fragment_coord_conventions (none) */ +/* Reuse tokens from ARB_provoking_vertex */ +/* reuse GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION */ +/* reuse GL_FIRST_VERTEX_CONVENTION */ +/* reuse GL_LAST_VERTEX_CONVENTION */ +/* reuse GL_PROVOKING_VERTEX */ +/* Reuse tokens from ARB_seamless_cube_map */ +/* reuse GL_TEXTURE_CUBE_MAP_SEAMLESS */ +/* Reuse tokens from ARB_sync */ +/* reuse GL_MAX_SERVER_WAIT_TIMEOUT */ +/* reuse GL_OBJECT_TYPE */ +/* reuse GL_SYNC_CONDITION */ +/* reuse GL_SYNC_STATUS */ +/* reuse GL_SYNC_FLAGS */ +/* reuse GL_SYNC_FENCE */ +/* reuse GL_SYNC_GPU_COMMANDS_COMPLETE */ +/* reuse GL_UNSIGNALED */ +/* reuse GL_SIGNALED */ +/* reuse GL_ALREADY_SIGNALED */ +/* reuse GL_TIMEOUT_EXPIRED */ +/* reuse GL_CONDITION_SATISFIED */ +/* reuse GL_WAIT_FAILED */ +/* reuse GL_TIMEOUT_IGNORED */ +/* reuse GL_SYNC_FLUSH_COMMANDS_BIT */ +/* reuse GL_TIMEOUT_IGNORED */ +/* Reuse tokens from ARB_texture_multisample */ +/* reuse GL_SAMPLE_POSITION */ +/* reuse GL_SAMPLE_MASK */ +/* reuse GL_SAMPLE_MASK_VALUE */ +/* reuse GL_MAX_SAMPLE_MASK_WORDS */ +/* reuse GL_TEXTURE_2D_MULTISAMPLE */ +/* reuse GL_PROXY_TEXTURE_2D_MULTISAMPLE */ +/* reuse GL_TEXTURE_2D_MULTISAMPLE_ARRAY */ +/* reuse GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY */ +/* reuse GL_TEXTURE_BINDING_2D_MULTISAMPLE */ +/* reuse GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY */ +/* reuse GL_TEXTURE_SAMPLES */ +/* reuse GL_TEXTURE_FIXED_SAMPLE_LOCATIONS */ +/* reuse GL_SAMPLER_2D_MULTISAMPLE */ +/* reuse GL_INT_SAMPLER_2D_MULTISAMPLE */ +/* reuse GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE */ +/* reuse GL_SAMPLER_2D_MULTISAMPLE_ARRAY */ +/* reuse GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY */ +/* reuse GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY */ +/* reuse GL_MAX_COLOR_TEXTURE_SAMPLES */ +/* reuse GL_MAX_DEPTH_TEXTURE_SAMPLES */ +/* reuse GL_MAX_INTEGER_SAMPLES */ +/* Don't need to reuse tokens from ARB_vertex_array_bgra since they're already in 1.2 core */ +#endif + +#ifndef GL_VERSION_3_3 +#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE +/* Reuse tokens from ARB_blend_func_extended */ +/* reuse GL_SRC1_COLOR */ +/* reuse GL_ONE_MINUS_SRC1_COLOR */ +/* reuse GL_ONE_MINUS_SRC1_ALPHA */ +/* reuse GL_MAX_DUAL_SOURCE_DRAW_BUFFERS */ +/* Reuse tokens from ARB_explicit_attrib_location (none) */ +/* Reuse tokens from ARB_occlusion_query2 */ +/* reuse GL_ANY_SAMPLES_PASSED */ +/* Reuse tokens from ARB_sampler_objects */ +/* reuse GL_SAMPLER_BINDING */ +/* Reuse tokens from ARB_shader_bit_encoding (none) */ +/* Reuse tokens from ARB_texture_rgb10_a2ui */ +/* reuse GL_RGB10_A2UI */ +/* Reuse tokens from ARB_texture_swizzle */ +/* reuse GL_TEXTURE_SWIZZLE_R */ +/* reuse GL_TEXTURE_SWIZZLE_G */ +/* reuse GL_TEXTURE_SWIZZLE_B */ +/* reuse GL_TEXTURE_SWIZZLE_A */ +/* reuse GL_TEXTURE_SWIZZLE_RGBA */ +/* Reuse tokens from ARB_timer_query */ +/* reuse GL_TIME_ELAPSED */ +/* reuse GL_TIMESTAMP */ +/* Reuse tokens from ARB_vertex_type_2_10_10_10_rev */ +/* reuse GL_INT_2_10_10_10_REV */ +#endif + +#ifndef GL_VERSION_4_0 +#define GL_SAMPLE_SHADING 0x8C36 +#define GL_MIN_SAMPLE_SHADING_VALUE 0x8C37 +#define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5E +#define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5F +#define GL_TEXTURE_CUBE_MAP_ARRAY 0x9009 +#define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY 0x900A +#define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY 0x900B +#define GL_SAMPLER_CUBE_MAP_ARRAY 0x900C +#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW 0x900D +#define GL_INT_SAMPLER_CUBE_MAP_ARRAY 0x900E +#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY 0x900F +/* Reuse tokens from ARB_texture_query_lod (none) */ +/* Reuse tokens from ARB_draw_buffers_blend (none) */ +/* Reuse tokens from ARB_draw_indirect */ +/* reuse GL_DRAW_INDIRECT_BUFFER */ +/* reuse GL_DRAW_INDIRECT_BUFFER_BINDING */ +/* Reuse tokens from ARB_gpu_shader5 */ +/* reuse GL_GEOMETRY_SHADER_INVOCATIONS */ +/* reuse GL_MAX_GEOMETRY_SHADER_INVOCATIONS */ +/* reuse GL_MIN_FRAGMENT_INTERPOLATION_OFFSET */ +/* reuse GL_MAX_FRAGMENT_INTERPOLATION_OFFSET */ +/* reuse GL_FRAGMENT_INTERPOLATION_OFFSET_BITS */ +/* reuse GL_MAX_VERTEX_STREAMS */ +/* Reuse tokens from ARB_gpu_shader_fp64 */ +/* reuse GL_DOUBLE_VEC2 */ +/* reuse GL_DOUBLE_VEC3 */ +/* reuse GL_DOUBLE_VEC4 */ +/* reuse GL_DOUBLE_MAT2 */ +/* reuse GL_DOUBLE_MAT3 */ +/* reuse GL_DOUBLE_MAT4 */ +/* reuse GL_DOUBLE_MAT2x3 */ +/* reuse GL_DOUBLE_MAT2x4 */ +/* reuse GL_DOUBLE_MAT3x2 */ +/* reuse GL_DOUBLE_MAT3x4 */ +/* reuse GL_DOUBLE_MAT4x2 */ +/* reuse GL_DOUBLE_MAT4x3 */ +/* Reuse tokens from ARB_shader_subroutine */ +/* reuse GL_ACTIVE_SUBROUTINES */ +/* reuse GL_ACTIVE_SUBROUTINE_UNIFORMS */ +/* reuse GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS */ +/* reuse GL_ACTIVE_SUBROUTINE_MAX_LENGTH */ +/* reuse GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH */ +/* reuse GL_MAX_SUBROUTINES */ +/* reuse GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS */ +/* reuse GL_NUM_COMPATIBLE_SUBROUTINES */ +/* reuse GL_COMPATIBLE_SUBROUTINES */ +/* Reuse tokens from ARB_tessellation_shader */ +/* reuse GL_PATCHES */ +/* reuse GL_PATCH_VERTICES */ +/* reuse GL_PATCH_DEFAULT_INNER_LEVEL */ +/* reuse GL_PATCH_DEFAULT_OUTER_LEVEL */ +/* reuse GL_TESS_CONTROL_OUTPUT_VERTICES */ +/* reuse GL_TESS_GEN_MODE */ +/* reuse GL_TESS_GEN_SPACING */ +/* reuse GL_TESS_GEN_VERTEX_ORDER */ +/* reuse GL_TESS_GEN_POINT_MODE */ +/* reuse GL_ISOLINES */ +/* reuse GL_FRACTIONAL_ODD */ +/* reuse GL_FRACTIONAL_EVEN */ +/* reuse GL_MAX_PATCH_VERTICES */ +/* reuse GL_MAX_TESS_GEN_LEVEL */ +/* reuse GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS */ +/* reuse GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS */ +/* reuse GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS */ +/* reuse GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS */ +/* reuse GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS */ +/* reuse GL_MAX_TESS_PATCH_COMPONENTS */ +/* reuse GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS */ +/* reuse GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS */ +/* reuse GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS */ +/* reuse GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS */ +/* reuse GL_MAX_TESS_CONTROL_INPUT_COMPONENTS */ +/* reuse GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS */ +/* reuse GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS */ +/* reuse GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS */ +/* reuse GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER */ +/* reuse GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER */ +/* reuse GL_TESS_EVALUATION_SHADER */ +/* reuse GL_TESS_CONTROL_SHADER */ +/* Reuse tokens from ARB_texture_buffer_object_rgb32 (none) */ +/* Reuse tokens from ARB_transform_feedback2 */ +/* reuse GL_TRANSFORM_FEEDBACK */ +/* reuse GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED */ +/* reuse GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE */ +/* reuse GL_TRANSFORM_FEEDBACK_BINDING */ +/* Reuse tokens from ARB_transform_feedback3 */ +/* reuse GL_MAX_TRANSFORM_FEEDBACK_BUFFERS */ +/* reuse GL_MAX_VERTEX_STREAMS */ +#endif + +#ifndef GL_VERSION_4_1 +/* Reuse tokens from ARB_ES2_compatibility */ +/* reuse GL_FIXED */ +/* reuse GL_IMPLEMENTATION_COLOR_READ_TYPE */ +/* reuse GL_IMPLEMENTATION_COLOR_READ_FORMAT */ +/* reuse GL_LOW_FLOAT */ +/* reuse GL_MEDIUM_FLOAT */ +/* reuse GL_HIGH_FLOAT */ +/* reuse GL_LOW_INT */ +/* reuse GL_MEDIUM_INT */ +/* reuse GL_HIGH_INT */ +/* reuse GL_SHADER_COMPILER */ +/* reuse GL_SHADER_BINARY_FORMATS */ +/* reuse GL_NUM_SHADER_BINARY_FORMATS */ +/* reuse GL_MAX_VERTEX_UNIFORM_VECTORS */ +/* reuse GL_MAX_VARYING_VECTORS */ +/* reuse GL_MAX_FRAGMENT_UNIFORM_VECTORS */ +/* reuse GL_RGB565 */ +/* Reuse tokens from ARB_get_program_binary */ +/* reuse GL_PROGRAM_BINARY_RETRIEVABLE_HINT */ +/* reuse GL_PROGRAM_BINARY_LENGTH */ +/* reuse GL_NUM_PROGRAM_BINARY_FORMATS */ +/* reuse GL_PROGRAM_BINARY_FORMATS */ +/* Reuse tokens from ARB_separate_shader_objects */ +/* reuse GL_VERTEX_SHADER_BIT */ +/* reuse GL_FRAGMENT_SHADER_BIT */ +/* reuse GL_GEOMETRY_SHADER_BIT */ +/* reuse GL_TESS_CONTROL_SHADER_BIT */ +/* reuse GL_TESS_EVALUATION_SHADER_BIT */ +/* reuse GL_ALL_SHADER_BITS */ +/* reuse GL_PROGRAM_SEPARABLE */ +/* reuse GL_ACTIVE_PROGRAM */ +/* reuse GL_PROGRAM_PIPELINE_BINDING */ +/* Reuse tokens from ARB_shader_precision (none) */ +/* Reuse tokens from ARB_vertex_attrib_64bit - all are in GL 3.0 and 4.0 already */ +/* Reuse tokens from ARB_viewport_array - some are in GL 1.1 and ARB_provoking_vertex already */ +/* reuse GL_MAX_VIEWPORTS */ +/* reuse GL_VIEWPORT_SUBPIXEL_BITS */ +/* reuse GL_VIEWPORT_BOUNDS_RANGE */ +/* reuse GL_LAYER_PROVOKING_VERTEX */ +/* reuse GL_VIEWPORT_INDEX_PROVOKING_VERTEX */ +/* reuse GL_UNDEFINED_VERTEX */ +#endif + +#ifndef GL_VERSION_4_2 +/* Reuse tokens from ARB_base_instance (none) */ +/* Reuse tokens from ARB_shading_language_420pack (none) */ +/* Reuse tokens from ARB_transform_feedback_instanced (none) */ +/* Reuse tokens from ARB_compressed_texture_pixel_storage */ +/* reuse GL_UNPACK_COMPRESSED_BLOCK_WIDTH */ +/* reuse GL_UNPACK_COMPRESSED_BLOCK_HEIGHT */ +/* reuse GL_UNPACK_COMPRESSED_BLOCK_DEPTH */ +/* reuse GL_UNPACK_COMPRESSED_BLOCK_SIZE */ +/* reuse GL_PACK_COMPRESSED_BLOCK_WIDTH */ +/* reuse GL_PACK_COMPRESSED_BLOCK_HEIGHT */ +/* reuse GL_PACK_COMPRESSED_BLOCK_DEPTH */ +/* reuse GL_PACK_COMPRESSED_BLOCK_SIZE */ +/* Reuse tokens from ARB_conservative_depth (none) */ +/* Reuse tokens from ARB_internalformat_query */ +/* reuse GL_NUM_SAMPLE_COUNTS */ +/* Reuse tokens from ARB_map_buffer_alignment */ +/* reuse GL_MIN_MAP_BUFFER_ALIGNMENT */ +/* Reuse tokens from ARB_shader_atomic_counters */ +/* reuse GL_ATOMIC_COUNTER_BUFFER */ +/* reuse GL_ATOMIC_COUNTER_BUFFER_BINDING */ +/* reuse GL_ATOMIC_COUNTER_BUFFER_START */ +/* reuse GL_ATOMIC_COUNTER_BUFFER_SIZE */ +/* reuse GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE */ +/* reuse GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS */ +/* reuse GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES */ +/* reuse GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER */ +/* reuse GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER */ +/* reuse GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER */ +/* reuse GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER */ +/* reuse GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER */ +/* reuse GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS */ +/* reuse GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS */ +/* reuse GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS */ +/* reuse GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS */ +/* reuse GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS */ +/* reuse GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS */ +/* reuse GL_MAX_VERTEX_ATOMIC_COUNTERS */ +/* reuse GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS */ +/* reuse GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS */ +/* reuse GL_MAX_GEOMETRY_ATOMIC_COUNTERS */ +/* reuse GL_MAX_FRAGMENT_ATOMIC_COUNTERS */ +/* reuse GL_MAX_COMBINED_ATOMIC_COUNTERS */ +/* reuse GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE */ +/* reuse GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS */ +/* reuse GL_ACTIVE_ATOMIC_COUNTER_BUFFERS */ +/* reuse GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX */ +/* reuse GL_UNSIGNED_INT_ATOMIC_COUNTER */ +/* Reuse tokens from ARB_shader_image_load_store */ +/* reuse GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT */ +/* reuse GL_ELEMENT_ARRAY_BARRIER_BIT */ +/* reuse GL_UNIFORM_BARRIER_BIT */ +/* reuse GL_TEXTURE_FETCH_BARRIER_BIT */ +/* reuse GL_SHADER_IMAGE_ACCESS_BARRIER_BIT */ +/* reuse GL_COMMAND_BARRIER_BIT */ +/* reuse GL_PIXEL_BUFFER_BARRIER_BIT */ +/* reuse GL_TEXTURE_UPDATE_BARRIER_BIT */ +/* reuse GL_BUFFER_UPDATE_BARRIER_BIT */ +/* reuse GL_FRAMEBUFFER_BARRIER_BIT */ +/* reuse GL_TRANSFORM_FEEDBACK_BARRIER_BIT */ +/* reuse GL_ATOMIC_COUNTER_BARRIER_BIT */ +/* reuse GL_ALL_BARRIER_BITS */ +/* reuse GL_MAX_IMAGE_UNITS */ +/* reuse GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS */ +/* reuse GL_IMAGE_BINDING_NAME */ +/* reuse GL_IMAGE_BINDING_LEVEL */ +/* reuse GL_IMAGE_BINDING_LAYERED */ +/* reuse GL_IMAGE_BINDING_LAYER */ +/* reuse GL_IMAGE_BINDING_ACCESS */ +/* reuse GL_IMAGE_1D */ +/* reuse GL_IMAGE_2D */ +/* reuse GL_IMAGE_3D */ +/* reuse GL_IMAGE_2D_RECT */ +/* reuse GL_IMAGE_CUBE */ +/* reuse GL_IMAGE_BUFFER */ +/* reuse GL_IMAGE_1D_ARRAY */ +/* reuse GL_IMAGE_2D_ARRAY */ +/* reuse GL_IMAGE_CUBE_MAP_ARRAY */ +/* reuse GL_IMAGE_2D_MULTISAMPLE */ +/* reuse GL_IMAGE_2D_MULTISAMPLE_ARRAY */ +/* reuse GL_INT_IMAGE_1D */ +/* reuse GL_INT_IMAGE_2D */ +/* reuse GL_INT_IMAGE_3D */ +/* reuse GL_INT_IMAGE_2D_RECT */ +/* reuse GL_INT_IMAGE_CUBE */ +/* reuse GL_INT_IMAGE_BUFFER */ +/* reuse GL_INT_IMAGE_1D_ARRAY */ +/* reuse GL_INT_IMAGE_2D_ARRAY */ +/* reuse GL_INT_IMAGE_CUBE_MAP_ARRAY */ +/* reuse GL_INT_IMAGE_2D_MULTISAMPLE */ +/* reuse GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY */ +/* reuse GL_UNSIGNED_INT_IMAGE_1D */ +/* reuse GL_UNSIGNED_INT_IMAGE_2D */ +/* reuse GL_UNSIGNED_INT_IMAGE_3D */ +/* reuse GL_UNSIGNED_INT_IMAGE_2D_RECT */ +/* reuse GL_UNSIGNED_INT_IMAGE_CUBE */ +/* reuse GL_UNSIGNED_INT_IMAGE_BUFFER */ +/* reuse GL_UNSIGNED_INT_IMAGE_1D_ARRAY */ +/* reuse GL_UNSIGNED_INT_IMAGE_2D_ARRAY */ +/* reuse GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY */ +/* reuse GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE */ +/* reuse GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY */ +/* reuse GL_MAX_IMAGE_SAMPLES */ +/* reuse GL_IMAGE_BINDING_FORMAT */ +/* reuse GL_IMAGE_FORMAT_COMPATIBILITY_TYPE */ +/* reuse GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE */ +/* reuse GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS */ +/* reuse GL_MAX_VERTEX_IMAGE_UNIFORMS */ +/* reuse GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS */ +/* reuse GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS */ +/* reuse GL_MAX_GEOMETRY_IMAGE_UNIFORMS */ +/* reuse GL_MAX_FRAGMENT_IMAGE_UNIFORMS */ +/* reuse GL_MAX_COMBINED_IMAGE_UNIFORMS */ +/* Reuse tokens from ARB_shading_language_packing (none) */ +/* Reuse tokens from ARB_texture_storage */ +/* reuse GL_TEXTURE_IMMUTABLE_FORMAT */ +#endif + +#ifndef GL_VERSION_4_3 +#define GL_NUM_SHADING_LANGUAGE_VERSIONS 0x82E9 +#define GL_VERTEX_ATTRIB_ARRAY_LONG 0x874E +/* Reuse tokens from ARB_arrays_of_arrays (none, GLSL only) */ +/* Reuse tokens from ARB_fragment_layer_viewport (none, GLSL only) */ +/* Reuse tokens from ARB_shader_image_size (none, GLSL only) */ +/* Reuse tokens from ARB_ES3_compatibility */ +/* reuse GL_COMPRESSED_RGB8_ETC2 */ +/* reuse GL_COMPRESSED_SRGB8_ETC2 */ +/* reuse GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 */ +/* reuse GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 */ +/* reuse GL_COMPRESSED_RGBA8_ETC2_EAC */ +/* reuse GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC */ +/* reuse GL_COMPRESSED_R11_EAC */ +/* reuse GL_COMPRESSED_SIGNED_R11_EAC */ +/* reuse GL_COMPRESSED_RG11_EAC */ +/* reuse GL_COMPRESSED_SIGNED_RG11_EAC */ +/* reuse GL_PRIMITIVE_RESTART_FIXED_INDEX */ +/* reuse GL_ANY_SAMPLES_PASSED_CONSERVATIVE */ +/* reuse GL_MAX_ELEMENT_INDEX */ +/* Reuse tokens from ARB_clear_buffer_object (none) */ +/* Reuse tokens from ARB_compute_shader */ +/* reuse GL_COMPUTE_SHADER */ +/* reuse GL_MAX_COMPUTE_UNIFORM_BLOCKS */ +/* reuse GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS */ +/* reuse GL_MAX_COMPUTE_IMAGE_UNIFORMS */ +/* reuse GL_MAX_COMPUTE_SHARED_MEMORY_SIZE */ +/* reuse GL_MAX_COMPUTE_UNIFORM_COMPONENTS */ +/* reuse GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS */ +/* reuse GL_MAX_COMPUTE_ATOMIC_COUNTERS */ +/* reuse GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS */ +/* reuse GL_MAX_COMPUTE_LOCAL_INVOCATIONS */ +/* reuse GL_MAX_COMPUTE_WORK_GROUP_COUNT */ +/* reuse GL_MAX_COMPUTE_WORK_GROUP_SIZE */ +/* reuse GL_COMPUTE_LOCAL_WORK_SIZE */ +/* reuse GL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER */ +/* reuse GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER */ +/* reuse GL_DISPATCH_INDIRECT_BUFFER */ +/* reuse GL_DISPATCH_INDIRECT_BUFFER_BINDING */ +/* Reuse tokens from ARB_copy_image (none) */ +/* Reuse tokens from KHR_debug */ +/* reuse GL_DEBUG_OUTPUT_SYNCHRONOUS */ +/* reuse GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH */ +/* reuse GL_DEBUG_CALLBACK_FUNCTION */ +/* reuse GL_DEBUG_CALLBACK_USER_PARAM */ +/* reuse GL_DEBUG_SOURCE_API */ +/* reuse GL_DEBUG_SOURCE_WINDOW_SYSTEM */ +/* reuse GL_DEBUG_SOURCE_SHADER_COMPILER */ +/* reuse GL_DEBUG_SOURCE_THIRD_PARTY */ +/* reuse GL_DEBUG_SOURCE_APPLICATION */ +/* reuse GL_DEBUG_SOURCE_OTHER */ +/* reuse GL_DEBUG_TYPE_ERROR */ +/* reuse GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR */ +/* reuse GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR */ +/* reuse GL_DEBUG_TYPE_PORTABILITY */ +/* reuse GL_DEBUG_TYPE_PERFORMANCE */ +/* reuse GL_DEBUG_TYPE_OTHER */ +/* reuse GL_MAX_DEBUG_MESSAGE_LENGTH */ +/* reuse GL_MAX_DEBUG_LOGGED_MESSAGES */ +/* reuse GL_DEBUG_LOGGED_MESSAGES */ +/* reuse GL_DEBUG_SEVERITY_HIGH */ +/* reuse GL_DEBUG_SEVERITY_MEDIUM */ +/* reuse GL_DEBUG_SEVERITY_LOW */ +/* reuse GL_DEBUG_TYPE_MARKER */ +/* reuse GL_DEBUG_TYPE_PUSH_GROUP */ +/* reuse GL_DEBUG_TYPE_POP_GROUP */ +/* reuse GL_DEBUG_SEVERITY_NOTIFICATION */ +/* reuse GL_MAX_DEBUG_GROUP_STACK_DEPTH */ +/* reuse GL_DEBUG_GROUP_STACK_DEPTH */ +/* reuse GL_BUFFER */ +/* reuse GL_SHADER */ +/* reuse GL_PROGRAM */ +/* reuse GL_QUERY */ +/* reuse GL_PROGRAM_PIPELINE */ +/* reuse GL_SAMPLER */ +/* reuse GL_DISPLAY_LIST */ +/* reuse GL_MAX_LABEL_LENGTH */ +/* reuse GL_DEBUG_OUTPUT */ +/* reuse GL_CONTEXT_FLAG_DEBUG_BIT */ +/* reuse GL_STACK_UNDERFLOW */ +/* reuse GL_STACK_OVERFLOW */ +/* Reuse tokens from ARB_explicit_uniform_location */ +/* reuse GL_MAX_UNIFORM_LOCATIONS */ +/* Reuse tokens from ARB_framebuffer_no_attachments */ +/* reuse GL_FRAMEBUFFER_DEFAULT_WIDTH */ +/* reuse GL_FRAMEBUFFER_DEFAULT_HEIGHT */ +/* reuse GL_FRAMEBUFFER_DEFAULT_LAYERS */ +/* reuse GL_FRAMEBUFFER_DEFAULT_SAMPLES */ +/* reuse GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS */ +/* reuse GL_MAX_FRAMEBUFFER_WIDTH */ +/* reuse GL_MAX_FRAMEBUFFER_HEIGHT */ +/* reuse GL_MAX_FRAMEBUFFER_LAYERS */ +/* reuse GL_MAX_FRAMEBUFFER_SAMPLES */ +/* Reuse tokens from ARB_internalformat_query2 */ +/* reuse GL_INTERNALFORMAT_SUPPORTED */ +/* reuse GL_INTERNALFORMAT_PREFERRED */ +/* reuse GL_INTERNALFORMAT_RED_SIZE */ +/* reuse GL_INTERNALFORMAT_GREEN_SIZE */ +/* reuse GL_INTERNALFORMAT_BLUE_SIZE */ +/* reuse GL_INTERNALFORMAT_ALPHA_SIZE */ +/* reuse GL_INTERNALFORMAT_DEPTH_SIZE */ +/* reuse GL_INTERNALFORMAT_STENCIL_SIZE */ +/* reuse GL_INTERNALFORMAT_SHARED_SIZE */ +/* reuse GL_INTERNALFORMAT_RED_TYPE */ +/* reuse GL_INTERNALFORMAT_GREEN_TYPE */ +/* reuse GL_INTERNALFORMAT_BLUE_TYPE */ +/* reuse GL_INTERNALFORMAT_ALPHA_TYPE */ +/* reuse GL_INTERNALFORMAT_DEPTH_TYPE */ +/* reuse GL_INTERNALFORMAT_STENCIL_TYPE */ +/* reuse GL_MAX_WIDTH */ +/* reuse GL_MAX_HEIGHT */ +/* reuse GL_MAX_DEPTH */ +/* reuse GL_MAX_LAYERS */ +/* reuse GL_MAX_COMBINED_DIMENSIONS */ +/* reuse GL_COLOR_COMPONENTS */ +/* reuse GL_DEPTH_COMPONENTS */ +/* reuse GL_STENCIL_COMPONENTS */ +/* reuse GL_COLOR_RENDERABLE */ +/* reuse GL_DEPTH_RENDERABLE */ +/* reuse GL_STENCIL_RENDERABLE */ +/* reuse GL_FRAMEBUFFER_RENDERABLE */ +/* reuse GL_FRAMEBUFFER_RENDERABLE_LAYERED */ +/* reuse GL_FRAMEBUFFER_BLEND */ +/* reuse GL_READ_PIXELS */ +/* reuse GL_READ_PIXELS_FORMAT */ +/* reuse GL_READ_PIXELS_TYPE */ +/* reuse GL_TEXTURE_IMAGE_FORMAT */ +/* reuse GL_TEXTURE_IMAGE_TYPE */ +/* reuse GL_GET_TEXTURE_IMAGE_FORMAT */ +/* reuse GL_GET_TEXTURE_IMAGE_TYPE */ +/* reuse GL_MIPMAP */ +/* reuse GL_MANUAL_GENERATE_MIPMAP */ +/* reuse GL_AUTO_GENERATE_MIPMAP */ +/* reuse GL_COLOR_ENCODING */ +/* reuse GL_SRGB_READ */ +/* reuse GL_SRGB_WRITE */ +/* reuse GL_FILTER */ +/* reuse GL_VERTEX_TEXTURE */ +/* reuse GL_TESS_CONTROL_TEXTURE */ +/* reuse GL_TESS_EVALUATION_TEXTURE */ +/* reuse GL_GEOMETRY_TEXTURE */ +/* reuse GL_FRAGMENT_TEXTURE */ +/* reuse GL_COMPUTE_TEXTURE */ +/* reuse GL_TEXTURE_SHADOW */ +/* reuse GL_TEXTURE_GATHER */ +/* reuse GL_TEXTURE_GATHER_SHADOW */ +/* reuse GL_SHADER_IMAGE_LOAD */ +/* reuse GL_SHADER_IMAGE_STORE */ +/* reuse GL_SHADER_IMAGE_ATOMIC */ +/* reuse GL_IMAGE_TEXEL_SIZE */ +/* reuse GL_IMAGE_COMPATIBILITY_CLASS */ +/* reuse GL_IMAGE_PIXEL_FORMAT */ +/* reuse GL_IMAGE_PIXEL_TYPE */ +/* reuse GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST */ +/* reuse GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST */ +/* reuse GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE */ +/* reuse GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_WRITE */ +/* reuse GL_TEXTURE_COMPRESSED_BLOCK_WIDTH */ +/* reuse GL_TEXTURE_COMPRESSED_BLOCK_HEIGHT */ +/* reuse GL_TEXTURE_COMPRESSED_BLOCK_SIZE */ +/* reuse GL_CLEAR_BUFFER */ +/* reuse GL_TEXTURE_VIEW */ +/* reuse GL_VIEW_COMPATIBILITY_CLASS */ +/* reuse GL_FULL_SUPPORT */ +/* reuse GL_CAVEAT_SUPPORT */ +/* reuse GL_IMAGE_CLASS_4_X_32 */ +/* reuse GL_IMAGE_CLASS_2_X_32 */ +/* reuse GL_IMAGE_CLASS_1_X_32 */ +/* reuse GL_IMAGE_CLASS_4_X_16 */ +/* reuse GL_IMAGE_CLASS_2_X_16 */ +/* reuse GL_IMAGE_CLASS_1_X_16 */ +/* reuse GL_IMAGE_CLASS_4_X_8 */ +/* reuse GL_IMAGE_CLASS_2_X_8 */ +/* reuse GL_IMAGE_CLASS_1_X_8 */ +/* reuse GL_IMAGE_CLASS_11_11_10 */ +/* reuse GL_IMAGE_CLASS_10_10_10_2 */ +/* reuse GL_VIEW_CLASS_128_BITS */ +/* reuse GL_VIEW_CLASS_96_BITS */ +/* reuse GL_VIEW_CLASS_64_BITS */ +/* reuse GL_VIEW_CLASS_48_BITS */ +/* reuse GL_VIEW_CLASS_32_BITS */ +/* reuse GL_VIEW_CLASS_24_BITS */ +/* reuse GL_VIEW_CLASS_16_BITS */ +/* reuse GL_VIEW_CLASS_8_BITS */ +/* reuse GL_VIEW_CLASS_S3TC_DXT1_RGB */ +/* reuse GL_VIEW_CLASS_S3TC_DXT1_RGBA */ +/* reuse GL_VIEW_CLASS_S3TC_DXT3_RGBA */ +/* reuse GL_VIEW_CLASS_S3TC_DXT5_RGBA */ +/* reuse GL_VIEW_CLASS_RGTC1_RED */ +/* reuse GL_VIEW_CLASS_RGTC2_RG */ +/* reuse GL_VIEW_CLASS_BPTC_UNORM */ +/* reuse GL_VIEW_CLASS_BPTC_FLOAT */ +/* Reuse tokens from ARB_invalidate_subdata (none) */ +/* Reuse tokens from ARB_multi_draw_indirect (none) */ +/* Reuse tokens from ARB_program_interface_query */ +/* reuse GL_UNIFORM */ +/* reuse GL_UNIFORM_BLOCK */ +/* reuse GL_PROGRAM_INPUT */ +/* reuse GL_PROGRAM_OUTPUT */ +/* reuse GL_BUFFER_VARIABLE */ +/* reuse GL_SHADER_STORAGE_BLOCK */ +/* reuse GL_VERTEX_SUBROUTINE */ +/* reuse GL_TESS_CONTROL_SUBROUTINE */ +/* reuse GL_TESS_EVALUATION_SUBROUTINE */ +/* reuse GL_GEOMETRY_SUBROUTINE */ +/* reuse GL_FRAGMENT_SUBROUTINE */ +/* reuse GL_COMPUTE_SUBROUTINE */ +/* reuse GL_VERTEX_SUBROUTINE_UNIFORM */ +/* reuse GL_TESS_CONTROL_SUBROUTINE_UNIFORM */ +/* reuse GL_TESS_EVALUATION_SUBROUTINE_UNIFORM */ +/* reuse GL_GEOMETRY_SUBROUTINE_UNIFORM */ +/* reuse GL_FRAGMENT_SUBROUTINE_UNIFORM */ +/* reuse GL_COMPUTE_SUBROUTINE_UNIFORM */ +/* reuse GL_TRANSFORM_FEEDBACK_VARYING */ +/* reuse GL_ACTIVE_RESOURCES */ +/* reuse GL_MAX_NAME_LENGTH */ +/* reuse GL_MAX_NUM_ACTIVE_VARIABLES */ +/* reuse GL_MAX_NUM_COMPATIBLE_SUBROUTINES */ +/* reuse GL_NAME_LENGTH */ +/* reuse GL_TYPE */ +/* reuse GL_ARRAY_SIZE */ +/* reuse GL_OFFSET */ +/* reuse GL_BLOCK_INDEX */ +/* reuse GL_ARRAY_STRIDE */ +/* reuse GL_MATRIX_STRIDE */ +/* reuse GL_IS_ROW_MAJOR */ +/* reuse GL_ATOMIC_COUNTER_BUFFER_INDEX */ +/* reuse GL_BUFFER_BINDING */ +/* reuse GL_BUFFER_DATA_SIZE */ +/* reuse GL_NUM_ACTIVE_VARIABLES */ +/* reuse GL_ACTIVE_VARIABLES */ +/* reuse GL_REFERENCED_BY_VERTEX_SHADER */ +/* reuse GL_REFERENCED_BY_TESS_CONTROL_SHADER */ +/* reuse GL_REFERENCED_BY_TESS_EVALUATION_SHADER */ +/* reuse GL_REFERENCED_BY_GEOMETRY_SHADER */ +/* reuse GL_REFERENCED_BY_FRAGMENT_SHADER */ +/* reuse GL_REFERENCED_BY_COMPUTE_SHADER */ +/* reuse GL_TOP_LEVEL_ARRAY_SIZE */ +/* reuse GL_TOP_LEVEL_ARRAY_STRIDE */ +/* reuse GL_LOCATION */ +/* reuse GL_LOCATION_INDEX */ +/* reuse GL_IS_PER_PATCH */ +/* Reuse tokens from ARB_robust_buffer_access_behavior (none) */ +/* Reuse tokens from ARB_shader_storage_buffer_object */ +/* reuse GL_SHADER_STORAGE_BUFFER */ +/* reuse GL_SHADER_STORAGE_BUFFER_BINDING */ +/* reuse GL_SHADER_STORAGE_BUFFER_START */ +/* reuse GL_SHADER_STORAGE_BUFFER_SIZE */ +/* reuse GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS */ +/* reuse GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS */ +/* reuse GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS */ +/* reuse GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS */ +/* reuse GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS */ +/* reuse GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS */ +/* reuse GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS */ +/* reuse GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS */ +/* reuse GL_MAX_SHADER_STORAGE_BLOCK_SIZE */ +/* reuse GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT */ +/* reuse GL_SHADER_STORAGE_BARRIER_BIT */ +/* reuse GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES */ +/* Reuse tokens from ARB_stencil_texturing */ +/* reuse GL_DEPTH_STENCIL_TEXTURE_MODE */ +/* Reuse tokens from ARB_texture_buffer_range */ +/* reuse GL_TEXTURE_BUFFER_OFFSET */ +/* reuse GL_TEXTURE_BUFFER_SIZE */ +/* reuse GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT */ +/* Reuse tokens from ARB_texture_query_levels (none) */ +/* Reuse tokens from ARB_texture_storage_multisample (none) */ +/* Reuse tokens from ARB_texture_view */ +/* reuse GL_TEXTURE_VIEW_MIN_LEVEL */ +/* reuse GL_TEXTURE_VIEW_NUM_LEVELS */ +/* reuse GL_TEXTURE_VIEW_MIN_LAYER */ +/* reuse GL_TEXTURE_VIEW_NUM_LAYERS */ +/* reuse GL_TEXTURE_IMMUTABLE_LEVELS */ +/* Reuse tokens from ARB_vertex_attrib_binding */ +/* reuse GL_VERTEX_ATTRIB_BINDING */ +/* reuse GL_VERTEX_ATTRIB_RELATIVE_OFFSET */ +/* reuse GL_VERTEX_BINDING_DIVISOR */ +/* reuse GL_VERTEX_BINDING_OFFSET */ +/* reuse GL_VERTEX_BINDING_STRIDE */ +/* reuse GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET */ +/* reuse GL_MAX_VERTEX_ATTRIB_BINDINGS */ +#endif + +#ifndef GL_ARB_depth_buffer_float +#define GL_DEPTH_COMPONENT32F 0x8CAC +#define GL_DEPTH32F_STENCIL8 0x8CAD +#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD +#endif + +#ifndef GL_ARB_framebuffer_object +#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 +#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210 +#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211 +#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212 +#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213 +#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214 +#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215 +#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216 +#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217 +#define GL_FRAMEBUFFER_DEFAULT 0x8218 +#define GL_FRAMEBUFFER_UNDEFINED 0x8219 +#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A +#define GL_MAX_RENDERBUFFER_SIZE 0x84E8 +#define GL_DEPTH_STENCIL 0x84F9 +#define GL_UNSIGNED_INT_24_8 0x84FA +#define GL_DEPTH24_STENCIL8 0x88F0 +#define GL_TEXTURE_STENCIL_SIZE 0x88F1 +#define GL_TEXTURE_RED_TYPE 0x8C10 +#define GL_TEXTURE_GREEN_TYPE 0x8C11 +#define GL_TEXTURE_BLUE_TYPE 0x8C12 +#define GL_TEXTURE_ALPHA_TYPE 0x8C13 +#define GL_TEXTURE_DEPTH_TYPE 0x8C16 +#define GL_UNSIGNED_NORMALIZED 0x8C17 +#define GL_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_DRAW_FRAMEBUFFER_BINDING GL_FRAMEBUFFER_BINDING +#define GL_RENDERBUFFER_BINDING 0x8CA7 +#define GL_READ_FRAMEBUFFER 0x8CA8 +#define GL_DRAW_FRAMEBUFFER 0x8CA9 +#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA +#define GL_RENDERBUFFER_SAMPLES 0x8CAB +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4 +#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 +#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB +#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC +#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD +#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF +#define GL_COLOR_ATTACHMENT0 0x8CE0 +#define GL_COLOR_ATTACHMENT1 0x8CE1 +#define GL_COLOR_ATTACHMENT2 0x8CE2 +#define GL_COLOR_ATTACHMENT3 0x8CE3 +#define GL_COLOR_ATTACHMENT4 0x8CE4 +#define GL_COLOR_ATTACHMENT5 0x8CE5 +#define GL_COLOR_ATTACHMENT6 0x8CE6 +#define GL_COLOR_ATTACHMENT7 0x8CE7 +#define GL_COLOR_ATTACHMENT8 0x8CE8 +#define GL_COLOR_ATTACHMENT9 0x8CE9 +#define GL_COLOR_ATTACHMENT10 0x8CEA +#define GL_COLOR_ATTACHMENT11 0x8CEB +#define GL_COLOR_ATTACHMENT12 0x8CEC +#define GL_COLOR_ATTACHMENT13 0x8CED +#define GL_COLOR_ATTACHMENT14 0x8CEE +#define GL_COLOR_ATTACHMENT15 0x8CEF +#define GL_DEPTH_ATTACHMENT 0x8D00 +#define GL_STENCIL_ATTACHMENT 0x8D20 +#define GL_FRAMEBUFFER 0x8D40 +#define GL_RENDERBUFFER 0x8D41 +#define GL_RENDERBUFFER_WIDTH 0x8D42 +#define GL_RENDERBUFFER_HEIGHT 0x8D43 +#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 +#define GL_STENCIL_INDEX1 0x8D46 +#define GL_STENCIL_INDEX4 0x8D47 +#define GL_STENCIL_INDEX8 0x8D48 +#define GL_STENCIL_INDEX16 0x8D49 +#define GL_RENDERBUFFER_RED_SIZE 0x8D50 +#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 +#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 +#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 +#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 +#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 +#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 +#define GL_MAX_SAMPLES 0x8D57 +#endif + +#ifndef GL_ARB_framebuffer_sRGB +#define GL_FRAMEBUFFER_SRGB 0x8DB9 +#endif + +#ifndef GL_ARB_half_float_vertex +#define GL_HALF_FLOAT 0x140B +#endif + +#ifndef GL_ARB_map_buffer_range +#define GL_MAP_READ_BIT 0x0001 +#define GL_MAP_WRITE_BIT 0x0002 +#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004 +#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 +#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010 +#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020 +#endif + +#ifndef GL_ARB_texture_compression_rgtc +#define GL_COMPRESSED_RED_RGTC1 0x8DBB +#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC +#define GL_COMPRESSED_RG_RGTC2 0x8DBD +#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE +#endif + +#ifndef GL_ARB_texture_rg +#define GL_RG 0x8227 +#define GL_RG_INTEGER 0x8228 +#define GL_R8 0x8229 +#define GL_R16 0x822A +#define GL_RG8 0x822B +#define GL_RG16 0x822C +#define GL_R16F 0x822D +#define GL_R32F 0x822E +#define GL_RG16F 0x822F +#define GL_RG32F 0x8230 +#define GL_R8I 0x8231 +#define GL_R8UI 0x8232 +#define GL_R16I 0x8233 +#define GL_R16UI 0x8234 +#define GL_R32I 0x8235 +#define GL_R32UI 0x8236 +#define GL_RG8I 0x8237 +#define GL_RG8UI 0x8238 +#define GL_RG16I 0x8239 +#define GL_RG16UI 0x823A +#define GL_RG32I 0x823B +#define GL_RG32UI 0x823C +#endif + +#ifndef GL_ARB_vertex_array_object +#define GL_VERTEX_ARRAY_BINDING 0x85B5 +#endif + +#ifndef GL_ARB_uniform_buffer_object +#define GL_UNIFORM_BUFFER 0x8A11 +#define GL_UNIFORM_BUFFER_BINDING 0x8A28 +#define GL_UNIFORM_BUFFER_START 0x8A29 +#define GL_UNIFORM_BUFFER_SIZE 0x8A2A +#define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B +#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C +#define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D +#define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E +#define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F +#define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30 +#define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31 +#define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32 +#define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33 +#define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34 +#define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35 +#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36 +#define GL_UNIFORM_TYPE 0x8A37 +#define GL_UNIFORM_SIZE 0x8A38 +#define GL_UNIFORM_NAME_LENGTH 0x8A39 +#define GL_UNIFORM_BLOCK_INDEX 0x8A3A +#define GL_UNIFORM_OFFSET 0x8A3B +#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C +#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D +#define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E +#define GL_UNIFORM_BLOCK_BINDING 0x8A3F +#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40 +#define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41 +#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42 +#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46 +#define GL_INVALID_INDEX 0xFFFFFFFFu +#endif + +#ifndef GL_ARB_copy_buffer +#define GL_COPY_READ_BUFFER_BINDING 0x8F36 +#define GL_COPY_READ_BUFFER GL_COPY_READ_BUFFER_BINDING +#define GL_COPY_WRITE_BUFFER_BINDING 0x8F37 +#define GL_COPY_WRITE_BUFFER GL_COPY_WRITE_BUFFER_BINDING +#endif + +#ifndef GL_ARB_depth_clamp +#define GL_DEPTH_CLAMP 0x864F +#endif + +#ifndef GL_ARB_draw_elements_base_vertex +#endif + +#ifndef GL_ARB_fragment_coord_conventions +#endif + +#ifndef GL_ARB_provoking_vertex +#define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION 0x8E4C +#define GL_FIRST_VERTEX_CONVENTION 0x8E4D +#define GL_LAST_VERTEX_CONVENTION 0x8E4E +#define GL_PROVOKING_VERTEX 0x8E4F +#endif + +#ifndef GL_ARB_seamless_cube_map +#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F +#endif + +#ifndef GL_ARB_sync +#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111 +#define GL_OBJECT_TYPE 0x9112 +#define GL_SYNC_CONDITION 0x9113 +#define GL_SYNC_STATUS 0x9114 +#define GL_SYNC_FLAGS 0x9115 +#define GL_SYNC_FENCE 0x9116 +#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 +#define GL_UNSIGNALED 0x9118 +#define GL_SIGNALED 0x9119 +#define GL_ALREADY_SIGNALED 0x911A +#define GL_TIMEOUT_EXPIRED 0x911B +#define GL_CONDITION_SATISFIED 0x911C +#define GL_WAIT_FAILED 0x911D +#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 +#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull +#endif + +#ifndef GL_ARB_texture_multisample +#define GL_SAMPLE_POSITION 0x8E50 +#define GL_SAMPLE_MASK 0x8E51 +#define GL_SAMPLE_MASK_VALUE 0x8E52 +#define GL_MAX_SAMPLE_MASK_WORDS 0x8E59 +#define GL_TEXTURE_2D_MULTISAMPLE 0x9100 +#define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101 +#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102 +#define GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103 +#define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104 +#define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105 +#define GL_TEXTURE_SAMPLES 0x9106 +#define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107 +#define GL_SAMPLER_2D_MULTISAMPLE 0x9108 +#define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109 +#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A +#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B +#define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C +#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D +#define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E +#define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F +#define GL_MAX_INTEGER_SAMPLES 0x9110 +#endif + +#ifndef GL_ARB_vertex_array_bgra +/* reuse GL_BGRA */ +#endif + +#ifndef GL_ARB_draw_buffers_blend +#endif + +#ifndef GL_ARB_sample_shading +#define GL_SAMPLE_SHADING_ARB 0x8C36 +#define GL_MIN_SAMPLE_SHADING_VALUE_ARB 0x8C37 +#endif + +#ifndef GL_ARB_texture_cube_map_array +#define GL_TEXTURE_CUBE_MAP_ARRAY_ARB 0x9009 +#define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY_ARB 0x900A +#define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY_ARB 0x900B +#define GL_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900C +#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_ARB 0x900D +#define GL_INT_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900E +#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900F +#endif + +#ifndef GL_ARB_texture_gather +#define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET_ARB 0x8E5E +#define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET_ARB 0x8E5F +#define GL_MAX_PROGRAM_TEXTURE_GATHER_COMPONENTS_ARB 0x8F9F +#endif + +#ifndef GL_ARB_texture_query_lod +#endif + +#ifndef GL_ARB_shading_language_include +#define GL_SHADER_INCLUDE_ARB 0x8DAE +#define GL_NAMED_STRING_LENGTH_ARB 0x8DE9 +#define GL_NAMED_STRING_TYPE_ARB 0x8DEA +#endif + +#ifndef GL_ARB_texture_compression_bptc +#define GL_COMPRESSED_RGBA_BPTC_UNORM_ARB 0x8E8C +#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB 0x8E8D +#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB 0x8E8E +#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB 0x8E8F +#endif + +#ifndef GL_ARB_blend_func_extended +#define GL_SRC1_COLOR 0x88F9 +/* reuse GL_SRC1_ALPHA */ +#define GL_ONE_MINUS_SRC1_COLOR 0x88FA +#define GL_ONE_MINUS_SRC1_ALPHA 0x88FB +#define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS 0x88FC +#endif + +#ifndef GL_ARB_explicit_attrib_location +#endif + +#ifndef GL_ARB_occlusion_query2 +#define GL_ANY_SAMPLES_PASSED 0x8C2F +#endif + +#ifndef GL_ARB_sampler_objects +#define GL_SAMPLER_BINDING 0x8919 +#endif + +#ifndef GL_ARB_shader_bit_encoding +#endif + +#ifndef GL_ARB_texture_rgb10_a2ui +#define GL_RGB10_A2UI 0x906F +#endif + +#ifndef GL_ARB_texture_swizzle +#define GL_TEXTURE_SWIZZLE_R 0x8E42 +#define GL_TEXTURE_SWIZZLE_G 0x8E43 +#define GL_TEXTURE_SWIZZLE_B 0x8E44 +#define GL_TEXTURE_SWIZZLE_A 0x8E45 +#define GL_TEXTURE_SWIZZLE_RGBA 0x8E46 +#endif + +#ifndef GL_ARB_timer_query +#define GL_TIME_ELAPSED 0x88BF +#define GL_TIMESTAMP 0x8E28 +#endif + +#ifndef GL_ARB_vertex_type_2_10_10_10_rev +/* reuse GL_UNSIGNED_INT_2_10_10_10_REV */ +#define GL_INT_2_10_10_10_REV 0x8D9F +#endif + +#ifndef GL_ARB_draw_indirect +#define GL_DRAW_INDIRECT_BUFFER 0x8F3F +#define GL_DRAW_INDIRECT_BUFFER_BINDING 0x8F43 +#endif + +#ifndef GL_ARB_gpu_shader5 +#define GL_GEOMETRY_SHADER_INVOCATIONS 0x887F +#define GL_MAX_GEOMETRY_SHADER_INVOCATIONS 0x8E5A +#define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET 0x8E5B +#define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET 0x8E5C +#define GL_FRAGMENT_INTERPOLATION_OFFSET_BITS 0x8E5D +/* reuse GL_MAX_VERTEX_STREAMS */ +#endif + +#ifndef GL_ARB_gpu_shader_fp64 +/* reuse GL_DOUBLE */ +#define GL_DOUBLE_VEC2 0x8FFC +#define GL_DOUBLE_VEC3 0x8FFD +#define GL_DOUBLE_VEC4 0x8FFE +#define GL_DOUBLE_MAT2 0x8F46 +#define GL_DOUBLE_MAT3 0x8F47 +#define GL_DOUBLE_MAT4 0x8F48 +#define GL_DOUBLE_MAT2x3 0x8F49 +#define GL_DOUBLE_MAT2x4 0x8F4A +#define GL_DOUBLE_MAT3x2 0x8F4B +#define GL_DOUBLE_MAT3x4 0x8F4C +#define GL_DOUBLE_MAT4x2 0x8F4D +#define GL_DOUBLE_MAT4x3 0x8F4E +#endif + +#ifndef GL_ARB_shader_subroutine +#define GL_ACTIVE_SUBROUTINES 0x8DE5 +#define GL_ACTIVE_SUBROUTINE_UNIFORMS 0x8DE6 +#define GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS 0x8E47 +#define GL_ACTIVE_SUBROUTINE_MAX_LENGTH 0x8E48 +#define GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH 0x8E49 +#define GL_MAX_SUBROUTINES 0x8DE7 +#define GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS 0x8DE8 +#define GL_NUM_COMPATIBLE_SUBROUTINES 0x8E4A +#define GL_COMPATIBLE_SUBROUTINES 0x8E4B +/* reuse GL_UNIFORM_SIZE */ +/* reuse GL_UNIFORM_NAME_LENGTH */ +#endif + +#ifndef GL_ARB_tessellation_shader +#define GL_PATCHES 0x000E +#define GL_PATCH_VERTICES 0x8E72 +#define GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73 +#define GL_PATCH_DEFAULT_OUTER_LEVEL 0x8E74 +#define GL_TESS_CONTROL_OUTPUT_VERTICES 0x8E75 +#define GL_TESS_GEN_MODE 0x8E76 +#define GL_TESS_GEN_SPACING 0x8E77 +#define GL_TESS_GEN_VERTEX_ORDER 0x8E78 +#define GL_TESS_GEN_POINT_MODE 0x8E79 +/* reuse GL_TRIANGLES */ +/* reuse GL_QUADS */ +#define GL_ISOLINES 0x8E7A +/* reuse GL_EQUAL */ +#define GL_FRACTIONAL_ODD 0x8E7B +#define GL_FRACTIONAL_EVEN 0x8E7C +/* reuse GL_CCW */ +/* reuse GL_CW */ +#define GL_MAX_PATCH_VERTICES 0x8E7D +#define GL_MAX_TESS_GEN_LEVEL 0x8E7E +#define GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E7F +#define GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E80 +#define GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS 0x8E81 +#define GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS 0x8E82 +#define GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS 0x8E83 +#define GL_MAX_TESS_PATCH_COMPONENTS 0x8E84 +#define GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS 0x8E85 +#define GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS 0x8E86 +#define GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS 0x8E89 +#define GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS 0x8E8A +#define GL_MAX_TESS_CONTROL_INPUT_COMPONENTS 0x886C +#define GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS 0x886D +#define GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E1E +#define GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E1F +#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER 0x84F0 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER 0x84F1 +#define GL_TESS_EVALUATION_SHADER 0x8E87 +#define GL_TESS_CONTROL_SHADER 0x8E88 +#endif + +#ifndef GL_ARB_texture_buffer_object_rgb32 +/* reuse GL_RGB32F */ +/* reuse GL_RGB32UI */ +/* reuse GL_RGB32I */ +#endif + +#ifndef GL_ARB_transform_feedback2 +#define GL_TRANSFORM_FEEDBACK 0x8E22 +#define GL_TRANSFORM_FEEDBACK_PAUSED 0x8E23 +#define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED GL_TRANSFORM_FEEDBACK_PAUSED +#define GL_TRANSFORM_FEEDBACK_ACTIVE 0x8E24 +#define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE GL_TRANSFORM_FEEDBACK_ACTIVE +#define GL_TRANSFORM_FEEDBACK_BINDING 0x8E25 +#endif + +#ifndef GL_ARB_transform_feedback3 +#define GL_MAX_TRANSFORM_FEEDBACK_BUFFERS 0x8E70 +#define GL_MAX_VERTEX_STREAMS 0x8E71 +#endif + +#ifndef GL_ARB_ES2_compatibility +#define GL_FIXED 0x140C +#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A +#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B +#define GL_LOW_FLOAT 0x8DF0 +#define GL_MEDIUM_FLOAT 0x8DF1 +#define GL_HIGH_FLOAT 0x8DF2 +#define GL_LOW_INT 0x8DF3 +#define GL_MEDIUM_INT 0x8DF4 +#define GL_HIGH_INT 0x8DF5 +#define GL_SHADER_COMPILER 0x8DFA +#define GL_SHADER_BINARY_FORMATS 0x8DF8 +#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9 +#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB +#define GL_MAX_VARYING_VECTORS 0x8DFC +#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD +#define GL_RGB565 0x8D62 +#endif + +#ifndef GL_ARB_get_program_binary +#define GL_PROGRAM_BINARY_RETRIEVABLE_HINT 0x8257 +#define GL_PROGRAM_BINARY_LENGTH 0x8741 +#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE +#define GL_PROGRAM_BINARY_FORMATS 0x87FF +#endif + +#ifndef GL_ARB_separate_shader_objects +#define GL_VERTEX_SHADER_BIT 0x00000001 +#define GL_FRAGMENT_SHADER_BIT 0x00000002 +#define GL_GEOMETRY_SHADER_BIT 0x00000004 +#define GL_TESS_CONTROL_SHADER_BIT 0x00000008 +#define GL_TESS_EVALUATION_SHADER_BIT 0x00000010 +#define GL_ALL_SHADER_BITS 0xFFFFFFFF +#define GL_PROGRAM_SEPARABLE 0x8258 +#define GL_ACTIVE_PROGRAM 0x8259 +#define GL_PROGRAM_PIPELINE_BINDING 0x825A +#endif + +#ifndef GL_ARB_shader_precision +#endif + +#ifndef GL_ARB_vertex_attrib_64bit +/* reuse GL_RGB32I */ +/* reuse GL_DOUBLE_VEC2 */ +/* reuse GL_DOUBLE_VEC3 */ +/* reuse GL_DOUBLE_VEC4 */ +/* reuse GL_DOUBLE_MAT2 */ +/* reuse GL_DOUBLE_MAT3 */ +/* reuse GL_DOUBLE_MAT4 */ +/* reuse GL_DOUBLE_MAT2x3 */ +/* reuse GL_DOUBLE_MAT2x4 */ +/* reuse GL_DOUBLE_MAT3x2 */ +/* reuse GL_DOUBLE_MAT3x4 */ +/* reuse GL_DOUBLE_MAT4x2 */ +/* reuse GL_DOUBLE_MAT4x3 */ +#endif + +#ifndef GL_ARB_viewport_array +/* reuse GL_SCISSOR_BOX */ +/* reuse GL_VIEWPORT */ +/* reuse GL_DEPTH_RANGE */ +/* reuse GL_SCISSOR_TEST */ +#define GL_MAX_VIEWPORTS 0x825B +#define GL_VIEWPORT_SUBPIXEL_BITS 0x825C +#define GL_VIEWPORT_BOUNDS_RANGE 0x825D +#define GL_LAYER_PROVOKING_VERTEX 0x825E +#define GL_VIEWPORT_INDEX_PROVOKING_VERTEX 0x825F +#define GL_UNDEFINED_VERTEX 0x8260 +/* reuse GL_FIRST_VERTEX_CONVENTION */ +/* reuse GL_LAST_VERTEX_CONVENTION */ +/* reuse GL_PROVOKING_VERTEX */ +#endif + +#ifndef GL_ARB_cl_event +#define GL_SYNC_CL_EVENT_ARB 0x8240 +#define GL_SYNC_CL_EVENT_COMPLETE_ARB 0x8241 +#endif + +#ifndef GL_ARB_debug_output +#define GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB 0x8242 +#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB 0x8243 +#define GL_DEBUG_CALLBACK_FUNCTION_ARB 0x8244 +#define GL_DEBUG_CALLBACK_USER_PARAM_ARB 0x8245 +#define GL_DEBUG_SOURCE_API_ARB 0x8246 +#define GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB 0x8247 +#define GL_DEBUG_SOURCE_SHADER_COMPILER_ARB 0x8248 +#define GL_DEBUG_SOURCE_THIRD_PARTY_ARB 0x8249 +#define GL_DEBUG_SOURCE_APPLICATION_ARB 0x824A +#define GL_DEBUG_SOURCE_OTHER_ARB 0x824B +#define GL_DEBUG_TYPE_ERROR_ARB 0x824C +#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB 0x824D +#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB 0x824E +#define GL_DEBUG_TYPE_PORTABILITY_ARB 0x824F +#define GL_DEBUG_TYPE_PERFORMANCE_ARB 0x8250 +#define GL_DEBUG_TYPE_OTHER_ARB 0x8251 +#define GL_MAX_DEBUG_MESSAGE_LENGTH_ARB 0x9143 +#define GL_MAX_DEBUG_LOGGED_MESSAGES_ARB 0x9144 +#define GL_DEBUG_LOGGED_MESSAGES_ARB 0x9145 +#define GL_DEBUG_SEVERITY_HIGH_ARB 0x9146 +#define GL_DEBUG_SEVERITY_MEDIUM_ARB 0x9147 +#define GL_DEBUG_SEVERITY_LOW_ARB 0x9148 +#endif + +#ifndef GL_ARB_robustness +/* reuse GL_NO_ERROR */ +#define GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB 0x00000004 +#define GL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 +#define GL_GUILTY_CONTEXT_RESET_ARB 0x8253 +#define GL_INNOCENT_CONTEXT_RESET_ARB 0x8254 +#define GL_UNKNOWN_CONTEXT_RESET_ARB 0x8255 +#define GL_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 +#define GL_NO_RESET_NOTIFICATION_ARB 0x8261 +#endif + +#ifndef GL_ARB_shader_stencil_export +#endif + +#ifndef GL_ARB_base_instance +#endif + +#ifndef GL_ARB_shading_language_420pack +#endif + +#ifndef GL_ARB_transform_feedback_instanced +#endif + +#ifndef GL_ARB_compressed_texture_pixel_storage +#define GL_UNPACK_COMPRESSED_BLOCK_WIDTH 0x9127 +#define GL_UNPACK_COMPRESSED_BLOCK_HEIGHT 0x9128 +#define GL_UNPACK_COMPRESSED_BLOCK_DEPTH 0x9129 +#define GL_UNPACK_COMPRESSED_BLOCK_SIZE 0x912A +#define GL_PACK_COMPRESSED_BLOCK_WIDTH 0x912B +#define GL_PACK_COMPRESSED_BLOCK_HEIGHT 0x912C +#define GL_PACK_COMPRESSED_BLOCK_DEPTH 0x912D +#define GL_PACK_COMPRESSED_BLOCK_SIZE 0x912E +#endif + +#ifndef GL_ARB_conservative_depth +#endif + +#ifndef GL_ARB_internalformat_query +#define GL_NUM_SAMPLE_COUNTS 0x9380 +#endif + +#ifndef GL_ARB_map_buffer_alignment +#define GL_MIN_MAP_BUFFER_ALIGNMENT 0x90BC +#endif + +#ifndef GL_ARB_shader_atomic_counters +#define GL_ATOMIC_COUNTER_BUFFER 0x92C0 +#define GL_ATOMIC_COUNTER_BUFFER_BINDING 0x92C1 +#define GL_ATOMIC_COUNTER_BUFFER_START 0x92C2 +#define GL_ATOMIC_COUNTER_BUFFER_SIZE 0x92C3 +#define GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE 0x92C4 +#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS 0x92C5 +#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES 0x92C6 +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER 0x92C7 +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER 0x92C8 +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER 0x92C9 +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER 0x92CA +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER 0x92CB +#define GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS 0x92CC +#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS 0x92CD +#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS 0x92CE +#define GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS 0x92CF +#define GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS 0x92D0 +#define GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS 0x92D1 +#define GL_MAX_VERTEX_ATOMIC_COUNTERS 0x92D2 +#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS 0x92D3 +#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS 0x92D4 +#define GL_MAX_GEOMETRY_ATOMIC_COUNTERS 0x92D5 +#define GL_MAX_FRAGMENT_ATOMIC_COUNTERS 0x92D6 +#define GL_MAX_COMBINED_ATOMIC_COUNTERS 0x92D7 +#define GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE 0x92D8 +#define GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS 0x92DC +#define GL_ACTIVE_ATOMIC_COUNTER_BUFFERS 0x92D9 +#define GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX 0x92DA +#define GL_UNSIGNED_INT_ATOMIC_COUNTER 0x92DB +#endif + +#ifndef GL_ARB_shader_image_load_store +#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001 +#define GL_ELEMENT_ARRAY_BARRIER_BIT 0x00000002 +#define GL_UNIFORM_BARRIER_BIT 0x00000004 +#define GL_TEXTURE_FETCH_BARRIER_BIT 0x00000008 +#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020 +#define GL_COMMAND_BARRIER_BIT 0x00000040 +#define GL_PIXEL_BUFFER_BARRIER_BIT 0x00000080 +#define GL_TEXTURE_UPDATE_BARRIER_BIT 0x00000100 +#define GL_BUFFER_UPDATE_BARRIER_BIT 0x00000200 +#define GL_FRAMEBUFFER_BARRIER_BIT 0x00000400 +#define GL_TRANSFORM_FEEDBACK_BARRIER_BIT 0x00000800 +#define GL_ATOMIC_COUNTER_BARRIER_BIT 0x00001000 +#define GL_ALL_BARRIER_BITS 0xFFFFFFFF +#define GL_MAX_IMAGE_UNITS 0x8F38 +#define GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS 0x8F39 +#define GL_IMAGE_BINDING_NAME 0x8F3A +#define GL_IMAGE_BINDING_LEVEL 0x8F3B +#define GL_IMAGE_BINDING_LAYERED 0x8F3C +#define GL_IMAGE_BINDING_LAYER 0x8F3D +#define GL_IMAGE_BINDING_ACCESS 0x8F3E +#define GL_IMAGE_1D 0x904C +#define GL_IMAGE_2D 0x904D +#define GL_IMAGE_3D 0x904E +#define GL_IMAGE_2D_RECT 0x904F +#define GL_IMAGE_CUBE 0x9050 +#define GL_IMAGE_BUFFER 0x9051 +#define GL_IMAGE_1D_ARRAY 0x9052 +#define GL_IMAGE_2D_ARRAY 0x9053 +#define GL_IMAGE_CUBE_MAP_ARRAY 0x9054 +#define GL_IMAGE_2D_MULTISAMPLE 0x9055 +#define GL_IMAGE_2D_MULTISAMPLE_ARRAY 0x9056 +#define GL_INT_IMAGE_1D 0x9057 +#define GL_INT_IMAGE_2D 0x9058 +#define GL_INT_IMAGE_3D 0x9059 +#define GL_INT_IMAGE_2D_RECT 0x905A +#define GL_INT_IMAGE_CUBE 0x905B +#define GL_INT_IMAGE_BUFFER 0x905C +#define GL_INT_IMAGE_1D_ARRAY 0x905D +#define GL_INT_IMAGE_2D_ARRAY 0x905E +#define GL_INT_IMAGE_CUBE_MAP_ARRAY 0x905F +#define GL_INT_IMAGE_2D_MULTISAMPLE 0x9060 +#define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x9061 +#define GL_UNSIGNED_INT_IMAGE_1D 0x9062 +#define GL_UNSIGNED_INT_IMAGE_2D 0x9063 +#define GL_UNSIGNED_INT_IMAGE_3D 0x9064 +#define GL_UNSIGNED_INT_IMAGE_2D_RECT 0x9065 +#define GL_UNSIGNED_INT_IMAGE_CUBE 0x9066 +#define GL_UNSIGNED_INT_IMAGE_BUFFER 0x9067 +#define GL_UNSIGNED_INT_IMAGE_1D_ARRAY 0x9068 +#define GL_UNSIGNED_INT_IMAGE_2D_ARRAY 0x9069 +#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY 0x906A +#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE 0x906B +#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x906C +#define GL_MAX_IMAGE_SAMPLES 0x906D +#define GL_IMAGE_BINDING_FORMAT 0x906E +#define GL_IMAGE_FORMAT_COMPATIBILITY_TYPE 0x90C7 +#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE 0x90C8 +#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS 0x90C9 +#define GL_MAX_VERTEX_IMAGE_UNIFORMS 0x90CA +#define GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS 0x90CB +#define GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS 0x90CC +#define GL_MAX_GEOMETRY_IMAGE_UNIFORMS 0x90CD +#define GL_MAX_FRAGMENT_IMAGE_UNIFORMS 0x90CE +#define GL_MAX_COMBINED_IMAGE_UNIFORMS 0x90CF +#endif + +#ifndef GL_ARB_shading_language_packing +#endif + +#ifndef GL_ARB_texture_storage +#define GL_TEXTURE_IMMUTABLE_FORMAT 0x912F +#endif + +#ifndef GL_KHR_texture_compression_astc_ldr +#define GL_COMPRESSED_RGBA_ASTC_4x4_KHR 0x93B0 +#define GL_COMPRESSED_RGBA_ASTC_5x4_KHR 0x93B1 +#define GL_COMPRESSED_RGBA_ASTC_5x5_KHR 0x93B2 +#define GL_COMPRESSED_RGBA_ASTC_6x5_KHR 0x93B3 +#define GL_COMPRESSED_RGBA_ASTC_6x6_KHR 0x93B4 +#define GL_COMPRESSED_RGBA_ASTC_8x5_KHR 0x93B5 +#define GL_COMPRESSED_RGBA_ASTC_8x6_KHR 0x93B6 +#define GL_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93B7 +#define GL_COMPRESSED_RGBA_ASTC_10x5_KHR 0x93B8 +#define GL_COMPRESSED_RGBA_ASTC_10x6_KHR 0x93B9 +#define GL_COMPRESSED_RGBA_ASTC_10x8_KHR 0x93BA +#define GL_COMPRESSED_RGBA_ASTC_10x10_KHR 0x93BB +#define GL_COMPRESSED_RGBA_ASTC_12x10_KHR 0x93BC +#define GL_COMPRESSED_RGBA_ASTC_12x12_KHR 0x93BD +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR 0x93D0 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR 0x93D1 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR 0x93D2 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR 0x93D3 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR 0x93D4 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR 0x93D5 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR 0x93D6 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR 0x93D7 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR 0x93D8 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR 0x93D9 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR 0x93DA +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR 0x93DB +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR 0x93DC +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR 0x93DD +#endif + +#ifndef GL_KHR_debug +#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 +#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243 +#define GL_DEBUG_CALLBACK_FUNCTION 0x8244 +#define GL_DEBUG_CALLBACK_USER_PARAM 0x8245 +#define GL_DEBUG_SOURCE_API 0x8246 +#define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247 +#define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248 +#define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249 +#define GL_DEBUG_SOURCE_APPLICATION 0x824A +#define GL_DEBUG_SOURCE_OTHER 0x824B +#define GL_DEBUG_TYPE_ERROR 0x824C +#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D +#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E +#define GL_DEBUG_TYPE_PORTABILITY 0x824F +#define GL_DEBUG_TYPE_PERFORMANCE 0x8250 +#define GL_DEBUG_TYPE_OTHER 0x8251 +#define GL_DEBUG_TYPE_MARKER 0x8268 +#define GL_DEBUG_TYPE_PUSH_GROUP 0x8269 +#define GL_DEBUG_TYPE_POP_GROUP 0x826A +#define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B +#define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C +#define GL_DEBUG_GROUP_STACK_DEPTH 0x826D +#define GL_BUFFER 0x82E0 +#define GL_SHADER 0x82E1 +#define GL_PROGRAM 0x82E2 +#define GL_QUERY 0x82E3 +#define GL_PROGRAM_PIPELINE 0x82E4 +#define GL_SAMPLER 0x82E6 +#define GL_DISPLAY_LIST 0x82E7 +/* DISPLAY_LIST used in compatibility profile only */ +#define GL_MAX_LABEL_LENGTH 0x82E8 +#define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143 +#define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144 +#define GL_DEBUG_LOGGED_MESSAGES 0x9145 +#define GL_DEBUG_SEVERITY_HIGH 0x9146 +#define GL_DEBUG_SEVERITY_MEDIUM 0x9147 +#define GL_DEBUG_SEVERITY_LOW 0x9148 +#define GL_DEBUG_OUTPUT 0x92E0 +#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 +/* reuse GL_STACK_UNDERFLOW */ +/* reuse GL_STACK_OVERFLOW */ +#endif + +#ifndef GL_ARB_arrays_of_arrays +#endif + +#ifndef GL_ARB_clear_buffer_object +#endif + +#ifndef GL_ARB_compute_shader +#define GL_COMPUTE_SHADER 0x91B9 +#define GL_MAX_COMPUTE_UNIFORM_BLOCKS 0x91BB +#define GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS 0x91BC +#define GL_MAX_COMPUTE_IMAGE_UNIFORMS 0x91BD +#define GL_MAX_COMPUTE_SHARED_MEMORY_SIZE 0x8262 +#define GL_MAX_COMPUTE_UNIFORM_COMPONENTS 0x8263 +#define GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS 0x8264 +#define GL_MAX_COMPUTE_ATOMIC_COUNTERS 0x8265 +#define GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS 0x8266 +#define GL_MAX_COMPUTE_LOCAL_INVOCATIONS 0x90EB +#define GL_MAX_COMPUTE_WORK_GROUP_COUNT 0x91BE +#define GL_MAX_COMPUTE_WORK_GROUP_SIZE 0x91BF +#define GL_COMPUTE_LOCAL_WORK_SIZE 0x8267 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER 0x90EC +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER 0x90ED +#define GL_DISPATCH_INDIRECT_BUFFER 0x90EE +#define GL_DISPATCH_INDIRECT_BUFFER_BINDING 0x90EF +#define GL_COMPUTE_SHADER_BIT 0x00000020 +#endif + +#ifndef GL_ARB_copy_image +#endif + +#ifndef GL_ARB_texture_view +#define GL_TEXTURE_VIEW_MIN_LEVEL 0x82DB +#define GL_TEXTURE_VIEW_NUM_LEVELS 0x82DC +#define GL_TEXTURE_VIEW_MIN_LAYER 0x82DD +#define GL_TEXTURE_VIEW_NUM_LAYERS 0x82DE +#define GL_TEXTURE_IMMUTABLE_LEVELS 0x82DF +#endif + +#ifndef GL_ARB_vertex_attrib_binding +#define GL_VERTEX_ATTRIB_BINDING 0x82D4 +#define GL_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D5 +#define GL_VERTEX_BINDING_DIVISOR 0x82D6 +#define GL_VERTEX_BINDING_OFFSET 0x82D7 +#define GL_VERTEX_BINDING_STRIDE 0x82D8 +#define GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D9 +#define GL_MAX_VERTEX_ATTRIB_BINDINGS 0x82DA +#endif + +#ifndef GL_ARB_robustness_isolation +#endif + +#ifndef GL_ARB_ES3_compatibility +#define GL_COMPRESSED_RGB8_ETC2 0x9274 +#define GL_COMPRESSED_SRGB8_ETC2 0x9275 +#define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276 +#define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277 +#define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 +#define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279 +#define GL_COMPRESSED_R11_EAC 0x9270 +#define GL_COMPRESSED_SIGNED_R11_EAC 0x9271 +#define GL_COMPRESSED_RG11_EAC 0x9272 +#define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273 +#define GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69 +#define GL_ANY_SAMPLES_PASSED_CONSERVATIVE 0x8D6A +#define GL_MAX_ELEMENT_INDEX 0x8D6B +#endif + +#ifndef GL_ARB_explicit_uniform_location +#define GL_MAX_UNIFORM_LOCATIONS 0x826E +#endif + +#ifndef GL_ARB_fragment_layer_viewport +#endif + +#ifndef GL_ARB_framebuffer_no_attachments +#define GL_FRAMEBUFFER_DEFAULT_WIDTH 0x9310 +#define GL_FRAMEBUFFER_DEFAULT_HEIGHT 0x9311 +#define GL_FRAMEBUFFER_DEFAULT_LAYERS 0x9312 +#define GL_FRAMEBUFFER_DEFAULT_SAMPLES 0x9313 +#define GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS 0x9314 +#define GL_MAX_FRAMEBUFFER_WIDTH 0x9315 +#define GL_MAX_FRAMEBUFFER_HEIGHT 0x9316 +#define GL_MAX_FRAMEBUFFER_LAYERS 0x9317 +#define GL_MAX_FRAMEBUFFER_SAMPLES 0x9318 +#endif + +#ifndef GL_ARB_internalformat_query2 +/* reuse GL_IMAGE_FORMAT_COMPATIBILITY_TYPE */ +/* reuse GL_NUM_SAMPLE_COUNTS */ +/* reuse GL_RENDERBUFFER */ +/* reuse GL_SAMPLES */ +/* reuse GL_TEXTURE_1D */ +/* reuse GL_TEXTURE_1D_ARRAY */ +/* reuse GL_TEXTURE_2D */ +/* reuse GL_TEXTURE_2D_ARRAY */ +/* reuse GL_TEXTURE_3D */ +/* reuse GL_TEXTURE_CUBE_MAP */ +/* reuse GL_TEXTURE_CUBE_MAP_ARRAY */ +/* reuse GL_TEXTURE_RECTANGLE */ +/* reuse GL_TEXTURE_BUFFER */ +/* reuse GL_TEXTURE_2D_MULTISAMPLE */ +/* reuse GL_TEXTURE_2D_MULTISAMPLE_ARRAY */ +/* reuse GL_TEXTURE_COMPRESSED */ +#define GL_INTERNALFORMAT_SUPPORTED 0x826F +#define GL_INTERNALFORMAT_PREFERRED 0x8270 +#define GL_INTERNALFORMAT_RED_SIZE 0x8271 +#define GL_INTERNALFORMAT_GREEN_SIZE 0x8272 +#define GL_INTERNALFORMAT_BLUE_SIZE 0x8273 +#define GL_INTERNALFORMAT_ALPHA_SIZE 0x8274 +#define GL_INTERNALFORMAT_DEPTH_SIZE 0x8275 +#define GL_INTERNALFORMAT_STENCIL_SIZE 0x8276 +#define GL_INTERNALFORMAT_SHARED_SIZE 0x8277 +#define GL_INTERNALFORMAT_RED_TYPE 0x8278 +#define GL_INTERNALFORMAT_GREEN_TYPE 0x8279 +#define GL_INTERNALFORMAT_BLUE_TYPE 0x827A +#define GL_INTERNALFORMAT_ALPHA_TYPE 0x827B +#define GL_INTERNALFORMAT_DEPTH_TYPE 0x827C +#define GL_INTERNALFORMAT_STENCIL_TYPE 0x827D +#define GL_MAX_WIDTH 0x827E +#define GL_MAX_HEIGHT 0x827F +#define GL_MAX_DEPTH 0x8280 +#define GL_MAX_LAYERS 0x8281 +#define GL_MAX_COMBINED_DIMENSIONS 0x8282 +#define GL_COLOR_COMPONENTS 0x8283 +#define GL_DEPTH_COMPONENTS 0x8284 +#define GL_STENCIL_COMPONENTS 0x8285 +#define GL_COLOR_RENDERABLE 0x8286 +#define GL_DEPTH_RENDERABLE 0x8287 +#define GL_STENCIL_RENDERABLE 0x8288 +#define GL_FRAMEBUFFER_RENDERABLE 0x8289 +#define GL_FRAMEBUFFER_RENDERABLE_LAYERED 0x828A +#define GL_FRAMEBUFFER_BLEND 0x828B +#define GL_READ_PIXELS 0x828C +#define GL_READ_PIXELS_FORMAT 0x828D +#define GL_READ_PIXELS_TYPE 0x828E +#define GL_TEXTURE_IMAGE_FORMAT 0x828F +#define GL_TEXTURE_IMAGE_TYPE 0x8290 +#define GL_GET_TEXTURE_IMAGE_FORMAT 0x8291 +#define GL_GET_TEXTURE_IMAGE_TYPE 0x8292 +#define GL_MIPMAP 0x8293 +#define GL_MANUAL_GENERATE_MIPMAP 0x8294 +#define GL_AUTO_GENERATE_MIPMAP 0x8295 +#define GL_COLOR_ENCODING 0x8296 +#define GL_SRGB_READ 0x8297 +#define GL_SRGB_WRITE 0x8298 +#define GL_SRGB_DECODE_ARB 0x8299 +#define GL_FILTER 0x829A +#define GL_VERTEX_TEXTURE 0x829B +#define GL_TESS_CONTROL_TEXTURE 0x829C +#define GL_TESS_EVALUATION_TEXTURE 0x829D +#define GL_GEOMETRY_TEXTURE 0x829E +#define GL_FRAGMENT_TEXTURE 0x829F +#define GL_COMPUTE_TEXTURE 0x82A0 +#define GL_TEXTURE_SHADOW 0x82A1 +#define GL_TEXTURE_GATHER 0x82A2 +#define GL_TEXTURE_GATHER_SHADOW 0x82A3 +#define GL_SHADER_IMAGE_LOAD 0x82A4 +#define GL_SHADER_IMAGE_STORE 0x82A5 +#define GL_SHADER_IMAGE_ATOMIC 0x82A6 +#define GL_IMAGE_TEXEL_SIZE 0x82A7 +#define GL_IMAGE_COMPATIBILITY_CLASS 0x82A8 +#define GL_IMAGE_PIXEL_FORMAT 0x82A9 +#define GL_IMAGE_PIXEL_TYPE 0x82AA +#define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST 0x82AC +#define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST 0x82AD +#define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE 0x82AE +#define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_WRITE 0x82AF +#define GL_TEXTURE_COMPRESSED_BLOCK_WIDTH 0x82B1 +#define GL_TEXTURE_COMPRESSED_BLOCK_HEIGHT 0x82B2 +#define GL_TEXTURE_COMPRESSED_BLOCK_SIZE 0x82B3 +#define GL_CLEAR_BUFFER 0x82B4 +#define GL_TEXTURE_VIEW 0x82B5 +#define GL_VIEW_COMPATIBILITY_CLASS 0x82B6 +#define GL_FULL_SUPPORT 0x82B7 +#define GL_CAVEAT_SUPPORT 0x82B8 +#define GL_IMAGE_CLASS_4_X_32 0x82B9 +#define GL_IMAGE_CLASS_2_X_32 0x82BA +#define GL_IMAGE_CLASS_1_X_32 0x82BB +#define GL_IMAGE_CLASS_4_X_16 0x82BC +#define GL_IMAGE_CLASS_2_X_16 0x82BD +#define GL_IMAGE_CLASS_1_X_16 0x82BE +#define GL_IMAGE_CLASS_4_X_8 0x82BF +#define GL_IMAGE_CLASS_2_X_8 0x82C0 +#define GL_IMAGE_CLASS_1_X_8 0x82C1 +#define GL_IMAGE_CLASS_11_11_10 0x82C2 +#define GL_IMAGE_CLASS_10_10_10_2 0x82C3 +#define GL_VIEW_CLASS_128_BITS 0x82C4 +#define GL_VIEW_CLASS_96_BITS 0x82C5 +#define GL_VIEW_CLASS_64_BITS 0x82C6 +#define GL_VIEW_CLASS_48_BITS 0x82C7 +#define GL_VIEW_CLASS_32_BITS 0x82C8 +#define GL_VIEW_CLASS_24_BITS 0x82C9 +#define GL_VIEW_CLASS_16_BITS 0x82CA +#define GL_VIEW_CLASS_8_BITS 0x82CB +#define GL_VIEW_CLASS_S3TC_DXT1_RGB 0x82CC +#define GL_VIEW_CLASS_S3TC_DXT1_RGBA 0x82CD +#define GL_VIEW_CLASS_S3TC_DXT3_RGBA 0x82CE +#define GL_VIEW_CLASS_S3TC_DXT5_RGBA 0x82CF +#define GL_VIEW_CLASS_RGTC1_RED 0x82D0 +#define GL_VIEW_CLASS_RGTC2_RG 0x82D1 +#define GL_VIEW_CLASS_BPTC_UNORM 0x82D2 +#define GL_VIEW_CLASS_BPTC_FLOAT 0x82D3 +#endif + +#ifndef GL_ARB_invalidate_subdata +#endif + +#ifndef GL_ARB_multi_draw_indirect +#endif + +#ifndef GL_ARB_program_interface_query +#define GL_UNIFORM 0x92E1 +#define GL_UNIFORM_BLOCK 0x92E2 +#define GL_PROGRAM_INPUT 0x92E3 +#define GL_PROGRAM_OUTPUT 0x92E4 +#define GL_BUFFER_VARIABLE 0x92E5 +#define GL_SHADER_STORAGE_BLOCK 0x92E6 +/* reuse GL_ATOMIC_COUNTER_BUFFER */ +#define GL_VERTEX_SUBROUTINE 0x92E8 +#define GL_TESS_CONTROL_SUBROUTINE 0x92E9 +#define GL_TESS_EVALUATION_SUBROUTINE 0x92EA +#define GL_GEOMETRY_SUBROUTINE 0x92EB +#define GL_FRAGMENT_SUBROUTINE 0x92EC +#define GL_COMPUTE_SUBROUTINE 0x92ED +#define GL_VERTEX_SUBROUTINE_UNIFORM 0x92EE +#define GL_TESS_CONTROL_SUBROUTINE_UNIFORM 0x92EF +#define GL_TESS_EVALUATION_SUBROUTINE_UNIFORM 0x92F0 +#define GL_GEOMETRY_SUBROUTINE_UNIFORM 0x92F1 +#define GL_FRAGMENT_SUBROUTINE_UNIFORM 0x92F2 +#define GL_COMPUTE_SUBROUTINE_UNIFORM 0x92F3 +#define GL_TRANSFORM_FEEDBACK_VARYING 0x92F4 +#define GL_ACTIVE_RESOURCES 0x92F5 +#define GL_MAX_NAME_LENGTH 0x92F6 +#define GL_MAX_NUM_ACTIVE_VARIABLES 0x92F7 +#define GL_MAX_NUM_COMPATIBLE_SUBROUTINES 0x92F8 +#define GL_NAME_LENGTH 0x92F9 +#define GL_TYPE 0x92FA +#define GL_ARRAY_SIZE 0x92FB +#define GL_OFFSET 0x92FC +#define GL_BLOCK_INDEX 0x92FD +#define GL_ARRAY_STRIDE 0x92FE +#define GL_MATRIX_STRIDE 0x92FF +#define GL_IS_ROW_MAJOR 0x9300 +#define GL_ATOMIC_COUNTER_BUFFER_INDEX 0x9301 +#define GL_BUFFER_BINDING 0x9302 +#define GL_BUFFER_DATA_SIZE 0x9303 +#define GL_NUM_ACTIVE_VARIABLES 0x9304 +#define GL_ACTIVE_VARIABLES 0x9305 +#define GL_REFERENCED_BY_VERTEX_SHADER 0x9306 +#define GL_REFERENCED_BY_TESS_CONTROL_SHADER 0x9307 +#define GL_REFERENCED_BY_TESS_EVALUATION_SHADER 0x9308 +#define GL_REFERENCED_BY_GEOMETRY_SHADER 0x9309 +#define GL_REFERENCED_BY_FRAGMENT_SHADER 0x930A +#define GL_REFERENCED_BY_COMPUTE_SHADER 0x930B +#define GL_TOP_LEVEL_ARRAY_SIZE 0x930C +#define GL_TOP_LEVEL_ARRAY_STRIDE 0x930D +#define GL_LOCATION 0x930E +#define GL_LOCATION_INDEX 0x930F +#define GL_IS_PER_PATCH 0x92E7 +/* reuse GL_NUM_COMPATIBLE_SUBROUTINES */ +/* reuse GL_COMPATIBLE_SUBROUTINES */ +#endif + +#ifndef GL_ARB_robust_buffer_access_behavior +#endif + +#ifndef GL_ARB_shader_image_size +#endif + +#ifndef GL_ARB_shader_storage_buffer_object +#define GL_SHADER_STORAGE_BUFFER 0x90D2 +#define GL_SHADER_STORAGE_BUFFER_BINDING 0x90D3 +#define GL_SHADER_STORAGE_BUFFER_START 0x90D4 +#define GL_SHADER_STORAGE_BUFFER_SIZE 0x90D5 +#define GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS 0x90D6 +#define GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS 0x90D7 +#define GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS 0x90D8 +#define GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS 0x90D9 +#define GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS 0x90DA +#define GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS 0x90DB +#define GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS 0x90DC +#define GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS 0x90DD +#define GL_MAX_SHADER_STORAGE_BLOCK_SIZE 0x90DE +#define GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT 0x90DF +#define GL_SHADER_STORAGE_BARRIER_BIT 0x2000 +#define GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS +/* reuse GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS */ +#endif + +#ifndef GL_ARB_stencil_texturing +#define GL_DEPTH_STENCIL_TEXTURE_MODE 0x90EA +#endif + +#ifndef GL_ARB_texture_buffer_range +#define GL_TEXTURE_BUFFER_OFFSET 0x919D +#define GL_TEXTURE_BUFFER_SIZE 0x919E +#define GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT 0x919F +#endif + +#ifndef GL_ARB_texture_query_levels +#endif + +#ifndef GL_ARB_texture_storage_multisample +#endif + + +/*************************************************************/ + +#include +#ifndef GL_VERSION_2_0 +/* GL type for program/shader text */ +typedef char GLchar; +#endif + +#ifndef GL_VERSION_1_5 +/* GL types for handling large vertex buffer objects */ +typedef ptrdiff_t GLintptr; +typedef ptrdiff_t GLsizeiptr; +#endif + +#ifndef GL_ARB_vertex_buffer_object +/* GL types for handling large vertex buffer objects */ +typedef ptrdiff_t GLintptrARB; +typedef ptrdiff_t GLsizeiptrARB; +#endif + +#ifndef GL_ARB_shader_objects +/* GL types for program/shader text and shader object handles */ +typedef char GLcharARB; +typedef unsigned int GLhandleARB; +#endif + +/* GL type for "half" precision (s10e5) float data in host memory */ +#ifndef GL_ARB_half_float_pixel +typedef unsigned short GLhalfARB; +#endif + +#ifndef GL_NV_half_float +typedef unsigned short GLhalfNV; +#endif + +#ifndef GLEXT_64_TYPES_DEFINED +/* This code block is duplicated in glxext.h, so must be protected */ +#define GLEXT_64_TYPES_DEFINED +/* Define int32_t, int64_t, and uint64_t types for UST/MSC */ +/* (as used in the GL_EXT_timer_query extension). */ +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#include +#elif defined(__sun__) || defined(__digital__) +#include +#if defined(__STDC__) +#if defined(__arch64__) || defined(_LP64) +typedef long int int64_t; +typedef unsigned long int uint64_t; +#else +typedef long long int int64_t; +typedef unsigned long long int uint64_t; +#endif /* __arch64__ */ +#endif /* __STDC__ */ +#elif defined( __VMS ) || defined(__sgi) +#include +#elif defined(__SCO__) || defined(__USLC__) +#include +#elif defined(__UNIXOS2__) || defined(__SOL64__) +typedef long int int32_t; +typedef long long int int64_t; +typedef unsigned long long int uint64_t; +#elif defined(_WIN32) && defined(__GNUC__) +#include +#elif defined(_WIN32) +typedef __int32 int32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +#else +/* Fallback if nothing above works */ +#include +#endif +#endif + +#ifndef GL_EXT_timer_query +typedef int64_t GLint64EXT; +typedef uint64_t GLuint64EXT; +#endif + +#ifndef GL_ARB_sync +typedef int64_t GLint64; +typedef uint64_t GLuint64; +typedef struct __GLsync *GLsync; +#endif + +#ifndef GL_ARB_cl_event +/* These incomplete types let us declare types compatible with OpenCL's cl_context and cl_event */ +struct _cl_context; +struct _cl_event; +#endif + +#ifndef GL_ARB_debug_output +typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,GLvoid *userParam); +#endif + +#ifndef GL_AMD_debug_output +typedef void (APIENTRY *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,GLvoid *userParam); +#endif + +#ifndef GL_KHR_debug +typedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,GLvoid *userParam); +#endif + +#ifndef GL_NV_vdpau_interop +typedef GLintptr GLvdpauSurfaceNV; +#endif + +#ifndef GL_VERSION_1_0 +#define GL_VERSION_1_0 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glCullFace (GLenum mode); +GLAPI void APIENTRY glFrontFace (GLenum mode); +GLAPI void APIENTRY glHint (GLenum target, GLenum mode); +GLAPI void APIENTRY glLineWidth (GLfloat width); +GLAPI void APIENTRY glPointSize (GLfloat size); +GLAPI void APIENTRY glPolygonMode (GLenum face, GLenum mode); +GLAPI void APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param); +GLAPI void APIENTRY glTexParameterfv (GLenum target, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param); +GLAPI void APIENTRY glTexParameteriv (GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glTexImage1D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +GLAPI void APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +GLAPI void APIENTRY glDrawBuffer (GLenum mode); +GLAPI void APIENTRY glClear (GLbitfield mask); +GLAPI void APIENTRY glClearColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +GLAPI void APIENTRY glClearStencil (GLint s); +GLAPI void APIENTRY glClearDepth (GLdouble depth); +GLAPI void APIENTRY glStencilMask (GLuint mask); +GLAPI void APIENTRY glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +GLAPI void APIENTRY glDepthMask (GLboolean flag); +GLAPI void APIENTRY glDisable (GLenum cap); +GLAPI void APIENTRY glEnable (GLenum cap); +GLAPI void APIENTRY glFinish (void); +GLAPI void APIENTRY glFlush (void); +GLAPI void APIENTRY glBlendFunc (GLenum sfactor, GLenum dfactor); +GLAPI void APIENTRY glLogicOp (GLenum opcode); +GLAPI void APIENTRY glStencilFunc (GLenum func, GLint ref, GLuint mask); +GLAPI void APIENTRY glStencilOp (GLenum fail, GLenum zfail, GLenum zpass); +GLAPI void APIENTRY glDepthFunc (GLenum func); +GLAPI void APIENTRY glPixelStoref (GLenum pname, GLfloat param); +GLAPI void APIENTRY glPixelStorei (GLenum pname, GLint param); +GLAPI void APIENTRY glReadBuffer (GLenum mode); +GLAPI void APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels); +GLAPI void APIENTRY glGetBooleanv (GLenum pname, GLboolean *params); +GLAPI void APIENTRY glGetDoublev (GLenum pname, GLdouble *params); +GLAPI GLenum APIENTRY glGetError (void); +GLAPI void APIENTRY glGetFloatv (GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetIntegerv (GLenum pname, GLint *params); +GLAPI const GLubyte * APIENTRY glGetString (GLenum name); +GLAPI void APIENTRY glGetTexImage (GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); +GLAPI void APIENTRY glGetTexParameterfv (GLenum target, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetTexParameteriv (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetTexLevelParameterfv (GLenum target, GLint level, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetTexLevelParameteriv (GLenum target, GLint level, GLenum pname, GLint *params); +GLAPI GLboolean APIENTRY glIsEnabled (GLenum cap); +GLAPI void APIENTRY glDepthRange (GLdouble near, GLdouble far); +GLAPI void APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLCULLFACEPROC) (GLenum mode); +typedef void (APIENTRYP PFNGLFRONTFACEPROC) (GLenum mode); +typedef void (APIENTRYP PFNGLHINTPROC) (GLenum target, GLenum mode); +typedef void (APIENTRYP PFNGLLINEWIDTHPROC) (GLfloat width); +typedef void (APIENTRYP PFNGLPOINTSIZEPROC) (GLfloat size); +typedef void (APIENTRYP PFNGLPOLYGONMODEPROC) (GLenum face, GLenum mode); +typedef void (APIENTRYP PFNGLSCISSORPROC) (GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLTEXPARAMETERFPROC) (GLenum target, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLTEXPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLTEXPARAMETERIPROC) (GLenum target, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLTEXPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLTEXIMAGE1DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (APIENTRYP PFNGLTEXIMAGE2DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (APIENTRYP PFNGLDRAWBUFFERPROC) (GLenum mode); +typedef void (APIENTRYP PFNGLCLEARPROC) (GLbitfield mask); +typedef void (APIENTRYP PFNGLCLEARCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +typedef void (APIENTRYP PFNGLCLEARSTENCILPROC) (GLint s); +typedef void (APIENTRYP PFNGLCLEARDEPTHPROC) (GLdouble depth); +typedef void (APIENTRYP PFNGLSTENCILMASKPROC) (GLuint mask); +typedef void (APIENTRYP PFNGLCOLORMASKPROC) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +typedef void (APIENTRYP PFNGLDEPTHMASKPROC) (GLboolean flag); +typedef void (APIENTRYP PFNGLDISABLEPROC) (GLenum cap); +typedef void (APIENTRYP PFNGLENABLEPROC) (GLenum cap); +typedef void (APIENTRYP PFNGLFINISHPROC) (void); +typedef void (APIENTRYP PFNGLFLUSHPROC) (void); +typedef void (APIENTRYP PFNGLBLENDFUNCPROC) (GLenum sfactor, GLenum dfactor); +typedef void (APIENTRYP PFNGLLOGICOPPROC) (GLenum opcode); +typedef void (APIENTRYP PFNGLSTENCILFUNCPROC) (GLenum func, GLint ref, GLuint mask); +typedef void (APIENTRYP PFNGLSTENCILOPPROC) (GLenum fail, GLenum zfail, GLenum zpass); +typedef void (APIENTRYP PFNGLDEPTHFUNCPROC) (GLenum func); +typedef void (APIENTRYP PFNGLPIXELSTOREFPROC) (GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLPIXELSTOREIPROC) (GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLREADBUFFERPROC) (GLenum mode); +typedef void (APIENTRYP PFNGLREADPIXELSPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels); +typedef void (APIENTRYP PFNGLGETBOOLEANVPROC) (GLenum pname, GLboolean *params); +typedef void (APIENTRYP PFNGLGETDOUBLEVPROC) (GLenum pname, GLdouble *params); +typedef GLenum (APIENTRYP PFNGLGETERRORPROC) (void); +typedef void (APIENTRYP PFNGLGETFLOATVPROC) (GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETINTEGERVPROC) (GLenum pname, GLint *params); +typedef const GLubyte * (APIENTRYP PFNGLGETSTRINGPROC) (GLenum name); +typedef void (APIENTRYP PFNGLGETTEXIMAGEPROC) (GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); +typedef void (APIENTRYP PFNGLGETTEXPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERFVPROC) (GLenum target, GLint level, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERIVPROC) (GLenum target, GLint level, GLenum pname, GLint *params); +typedef GLboolean (APIENTRYP PFNGLISENABLEDPROC) (GLenum cap); +typedef void (APIENTRYP PFNGLDEPTHRANGEPROC) (GLdouble near, GLdouble far); +typedef void (APIENTRYP PFNGLVIEWPORTPROC) (GLint x, GLint y, GLsizei width, GLsizei height); +#endif + +#ifndef GL_VERSION_1_1 +#define GL_VERSION_1_1 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count); +GLAPI void APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); +GLAPI void APIENTRY glGetPointerv (GLenum pname, GLvoid* *params); +GLAPI void APIENTRY glPolygonOffset (GLfloat factor, GLfloat units); +GLAPI void APIENTRY glCopyTexImage1D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); +GLAPI void APIENTRY glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +GLAPI void APIENTRY glCopyTexSubImage1D (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +GLAPI void APIENTRY glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glTexSubImage1D (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); +GLAPI void APIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +GLAPI void APIENTRY glBindTexture (GLenum target, GLuint texture); +GLAPI void APIENTRY glDeleteTextures (GLsizei n, const GLuint *textures); +GLAPI void APIENTRY glGenTextures (GLsizei n, GLuint *textures); +GLAPI GLboolean APIENTRY glIsTexture (GLuint texture); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLDRAWARRAYSPROC) (GLenum mode, GLint first, GLsizei count); +typedef void (APIENTRYP PFNGLDRAWELEMENTSPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); +typedef void (APIENTRYP PFNGLGETPOINTERVPROC) (GLenum pname, GLvoid* *params); +typedef void (APIENTRYP PFNGLPOLYGONOFFSETPROC) (GLfloat factor, GLfloat units); +typedef void (APIENTRYP PFNGLCOPYTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); +typedef void (APIENTRYP PFNGLCOPYTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (APIENTRYP PFNGLBINDTEXTUREPROC) (GLenum target, GLuint texture); +typedef void (APIENTRYP PFNGLDELETETEXTURESPROC) (GLsizei n, const GLuint *textures); +typedef void (APIENTRYP PFNGLGENTEXTURESPROC) (GLsizei n, GLuint *textures); +typedef GLboolean (APIENTRYP PFNGLISTEXTUREPROC) (GLuint texture); +#endif + +#ifndef GL_VERSION_1_2 +#define GL_VERSION_1_2 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glBlendColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +GLAPI void APIENTRY glBlendEquation (GLenum mode); +GLAPI void APIENTRY glDrawRangeElements (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); +GLAPI void APIENTRY glTexImage3D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +GLAPI void APIENTRY glTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); +GLAPI void APIENTRY glCopyTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLBLENDCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode); +typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); +typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +#endif + +#ifndef GL_VERSION_1_3 +#define GL_VERSION_1_3 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glActiveTexture (GLenum texture); +GLAPI void APIENTRY glSampleCoverage (GLfloat value, GLboolean invert); +GLAPI void APIENTRY glCompressedTexImage3D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); +GLAPI void APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); +GLAPI void APIENTRY glCompressedTexImage1D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); +GLAPI void APIENTRY glCompressedTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); +GLAPI void APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); +GLAPI void APIENTRY glCompressedTexSubImage1D (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); +GLAPI void APIENTRY glGetCompressedTexImage (GLenum target, GLint level, GLvoid *img); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture); +typedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC) (GLfloat value, GLboolean invert); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); +typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint level, GLvoid *img); +#endif + +#ifndef GL_VERSION_1_4 +#define GL_VERSION_1_4 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glBlendFuncSeparate (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +GLAPI void APIENTRY glMultiDrawArrays (GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount); +GLAPI void APIENTRY glMultiDrawElements (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* const *indices, GLsizei drawcount); +GLAPI void APIENTRY glPointParameterf (GLenum pname, GLfloat param); +GLAPI void APIENTRY glPointParameterfv (GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glPointParameteri (GLenum pname, GLint param); +GLAPI void APIENTRY glPointParameteriv (GLenum pname, const GLint *params); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount); +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* const *indices, GLsizei drawcount); +typedef void (APIENTRYP PFNGLPOINTPARAMETERFPROC) (GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLPOINTPARAMETERFVPROC) (GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLPOINTPARAMETERIPROC) (GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLPOINTPARAMETERIVPROC) (GLenum pname, const GLint *params); +#endif + +#ifndef GL_VERSION_1_5 +#define GL_VERSION_1_5 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glGenQueries (GLsizei n, GLuint *ids); +GLAPI void APIENTRY glDeleteQueries (GLsizei n, const GLuint *ids); +GLAPI GLboolean APIENTRY glIsQuery (GLuint id); +GLAPI void APIENTRY glBeginQuery (GLenum target, GLuint id); +GLAPI void APIENTRY glEndQuery (GLenum target); +GLAPI void APIENTRY glGetQueryiv (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetQueryObjectiv (GLuint id, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetQueryObjectuiv (GLuint id, GLenum pname, GLuint *params); +GLAPI void APIENTRY glBindBuffer (GLenum target, GLuint buffer); +GLAPI void APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers); +GLAPI void APIENTRY glGenBuffers (GLsizei n, GLuint *buffers); +GLAPI GLboolean APIENTRY glIsBuffer (GLuint buffer); +GLAPI void APIENTRY glBufferData (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage); +GLAPI void APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data); +GLAPI void APIENTRY glGetBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data); +GLAPI GLvoid* APIENTRY glMapBuffer (GLenum target, GLenum access); +GLAPI GLboolean APIENTRY glUnmapBuffer (GLenum target); +GLAPI void APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetBufferPointerv (GLenum target, GLenum pname, GLvoid* *params); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLGENQUERIESPROC) (GLsizei n, GLuint *ids); +typedef void (APIENTRYP PFNGLDELETEQUERIESPROC) (GLsizei n, const GLuint *ids); +typedef GLboolean (APIENTRYP PFNGLISQUERYPROC) (GLuint id); +typedef void (APIENTRYP PFNGLBEGINQUERYPROC) (GLenum target, GLuint id); +typedef void (APIENTRYP PFNGLENDQUERYPROC) (GLenum target); +typedef void (APIENTRYP PFNGLGETQUERYIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVPROC) (GLuint id, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVPROC) (GLuint id, GLenum pname, GLuint *params); +typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer); +typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers); +typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers); +typedef GLboolean (APIENTRYP PFNGLISBUFFERPROC) (GLuint buffer); +typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage); +typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data); +typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data); +typedef GLvoid* (APIENTRYP PFNGLMAPBUFFERPROC) (GLenum target, GLenum access); +typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC) (GLenum target); +typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC) (GLenum target, GLenum pname, GLvoid* *params); +#endif + +#ifndef GL_VERSION_2_0 +#define GL_VERSION_2_0 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha); +GLAPI void APIENTRY glDrawBuffers (GLsizei n, const GLenum *bufs); +GLAPI void APIENTRY glStencilOpSeparate (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); +GLAPI void APIENTRY glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask); +GLAPI void APIENTRY glStencilMaskSeparate (GLenum face, GLuint mask); +GLAPI void APIENTRY glAttachShader (GLuint program, GLuint shader); +GLAPI void APIENTRY glBindAttribLocation (GLuint program, GLuint index, const GLchar *name); +GLAPI void APIENTRY glCompileShader (GLuint shader); +GLAPI GLuint APIENTRY glCreateProgram (void); +GLAPI GLuint APIENTRY glCreateShader (GLenum type); +GLAPI void APIENTRY glDeleteProgram (GLuint program); +GLAPI void APIENTRY glDeleteShader (GLuint shader); +GLAPI void APIENTRY glDetachShader (GLuint program, GLuint shader); +GLAPI void APIENTRY glDisableVertexAttribArray (GLuint index); +GLAPI void APIENTRY glEnableVertexAttribArray (GLuint index); +GLAPI void APIENTRY glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +GLAPI void APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +GLAPI void APIENTRY glGetAttachedShaders (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *obj); +GLAPI GLint APIENTRY glGetAttribLocation (GLuint program, const GLchar *name); +GLAPI void APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +GLAPI void APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +GLAPI void APIENTRY glGetShaderSource (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); +GLAPI GLint APIENTRY glGetUniformLocation (GLuint program, const GLchar *name); +GLAPI void APIENTRY glGetUniformfv (GLuint program, GLint location, GLfloat *params); +GLAPI void APIENTRY glGetUniformiv (GLuint program, GLint location, GLint *params); +GLAPI void APIENTRY glGetVertexAttribdv (GLuint index, GLenum pname, GLdouble *params); +GLAPI void APIENTRY glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, GLvoid* *pointer); +GLAPI GLboolean APIENTRY glIsProgram (GLuint program); +GLAPI GLboolean APIENTRY glIsShader (GLuint shader); +GLAPI void APIENTRY glLinkProgram (GLuint program); +GLAPI void APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar* const *string, const GLint *length); +GLAPI void APIENTRY glUseProgram (GLuint program); +GLAPI void APIENTRY glUniform1f (GLint location, GLfloat v0); +GLAPI void APIENTRY glUniform2f (GLint location, GLfloat v0, GLfloat v1); +GLAPI void APIENTRY glUniform3f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +GLAPI void APIENTRY glUniform4f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +GLAPI void APIENTRY glUniform1i (GLint location, GLint v0); +GLAPI void APIENTRY glUniform2i (GLint location, GLint v0, GLint v1); +GLAPI void APIENTRY glUniform3i (GLint location, GLint v0, GLint v1, GLint v2); +GLAPI void APIENTRY glUniform4i (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +GLAPI void APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glUniform2fv (GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glUniform3fv (GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glUniform1iv (GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glUniform2iv (GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glUniform3iv (GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glUniform4iv (GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glValidateProgram (GLuint program); +GLAPI void APIENTRY glVertexAttrib1d (GLuint index, GLdouble x); +GLAPI void APIENTRY glVertexAttrib1dv (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib1f (GLuint index, GLfloat x); +GLAPI void APIENTRY glVertexAttrib1fv (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib1s (GLuint index, GLshort x); +GLAPI void APIENTRY glVertexAttrib1sv (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib2d (GLuint index, GLdouble x, GLdouble y); +GLAPI void APIENTRY glVertexAttrib2dv (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib2f (GLuint index, GLfloat x, GLfloat y); +GLAPI void APIENTRY glVertexAttrib2fv (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib2s (GLuint index, GLshort x, GLshort y); +GLAPI void APIENTRY glVertexAttrib2sv (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib3d (GLuint index, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glVertexAttrib3dv (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib3f (GLuint index, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glVertexAttrib3fv (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib3s (GLuint index, GLshort x, GLshort y, GLshort z); +GLAPI void APIENTRY glVertexAttrib3sv (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib4Nbv (GLuint index, const GLbyte *v); +GLAPI void APIENTRY glVertexAttrib4Niv (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttrib4Nsv (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib4Nub (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); +GLAPI void APIENTRY glVertexAttrib4Nubv (GLuint index, const GLubyte *v); +GLAPI void APIENTRY glVertexAttrib4Nuiv (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttrib4Nusv (GLuint index, const GLushort *v); +GLAPI void APIENTRY glVertexAttrib4bv (GLuint index, const GLbyte *v); +GLAPI void APIENTRY glVertexAttrib4d (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glVertexAttrib4dv (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib4f (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI void APIENTRY glVertexAttrib4fv (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib4iv (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttrib4s (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); +GLAPI void APIENTRY glVertexAttrib4sv (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib4ubv (GLuint index, const GLubyte *v); +GLAPI void APIENTRY glVertexAttrib4uiv (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttrib4usv (GLuint index, const GLushort *v); +GLAPI void APIENTRY glVertexAttribPointer (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha); +typedef void (APIENTRYP PFNGLDRAWBUFFERSPROC) (GLsizei n, const GLenum *bufs); +typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); +typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC) (GLenum face, GLenum func, GLint ref, GLuint mask); +typedef void (APIENTRYP PFNGLSTENCILMASKSEPARATEPROC) (GLenum face, GLuint mask); +typedef void (APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader); +typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar *name); +typedef void (APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader); +typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC) (void); +typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC) (GLenum type); +typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program); +typedef void (APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader); +typedef void (APIENTRYP PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader); +typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index); +typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index); +typedef void (APIENTRYP PFNGLGETACTIVEATTRIBPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +typedef void (APIENTRYP PFNGLGETATTACHEDSHADERSPROC) (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *obj); +typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name); +typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +typedef void (APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +typedef void (APIENTRYP PFNGLGETSHADERSOURCEPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); +typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name); +typedef void (APIENTRYP PFNGLGETUNIFORMFVPROC) (GLuint program, GLint location, GLfloat *params); +typedef void (APIENTRYP PFNGLGETUNIFORMIVPROC) (GLuint program, GLint location, GLint *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVPROC) (GLuint index, GLenum pname, GLdouble *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVPROC) (GLuint index, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC) (GLuint index, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC) (GLuint index, GLenum pname, GLvoid* *pointer); +typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC) (GLuint program); +typedef GLboolean (APIENTRYP PFNGLISSHADERPROC) (GLuint shader); +typedef void (APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program); +typedef void (APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar* const *string, const GLint *length); +typedef void (APIENTRYP PFNGLUSEPROGRAMPROC) (GLuint program); +typedef void (APIENTRYP PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0); +typedef void (APIENTRYP PFNGLUNIFORM2FPROC) (GLint location, GLfloat v0, GLfloat v1); +typedef void (APIENTRYP PFNGLUNIFORM3FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +typedef void (APIENTRYP PFNGLUNIFORM4FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +typedef void (APIENTRYP PFNGLUNIFORM1IPROC) (GLint location, GLint v0); +typedef void (APIENTRYP PFNGLUNIFORM2IPROC) (GLint location, GLint v0, GLint v1); +typedef void (APIENTRYP PFNGLUNIFORM3IPROC) (GLint location, GLint v0, GLint v1, GLint v2); +typedef void (APIENTRYP PFNGLUNIFORM4IPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +typedef void (APIENTRYP PFNGLUNIFORM1FVPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORM2FVPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORM3FVPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORM4FVPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORM1IVPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLUNIFORM2IVPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLUNIFORM3IVPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLUNIFORM4IVPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC) (GLuint program); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DPROC) (GLuint index, GLdouble x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FPROC) (GLuint index, GLfloat x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SPROC) (GLuint index, GLshort x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DPROC) (GLuint index, GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FPROC) (GLuint index, GLfloat x, GLfloat y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SPROC) (GLuint index, GLshort x, GLshort y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SPROC) (GLuint index, GLshort x, GLshort y, GLshort z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVPROC) (GLuint index, const GLbyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVPROC) (GLuint index, const GLubyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVPROC) (GLuint index, const GLushort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVPROC) (GLuint index, const GLbyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVPROC) (GLuint index, const GLubyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVPROC) (GLuint index, const GLushort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); +#endif + +#ifndef GL_VERSION_2_1 +#define GL_VERSION_2_1 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glUniformMatrix2x3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix3x2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix2x4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix4x2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix3x4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix4x3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +#endif + +#ifndef GL_VERSION_3_0 +#define GL_VERSION_3_0 1 +/* OpenGL 3.0 also reuses entry points from these extensions: */ +/* ARB_framebuffer_object */ +/* ARB_map_buffer_range */ +/* ARB_vertex_array_object */ +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glColorMaski (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); +GLAPI void APIENTRY glGetBooleani_v (GLenum target, GLuint index, GLboolean *data); +GLAPI void APIENTRY glGetIntegeri_v (GLenum target, GLuint index, GLint *data); +GLAPI void APIENTRY glEnablei (GLenum target, GLuint index); +GLAPI void APIENTRY glDisablei (GLenum target, GLuint index); +GLAPI GLboolean APIENTRY glIsEnabledi (GLenum target, GLuint index); +GLAPI void APIENTRY glBeginTransformFeedback (GLenum primitiveMode); +GLAPI void APIENTRY glEndTransformFeedback (void); +GLAPI void APIENTRY glBindBufferRange (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +GLAPI void APIENTRY glBindBufferBase (GLenum target, GLuint index, GLuint buffer); +GLAPI void APIENTRY glTransformFeedbackVaryings (GLuint program, GLsizei count, const GLchar* const *varyings, GLenum bufferMode); +GLAPI void APIENTRY glGetTransformFeedbackVarying (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); +GLAPI void APIENTRY glClampColor (GLenum target, GLenum clamp); +GLAPI void APIENTRY glBeginConditionalRender (GLuint id, GLenum mode); +GLAPI void APIENTRY glEndConditionalRender (void); +GLAPI void APIENTRY glVertexAttribIPointer (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +GLAPI void APIENTRY glGetVertexAttribIiv (GLuint index, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetVertexAttribIuiv (GLuint index, GLenum pname, GLuint *params); +GLAPI void APIENTRY glVertexAttribI1i (GLuint index, GLint x); +GLAPI void APIENTRY glVertexAttribI2i (GLuint index, GLint x, GLint y); +GLAPI void APIENTRY glVertexAttribI3i (GLuint index, GLint x, GLint y, GLint z); +GLAPI void APIENTRY glVertexAttribI4i (GLuint index, GLint x, GLint y, GLint z, GLint w); +GLAPI void APIENTRY glVertexAttribI1ui (GLuint index, GLuint x); +GLAPI void APIENTRY glVertexAttribI2ui (GLuint index, GLuint x, GLuint y); +GLAPI void APIENTRY glVertexAttribI3ui (GLuint index, GLuint x, GLuint y, GLuint z); +GLAPI void APIENTRY glVertexAttribI4ui (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +GLAPI void APIENTRY glVertexAttribI1iv (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttribI2iv (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttribI3iv (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttribI4iv (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttribI1uiv (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttribI2uiv (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttribI3uiv (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttribI4uiv (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttribI4bv (GLuint index, const GLbyte *v); +GLAPI void APIENTRY glVertexAttribI4sv (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttribI4ubv (GLuint index, const GLubyte *v); +GLAPI void APIENTRY glVertexAttribI4usv (GLuint index, const GLushort *v); +GLAPI void APIENTRY glGetUniformuiv (GLuint program, GLint location, GLuint *params); +GLAPI void APIENTRY glBindFragDataLocation (GLuint program, GLuint color, const GLchar *name); +GLAPI GLint APIENTRY glGetFragDataLocation (GLuint program, const GLchar *name); +GLAPI void APIENTRY glUniform1ui (GLint location, GLuint v0); +GLAPI void APIENTRY glUniform2ui (GLint location, GLuint v0, GLuint v1); +GLAPI void APIENTRY glUniform3ui (GLint location, GLuint v0, GLuint v1, GLuint v2); +GLAPI void APIENTRY glUniform4ui (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +GLAPI void APIENTRY glUniform1uiv (GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glUniform2uiv (GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glUniform3uiv (GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glUniform4uiv (GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glTexParameterIiv (GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glTexParameterIuiv (GLenum target, GLenum pname, const GLuint *params); +GLAPI void APIENTRY glGetTexParameterIiv (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetTexParameterIuiv (GLenum target, GLenum pname, GLuint *params); +GLAPI void APIENTRY glClearBufferiv (GLenum buffer, GLint drawbuffer, const GLint *value); +GLAPI void APIENTRY glClearBufferuiv (GLenum buffer, GLint drawbuffer, const GLuint *value); +GLAPI void APIENTRY glClearBufferfv (GLenum buffer, GLint drawbuffer, const GLfloat *value); +GLAPI void APIENTRY glClearBufferfi (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); +GLAPI const GLubyte * APIENTRY glGetStringi (GLenum name, GLuint index); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLCOLORMASKIPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); +typedef void (APIENTRYP PFNGLGETBOOLEANI_VPROC) (GLenum target, GLuint index, GLboolean *data); +typedef void (APIENTRYP PFNGLGETINTEGERI_VPROC) (GLenum target, GLuint index, GLint *data); +typedef void (APIENTRYP PFNGLENABLEIPROC) (GLenum target, GLuint index); +typedef void (APIENTRYP PFNGLDISABLEIPROC) (GLenum target, GLuint index); +typedef GLboolean (APIENTRYP PFNGLISENABLEDIPROC) (GLenum target, GLuint index); +typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKPROC) (GLenum primitiveMode); +typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKPROC) (void); +typedef void (APIENTRYP PFNGLBINDBUFFERRANGEPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +typedef void (APIENTRYP PFNGLBINDBUFFERBASEPROC) (GLenum target, GLuint index, GLuint buffer); +typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSPROC) (GLuint program, GLsizei count, const GLchar* const *varyings, GLenum bufferMode); +typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); +typedef void (APIENTRYP PFNGLCLAMPCOLORPROC) (GLenum target, GLenum clamp); +typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERPROC) (GLuint id, GLenum mode); +typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERPROC) (void); +typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVPROC) (GLuint index, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVPROC) (GLuint index, GLenum pname, GLuint *params); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IPROC) (GLuint index, GLint x); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IPROC) (GLuint index, GLint x, GLint y); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IPROC) (GLuint index, GLint x, GLint y, GLint z); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IPROC) (GLuint index, GLint x, GLint y, GLint z, GLint w); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIPROC) (GLuint index, GLuint x); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIPROC) (GLuint index, GLuint x, GLuint y); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVPROC) (GLuint index, const GLbyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVPROC) (GLuint index, const GLubyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVPROC) (GLuint index, const GLushort *v); +typedef void (APIENTRYP PFNGLGETUNIFORMUIVPROC) (GLuint program, GLint location, GLuint *params); +typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONPROC) (GLuint program, GLuint color, const GLchar *name); +typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONPROC) (GLuint program, const GLchar *name); +typedef void (APIENTRYP PFNGLUNIFORM1UIPROC) (GLint location, GLuint v0); +typedef void (APIENTRYP PFNGLUNIFORM2UIPROC) (GLint location, GLuint v0, GLuint v1); +typedef void (APIENTRYP PFNGLUNIFORM3UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2); +typedef void (APIENTRYP PFNGLUNIFORM4UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +typedef void (APIENTRYP PFNGLUNIFORM1UIVPROC) (GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLUNIFORM2UIVPROC) (GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLUNIFORM3UIVPROC) (GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLUNIFORM4UIVPROC) (GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, const GLuint *params); +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, GLuint *params); +typedef void (APIENTRYP PFNGLCLEARBUFFERIVPROC) (GLenum buffer, GLint drawbuffer, const GLint *value); +typedef void (APIENTRYP PFNGLCLEARBUFFERUIVPROC) (GLenum buffer, GLint drawbuffer, const GLuint *value); +typedef void (APIENTRYP PFNGLCLEARBUFFERFVPROC) (GLenum buffer, GLint drawbuffer, const GLfloat *value); +typedef void (APIENTRYP PFNGLCLEARBUFFERFIPROC) (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); +typedef const GLubyte * (APIENTRYP PFNGLGETSTRINGIPROC) (GLenum name, GLuint index); +#endif + +#ifndef GL_VERSION_3_1 +#define GL_VERSION_3_1 1 +/* OpenGL 3.1 also reuses entry points from these extensions: */ +/* ARB_copy_buffer */ +/* ARB_uniform_buffer_object */ +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glDrawArraysInstanced (GLenum mode, GLint first, GLsizei count, GLsizei instancecount); +GLAPI void APIENTRY glDrawElementsInstanced (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instancecount); +GLAPI void APIENTRY glTexBuffer (GLenum target, GLenum internalformat, GLuint buffer); +GLAPI void APIENTRY glPrimitiveRestartIndex (GLuint index); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount); +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instancecount); +typedef void (APIENTRYP PFNGLTEXBUFFERPROC) (GLenum target, GLenum internalformat, GLuint buffer); +typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXPROC) (GLuint index); +#endif + +#ifndef GL_VERSION_3_2 +#define GL_VERSION_3_2 1 +/* OpenGL 3.2 also reuses entry points from these extensions: */ +/* ARB_draw_elements_base_vertex */ +/* ARB_provoking_vertex */ +/* ARB_sync */ +/* ARB_texture_multisample */ +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glGetInteger64i_v (GLenum target, GLuint index, GLint64 *data); +GLAPI void APIENTRY glGetBufferParameteri64v (GLenum target, GLenum pname, GLint64 *params); +GLAPI void APIENTRY glFramebufferTexture (GLenum target, GLenum attachment, GLuint texture, GLint level); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLGETINTEGER64I_VPROC) (GLenum target, GLuint index, GLint64 *data); +typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERI64VPROC) (GLenum target, GLenum pname, GLint64 *params); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level); +#endif + +#ifndef GL_VERSION_3_3 +#define GL_VERSION_3_3 1 +/* OpenGL 3.3 also reuses entry points from these extensions: */ +/* ARB_blend_func_extended */ +/* ARB_sampler_objects */ +/* ARB_explicit_attrib_location, but it has none */ +/* ARB_occlusion_query2 (no entry points) */ +/* ARB_shader_bit_encoding (no entry points) */ +/* ARB_texture_rgb10_a2ui (no entry points) */ +/* ARB_texture_swizzle (no entry points) */ +/* ARB_timer_query */ +/* ARB_vertex_type_2_10_10_10_rev */ +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glVertexAttribDivisor (GLuint index, GLuint divisor); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLVERTEXATTRIBDIVISORPROC) (GLuint index, GLuint divisor); +#endif + +#ifndef GL_VERSION_4_0 +#define GL_VERSION_4_0 1 +/* OpenGL 4.0 also reuses entry points from these extensions: */ +/* ARB_texture_query_lod (no entry points) */ +/* ARB_draw_indirect */ +/* ARB_gpu_shader5 (no entry points) */ +/* ARB_gpu_shader_fp64 */ +/* ARB_shader_subroutine */ +/* ARB_tessellation_shader */ +/* ARB_texture_buffer_object_rgb32 (no entry points) */ +/* ARB_texture_cube_map_array (no entry points) */ +/* ARB_texture_gather (no entry points) */ +/* ARB_transform_feedback2 */ +/* ARB_transform_feedback3 */ +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glMinSampleShading (GLfloat value); +GLAPI void APIENTRY glBlendEquationi (GLuint buf, GLenum mode); +GLAPI void APIENTRY glBlendEquationSeparatei (GLuint buf, GLenum modeRGB, GLenum modeAlpha); +GLAPI void APIENTRY glBlendFunci (GLuint buf, GLenum src, GLenum dst); +GLAPI void APIENTRY glBlendFuncSeparatei (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLMINSAMPLESHADINGPROC) (GLfloat value); +typedef void (APIENTRYP PFNGLBLENDEQUATIONIPROC) (GLuint buf, GLenum mode); +typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEIPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha); +typedef void (APIENTRYP PFNGLBLENDFUNCIPROC) (GLuint buf, GLenum src, GLenum dst); +typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEIPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +#endif + +#ifndef GL_VERSION_4_1 +#define GL_VERSION_4_1 1 +/* OpenGL 4.1 reuses entry points from these extensions: */ +/* ARB_ES2_compatibility */ +/* ARB_get_program_binary */ +/* ARB_separate_shader_objects */ +/* ARB_shader_precision (no entry points) */ +/* ARB_vertex_attrib_64bit */ +/* ARB_viewport_array */ +#endif + +#ifndef GL_VERSION_4_2 +#define GL_VERSION_4_2 1 +/* OpenGL 4.2 reuses entry points from these extensions: */ +/* ARB_base_instance */ +/* ARB_shading_language_420pack (no entry points) */ +/* ARB_transform_feedback_instanced */ +/* ARB_compressed_texture_pixel_storage (no entry points) */ +/* ARB_conservative_depth (no entry points) */ +/* ARB_internalformat_query */ +/* ARB_map_buffer_alignment (no entry points) */ +/* ARB_shader_atomic_counters */ +/* ARB_shader_image_load_store */ +/* ARB_shading_language_packing (no entry points) */ +/* ARB_texture_storage */ +#endif + +#ifndef GL_VERSION_4_3 +#define GL_VERSION_4_3 1 +/* OpenGL 4.3 reuses entry points from these extensions: */ +/* ARB_arrays_of_arrays (no entry points, GLSL only) */ +/* ARB_fragment_layer_viewport (no entry points, GLSL only) */ +/* ARB_shader_image_size (no entry points, GLSL only) */ +/* ARB_ES3_compatibility (no entry points) */ +/* ARB_clear_buffer_object */ +/* ARB_compute_shader */ +/* ARB_copy_image */ +/* KHR_debug (includes ARB_debug_output commands promoted to KHR without suffixes) */ +/* ARB_explicit_uniform_location (no entry points) */ +/* ARB_framebuffer_no_attachments */ +/* ARB_internalformat_query2 */ +/* ARB_invalidate_subdata */ +/* ARB_multi_draw_indirect */ +/* ARB_program_interface_query */ +/* ARB_robust_buffer_access_behavior (no entry points) */ +/* ARB_shader_storage_buffer_object */ +/* ARB_stencil_texturing (no entry points) */ +/* ARB_texture_buffer_range */ +/* ARB_texture_query_levels (no entry points) */ +/* ARB_texture_storage_multisample */ +/* ARB_texture_view */ +/* ARB_vertex_attrib_binding */ +#endif + +#ifndef GL_ARB_depth_buffer_float +#define GL_ARB_depth_buffer_float 1 +#endif + +#ifndef GL_ARB_framebuffer_object +#define GL_ARB_framebuffer_object 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI GLboolean APIENTRY glIsRenderbuffer (GLuint renderbuffer); +GLAPI void APIENTRY glBindRenderbuffer (GLenum target, GLuint renderbuffer); +GLAPI void APIENTRY glDeleteRenderbuffers (GLsizei n, const GLuint *renderbuffers); +GLAPI void APIENTRY glGenRenderbuffers (GLsizei n, GLuint *renderbuffers); +GLAPI void APIENTRY glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint *params); +GLAPI GLboolean APIENTRY glIsFramebuffer (GLuint framebuffer); +GLAPI void APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer); +GLAPI void APIENTRY glDeleteFramebuffers (GLsizei n, const GLuint *framebuffers); +GLAPI void APIENTRY glGenFramebuffers (GLsizei n, GLuint *framebuffers); +GLAPI GLenum APIENTRY glCheckFramebufferStatus (GLenum target); +GLAPI void APIENTRY glFramebufferTexture1D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI void APIENTRY glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI void APIENTRY glFramebufferTexture3D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +GLAPI void APIENTRY glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +GLAPI void APIENTRY glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint *params); +GLAPI void APIENTRY glGenerateMipmap (GLenum target); +GLAPI void APIENTRY glBlitFramebuffer (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +GLAPI void APIENTRY glRenderbufferStorageMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glFramebufferTextureLayer (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +#endif /* GLCOREARB_PROTOTYPES */ +typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFERPROC) (GLuint renderbuffer); +typedef void (APIENTRYP PFNGLBINDRENDERBUFFERPROC) (GLenum target, GLuint renderbuffer); +typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSPROC) (GLsizei n, const GLuint *renderbuffers); +typedef void (APIENTRYP PFNGLGENRENDERBUFFERSPROC) (GLsizei n, GLuint *renderbuffers); +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFERPROC) (GLuint framebuffer); +typedef void (APIENTRYP PFNGLBINDFRAMEBUFFERPROC) (GLenum target, GLuint framebuffer); +typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC) (GLsizei n, const GLuint *framebuffers); +typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSPROC) (GLsizei n, GLuint *framebuffers); +typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSPROC) (GLenum target); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFERPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGENERATEMIPMAPPROC) (GLenum target); +typedef void (APIENTRYP PFNGLBLITFRAMEBUFFERPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +#endif + +#ifndef GL_ARB_framebuffer_sRGB +#define GL_ARB_framebuffer_sRGB 1 +#endif + +#ifndef GL_ARB_half_float_vertex +#define GL_ARB_half_float_vertex 1 +#endif + +#ifndef GL_ARB_map_buffer_range +#define GL_ARB_map_buffer_range 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI GLvoid* APIENTRY glMapBufferRange (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); +GLAPI void APIENTRY glFlushMappedBufferRange (GLenum target, GLintptr offset, GLsizeiptr length); +#endif /* GLCOREARB_PROTOTYPES */ +typedef GLvoid* (APIENTRYP PFNGLMAPBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); +typedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length); +#endif + +#ifndef GL_ARB_texture_compression_rgtc +#define GL_ARB_texture_compression_rgtc 1 +#endif + +#ifndef GL_ARB_texture_rg +#define GL_ARB_texture_rg 1 +#endif + +#ifndef GL_ARB_vertex_array_object +#define GL_ARB_vertex_array_object 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glBindVertexArray (GLuint array); +GLAPI void APIENTRY glDeleteVertexArrays (GLsizei n, const GLuint *arrays); +GLAPI void APIENTRY glGenVertexArrays (GLsizei n, GLuint *arrays); +GLAPI GLboolean APIENTRY glIsVertexArray (GLuint array); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC) (GLuint array); +typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint *arrays); +typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays); +typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYPROC) (GLuint array); +#endif + +#ifndef GL_ARB_uniform_buffer_object +#define GL_ARB_uniform_buffer_object 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glGetUniformIndices (GLuint program, GLsizei uniformCount, const GLchar* const *uniformNames, GLuint *uniformIndices); +GLAPI void APIENTRY glGetActiveUniformsiv (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetActiveUniformName (GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName); +GLAPI GLuint APIENTRY glGetUniformBlockIndex (GLuint program, const GLchar *uniformBlockName); +GLAPI void APIENTRY glGetActiveUniformBlockiv (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetActiveUniformBlockName (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName); +GLAPI void APIENTRY glUniformBlockBinding (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLGETUNIFORMINDICESPROC) (GLuint program, GLsizei uniformCount, const GLchar* const *uniformNames, GLuint *uniformIndices); +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMSIVPROC) (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMNAMEPROC) (GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName); +typedef GLuint (APIENTRYP PFNGLGETUNIFORMBLOCKINDEXPROC) (GLuint program, const GLchar *uniformBlockName); +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKIVPROC) (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC) (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName); +typedef void (APIENTRYP PFNGLUNIFORMBLOCKBINDINGPROC) (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); +#endif + +#ifndef GL_ARB_copy_buffer +#define GL_ARB_copy_buffer 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glCopyBufferSubData (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLCOPYBUFFERSUBDATAPROC) (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); +#endif + +#ifndef GL_ARB_depth_clamp +#define GL_ARB_depth_clamp 1 +#endif + +#ifndef GL_ARB_draw_elements_base_vertex +#define GL_ARB_draw_elements_base_vertex 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glDrawElementsBaseVertex (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex); +GLAPI void APIENTRY glDrawRangeElementsBaseVertex (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex); +GLAPI void APIENTRY glDrawElementsInstancedBaseVertex (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instancecount, GLint basevertex); +GLAPI void APIENTRY glMultiDrawElementsBaseVertex (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* const *indices, GLsizei drawcount, const GLint *basevertex); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex); +typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex); +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instancecount, GLint basevertex); +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* const *indices, GLsizei drawcount, const GLint *basevertex); +#endif + +#ifndef GL_ARB_fragment_coord_conventions +#define GL_ARB_fragment_coord_conventions 1 +#endif + +#ifndef GL_ARB_provoking_vertex +#define GL_ARB_provoking_vertex 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glProvokingVertex (GLenum mode); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLPROVOKINGVERTEXPROC) (GLenum mode); +#endif + +#ifndef GL_ARB_seamless_cube_map +#define GL_ARB_seamless_cube_map 1 +#endif + +#ifndef GL_ARB_sync +#define GL_ARB_sync 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI GLsync APIENTRY glFenceSync (GLenum condition, GLbitfield flags); +GLAPI GLboolean APIENTRY glIsSync (GLsync sync); +GLAPI void APIENTRY glDeleteSync (GLsync sync); +GLAPI GLenum APIENTRY glClientWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout); +GLAPI void APIENTRY glWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout); +GLAPI void APIENTRY glGetInteger64v (GLenum pname, GLint64 *params); +GLAPI void APIENTRY glGetSynciv (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); +#endif /* GLCOREARB_PROTOTYPES */ +typedef GLsync (APIENTRYP PFNGLFENCESYNCPROC) (GLenum condition, GLbitfield flags); +typedef GLboolean (APIENTRYP PFNGLISSYNCPROC) (GLsync sync); +typedef void (APIENTRYP PFNGLDELETESYNCPROC) (GLsync sync); +typedef GLenum (APIENTRYP PFNGLCLIENTWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout); +typedef void (APIENTRYP PFNGLWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout); +typedef void (APIENTRYP PFNGLGETINTEGER64VPROC) (GLenum pname, GLint64 *params); +typedef void (APIENTRYP PFNGLGETSYNCIVPROC) (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); +#endif + +#ifndef GL_ARB_texture_multisample +#define GL_ARB_texture_multisample 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glTexImage2DMultisample (GLenum target, GLsizei samples, GLint internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +GLAPI void APIENTRY glTexImage3DMultisample (GLenum target, GLsizei samples, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +GLAPI void APIENTRY glGetMultisamplefv (GLenum pname, GLuint index, GLfloat *val); +GLAPI void APIENTRY glSampleMaski (GLuint index, GLbitfield mask); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLint internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +typedef void (APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +typedef void (APIENTRYP PFNGLGETMULTISAMPLEFVPROC) (GLenum pname, GLuint index, GLfloat *val); +typedef void (APIENTRYP PFNGLSAMPLEMASKIPROC) (GLuint index, GLbitfield mask); +#endif + +#ifndef GL_ARB_vertex_array_bgra +#define GL_ARB_vertex_array_bgra 1 +#endif + +#ifndef GL_ARB_draw_buffers_blend +#define GL_ARB_draw_buffers_blend 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glBlendEquationiARB (GLuint buf, GLenum mode); +GLAPI void APIENTRY glBlendEquationSeparateiARB (GLuint buf, GLenum modeRGB, GLenum modeAlpha); +GLAPI void APIENTRY glBlendFunciARB (GLuint buf, GLenum src, GLenum dst); +GLAPI void APIENTRY glBlendFuncSeparateiARB (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLBLENDEQUATIONIARBPROC) (GLuint buf, GLenum mode); +typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEIARBPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha); +typedef void (APIENTRYP PFNGLBLENDFUNCIARBPROC) (GLuint buf, GLenum src, GLenum dst); +typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEIARBPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +#endif + +#ifndef GL_ARB_sample_shading +#define GL_ARB_sample_shading 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glMinSampleShadingARB (GLfloat value); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLMINSAMPLESHADINGARBPROC) (GLfloat value); +#endif + +#ifndef GL_ARB_texture_cube_map_array +#define GL_ARB_texture_cube_map_array 1 +#endif + +#ifndef GL_ARB_texture_gather +#define GL_ARB_texture_gather 1 +#endif + +#ifndef GL_ARB_texture_query_lod +#define GL_ARB_texture_query_lod 1 +#endif + +#ifndef GL_ARB_shading_language_include +#define GL_ARB_shading_language_include 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glNamedStringARB (GLenum type, GLint namelen, const GLchar *name, GLint stringlen, const GLchar *string); +GLAPI void APIENTRY glDeleteNamedStringARB (GLint namelen, const GLchar *name); +GLAPI void APIENTRY glCompileShaderIncludeARB (GLuint shader, GLsizei count, const GLchar* *path, const GLint *length); +GLAPI GLboolean APIENTRY glIsNamedStringARB (GLint namelen, const GLchar *name); +GLAPI void APIENTRY glGetNamedStringARB (GLint namelen, const GLchar *name, GLsizei bufSize, GLint *stringlen, GLchar *string); +GLAPI void APIENTRY glGetNamedStringivARB (GLint namelen, const GLchar *name, GLenum pname, GLint *params); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLNAMEDSTRINGARBPROC) (GLenum type, GLint namelen, const GLchar *name, GLint stringlen, const GLchar *string); +typedef void (APIENTRYP PFNGLDELETENAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name); +typedef void (APIENTRYP PFNGLCOMPILESHADERINCLUDEARBPROC) (GLuint shader, GLsizei count, const GLchar* *path, const GLint *length); +typedef GLboolean (APIENTRYP PFNGLISNAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name); +typedef void (APIENTRYP PFNGLGETNAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name, GLsizei bufSize, GLint *stringlen, GLchar *string); +typedef void (APIENTRYP PFNGLGETNAMEDSTRINGIVARBPROC) (GLint namelen, const GLchar *name, GLenum pname, GLint *params); +#endif + +#ifndef GL_ARB_texture_compression_bptc +#define GL_ARB_texture_compression_bptc 1 +#endif + +#ifndef GL_ARB_blend_func_extended +#define GL_ARB_blend_func_extended 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glBindFragDataLocationIndexed (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name); +GLAPI GLint APIENTRY glGetFragDataIndex (GLuint program, const GLchar *name); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONINDEXEDPROC) (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name); +typedef GLint (APIENTRYP PFNGLGETFRAGDATAINDEXPROC) (GLuint program, const GLchar *name); +#endif + +#ifndef GL_ARB_explicit_attrib_location +#define GL_ARB_explicit_attrib_location 1 +#endif + +#ifndef GL_ARB_occlusion_query2 +#define GL_ARB_occlusion_query2 1 +#endif + +#ifndef GL_ARB_sampler_objects +#define GL_ARB_sampler_objects 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glGenSamplers (GLsizei count, GLuint *samplers); +GLAPI void APIENTRY glDeleteSamplers (GLsizei count, const GLuint *samplers); +GLAPI GLboolean APIENTRY glIsSampler (GLuint sampler); +GLAPI void APIENTRY glBindSampler (GLuint unit, GLuint sampler); +GLAPI void APIENTRY glSamplerParameteri (GLuint sampler, GLenum pname, GLint param); +GLAPI void APIENTRY glSamplerParameteriv (GLuint sampler, GLenum pname, const GLint *param); +GLAPI void APIENTRY glSamplerParameterf (GLuint sampler, GLenum pname, GLfloat param); +GLAPI void APIENTRY glSamplerParameterfv (GLuint sampler, GLenum pname, const GLfloat *param); +GLAPI void APIENTRY glSamplerParameterIiv (GLuint sampler, GLenum pname, const GLint *param); +GLAPI void APIENTRY glSamplerParameterIuiv (GLuint sampler, GLenum pname, const GLuint *param); +GLAPI void APIENTRY glGetSamplerParameteriv (GLuint sampler, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetSamplerParameterIiv (GLuint sampler, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetSamplerParameterfv (GLuint sampler, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetSamplerParameterIuiv (GLuint sampler, GLenum pname, GLuint *params); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLGENSAMPLERSPROC) (GLsizei count, GLuint *samplers); +typedef void (APIENTRYP PFNGLDELETESAMPLERSPROC) (GLsizei count, const GLuint *samplers); +typedef GLboolean (APIENTRYP PFNGLISSAMPLERPROC) (GLuint sampler); +typedef void (APIENTRYP PFNGLBINDSAMPLERPROC) (GLuint unit, GLuint sampler); +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIPROC) (GLuint sampler, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, const GLint *param); +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFPROC) (GLuint sampler, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, const GLfloat *param); +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIIVPROC) (GLuint sampler, GLenum pname, const GLint *param); +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, const GLuint *param); +typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIIVPROC) (GLuint sampler, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, GLuint *params); +#endif + +#ifndef GL_ARB_shader_bit_encoding +#define GL_ARB_shader_bit_encoding 1 +#endif + +#ifndef GL_ARB_texture_rgb10_a2ui +#define GL_ARB_texture_rgb10_a2ui 1 +#endif + +#ifndef GL_ARB_texture_swizzle +#define GL_ARB_texture_swizzle 1 +#endif + +#ifndef GL_ARB_timer_query +#define GL_ARB_timer_query 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glQueryCounter (GLuint id, GLenum target); +GLAPI void APIENTRY glGetQueryObjecti64v (GLuint id, GLenum pname, GLint64 *params); +GLAPI void APIENTRY glGetQueryObjectui64v (GLuint id, GLenum pname, GLuint64 *params); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLQUERYCOUNTERPROC) (GLuint id, GLenum target); +typedef void (APIENTRYP PFNGLGETQUERYOBJECTI64VPROC) (GLuint id, GLenum pname, GLint64 *params); +typedef void (APIENTRYP PFNGLGETQUERYOBJECTUI64VPROC) (GLuint id, GLenum pname, GLuint64 *params); +#endif + +#ifndef GL_ARB_vertex_type_2_10_10_10_rev +#define GL_ARB_vertex_type_2_10_10_10_rev 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glVertexP2ui (GLenum type, GLuint value); +GLAPI void APIENTRY glVertexP2uiv (GLenum type, const GLuint *value); +GLAPI void APIENTRY glVertexP3ui (GLenum type, GLuint value); +GLAPI void APIENTRY glVertexP3uiv (GLenum type, const GLuint *value); +GLAPI void APIENTRY glVertexP4ui (GLenum type, GLuint value); +GLAPI void APIENTRY glVertexP4uiv (GLenum type, const GLuint *value); +GLAPI void APIENTRY glTexCoordP1ui (GLenum type, GLuint coords); +GLAPI void APIENTRY glTexCoordP1uiv (GLenum type, const GLuint *coords); +GLAPI void APIENTRY glTexCoordP2ui (GLenum type, GLuint coords); +GLAPI void APIENTRY glTexCoordP2uiv (GLenum type, const GLuint *coords); +GLAPI void APIENTRY glTexCoordP3ui (GLenum type, GLuint coords); +GLAPI void APIENTRY glTexCoordP3uiv (GLenum type, const GLuint *coords); +GLAPI void APIENTRY glTexCoordP4ui (GLenum type, GLuint coords); +GLAPI void APIENTRY glTexCoordP4uiv (GLenum type, const GLuint *coords); +GLAPI void APIENTRY glMultiTexCoordP1ui (GLenum texture, GLenum type, GLuint coords); +GLAPI void APIENTRY glMultiTexCoordP1uiv (GLenum texture, GLenum type, const GLuint *coords); +GLAPI void APIENTRY glMultiTexCoordP2ui (GLenum texture, GLenum type, GLuint coords); +GLAPI void APIENTRY glMultiTexCoordP2uiv (GLenum texture, GLenum type, const GLuint *coords); +GLAPI void APIENTRY glMultiTexCoordP3ui (GLenum texture, GLenum type, GLuint coords); +GLAPI void APIENTRY glMultiTexCoordP3uiv (GLenum texture, GLenum type, const GLuint *coords); +GLAPI void APIENTRY glMultiTexCoordP4ui (GLenum texture, GLenum type, GLuint coords); +GLAPI void APIENTRY glMultiTexCoordP4uiv (GLenum texture, GLenum type, const GLuint *coords); +GLAPI void APIENTRY glNormalP3ui (GLenum type, GLuint coords); +GLAPI void APIENTRY glNormalP3uiv (GLenum type, const GLuint *coords); +GLAPI void APIENTRY glColorP3ui (GLenum type, GLuint color); +GLAPI void APIENTRY glColorP3uiv (GLenum type, const GLuint *color); +GLAPI void APIENTRY glColorP4ui (GLenum type, GLuint color); +GLAPI void APIENTRY glColorP4uiv (GLenum type, const GLuint *color); +GLAPI void APIENTRY glSecondaryColorP3ui (GLenum type, GLuint color); +GLAPI void APIENTRY glSecondaryColorP3uiv (GLenum type, const GLuint *color); +GLAPI void APIENTRY glVertexAttribP1ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); +GLAPI void APIENTRY glVertexAttribP1uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +GLAPI void APIENTRY glVertexAttribP2ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); +GLAPI void APIENTRY glVertexAttribP2uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +GLAPI void APIENTRY glVertexAttribP3ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); +GLAPI void APIENTRY glVertexAttribP3uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +GLAPI void APIENTRY glVertexAttribP4ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); +GLAPI void APIENTRY glVertexAttribP4uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLVERTEXP2UIPROC) (GLenum type, GLuint value); +typedef void (APIENTRYP PFNGLVERTEXP2UIVPROC) (GLenum type, const GLuint *value); +typedef void (APIENTRYP PFNGLVERTEXP3UIPROC) (GLenum type, GLuint value); +typedef void (APIENTRYP PFNGLVERTEXP3UIVPROC) (GLenum type, const GLuint *value); +typedef void (APIENTRYP PFNGLVERTEXP4UIPROC) (GLenum type, GLuint value); +typedef void (APIENTRYP PFNGLVERTEXP4UIVPROC) (GLenum type, const GLuint *value); +typedef void (APIENTRYP PFNGLTEXCOORDP1UIPROC) (GLenum type, GLuint coords); +typedef void (APIENTRYP PFNGLTEXCOORDP1UIVPROC) (GLenum type, const GLuint *coords); +typedef void (APIENTRYP PFNGLTEXCOORDP2UIPROC) (GLenum type, GLuint coords); +typedef void (APIENTRYP PFNGLTEXCOORDP2UIVPROC) (GLenum type, const GLuint *coords); +typedef void (APIENTRYP PFNGLTEXCOORDP3UIPROC) (GLenum type, GLuint coords); +typedef void (APIENTRYP PFNGLTEXCOORDP3UIVPROC) (GLenum type, const GLuint *coords); +typedef void (APIENTRYP PFNGLTEXCOORDP4UIPROC) (GLenum type, GLuint coords); +typedef void (APIENTRYP PFNGLTEXCOORDP4UIVPROC) (GLenum type, const GLuint *coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIPROC) (GLenum texture, GLenum type, GLuint coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIVPROC) (GLenum texture, GLenum type, const GLuint *coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIPROC) (GLenum texture, GLenum type, GLuint coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIVPROC) (GLenum texture, GLenum type, const GLuint *coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIPROC) (GLenum texture, GLenum type, GLuint coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIVPROC) (GLenum texture, GLenum type, const GLuint *coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIPROC) (GLenum texture, GLenum type, GLuint coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIVPROC) (GLenum texture, GLenum type, const GLuint *coords); +typedef void (APIENTRYP PFNGLNORMALP3UIPROC) (GLenum type, GLuint coords); +typedef void (APIENTRYP PFNGLNORMALP3UIVPROC) (GLenum type, const GLuint *coords); +typedef void (APIENTRYP PFNGLCOLORP3UIPROC) (GLenum type, GLuint color); +typedef void (APIENTRYP PFNGLCOLORP3UIVPROC) (GLenum type, const GLuint *color); +typedef void (APIENTRYP PFNGLCOLORP4UIPROC) (GLenum type, GLuint color); +typedef void (APIENTRYP PFNGLCOLORP4UIVPROC) (GLenum type, const GLuint *color); +typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIPROC) (GLenum type, GLuint color); +typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIVPROC) (GLenum type, const GLuint *color); +typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); +typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); +typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); +typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); +typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +#endif + +#ifndef GL_ARB_draw_indirect +#define GL_ARB_draw_indirect 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glDrawArraysIndirect (GLenum mode, const GLvoid *indirect); +GLAPI void APIENTRY glDrawElementsIndirect (GLenum mode, GLenum type, const GLvoid *indirect); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLDRAWARRAYSINDIRECTPROC) (GLenum mode, const GLvoid *indirect); +typedef void (APIENTRYP PFNGLDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const GLvoid *indirect); +#endif + +#ifndef GL_ARB_gpu_shader5 +#define GL_ARB_gpu_shader5 1 +#endif + +#ifndef GL_ARB_gpu_shader_fp64 +#define GL_ARB_gpu_shader_fp64 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glUniform1d (GLint location, GLdouble x); +GLAPI void APIENTRY glUniform2d (GLint location, GLdouble x, GLdouble y); +GLAPI void APIENTRY glUniform3d (GLint location, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glUniform4d (GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glUniform1dv (GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glUniform2dv (GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glUniform3dv (GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glUniform4dv (GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix2x3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix2x4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix3x2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix3x4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix4x2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix4x3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glGetUniformdv (GLuint program, GLint location, GLdouble *params); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLUNIFORM1DPROC) (GLint location, GLdouble x); +typedef void (APIENTRYP PFNGLUNIFORM2DPROC) (GLint location, GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLUNIFORM3DPROC) (GLint location, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLUNIFORM4DPROC) (GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLUNIFORM1DVPROC) (GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORM2DVPROC) (GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORM3DVPROC) (GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORM4DVPROC) (GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLGETUNIFORMDVPROC) (GLuint program, GLint location, GLdouble *params); +#endif + +#ifndef GL_ARB_shader_subroutine +#define GL_ARB_shader_subroutine 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI GLint APIENTRY glGetSubroutineUniformLocation (GLuint program, GLenum shadertype, const GLchar *name); +GLAPI GLuint APIENTRY glGetSubroutineIndex (GLuint program, GLenum shadertype, const GLchar *name); +GLAPI void APIENTRY glGetActiveSubroutineUniformiv (GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values); +GLAPI void APIENTRY glGetActiveSubroutineUniformName (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name); +GLAPI void APIENTRY glGetActiveSubroutineName (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name); +GLAPI void APIENTRY glUniformSubroutinesuiv (GLenum shadertype, GLsizei count, const GLuint *indices); +GLAPI void APIENTRY glGetUniformSubroutineuiv (GLenum shadertype, GLint location, GLuint *params); +GLAPI void APIENTRY glGetProgramStageiv (GLuint program, GLenum shadertype, GLenum pname, GLint *values); +#endif /* GLCOREARB_PROTOTYPES */ +typedef GLint (APIENTRYP PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC) (GLuint program, GLenum shadertype, const GLchar *name); +typedef GLuint (APIENTRYP PFNGLGETSUBROUTINEINDEXPROC) (GLuint program, GLenum shadertype, const GLchar *name); +typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC) (GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values); +typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC) (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name); +typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINENAMEPROC) (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name); +typedef void (APIENTRYP PFNGLUNIFORMSUBROUTINESUIVPROC) (GLenum shadertype, GLsizei count, const GLuint *indices); +typedef void (APIENTRYP PFNGLGETUNIFORMSUBROUTINEUIVPROC) (GLenum shadertype, GLint location, GLuint *params); +typedef void (APIENTRYP PFNGLGETPROGRAMSTAGEIVPROC) (GLuint program, GLenum shadertype, GLenum pname, GLint *values); +#endif + +#ifndef GL_ARB_tessellation_shader +#define GL_ARB_tessellation_shader 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glPatchParameteri (GLenum pname, GLint value); +GLAPI void APIENTRY glPatchParameterfv (GLenum pname, const GLfloat *values); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLPATCHPARAMETERIPROC) (GLenum pname, GLint value); +typedef void (APIENTRYP PFNGLPATCHPARAMETERFVPROC) (GLenum pname, const GLfloat *values); +#endif + +#ifndef GL_ARB_texture_buffer_object_rgb32 +#define GL_ARB_texture_buffer_object_rgb32 1 +#endif + +#ifndef GL_ARB_transform_feedback2 +#define GL_ARB_transform_feedback2 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glBindTransformFeedback (GLenum target, GLuint id); +GLAPI void APIENTRY glDeleteTransformFeedbacks (GLsizei n, const GLuint *ids); +GLAPI void APIENTRY glGenTransformFeedbacks (GLsizei n, GLuint *ids); +GLAPI GLboolean APIENTRY glIsTransformFeedback (GLuint id); +GLAPI void APIENTRY glPauseTransformFeedback (void); +GLAPI void APIENTRY glResumeTransformFeedback (void); +GLAPI void APIENTRY glDrawTransformFeedback (GLenum mode, GLuint id); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLBINDTRANSFORMFEEDBACKPROC) (GLenum target, GLuint id); +typedef void (APIENTRYP PFNGLDELETETRANSFORMFEEDBACKSPROC) (GLsizei n, const GLuint *ids); +typedef void (APIENTRYP PFNGLGENTRANSFORMFEEDBACKSPROC) (GLsizei n, GLuint *ids); +typedef GLboolean (APIENTRYP PFNGLISTRANSFORMFEEDBACKPROC) (GLuint id); +typedef void (APIENTRYP PFNGLPAUSETRANSFORMFEEDBACKPROC) (void); +typedef void (APIENTRYP PFNGLRESUMETRANSFORMFEEDBACKPROC) (void); +typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKPROC) (GLenum mode, GLuint id); +#endif + +#ifndef GL_ARB_transform_feedback3 +#define GL_ARB_transform_feedback3 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glDrawTransformFeedbackStream (GLenum mode, GLuint id, GLuint stream); +GLAPI void APIENTRY glBeginQueryIndexed (GLenum target, GLuint index, GLuint id); +GLAPI void APIENTRY glEndQueryIndexed (GLenum target, GLuint index); +GLAPI void APIENTRY glGetQueryIndexediv (GLenum target, GLuint index, GLenum pname, GLint *params); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC) (GLenum mode, GLuint id, GLuint stream); +typedef void (APIENTRYP PFNGLBEGINQUERYINDEXEDPROC) (GLenum target, GLuint index, GLuint id); +typedef void (APIENTRYP PFNGLENDQUERYINDEXEDPROC) (GLenum target, GLuint index); +typedef void (APIENTRYP PFNGLGETQUERYINDEXEDIVPROC) (GLenum target, GLuint index, GLenum pname, GLint *params); +#endif + +#ifndef GL_ARB_ES2_compatibility +#define GL_ARB_ES2_compatibility 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glReleaseShaderCompiler (void); +GLAPI void APIENTRY glShaderBinary (GLsizei count, const GLuint *shaders, GLenum binaryformat, const GLvoid *binary, GLsizei length); +GLAPI void APIENTRY glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision); +GLAPI void APIENTRY glDepthRangef (GLfloat n, GLfloat f); +GLAPI void APIENTRY glClearDepthf (GLfloat d); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLRELEASESHADERCOMPILERPROC) (void); +typedef void (APIENTRYP PFNGLSHADERBINARYPROC) (GLsizei count, const GLuint *shaders, GLenum binaryformat, const GLvoid *binary, GLsizei length); +typedef void (APIENTRYP PFNGLGETSHADERPRECISIONFORMATPROC) (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision); +typedef void (APIENTRYP PFNGLDEPTHRANGEFPROC) (GLfloat n, GLfloat f); +typedef void (APIENTRYP PFNGLCLEARDEPTHFPROC) (GLfloat d); +#endif + +#ifndef GL_ARB_get_program_binary +#define GL_ARB_get_program_binary 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glGetProgramBinary (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary); +GLAPI void APIENTRY glProgramBinary (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLsizei length); +GLAPI void APIENTRY glProgramParameteri (GLuint program, GLenum pname, GLint value); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLGETPROGRAMBINARYPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary); +typedef void (APIENTRYP PFNGLPROGRAMBINARYPROC) (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLsizei length); +typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIPROC) (GLuint program, GLenum pname, GLint value); +#endif + +#ifndef GL_ARB_separate_shader_objects +#define GL_ARB_separate_shader_objects 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glUseProgramStages (GLuint pipeline, GLbitfield stages, GLuint program); +GLAPI void APIENTRY glActiveShaderProgram (GLuint pipeline, GLuint program); +GLAPI GLuint APIENTRY glCreateShaderProgramv (GLenum type, GLsizei count, const GLchar* const *strings); +GLAPI void APIENTRY glBindProgramPipeline (GLuint pipeline); +GLAPI void APIENTRY glDeleteProgramPipelines (GLsizei n, const GLuint *pipelines); +GLAPI void APIENTRY glGenProgramPipelines (GLsizei n, GLuint *pipelines); +GLAPI GLboolean APIENTRY glIsProgramPipeline (GLuint pipeline); +GLAPI void APIENTRY glGetProgramPipelineiv (GLuint pipeline, GLenum pname, GLint *params); +GLAPI void APIENTRY glProgramUniform1i (GLuint program, GLint location, GLint v0); +GLAPI void APIENTRY glProgramUniform1iv (GLuint program, GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glProgramUniform1f (GLuint program, GLint location, GLfloat v0); +GLAPI void APIENTRY glProgramUniform1fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glProgramUniform1d (GLuint program, GLint location, GLdouble v0); +GLAPI void APIENTRY glProgramUniform1dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glProgramUniform1ui (GLuint program, GLint location, GLuint v0); +GLAPI void APIENTRY glProgramUniform1uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glProgramUniform2i (GLuint program, GLint location, GLint v0, GLint v1); +GLAPI void APIENTRY glProgramUniform2iv (GLuint program, GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glProgramUniform2f (GLuint program, GLint location, GLfloat v0, GLfloat v1); +GLAPI void APIENTRY glProgramUniform2fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glProgramUniform2d (GLuint program, GLint location, GLdouble v0, GLdouble v1); +GLAPI void APIENTRY glProgramUniform2dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glProgramUniform2ui (GLuint program, GLint location, GLuint v0, GLuint v1); +GLAPI void APIENTRY glProgramUniform2uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glProgramUniform3i (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); +GLAPI void APIENTRY glProgramUniform3iv (GLuint program, GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glProgramUniform3f (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +GLAPI void APIENTRY glProgramUniform3fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glProgramUniform3d (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2); +GLAPI void APIENTRY glProgramUniform3dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glProgramUniform3ui (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); +GLAPI void APIENTRY glProgramUniform3uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glProgramUniform4i (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +GLAPI void APIENTRY glProgramUniform4iv (GLuint program, GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glProgramUniform4f (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +GLAPI void APIENTRY glProgramUniform4fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glProgramUniform4d (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3); +GLAPI void APIENTRY glProgramUniform4dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glProgramUniform4ui (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +GLAPI void APIENTRY glProgramUniform4uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glProgramUniformMatrix2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix2x3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix3x2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix2x4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix4x2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix3x4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix4x3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix2x3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix3x2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix2x4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix4x2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix3x4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix4x3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glValidateProgramPipeline (GLuint pipeline); +GLAPI void APIENTRY glGetProgramPipelineInfoLog (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLUSEPROGRAMSTAGESPROC) (GLuint pipeline, GLbitfield stages, GLuint program); +typedef void (APIENTRYP PFNGLACTIVESHADERPROGRAMPROC) (GLuint pipeline, GLuint program); +typedef GLuint (APIENTRYP PFNGLCREATESHADERPROGRAMVPROC) (GLenum type, GLsizei count, const GLchar* const *strings); +typedef void (APIENTRYP PFNGLBINDPROGRAMPIPELINEPROC) (GLuint pipeline); +typedef void (APIENTRYP PFNGLDELETEPROGRAMPIPELINESPROC) (GLsizei n, const GLuint *pipelines); +typedef void (APIENTRYP PFNGLGENPROGRAMPIPELINESPROC) (GLsizei n, GLuint *pipelines); +typedef GLboolean (APIENTRYP PFNGLISPROGRAMPIPELINEPROC) (GLuint pipeline); +typedef void (APIENTRYP PFNGLGETPROGRAMPIPELINEIVPROC) (GLuint pipeline, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IPROC) (GLuint program, GLint location, GLint v0); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FPROC) (GLuint program, GLint location, GLfloat v0); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DPROC) (GLuint program, GLint location, GLdouble v0); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIPROC) (GLuint program, GLint location, GLuint v0); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IPROC) (GLuint program, GLint location, GLint v0, GLint v1); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPIPELINEPROC) (GLuint pipeline); +typedef void (APIENTRYP PFNGLGETPROGRAMPIPELINEINFOLOGPROC) (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +#endif + +#ifndef GL_ARB_vertex_attrib_64bit +#define GL_ARB_vertex_attrib_64bit 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glVertexAttribL1d (GLuint index, GLdouble x); +GLAPI void APIENTRY glVertexAttribL2d (GLuint index, GLdouble x, GLdouble y); +GLAPI void APIENTRY glVertexAttribL3d (GLuint index, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glVertexAttribL4d (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glVertexAttribL1dv (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribL2dv (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribL3dv (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribL4dv (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribLPointer (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +GLAPI void APIENTRY glGetVertexAttribLdv (GLuint index, GLenum pname, GLdouble *params); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DPROC) (GLuint index, GLdouble x); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DPROC) (GLuint index, GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLDVPROC) (GLuint index, GLenum pname, GLdouble *params); +#endif + +#ifndef GL_ARB_viewport_array +#define GL_ARB_viewport_array 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glViewportArrayv (GLuint first, GLsizei count, const GLfloat *v); +GLAPI void APIENTRY glViewportIndexedf (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h); +GLAPI void APIENTRY glViewportIndexedfv (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glScissorArrayv (GLuint first, GLsizei count, const GLint *v); +GLAPI void APIENTRY glScissorIndexed (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height); +GLAPI void APIENTRY glScissorIndexedv (GLuint index, const GLint *v); +GLAPI void APIENTRY glDepthRangeArrayv (GLuint first, GLsizei count, const GLdouble *v); +GLAPI void APIENTRY glDepthRangeIndexed (GLuint index, GLdouble n, GLdouble f); +GLAPI void APIENTRY glGetFloati_v (GLenum target, GLuint index, GLfloat *data); +GLAPI void APIENTRY glGetDoublei_v (GLenum target, GLuint index, GLdouble *data); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLVIEWPORTARRAYVPROC) (GLuint first, GLsizei count, const GLfloat *v); +typedef void (APIENTRYP PFNGLVIEWPORTINDEXEDFPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h); +typedef void (APIENTRYP PFNGLVIEWPORTINDEXEDFVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLSCISSORARRAYVPROC) (GLuint first, GLsizei count, const GLint *v); +typedef void (APIENTRYP PFNGLSCISSORINDEXEDPROC) (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLSCISSORINDEXEDVPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLDEPTHRANGEARRAYVPROC) (GLuint first, GLsizei count, const GLdouble *v); +typedef void (APIENTRYP PFNGLDEPTHRANGEINDEXEDPROC) (GLuint index, GLdouble n, GLdouble f); +typedef void (APIENTRYP PFNGLGETFLOATI_VPROC) (GLenum target, GLuint index, GLfloat *data); +typedef void (APIENTRYP PFNGLGETDOUBLEI_VPROC) (GLenum target, GLuint index, GLdouble *data); +#endif + +#ifndef GL_ARB_cl_event +#define GL_ARB_cl_event 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI GLsync APIENTRY glCreateSyncFromCLeventARB (struct _cl_context * context, struct _cl_event * event, GLbitfield flags); +#endif /* GLCOREARB_PROTOTYPES */ +typedef GLsync (APIENTRYP PFNGLCREATESYNCFROMCLEVENTARBPROC) (struct _cl_context * context, struct _cl_event * event, GLbitfield flags); +#endif + +#ifndef GL_ARB_debug_output +#define GL_ARB_debug_output 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glDebugMessageControlARB (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); +GLAPI void APIENTRY glDebugMessageInsertARB (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); +GLAPI void APIENTRY glDebugMessageCallbackARB (GLDEBUGPROCARB callback, const GLvoid *userParam); +GLAPI GLuint APIENTRY glGetDebugMessageLogARB (GLuint count, GLsizei bufsize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLARBPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); +typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTARBPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); +typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKARBPROC) (GLDEBUGPROCARB callback, const GLvoid *userParam); +typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGARBPROC) (GLuint count, GLsizei bufsize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); +#endif + +#ifndef GL_ARB_robustness +#define GL_ARB_robustness 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI GLenum APIENTRY glGetGraphicsResetStatusARB (void); +GLAPI void APIENTRY glGetnTexImageARB (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, GLvoid *img); +GLAPI void APIENTRY glReadnPixelsARB (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, GLvoid *data); +GLAPI void APIENTRY glGetnCompressedTexImageARB (GLenum target, GLint lod, GLsizei bufSize, GLvoid *img); +GLAPI void APIENTRY glGetnUniformfvARB (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); +GLAPI void APIENTRY glGetnUniformivARB (GLuint program, GLint location, GLsizei bufSize, GLint *params); +GLAPI void APIENTRY glGetnUniformuivARB (GLuint program, GLint location, GLsizei bufSize, GLuint *params); +GLAPI void APIENTRY glGetnUniformdvARB (GLuint program, GLint location, GLsizei bufSize, GLdouble *params); +#endif /* GLCOREARB_PROTOTYPES */ +typedef GLenum (APIENTRYP PFNGLGETGRAPHICSRESETSTATUSARBPROC) (void); +typedef void (APIENTRYP PFNGLGETNTEXIMAGEARBPROC) (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, GLvoid *img); +typedef void (APIENTRYP PFNGLREADNPIXELSARBPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, GLvoid *data); +typedef void (APIENTRYP PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint lod, GLsizei bufSize, GLvoid *img); +typedef void (APIENTRYP PFNGLGETNUNIFORMFVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); +typedef void (APIENTRYP PFNGLGETNUNIFORMIVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params); +typedef void (APIENTRYP PFNGLGETNUNIFORMUIVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint *params); +typedef void (APIENTRYP PFNGLGETNUNIFORMDVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLdouble *params); +#endif + +#ifndef GL_ARB_shader_stencil_export +#define GL_ARB_shader_stencil_export 1 +#endif + +#ifndef GL_ARB_base_instance +#define GL_ARB_base_instance 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glDrawArraysInstancedBaseInstance (GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance); +GLAPI void APIENTRY glDrawElementsInstancedBaseInstance (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance); +GLAPI void APIENTRY glDrawElementsInstancedBaseVertexBaseInstance (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance); +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance); +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance); +#endif + +#ifndef GL_ARB_shading_language_420pack +#define GL_ARB_shading_language_420pack 1 +#endif + +#ifndef GL_ARB_transform_feedback_instanced +#define GL_ARB_transform_feedback_instanced 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glDrawTransformFeedbackInstanced (GLenum mode, GLuint id, GLsizei instancecount); +GLAPI void APIENTRY glDrawTransformFeedbackStreamInstanced (GLenum mode, GLuint id, GLuint stream, GLsizei instancecount); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC) (GLenum mode, GLuint id, GLsizei instancecount); +typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC) (GLenum mode, GLuint id, GLuint stream, GLsizei instancecount); +#endif + +#ifndef GL_ARB_compressed_texture_pixel_storage +#define GL_ARB_compressed_texture_pixel_storage 1 +#endif + +#ifndef GL_ARB_conservative_depth +#define GL_ARB_conservative_depth 1 +#endif + +#ifndef GL_ARB_internalformat_query +#define GL_ARB_internalformat_query 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glGetInternalformativ (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLGETINTERNALFORMATIVPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params); +#endif + +#ifndef GL_ARB_map_buffer_alignment +#define GL_ARB_map_buffer_alignment 1 +#endif + +#ifndef GL_ARB_shader_atomic_counters +#define GL_ARB_shader_atomic_counters 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glGetActiveAtomicCounterBufferiv (GLuint program, GLuint bufferIndex, GLenum pname, GLint *params); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC) (GLuint program, GLuint bufferIndex, GLenum pname, GLint *params); +#endif + +#ifndef GL_ARB_shader_image_load_store +#define GL_ARB_shader_image_load_store 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glBindImageTexture (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); +GLAPI void APIENTRY glMemoryBarrier (GLbitfield barriers); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLBINDIMAGETEXTUREPROC) (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); +typedef void (APIENTRYP PFNGLMEMORYBARRIERPROC) (GLbitfield barriers); +#endif + +#ifndef GL_ARB_shading_language_packing +#define GL_ARB_shading_language_packing 1 +#endif + +#ifndef GL_ARB_texture_storage +#define GL_ARB_texture_storage 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glTexStorage1D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); +GLAPI void APIENTRY glTexStorage2D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glTexStorage3D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); +GLAPI void APIENTRY glTextureStorage1DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); +GLAPI void APIENTRY glTextureStorage2DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glTextureStorage3DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLTEXSTORAGE1DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); +typedef void (APIENTRYP PFNGLTEXSTORAGE2DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLTEXSTORAGE3DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); +typedef void (APIENTRYP PFNGLTEXTURESTORAGE1DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); +typedef void (APIENTRYP PFNGLTEXTURESTORAGE2DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLTEXTURESTORAGE3DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); +#endif + +#ifndef GL_KHR_texture_compression_astc_ldr +#define GL_KHR_texture_compression_astc_ldr 1 +#endif + +#ifndef GL_KHR_debug +#define GL_KHR_debug 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glDebugMessageControl (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); +GLAPI void APIENTRY glDebugMessageInsert (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); +GLAPI void APIENTRY glDebugMessageCallback (GLDEBUGPROC callback, const void *userParam); +GLAPI GLuint APIENTRY glGetDebugMessageLog (GLuint count, GLsizei bufsize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); +GLAPI void APIENTRY glPushDebugGroup (GLenum source, GLuint id, GLsizei length, const GLchar *message); +GLAPI void APIENTRY glPopDebugGroup (void); +GLAPI void APIENTRY glObjectLabel (GLenum identifier, GLuint name, GLsizei length, const GLchar *label); +GLAPI void APIENTRY glGetObjectLabel (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label); +GLAPI void APIENTRY glObjectPtrLabel (const void *ptr, GLsizei length, const GLchar *label); +GLAPI void APIENTRY glGetObjectPtrLabel (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); +typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); +typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKPROC) (GLDEBUGPROC callback, const void *userParam); +typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGPROC) (GLuint count, GLsizei bufsize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); +typedef void (APIENTRYP PFNGLPUSHDEBUGGROUPPROC) (GLenum source, GLuint id, GLsizei length, const GLchar *message); +typedef void (APIENTRYP PFNGLPOPDEBUGGROUPPROC) (void); +typedef void (APIENTRYP PFNGLOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei length, const GLchar *label); +typedef void (APIENTRYP PFNGLGETOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label); +typedef void (APIENTRYP PFNGLOBJECTPTRLABELPROC) (const void *ptr, GLsizei length, const GLchar *label); +typedef void (APIENTRYP PFNGLGETOBJECTPTRLABELPROC) (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label); +#endif + +#ifndef GL_ARB_arrays_of_arrays +#define GL_ARB_arrays_of_arrays 1 +#endif + +#ifndef GL_ARB_clear_buffer_object +#define GL_ARB_clear_buffer_object 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glClearBufferData (GLenum target, GLenum internalformat, GLenum format, GLenum type, const void *data); +GLAPI void APIENTRY glClearBufferSubData (GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data); +GLAPI void APIENTRY glClearNamedBufferDataEXT (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data); +GLAPI void APIENTRY glClearNamedBufferSubDataEXT (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, GLsizeiptr offset, GLsizeiptr size, const void *data); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLCLEARBUFFERDATAPROC) (GLenum target, GLenum internalformat, GLenum format, GLenum type, const void *data); +typedef void (APIENTRYP PFNGLCLEARBUFFERSUBDATAPROC) (GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data); +typedef void (APIENTRYP PFNGLCLEARNAMEDBUFFERDATAEXTPROC) (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data); +typedef void (APIENTRYP PFNGLCLEARNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, GLsizeiptr offset, GLsizeiptr size, const void *data); +#endif + +#ifndef GL_ARB_compute_shader +#define GL_ARB_compute_shader 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glDispatchCompute (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z); +GLAPI void APIENTRY glDispatchComputeIndirect (GLintptr indirect); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEPROC) (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z); +typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEINDIRECTPROC) (GLintptr indirect); +#endif + +#ifndef GL_ARB_copy_image +#define GL_ARB_copy_image 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glCopyImageSubData (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLCOPYIMAGESUBDATAPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth); +#endif + +#ifndef GL_ARB_texture_view +#define GL_ARB_texture_view 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glTextureView (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLTEXTUREVIEWPROC) (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers); +#endif + +#ifndef GL_ARB_vertex_attrib_binding +#define GL_ARB_vertex_attrib_binding 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glBindVertexBuffer (GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); +GLAPI void APIENTRY glVertexAttribFormat (GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); +GLAPI void APIENTRY glVertexAttribIFormat (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +GLAPI void APIENTRY glVertexAttribLFormat (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +GLAPI void APIENTRY glVertexAttribBinding (GLuint attribindex, GLuint bindingindex); +GLAPI void APIENTRY glVertexBindingDivisor (GLuint bindingindex, GLuint divisor); +GLAPI void APIENTRY glVertexArrayBindVertexBufferEXT (GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); +GLAPI void APIENTRY glVertexArrayVertexAttribFormatEXT (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); +GLAPI void APIENTRY glVertexArrayVertexAttribIFormatEXT (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +GLAPI void APIENTRY glVertexArrayVertexAttribLFormatEXT (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +GLAPI void APIENTRY glVertexArrayVertexAttribBindingEXT (GLuint vaobj, GLuint attribindex, GLuint bindingindex); +GLAPI void APIENTRY glVertexArrayVertexBindingDivisorEXT (GLuint vaobj, GLuint bindingindex, GLuint divisor); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLBINDVERTEXBUFFERPROC) (GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); +typedef void (APIENTRYP PFNGLVERTEXATTRIBFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); +typedef void (APIENTRYP PFNGLVERTEXATTRIBIFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +typedef void (APIENTRYP PFNGLVERTEXATTRIBLFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +typedef void (APIENTRYP PFNGLVERTEXATTRIBBINDINGPROC) (GLuint attribindex, GLuint bindingindex); +typedef void (APIENTRYP PFNGLVERTEXBINDINGDIVISORPROC) (GLuint bindingindex, GLuint divisor); +typedef void (APIENTRYP PFNGLVERTEXARRAYBINDVERTEXBUFFEREXTPROC) (GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); +typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBFORMATEXTPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); +typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBIFORMATEXTPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBLFORMATEXTPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBBINDINGEXTPROC) (GLuint vaobj, GLuint attribindex, GLuint bindingindex); +typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXBINDINGDIVISOREXTPROC) (GLuint vaobj, GLuint bindingindex, GLuint divisor); +#endif + +#ifndef GL_ARB_robustness_isolation +#define GL_ARB_robustness_isolation 1 +#endif + +#ifndef GL_ARB_ES3_compatibility +#define GL_ARB_ES3_compatibility 1 +#endif + +#ifndef GL_ARB_explicit_uniform_location +#define GL_ARB_explicit_uniform_location 1 +#endif + +#ifndef GL_ARB_fragment_layer_viewport +#define GL_ARB_fragment_layer_viewport 1 +#endif + +#ifndef GL_ARB_framebuffer_no_attachments +#define GL_ARB_framebuffer_no_attachments 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glFramebufferParameteri (GLenum target, GLenum pname, GLint param); +GLAPI void APIENTRY glGetFramebufferParameteriv (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glNamedFramebufferParameteriEXT (GLuint framebuffer, GLenum pname, GLint param); +GLAPI void APIENTRY glGetNamedFramebufferParameterivEXT (GLuint framebuffer, GLenum pname, GLint *params); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLFRAMEBUFFERPARAMETERIPROC) (GLenum target, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERPARAMETERIEXTPROC) (GLuint framebuffer, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVEXTPROC) (GLuint framebuffer, GLenum pname, GLint *params); +#endif + +#ifndef GL_ARB_internalformat_query2 +#define GL_ARB_internalformat_query2 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glGetInternalformati64v (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint64 *params); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLGETINTERNALFORMATI64VPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint64 *params); +#endif + +#ifndef GL_ARB_invalidate_subdata +#define GL_ARB_invalidate_subdata 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glInvalidateTexSubImage (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth); +GLAPI void APIENTRY glInvalidateTexImage (GLuint texture, GLint level); +GLAPI void APIENTRY glInvalidateBufferSubData (GLuint buffer, GLintptr offset, GLsizeiptr length); +GLAPI void APIENTRY glInvalidateBufferData (GLuint buffer); +GLAPI void APIENTRY glInvalidateFramebuffer (GLenum target, GLsizei numAttachments, const GLenum *attachments); +GLAPI void APIENTRY glInvalidateSubFramebuffer (GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLINVALIDATETEXSUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth); +typedef void (APIENTRYP PFNGLINVALIDATETEXIMAGEPROC) (GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLINVALIDATEBUFFERSUBDATAPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length); +typedef void (APIENTRYP PFNGLINVALIDATEBUFFERDATAPROC) (GLuint buffer); +typedef void (APIENTRYP PFNGLINVALIDATEFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments); +typedef void (APIENTRYP PFNGLINVALIDATESUBFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); +#endif + +#ifndef GL_ARB_multi_draw_indirect +#define GL_ARB_multi_draw_indirect 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glMultiDrawArraysIndirect (GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride); +GLAPI void APIENTRY glMultiDrawElementsIndirect (GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTPROC) (GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride); +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride); +#endif + +#ifndef GL_ARB_program_interface_query +#define GL_ARB_program_interface_query 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glGetProgramInterfaceiv (GLuint program, GLenum programInterface, GLenum pname, GLint *params); +GLAPI GLuint APIENTRY glGetProgramResourceIndex (GLuint program, GLenum programInterface, const GLchar *name); +GLAPI void APIENTRY glGetProgramResourceName (GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name); +GLAPI void APIENTRY glGetProgramResourceiv (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params); +GLAPI GLint APIENTRY glGetProgramResourceLocation (GLuint program, GLenum programInterface, const GLchar *name); +GLAPI GLint APIENTRY glGetProgramResourceLocationIndex (GLuint program, GLenum programInterface, const GLchar *name); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLGETPROGRAMINTERFACEIVPROC) (GLuint program, GLenum programInterface, GLenum pname, GLint *params); +typedef GLuint (APIENTRYP PFNGLGETPROGRAMRESOURCEINDEXPROC) (GLuint program, GLenum programInterface, const GLchar *name); +typedef void (APIENTRYP PFNGLGETPROGRAMRESOURCENAMEPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name); +typedef void (APIENTRYP PFNGLGETPROGRAMRESOURCEIVPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params); +typedef GLint (APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONPROC) (GLuint program, GLenum programInterface, const GLchar *name); +typedef GLint (APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC) (GLuint program, GLenum programInterface, const GLchar *name); +#endif + +#ifndef GL_ARB_robust_buffer_access_behavior +#define GL_ARB_robust_buffer_access_behavior 1 +#endif + +#ifndef GL_ARB_shader_image_size +#define GL_ARB_shader_image_size 1 +#endif + +#ifndef GL_ARB_shader_storage_buffer_object +#define GL_ARB_shader_storage_buffer_object 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glShaderStorageBlockBinding (GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLSHADERSTORAGEBLOCKBINDINGPROC) (GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding); +#endif + +#ifndef GL_ARB_stencil_texturing +#define GL_ARB_stencil_texturing 1 +#endif + +#ifndef GL_ARB_texture_buffer_range +#define GL_ARB_texture_buffer_range 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glTexBufferRange (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); +GLAPI void APIENTRY glTextureBufferRangeEXT (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLTEXBUFFERRANGEPROC) (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); +typedef void (APIENTRYP PFNGLTEXTUREBUFFERRANGEEXTPROC) (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); +#endif + +#ifndef GL_ARB_texture_query_levels +#define GL_ARB_texture_query_levels 1 +#endif + +#ifndef GL_ARB_texture_storage_multisample +#define GL_ARB_texture_storage_multisample 1 +#ifdef GLCOREARB_PROTOTYPES +GLAPI void APIENTRY glTexStorage2DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +GLAPI void APIENTRY glTexStorage3DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +GLAPI void APIENTRY glTextureStorage2DMultisampleEXT (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +GLAPI void APIENTRY glTextureStorage3DMultisampleEXT (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +#endif /* GLCOREARB_PROTOTYPES */ +typedef void (APIENTRYP PFNGLTEXSTORAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +typedef void (APIENTRYP PFNGLTEXSTORAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +typedef void (APIENTRYP PFNGLTEXTURESTORAGE2DMULTISAMPLEEXTPROC) (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +typedef void (APIENTRYP PFNGLTEXTURESTORAGE3DMULTISAMPLEEXTPROC) (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +#endif + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/3rdparty/imgui-node-editor/external/gl3w/Source/gl3w.c b/3rdparty/imgui-node-editor/external/gl3w/Source/gl3w.c new file mode 100755 index 0000000..464e017 --- /dev/null +++ b/3rdparty/imgui-node-editor/external/gl3w/Source/gl3w.c @@ -0,0 +1,1344 @@ +#include + +#ifdef _MSC_VER +#pragma warning (disable: 4055) // warning C4055: 'type cast' : from data pointer 'void *' to function pointer +#pragma warning (disable: 4152) // warning C4152: nonstandard extension, function/data pointer conversion in expression +#endif + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN 1 +#include + +static HMODULE libgl; + +static void open_libgl(void) +{ + libgl = LoadLibraryA("opengl32.dll"); +} + +static void close_libgl(void) +{ + FreeLibrary(libgl); +} + +static void *get_proc(const char *proc) +{ + void *res; + + res = wglGetProcAddress(proc); + if (!res) + res = GetProcAddress(libgl, proc); + return res; +} +#elif defined(__APPLE__) || defined(__APPLE_CC__) +#include + +CFBundleRef bundle; +CFURLRef bundleURL; + +static void open_libgl(void) +{ + bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, + CFSTR("/System/Library/Frameworks/OpenGL.framework"), + kCFURLPOSIXPathStyle, true); + + bundle = CFBundleCreate(kCFAllocatorDefault, bundleURL); + assert(bundle != NULL); +} + +static void close_libgl(void) +{ + CFRelease(bundle); + CFRelease(bundleURL); +} + +static void *get_proc(const char *proc) +{ + void *res; + + CFStringRef procname = CFStringCreateWithCString(kCFAllocatorDefault, proc, + kCFStringEncodingASCII); + res = CFBundleGetFunctionPointerForName(bundle, procname); + CFRelease(procname); + return res; +} +#else +#include +#include + +static void *libgl; + +static void open_libgl(void) +{ + libgl = dlopen("libGL.so.1", RTLD_LAZY | RTLD_GLOBAL); +} + +static void close_libgl(void) +{ + dlclose(libgl); +} + +static void *get_proc(const char *proc) +{ + void *res; + + res = (void*)glXGetProcAddress((const GLubyte *) proc); + if (!res) + res = dlsym(libgl, proc); + return res; +} +#endif + +static struct { + int major, minor; +} version; + +static int parse_version(void) +{ + if (!glGetIntegerv) + return -1; + + glGetIntegerv(GL_MAJOR_VERSION, &version.major); + glGetIntegerv(GL_MINOR_VERSION, &version.minor); + + if (version.major < 3) + return -1; + return 0; +} + +static void load_procs(void); + +int gl3wInit(void) +{ + open_libgl(); + load_procs(); + close_libgl(); + return parse_version(); +} + +int gl3wIsSupported(int major, int minor) +{ + if (major < 3) + return 0; + if (version.major == major) + return version.minor >= minor; + return version.major >= major; +} + +void *gl3wGetProcAddress(const char *proc) +{ + return get_proc(proc); +} + +PFNGLCULLFACEPROC gl3wCullFace; +PFNGLFRONTFACEPROC gl3wFrontFace; +PFNGLHINTPROC gl3wHint; +PFNGLLINEWIDTHPROC gl3wLineWidth; +PFNGLPOINTSIZEPROC gl3wPointSize; +PFNGLPOLYGONMODEPROC gl3wPolygonMode; +PFNGLSCISSORPROC gl3wScissor; +PFNGLTEXPARAMETERFPROC gl3wTexParameterf; +PFNGLTEXPARAMETERFVPROC gl3wTexParameterfv; +PFNGLTEXPARAMETERIPROC gl3wTexParameteri; +PFNGLTEXPARAMETERIVPROC gl3wTexParameteriv; +PFNGLTEXIMAGE1DPROC gl3wTexImage1D; +PFNGLTEXIMAGE2DPROC gl3wTexImage2D; +PFNGLDRAWBUFFERPROC gl3wDrawBuffer; +PFNGLCLEARPROC gl3wClear; +PFNGLCLEARCOLORPROC gl3wClearColor; +PFNGLCLEARSTENCILPROC gl3wClearStencil; +PFNGLCLEARDEPTHPROC gl3wClearDepth; +PFNGLSTENCILMASKPROC gl3wStencilMask; +PFNGLCOLORMASKPROC gl3wColorMask; +PFNGLDEPTHMASKPROC gl3wDepthMask; +PFNGLDISABLEPROC gl3wDisable; +PFNGLENABLEPROC gl3wEnable; +PFNGLFINISHPROC gl3wFinish; +PFNGLFLUSHPROC gl3wFlush; +PFNGLBLENDFUNCPROC gl3wBlendFunc; +PFNGLLOGICOPPROC gl3wLogicOp; +PFNGLSTENCILFUNCPROC gl3wStencilFunc; +PFNGLSTENCILOPPROC gl3wStencilOp; +PFNGLDEPTHFUNCPROC gl3wDepthFunc; +PFNGLPIXELSTOREFPROC gl3wPixelStoref; +PFNGLPIXELSTOREIPROC gl3wPixelStorei; +PFNGLREADBUFFERPROC gl3wReadBuffer; +PFNGLREADPIXELSPROC gl3wReadPixels; +PFNGLGETBOOLEANVPROC gl3wGetBooleanv; +PFNGLGETDOUBLEVPROC gl3wGetDoublev; +PFNGLGETERRORPROC gl3wGetError; +PFNGLGETFLOATVPROC gl3wGetFloatv; +PFNGLGETINTEGERVPROC gl3wGetIntegerv; +PFNGLGETSTRINGPROC gl3wGetString; +PFNGLGETTEXIMAGEPROC gl3wGetTexImage; +PFNGLGETTEXPARAMETERFVPROC gl3wGetTexParameterfv; +PFNGLGETTEXPARAMETERIVPROC gl3wGetTexParameteriv; +PFNGLGETTEXLEVELPARAMETERFVPROC gl3wGetTexLevelParameterfv; +PFNGLGETTEXLEVELPARAMETERIVPROC gl3wGetTexLevelParameteriv; +PFNGLISENABLEDPROC gl3wIsEnabled; +PFNGLDEPTHRANGEPROC gl3wDepthRange; +PFNGLVIEWPORTPROC gl3wViewport; +PFNGLDRAWARRAYSPROC gl3wDrawArrays; +PFNGLDRAWELEMENTSPROC gl3wDrawElements; +PFNGLGETPOINTERVPROC gl3wGetPointerv; +PFNGLPOLYGONOFFSETPROC gl3wPolygonOffset; +PFNGLCOPYTEXIMAGE1DPROC gl3wCopyTexImage1D; +PFNGLCOPYTEXIMAGE2DPROC gl3wCopyTexImage2D; +PFNGLCOPYTEXSUBIMAGE1DPROC gl3wCopyTexSubImage1D; +PFNGLCOPYTEXSUBIMAGE2DPROC gl3wCopyTexSubImage2D; +PFNGLTEXSUBIMAGE1DPROC gl3wTexSubImage1D; +PFNGLTEXSUBIMAGE2DPROC gl3wTexSubImage2D; +PFNGLBINDTEXTUREPROC gl3wBindTexture; +PFNGLDELETETEXTURESPROC gl3wDeleteTextures; +PFNGLGENTEXTURESPROC gl3wGenTextures; +PFNGLISTEXTUREPROC gl3wIsTexture; +PFNGLBLENDCOLORPROC gl3wBlendColor; +PFNGLBLENDEQUATIONPROC gl3wBlendEquation; +PFNGLDRAWRANGEELEMENTSPROC gl3wDrawRangeElements; +PFNGLTEXIMAGE3DPROC gl3wTexImage3D; +PFNGLTEXSUBIMAGE3DPROC gl3wTexSubImage3D; +PFNGLCOPYTEXSUBIMAGE3DPROC gl3wCopyTexSubImage3D; +PFNGLACTIVETEXTUREPROC gl3wActiveTexture; +PFNGLSAMPLECOVERAGEPROC gl3wSampleCoverage; +PFNGLCOMPRESSEDTEXIMAGE3DPROC gl3wCompressedTexImage3D; +PFNGLCOMPRESSEDTEXIMAGE2DPROC gl3wCompressedTexImage2D; +PFNGLCOMPRESSEDTEXIMAGE1DPROC gl3wCompressedTexImage1D; +PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC gl3wCompressedTexSubImage3D; +PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC gl3wCompressedTexSubImage2D; +PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC gl3wCompressedTexSubImage1D; +PFNGLGETCOMPRESSEDTEXIMAGEPROC gl3wGetCompressedTexImage; +PFNGLBLENDFUNCSEPARATEPROC gl3wBlendFuncSeparate; +PFNGLMULTIDRAWARRAYSPROC gl3wMultiDrawArrays; +PFNGLMULTIDRAWELEMENTSPROC gl3wMultiDrawElements; +PFNGLPOINTPARAMETERFPROC gl3wPointParameterf; +PFNGLPOINTPARAMETERFVPROC gl3wPointParameterfv; +PFNGLPOINTPARAMETERIPROC gl3wPointParameteri; +PFNGLPOINTPARAMETERIVPROC gl3wPointParameteriv; +PFNGLGENQUERIESPROC gl3wGenQueries; +PFNGLDELETEQUERIESPROC gl3wDeleteQueries; +PFNGLISQUERYPROC gl3wIsQuery; +PFNGLBEGINQUERYPROC gl3wBeginQuery; +PFNGLENDQUERYPROC gl3wEndQuery; +PFNGLGETQUERYIVPROC gl3wGetQueryiv; +PFNGLGETQUERYOBJECTIVPROC gl3wGetQueryObjectiv; +PFNGLGETQUERYOBJECTUIVPROC gl3wGetQueryObjectuiv; +PFNGLBINDBUFFERPROC gl3wBindBuffer; +PFNGLDELETEBUFFERSPROC gl3wDeleteBuffers; +PFNGLGENBUFFERSPROC gl3wGenBuffers; +PFNGLISBUFFERPROC gl3wIsBuffer; +PFNGLBUFFERDATAPROC gl3wBufferData; +PFNGLBUFFERSUBDATAPROC gl3wBufferSubData; +PFNGLGETBUFFERSUBDATAPROC gl3wGetBufferSubData; +PFNGLMAPBUFFERPROC gl3wMapBuffer; +PFNGLUNMAPBUFFERPROC gl3wUnmapBuffer; +PFNGLGETBUFFERPARAMETERIVPROC gl3wGetBufferParameteriv; +PFNGLGETBUFFERPOINTERVPROC gl3wGetBufferPointerv; +PFNGLBLENDEQUATIONSEPARATEPROC gl3wBlendEquationSeparate; +PFNGLDRAWBUFFERSPROC gl3wDrawBuffers; +PFNGLSTENCILOPSEPARATEPROC gl3wStencilOpSeparate; +PFNGLSTENCILFUNCSEPARATEPROC gl3wStencilFuncSeparate; +PFNGLSTENCILMASKSEPARATEPROC gl3wStencilMaskSeparate; +PFNGLATTACHSHADERPROC gl3wAttachShader; +PFNGLBINDATTRIBLOCATIONPROC gl3wBindAttribLocation; +PFNGLCOMPILESHADERPROC gl3wCompileShader; +PFNGLCREATEPROGRAMPROC gl3wCreateProgram; +PFNGLCREATESHADERPROC gl3wCreateShader; +PFNGLDELETEPROGRAMPROC gl3wDeleteProgram; +PFNGLDELETESHADERPROC gl3wDeleteShader; +PFNGLDETACHSHADERPROC gl3wDetachShader; +PFNGLDISABLEVERTEXATTRIBARRAYPROC gl3wDisableVertexAttribArray; +PFNGLENABLEVERTEXATTRIBARRAYPROC gl3wEnableVertexAttribArray; +PFNGLGETACTIVEATTRIBPROC gl3wGetActiveAttrib; +PFNGLGETACTIVEUNIFORMPROC gl3wGetActiveUniform; +PFNGLGETATTACHEDSHADERSPROC gl3wGetAttachedShaders; +PFNGLGETATTRIBLOCATIONPROC gl3wGetAttribLocation; +PFNGLGETPROGRAMIVPROC gl3wGetProgramiv; +PFNGLGETPROGRAMINFOLOGPROC gl3wGetProgramInfoLog; +PFNGLGETSHADERIVPROC gl3wGetShaderiv; +PFNGLGETSHADERINFOLOGPROC gl3wGetShaderInfoLog; +PFNGLGETSHADERSOURCEPROC gl3wGetShaderSource; +PFNGLGETUNIFORMLOCATIONPROC gl3wGetUniformLocation; +PFNGLGETUNIFORMFVPROC gl3wGetUniformfv; +PFNGLGETUNIFORMIVPROC gl3wGetUniformiv; +PFNGLGETVERTEXATTRIBDVPROC gl3wGetVertexAttribdv; +PFNGLGETVERTEXATTRIBFVPROC gl3wGetVertexAttribfv; +PFNGLGETVERTEXATTRIBIVPROC gl3wGetVertexAttribiv; +PFNGLGETVERTEXATTRIBPOINTERVPROC gl3wGetVertexAttribPointerv; +PFNGLISPROGRAMPROC gl3wIsProgram; +PFNGLISSHADERPROC gl3wIsShader; +PFNGLLINKPROGRAMPROC gl3wLinkProgram; +PFNGLSHADERSOURCEPROC gl3wShaderSource; +PFNGLUSEPROGRAMPROC gl3wUseProgram; +PFNGLUNIFORM1FPROC gl3wUniform1f; +PFNGLUNIFORM2FPROC gl3wUniform2f; +PFNGLUNIFORM3FPROC gl3wUniform3f; +PFNGLUNIFORM4FPROC gl3wUniform4f; +PFNGLUNIFORM1IPROC gl3wUniform1i; +PFNGLUNIFORM2IPROC gl3wUniform2i; +PFNGLUNIFORM3IPROC gl3wUniform3i; +PFNGLUNIFORM4IPROC gl3wUniform4i; +PFNGLUNIFORM1FVPROC gl3wUniform1fv; +PFNGLUNIFORM2FVPROC gl3wUniform2fv; +PFNGLUNIFORM3FVPROC gl3wUniform3fv; +PFNGLUNIFORM4FVPROC gl3wUniform4fv; +PFNGLUNIFORM1IVPROC gl3wUniform1iv; +PFNGLUNIFORM2IVPROC gl3wUniform2iv; +PFNGLUNIFORM3IVPROC gl3wUniform3iv; +PFNGLUNIFORM4IVPROC gl3wUniform4iv; +PFNGLUNIFORMMATRIX2FVPROC gl3wUniformMatrix2fv; +PFNGLUNIFORMMATRIX3FVPROC gl3wUniformMatrix3fv; +PFNGLUNIFORMMATRIX4FVPROC gl3wUniformMatrix4fv; +PFNGLVALIDATEPROGRAMPROC gl3wValidateProgram; +PFNGLVERTEXATTRIB1DPROC gl3wVertexAttrib1d; +PFNGLVERTEXATTRIB1DVPROC gl3wVertexAttrib1dv; +PFNGLVERTEXATTRIB1FPROC gl3wVertexAttrib1f; +PFNGLVERTEXATTRIB1FVPROC gl3wVertexAttrib1fv; +PFNGLVERTEXATTRIB1SPROC gl3wVertexAttrib1s; +PFNGLVERTEXATTRIB1SVPROC gl3wVertexAttrib1sv; +PFNGLVERTEXATTRIB2DPROC gl3wVertexAttrib2d; +PFNGLVERTEXATTRIB2DVPROC gl3wVertexAttrib2dv; +PFNGLVERTEXATTRIB2FPROC gl3wVertexAttrib2f; +PFNGLVERTEXATTRIB2FVPROC gl3wVertexAttrib2fv; +PFNGLVERTEXATTRIB2SPROC gl3wVertexAttrib2s; +PFNGLVERTEXATTRIB2SVPROC gl3wVertexAttrib2sv; +PFNGLVERTEXATTRIB3DPROC gl3wVertexAttrib3d; +PFNGLVERTEXATTRIB3DVPROC gl3wVertexAttrib3dv; +PFNGLVERTEXATTRIB3FPROC gl3wVertexAttrib3f; +PFNGLVERTEXATTRIB3FVPROC gl3wVertexAttrib3fv; +PFNGLVERTEXATTRIB3SPROC gl3wVertexAttrib3s; +PFNGLVERTEXATTRIB3SVPROC gl3wVertexAttrib3sv; +PFNGLVERTEXATTRIB4NBVPROC gl3wVertexAttrib4Nbv; +PFNGLVERTEXATTRIB4NIVPROC gl3wVertexAttrib4Niv; +PFNGLVERTEXATTRIB4NSVPROC gl3wVertexAttrib4Nsv; +PFNGLVERTEXATTRIB4NUBPROC gl3wVertexAttrib4Nub; +PFNGLVERTEXATTRIB4NUBVPROC gl3wVertexAttrib4Nubv; +PFNGLVERTEXATTRIB4NUIVPROC gl3wVertexAttrib4Nuiv; +PFNGLVERTEXATTRIB4NUSVPROC gl3wVertexAttrib4Nusv; +PFNGLVERTEXATTRIB4BVPROC gl3wVertexAttrib4bv; +PFNGLVERTEXATTRIB4DPROC gl3wVertexAttrib4d; +PFNGLVERTEXATTRIB4DVPROC gl3wVertexAttrib4dv; +PFNGLVERTEXATTRIB4FPROC gl3wVertexAttrib4f; +PFNGLVERTEXATTRIB4FVPROC gl3wVertexAttrib4fv; +PFNGLVERTEXATTRIB4IVPROC gl3wVertexAttrib4iv; +PFNGLVERTEXATTRIB4SPROC gl3wVertexAttrib4s; +PFNGLVERTEXATTRIB4SVPROC gl3wVertexAttrib4sv; +PFNGLVERTEXATTRIB4UBVPROC gl3wVertexAttrib4ubv; +PFNGLVERTEXATTRIB4UIVPROC gl3wVertexAttrib4uiv; +PFNGLVERTEXATTRIB4USVPROC gl3wVertexAttrib4usv; +PFNGLVERTEXATTRIBPOINTERPROC gl3wVertexAttribPointer; +PFNGLUNIFORMMATRIX2X3FVPROC gl3wUniformMatrix2x3fv; +PFNGLUNIFORMMATRIX3X2FVPROC gl3wUniformMatrix3x2fv; +PFNGLUNIFORMMATRIX2X4FVPROC gl3wUniformMatrix2x4fv; +PFNGLUNIFORMMATRIX4X2FVPROC gl3wUniformMatrix4x2fv; +PFNGLUNIFORMMATRIX3X4FVPROC gl3wUniformMatrix3x4fv; +PFNGLUNIFORMMATRIX4X3FVPROC gl3wUniformMatrix4x3fv; +PFNGLCOLORMASKIPROC gl3wColorMaski; +PFNGLGETBOOLEANI_VPROC gl3wGetBooleani_v; +PFNGLGETINTEGERI_VPROC gl3wGetIntegeri_v; +PFNGLENABLEIPROC gl3wEnablei; +PFNGLDISABLEIPROC gl3wDisablei; +PFNGLISENABLEDIPROC gl3wIsEnabledi; +PFNGLBEGINTRANSFORMFEEDBACKPROC gl3wBeginTransformFeedback; +PFNGLENDTRANSFORMFEEDBACKPROC gl3wEndTransformFeedback; +PFNGLBINDBUFFERRANGEPROC gl3wBindBufferRange; +PFNGLBINDBUFFERBASEPROC gl3wBindBufferBase; +PFNGLTRANSFORMFEEDBACKVARYINGSPROC gl3wTransformFeedbackVaryings; +PFNGLGETTRANSFORMFEEDBACKVARYINGPROC gl3wGetTransformFeedbackVarying; +PFNGLCLAMPCOLORPROC gl3wClampColor; +PFNGLBEGINCONDITIONALRENDERPROC gl3wBeginConditionalRender; +PFNGLENDCONDITIONALRENDERPROC gl3wEndConditionalRender; +PFNGLVERTEXATTRIBIPOINTERPROC gl3wVertexAttribIPointer; +PFNGLGETVERTEXATTRIBIIVPROC gl3wGetVertexAttribIiv; +PFNGLGETVERTEXATTRIBIUIVPROC gl3wGetVertexAttribIuiv; +PFNGLVERTEXATTRIBI1IPROC gl3wVertexAttribI1i; +PFNGLVERTEXATTRIBI2IPROC gl3wVertexAttribI2i; +PFNGLVERTEXATTRIBI3IPROC gl3wVertexAttribI3i; +PFNGLVERTEXATTRIBI4IPROC gl3wVertexAttribI4i; +PFNGLVERTEXATTRIBI1UIPROC gl3wVertexAttribI1ui; +PFNGLVERTEXATTRIBI2UIPROC gl3wVertexAttribI2ui; +PFNGLVERTEXATTRIBI3UIPROC gl3wVertexAttribI3ui; +PFNGLVERTEXATTRIBI4UIPROC gl3wVertexAttribI4ui; +PFNGLVERTEXATTRIBI1IVPROC gl3wVertexAttribI1iv; +PFNGLVERTEXATTRIBI2IVPROC gl3wVertexAttribI2iv; +PFNGLVERTEXATTRIBI3IVPROC gl3wVertexAttribI3iv; +PFNGLVERTEXATTRIBI4IVPROC gl3wVertexAttribI4iv; +PFNGLVERTEXATTRIBI1UIVPROC gl3wVertexAttribI1uiv; +PFNGLVERTEXATTRIBI2UIVPROC gl3wVertexAttribI2uiv; +PFNGLVERTEXATTRIBI3UIVPROC gl3wVertexAttribI3uiv; +PFNGLVERTEXATTRIBI4UIVPROC gl3wVertexAttribI4uiv; +PFNGLVERTEXATTRIBI4BVPROC gl3wVertexAttribI4bv; +PFNGLVERTEXATTRIBI4SVPROC gl3wVertexAttribI4sv; +PFNGLVERTEXATTRIBI4UBVPROC gl3wVertexAttribI4ubv; +PFNGLVERTEXATTRIBI4USVPROC gl3wVertexAttribI4usv; +PFNGLGETUNIFORMUIVPROC gl3wGetUniformuiv; +PFNGLBINDFRAGDATALOCATIONPROC gl3wBindFragDataLocation; +PFNGLGETFRAGDATALOCATIONPROC gl3wGetFragDataLocation; +PFNGLUNIFORM1UIPROC gl3wUniform1ui; +PFNGLUNIFORM2UIPROC gl3wUniform2ui; +PFNGLUNIFORM3UIPROC gl3wUniform3ui; +PFNGLUNIFORM4UIPROC gl3wUniform4ui; +PFNGLUNIFORM1UIVPROC gl3wUniform1uiv; +PFNGLUNIFORM2UIVPROC gl3wUniform2uiv; +PFNGLUNIFORM3UIVPROC gl3wUniform3uiv; +PFNGLUNIFORM4UIVPROC gl3wUniform4uiv; +PFNGLTEXPARAMETERIIVPROC gl3wTexParameterIiv; +PFNGLTEXPARAMETERIUIVPROC gl3wTexParameterIuiv; +PFNGLGETTEXPARAMETERIIVPROC gl3wGetTexParameterIiv; +PFNGLGETTEXPARAMETERIUIVPROC gl3wGetTexParameterIuiv; +PFNGLCLEARBUFFERIVPROC gl3wClearBufferiv; +PFNGLCLEARBUFFERUIVPROC gl3wClearBufferuiv; +PFNGLCLEARBUFFERFVPROC gl3wClearBufferfv; +PFNGLCLEARBUFFERFIPROC gl3wClearBufferfi; +PFNGLGETSTRINGIPROC gl3wGetStringi; +PFNGLDRAWARRAYSINSTANCEDPROC gl3wDrawArraysInstanced; +PFNGLDRAWELEMENTSINSTANCEDPROC gl3wDrawElementsInstanced; +PFNGLTEXBUFFERPROC gl3wTexBuffer; +PFNGLPRIMITIVERESTARTINDEXPROC gl3wPrimitiveRestartIndex; +PFNGLGETINTEGER64I_VPROC gl3wGetInteger64i_v; +PFNGLGETBUFFERPARAMETERI64VPROC gl3wGetBufferParameteri64v; +PFNGLFRAMEBUFFERTEXTUREPROC gl3wFramebufferTexture; +PFNGLVERTEXATTRIBDIVISORPROC gl3wVertexAttribDivisor; +PFNGLMINSAMPLESHADINGPROC gl3wMinSampleShading; +PFNGLBLENDEQUATIONIPROC gl3wBlendEquationi; +PFNGLBLENDEQUATIONSEPARATEIPROC gl3wBlendEquationSeparatei; +PFNGLBLENDFUNCIPROC gl3wBlendFunci; +PFNGLBLENDFUNCSEPARATEIPROC gl3wBlendFuncSeparatei; +PFNGLISRENDERBUFFERPROC gl3wIsRenderbuffer; +PFNGLBINDRENDERBUFFERPROC gl3wBindRenderbuffer; +PFNGLDELETERENDERBUFFERSPROC gl3wDeleteRenderbuffers; +PFNGLGENRENDERBUFFERSPROC gl3wGenRenderbuffers; +PFNGLRENDERBUFFERSTORAGEPROC gl3wRenderbufferStorage; +PFNGLGETRENDERBUFFERPARAMETERIVPROC gl3wGetRenderbufferParameteriv; +PFNGLISFRAMEBUFFERPROC gl3wIsFramebuffer; +PFNGLBINDFRAMEBUFFERPROC gl3wBindFramebuffer; +PFNGLDELETEFRAMEBUFFERSPROC gl3wDeleteFramebuffers; +PFNGLGENFRAMEBUFFERSPROC gl3wGenFramebuffers; +PFNGLCHECKFRAMEBUFFERSTATUSPROC gl3wCheckFramebufferStatus; +PFNGLFRAMEBUFFERTEXTURE1DPROC gl3wFramebufferTexture1D; +PFNGLFRAMEBUFFERTEXTURE2DPROC gl3wFramebufferTexture2D; +PFNGLFRAMEBUFFERTEXTURE3DPROC gl3wFramebufferTexture3D; +PFNGLFRAMEBUFFERRENDERBUFFERPROC gl3wFramebufferRenderbuffer; +PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC gl3wGetFramebufferAttachmentParameteriv; +PFNGLGENERATEMIPMAPPROC gl3wGenerateMipmap; +PFNGLBLITFRAMEBUFFERPROC gl3wBlitFramebuffer; +PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC gl3wRenderbufferStorageMultisample; +PFNGLFRAMEBUFFERTEXTURELAYERPROC gl3wFramebufferTextureLayer; +PFNGLMAPBUFFERRANGEPROC gl3wMapBufferRange; +PFNGLFLUSHMAPPEDBUFFERRANGEPROC gl3wFlushMappedBufferRange; +PFNGLBINDVERTEXARRAYPROC gl3wBindVertexArray; +PFNGLDELETEVERTEXARRAYSPROC gl3wDeleteVertexArrays; +PFNGLGENVERTEXARRAYSPROC gl3wGenVertexArrays; +PFNGLISVERTEXARRAYPROC gl3wIsVertexArray; +PFNGLGETUNIFORMINDICESPROC gl3wGetUniformIndices; +PFNGLGETACTIVEUNIFORMSIVPROC gl3wGetActiveUniformsiv; +PFNGLGETACTIVEUNIFORMNAMEPROC gl3wGetActiveUniformName; +PFNGLGETUNIFORMBLOCKINDEXPROC gl3wGetUniformBlockIndex; +PFNGLGETACTIVEUNIFORMBLOCKIVPROC gl3wGetActiveUniformBlockiv; +PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC gl3wGetActiveUniformBlockName; +PFNGLUNIFORMBLOCKBINDINGPROC gl3wUniformBlockBinding; +PFNGLCOPYBUFFERSUBDATAPROC gl3wCopyBufferSubData; +PFNGLDRAWELEMENTSBASEVERTEXPROC gl3wDrawElementsBaseVertex; +PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC gl3wDrawRangeElementsBaseVertex; +PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC gl3wDrawElementsInstancedBaseVertex; +PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC gl3wMultiDrawElementsBaseVertex; +PFNGLPROVOKINGVERTEXPROC gl3wProvokingVertex; +PFNGLFENCESYNCPROC gl3wFenceSync; +PFNGLISSYNCPROC gl3wIsSync; +PFNGLDELETESYNCPROC gl3wDeleteSync; +PFNGLCLIENTWAITSYNCPROC gl3wClientWaitSync; +PFNGLWAITSYNCPROC gl3wWaitSync; +PFNGLGETINTEGER64VPROC gl3wGetInteger64v; +PFNGLGETSYNCIVPROC gl3wGetSynciv; +PFNGLTEXIMAGE2DMULTISAMPLEPROC gl3wTexImage2DMultisample; +PFNGLTEXIMAGE3DMULTISAMPLEPROC gl3wTexImage3DMultisample; +PFNGLGETMULTISAMPLEFVPROC gl3wGetMultisamplefv; +PFNGLSAMPLEMASKIPROC gl3wSampleMaski; +PFNGLBLENDEQUATIONIARBPROC gl3wBlendEquationiARB; +PFNGLBLENDEQUATIONSEPARATEIARBPROC gl3wBlendEquationSeparateiARB; +PFNGLBLENDFUNCIARBPROC gl3wBlendFunciARB; +PFNGLBLENDFUNCSEPARATEIARBPROC gl3wBlendFuncSeparateiARB; +PFNGLMINSAMPLESHADINGARBPROC gl3wMinSampleShadingARB; +PFNGLNAMEDSTRINGARBPROC gl3wNamedStringARB; +PFNGLDELETENAMEDSTRINGARBPROC gl3wDeleteNamedStringARB; +PFNGLCOMPILESHADERINCLUDEARBPROC gl3wCompileShaderIncludeARB; +PFNGLISNAMEDSTRINGARBPROC gl3wIsNamedStringARB; +PFNGLGETNAMEDSTRINGARBPROC gl3wGetNamedStringARB; +PFNGLGETNAMEDSTRINGIVARBPROC gl3wGetNamedStringivARB; +PFNGLBINDFRAGDATALOCATIONINDEXEDPROC gl3wBindFragDataLocationIndexed; +PFNGLGETFRAGDATAINDEXPROC gl3wGetFragDataIndex; +PFNGLGENSAMPLERSPROC gl3wGenSamplers; +PFNGLDELETESAMPLERSPROC gl3wDeleteSamplers; +PFNGLISSAMPLERPROC gl3wIsSampler; +PFNGLBINDSAMPLERPROC gl3wBindSampler; +PFNGLSAMPLERPARAMETERIPROC gl3wSamplerParameteri; +PFNGLSAMPLERPARAMETERIVPROC gl3wSamplerParameteriv; +PFNGLSAMPLERPARAMETERFPROC gl3wSamplerParameterf; +PFNGLSAMPLERPARAMETERFVPROC gl3wSamplerParameterfv; +PFNGLSAMPLERPARAMETERIIVPROC gl3wSamplerParameterIiv; +PFNGLSAMPLERPARAMETERIUIVPROC gl3wSamplerParameterIuiv; +PFNGLGETSAMPLERPARAMETERIVPROC gl3wGetSamplerParameteriv; +PFNGLGETSAMPLERPARAMETERIIVPROC gl3wGetSamplerParameterIiv; +PFNGLGETSAMPLERPARAMETERFVPROC gl3wGetSamplerParameterfv; +PFNGLGETSAMPLERPARAMETERIUIVPROC gl3wGetSamplerParameterIuiv; +PFNGLQUERYCOUNTERPROC gl3wQueryCounter; +PFNGLGETQUERYOBJECTI64VPROC gl3wGetQueryObjecti64v; +PFNGLGETQUERYOBJECTUI64VPROC gl3wGetQueryObjectui64v; +PFNGLVERTEXP2UIPROC gl3wVertexP2ui; +PFNGLVERTEXP2UIVPROC gl3wVertexP2uiv; +PFNGLVERTEXP3UIPROC gl3wVertexP3ui; +PFNGLVERTEXP3UIVPROC gl3wVertexP3uiv; +PFNGLVERTEXP4UIPROC gl3wVertexP4ui; +PFNGLVERTEXP4UIVPROC gl3wVertexP4uiv; +PFNGLTEXCOORDP1UIPROC gl3wTexCoordP1ui; +PFNGLTEXCOORDP1UIVPROC gl3wTexCoordP1uiv; +PFNGLTEXCOORDP2UIPROC gl3wTexCoordP2ui; +PFNGLTEXCOORDP2UIVPROC gl3wTexCoordP2uiv; +PFNGLTEXCOORDP3UIPROC gl3wTexCoordP3ui; +PFNGLTEXCOORDP3UIVPROC gl3wTexCoordP3uiv; +PFNGLTEXCOORDP4UIPROC gl3wTexCoordP4ui; +PFNGLTEXCOORDP4UIVPROC gl3wTexCoordP4uiv; +PFNGLMULTITEXCOORDP1UIPROC gl3wMultiTexCoordP1ui; +PFNGLMULTITEXCOORDP1UIVPROC gl3wMultiTexCoordP1uiv; +PFNGLMULTITEXCOORDP2UIPROC gl3wMultiTexCoordP2ui; +PFNGLMULTITEXCOORDP2UIVPROC gl3wMultiTexCoordP2uiv; +PFNGLMULTITEXCOORDP3UIPROC gl3wMultiTexCoordP3ui; +PFNGLMULTITEXCOORDP3UIVPROC gl3wMultiTexCoordP3uiv; +PFNGLMULTITEXCOORDP4UIPROC gl3wMultiTexCoordP4ui; +PFNGLMULTITEXCOORDP4UIVPROC gl3wMultiTexCoordP4uiv; +PFNGLNORMALP3UIPROC gl3wNormalP3ui; +PFNGLNORMALP3UIVPROC gl3wNormalP3uiv; +PFNGLCOLORP3UIPROC gl3wColorP3ui; +PFNGLCOLORP3UIVPROC gl3wColorP3uiv; +PFNGLCOLORP4UIPROC gl3wColorP4ui; +PFNGLCOLORP4UIVPROC gl3wColorP4uiv; +PFNGLSECONDARYCOLORP3UIPROC gl3wSecondaryColorP3ui; +PFNGLSECONDARYCOLORP3UIVPROC gl3wSecondaryColorP3uiv; +PFNGLVERTEXATTRIBP1UIPROC gl3wVertexAttribP1ui; +PFNGLVERTEXATTRIBP1UIVPROC gl3wVertexAttribP1uiv; +PFNGLVERTEXATTRIBP2UIPROC gl3wVertexAttribP2ui; +PFNGLVERTEXATTRIBP2UIVPROC gl3wVertexAttribP2uiv; +PFNGLVERTEXATTRIBP3UIPROC gl3wVertexAttribP3ui; +PFNGLVERTEXATTRIBP3UIVPROC gl3wVertexAttribP3uiv; +PFNGLVERTEXATTRIBP4UIPROC gl3wVertexAttribP4ui; +PFNGLVERTEXATTRIBP4UIVPROC gl3wVertexAttribP4uiv; +PFNGLDRAWARRAYSINDIRECTPROC gl3wDrawArraysIndirect; +PFNGLDRAWELEMENTSINDIRECTPROC gl3wDrawElementsIndirect; +PFNGLUNIFORM1DPROC gl3wUniform1d; +PFNGLUNIFORM2DPROC gl3wUniform2d; +PFNGLUNIFORM3DPROC gl3wUniform3d; +PFNGLUNIFORM4DPROC gl3wUniform4d; +PFNGLUNIFORM1DVPROC gl3wUniform1dv; +PFNGLUNIFORM2DVPROC gl3wUniform2dv; +PFNGLUNIFORM3DVPROC gl3wUniform3dv; +PFNGLUNIFORM4DVPROC gl3wUniform4dv; +PFNGLUNIFORMMATRIX2DVPROC gl3wUniformMatrix2dv; +PFNGLUNIFORMMATRIX3DVPROC gl3wUniformMatrix3dv; +PFNGLUNIFORMMATRIX4DVPROC gl3wUniformMatrix4dv; +PFNGLUNIFORMMATRIX2X3DVPROC gl3wUniformMatrix2x3dv; +PFNGLUNIFORMMATRIX2X4DVPROC gl3wUniformMatrix2x4dv; +PFNGLUNIFORMMATRIX3X2DVPROC gl3wUniformMatrix3x2dv; +PFNGLUNIFORMMATRIX3X4DVPROC gl3wUniformMatrix3x4dv; +PFNGLUNIFORMMATRIX4X2DVPROC gl3wUniformMatrix4x2dv; +PFNGLUNIFORMMATRIX4X3DVPROC gl3wUniformMatrix4x3dv; +PFNGLGETUNIFORMDVPROC gl3wGetUniformdv; +PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC gl3wGetSubroutineUniformLocation; +PFNGLGETSUBROUTINEINDEXPROC gl3wGetSubroutineIndex; +PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC gl3wGetActiveSubroutineUniformiv; +PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC gl3wGetActiveSubroutineUniformName; +PFNGLGETACTIVESUBROUTINENAMEPROC gl3wGetActiveSubroutineName; +PFNGLUNIFORMSUBROUTINESUIVPROC gl3wUniformSubroutinesuiv; +PFNGLGETUNIFORMSUBROUTINEUIVPROC gl3wGetUniformSubroutineuiv; +PFNGLGETPROGRAMSTAGEIVPROC gl3wGetProgramStageiv; +PFNGLPATCHPARAMETERIPROC gl3wPatchParameteri; +PFNGLPATCHPARAMETERFVPROC gl3wPatchParameterfv; +PFNGLBINDTRANSFORMFEEDBACKPROC gl3wBindTransformFeedback; +PFNGLDELETETRANSFORMFEEDBACKSPROC gl3wDeleteTransformFeedbacks; +PFNGLGENTRANSFORMFEEDBACKSPROC gl3wGenTransformFeedbacks; +PFNGLISTRANSFORMFEEDBACKPROC gl3wIsTransformFeedback; +PFNGLPAUSETRANSFORMFEEDBACKPROC gl3wPauseTransformFeedback; +PFNGLRESUMETRANSFORMFEEDBACKPROC gl3wResumeTransformFeedback; +PFNGLDRAWTRANSFORMFEEDBACKPROC gl3wDrawTransformFeedback; +PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC gl3wDrawTransformFeedbackStream; +PFNGLBEGINQUERYINDEXEDPROC gl3wBeginQueryIndexed; +PFNGLENDQUERYINDEXEDPROC gl3wEndQueryIndexed; +PFNGLGETQUERYINDEXEDIVPROC gl3wGetQueryIndexediv; +PFNGLRELEASESHADERCOMPILERPROC gl3wReleaseShaderCompiler; +PFNGLSHADERBINARYPROC gl3wShaderBinary; +PFNGLGETSHADERPRECISIONFORMATPROC gl3wGetShaderPrecisionFormat; +PFNGLDEPTHRANGEFPROC gl3wDepthRangef; +PFNGLCLEARDEPTHFPROC gl3wClearDepthf; +PFNGLGETPROGRAMBINARYPROC gl3wGetProgramBinary; +PFNGLPROGRAMBINARYPROC gl3wProgramBinary; +PFNGLPROGRAMPARAMETERIPROC gl3wProgramParameteri; +PFNGLUSEPROGRAMSTAGESPROC gl3wUseProgramStages; +PFNGLACTIVESHADERPROGRAMPROC gl3wActiveShaderProgram; +PFNGLCREATESHADERPROGRAMVPROC gl3wCreateShaderProgramv; +PFNGLBINDPROGRAMPIPELINEPROC gl3wBindProgramPipeline; +PFNGLDELETEPROGRAMPIPELINESPROC gl3wDeleteProgramPipelines; +PFNGLGENPROGRAMPIPELINESPROC gl3wGenProgramPipelines; +PFNGLISPROGRAMPIPELINEPROC gl3wIsProgramPipeline; +PFNGLGETPROGRAMPIPELINEIVPROC gl3wGetProgramPipelineiv; +PFNGLPROGRAMUNIFORM1IPROC gl3wProgramUniform1i; +PFNGLPROGRAMUNIFORM1IVPROC gl3wProgramUniform1iv; +PFNGLPROGRAMUNIFORM1FPROC gl3wProgramUniform1f; +PFNGLPROGRAMUNIFORM1FVPROC gl3wProgramUniform1fv; +PFNGLPROGRAMUNIFORM1DPROC gl3wProgramUniform1d; +PFNGLPROGRAMUNIFORM1DVPROC gl3wProgramUniform1dv; +PFNGLPROGRAMUNIFORM1UIPROC gl3wProgramUniform1ui; +PFNGLPROGRAMUNIFORM1UIVPROC gl3wProgramUniform1uiv; +PFNGLPROGRAMUNIFORM2IPROC gl3wProgramUniform2i; +PFNGLPROGRAMUNIFORM2IVPROC gl3wProgramUniform2iv; +PFNGLPROGRAMUNIFORM2FPROC gl3wProgramUniform2f; +PFNGLPROGRAMUNIFORM2FVPROC gl3wProgramUniform2fv; +PFNGLPROGRAMUNIFORM2DPROC gl3wProgramUniform2d; +PFNGLPROGRAMUNIFORM2DVPROC gl3wProgramUniform2dv; +PFNGLPROGRAMUNIFORM2UIPROC gl3wProgramUniform2ui; +PFNGLPROGRAMUNIFORM2UIVPROC gl3wProgramUniform2uiv; +PFNGLPROGRAMUNIFORM3IPROC gl3wProgramUniform3i; +PFNGLPROGRAMUNIFORM3IVPROC gl3wProgramUniform3iv; +PFNGLPROGRAMUNIFORM3FPROC gl3wProgramUniform3f; +PFNGLPROGRAMUNIFORM3FVPROC gl3wProgramUniform3fv; +PFNGLPROGRAMUNIFORM3DPROC gl3wProgramUniform3d; +PFNGLPROGRAMUNIFORM3DVPROC gl3wProgramUniform3dv; +PFNGLPROGRAMUNIFORM3UIPROC gl3wProgramUniform3ui; +PFNGLPROGRAMUNIFORM3UIVPROC gl3wProgramUniform3uiv; +PFNGLPROGRAMUNIFORM4IPROC gl3wProgramUniform4i; +PFNGLPROGRAMUNIFORM4IVPROC gl3wProgramUniform4iv; +PFNGLPROGRAMUNIFORM4FPROC gl3wProgramUniform4f; +PFNGLPROGRAMUNIFORM4FVPROC gl3wProgramUniform4fv; +PFNGLPROGRAMUNIFORM4DPROC gl3wProgramUniform4d; +PFNGLPROGRAMUNIFORM4DVPROC gl3wProgramUniform4dv; +PFNGLPROGRAMUNIFORM4UIPROC gl3wProgramUniform4ui; +PFNGLPROGRAMUNIFORM4UIVPROC gl3wProgramUniform4uiv; +PFNGLPROGRAMUNIFORMMATRIX2FVPROC gl3wProgramUniformMatrix2fv; +PFNGLPROGRAMUNIFORMMATRIX3FVPROC gl3wProgramUniformMatrix3fv; +PFNGLPROGRAMUNIFORMMATRIX4FVPROC gl3wProgramUniformMatrix4fv; +PFNGLPROGRAMUNIFORMMATRIX2DVPROC gl3wProgramUniformMatrix2dv; +PFNGLPROGRAMUNIFORMMATRIX3DVPROC gl3wProgramUniformMatrix3dv; +PFNGLPROGRAMUNIFORMMATRIX4DVPROC gl3wProgramUniformMatrix4dv; +PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC gl3wProgramUniformMatrix2x3fv; +PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC gl3wProgramUniformMatrix3x2fv; +PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC gl3wProgramUniformMatrix2x4fv; +PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC gl3wProgramUniformMatrix4x2fv; +PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC gl3wProgramUniformMatrix3x4fv; +PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC gl3wProgramUniformMatrix4x3fv; +PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC gl3wProgramUniformMatrix2x3dv; +PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC gl3wProgramUniformMatrix3x2dv; +PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC gl3wProgramUniformMatrix2x4dv; +PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC gl3wProgramUniformMatrix4x2dv; +PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC gl3wProgramUniformMatrix3x4dv; +PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC gl3wProgramUniformMatrix4x3dv; +PFNGLVALIDATEPROGRAMPIPELINEPROC gl3wValidateProgramPipeline; +PFNGLGETPROGRAMPIPELINEINFOLOGPROC gl3wGetProgramPipelineInfoLog; +PFNGLVERTEXATTRIBL1DPROC gl3wVertexAttribL1d; +PFNGLVERTEXATTRIBL2DPROC gl3wVertexAttribL2d; +PFNGLVERTEXATTRIBL3DPROC gl3wVertexAttribL3d; +PFNGLVERTEXATTRIBL4DPROC gl3wVertexAttribL4d; +PFNGLVERTEXATTRIBL1DVPROC gl3wVertexAttribL1dv; +PFNGLVERTEXATTRIBL2DVPROC gl3wVertexAttribL2dv; +PFNGLVERTEXATTRIBL3DVPROC gl3wVertexAttribL3dv; +PFNGLVERTEXATTRIBL4DVPROC gl3wVertexAttribL4dv; +PFNGLVERTEXATTRIBLPOINTERPROC gl3wVertexAttribLPointer; +PFNGLGETVERTEXATTRIBLDVPROC gl3wGetVertexAttribLdv; +PFNGLVIEWPORTARRAYVPROC gl3wViewportArrayv; +PFNGLVIEWPORTINDEXEDFPROC gl3wViewportIndexedf; +PFNGLVIEWPORTINDEXEDFVPROC gl3wViewportIndexedfv; +PFNGLSCISSORARRAYVPROC gl3wScissorArrayv; +PFNGLSCISSORINDEXEDPROC gl3wScissorIndexed; +PFNGLSCISSORINDEXEDVPROC gl3wScissorIndexedv; +PFNGLDEPTHRANGEARRAYVPROC gl3wDepthRangeArrayv; +PFNGLDEPTHRANGEINDEXEDPROC gl3wDepthRangeIndexed; +PFNGLGETFLOATI_VPROC gl3wGetFloati_v; +PFNGLGETDOUBLEI_VPROC gl3wGetDoublei_v; +PFNGLCREATESYNCFROMCLEVENTARBPROC gl3wCreateSyncFromCLeventARB; +PFNGLDEBUGMESSAGECONTROLARBPROC gl3wDebugMessageControlARB; +PFNGLDEBUGMESSAGEINSERTARBPROC gl3wDebugMessageInsertARB; +PFNGLDEBUGMESSAGECALLBACKARBPROC gl3wDebugMessageCallbackARB; +PFNGLGETDEBUGMESSAGELOGARBPROC gl3wGetDebugMessageLogARB; +PFNGLGETGRAPHICSRESETSTATUSARBPROC gl3wGetGraphicsResetStatusARB; +PFNGLGETNTEXIMAGEARBPROC gl3wGetnTexImageARB; +PFNGLREADNPIXELSARBPROC gl3wReadnPixelsARB; +PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC gl3wGetnCompressedTexImageARB; +PFNGLGETNUNIFORMFVARBPROC gl3wGetnUniformfvARB; +PFNGLGETNUNIFORMIVARBPROC gl3wGetnUniformivARB; +PFNGLGETNUNIFORMUIVARBPROC gl3wGetnUniformuivARB; +PFNGLGETNUNIFORMDVARBPROC gl3wGetnUniformdvARB; +PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC gl3wDrawArraysInstancedBaseInstance; +PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC gl3wDrawElementsInstancedBaseInstance; +PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC gl3wDrawElementsInstancedBaseVertexBaseInstance; +PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC gl3wDrawTransformFeedbackInstanced; +PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC gl3wDrawTransformFeedbackStreamInstanced; +PFNGLGETINTERNALFORMATIVPROC gl3wGetInternalformativ; +PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC gl3wGetActiveAtomicCounterBufferiv; +PFNGLBINDIMAGETEXTUREPROC gl3wBindImageTexture; +PFNGLMEMORYBARRIERPROC gl3wMemoryBarrier; +PFNGLTEXSTORAGE1DPROC gl3wTexStorage1D; +PFNGLTEXSTORAGE2DPROC gl3wTexStorage2D; +PFNGLTEXSTORAGE3DPROC gl3wTexStorage3D; +PFNGLTEXTURESTORAGE1DEXTPROC gl3wTextureStorage1DEXT; +PFNGLTEXTURESTORAGE2DEXTPROC gl3wTextureStorage2DEXT; +PFNGLTEXTURESTORAGE3DEXTPROC gl3wTextureStorage3DEXT; +PFNGLDEBUGMESSAGECONTROLPROC gl3wDebugMessageControl; +PFNGLDEBUGMESSAGEINSERTPROC gl3wDebugMessageInsert; +PFNGLDEBUGMESSAGECALLBACKPROC gl3wDebugMessageCallback; +PFNGLGETDEBUGMESSAGELOGPROC gl3wGetDebugMessageLog; +PFNGLPUSHDEBUGGROUPPROC gl3wPushDebugGroup; +PFNGLPOPDEBUGGROUPPROC gl3wPopDebugGroup; +PFNGLOBJECTLABELPROC gl3wObjectLabel; +PFNGLGETOBJECTLABELPROC gl3wGetObjectLabel; +PFNGLOBJECTPTRLABELPROC gl3wObjectPtrLabel; +PFNGLGETOBJECTPTRLABELPROC gl3wGetObjectPtrLabel; +PFNGLCLEARBUFFERDATAPROC gl3wClearBufferData; +PFNGLCLEARBUFFERSUBDATAPROC gl3wClearBufferSubData; +PFNGLCLEARNAMEDBUFFERDATAEXTPROC gl3wClearNamedBufferDataEXT; +PFNGLCLEARNAMEDBUFFERSUBDATAEXTPROC gl3wClearNamedBufferSubDataEXT; +PFNGLDISPATCHCOMPUTEPROC gl3wDispatchCompute; +PFNGLDISPATCHCOMPUTEINDIRECTPROC gl3wDispatchComputeIndirect; +PFNGLCOPYIMAGESUBDATAPROC gl3wCopyImageSubData; +PFNGLTEXTUREVIEWPROC gl3wTextureView; +PFNGLBINDVERTEXBUFFERPROC gl3wBindVertexBuffer; +PFNGLVERTEXATTRIBFORMATPROC gl3wVertexAttribFormat; +PFNGLVERTEXATTRIBIFORMATPROC gl3wVertexAttribIFormat; +PFNGLVERTEXATTRIBLFORMATPROC gl3wVertexAttribLFormat; +PFNGLVERTEXATTRIBBINDINGPROC gl3wVertexAttribBinding; +PFNGLVERTEXBINDINGDIVISORPROC gl3wVertexBindingDivisor; +PFNGLVERTEXARRAYBINDVERTEXBUFFEREXTPROC gl3wVertexArrayBindVertexBufferEXT; +PFNGLVERTEXARRAYVERTEXATTRIBFORMATEXTPROC gl3wVertexArrayVertexAttribFormatEXT; +PFNGLVERTEXARRAYVERTEXATTRIBIFORMATEXTPROC gl3wVertexArrayVertexAttribIFormatEXT; +PFNGLVERTEXARRAYVERTEXATTRIBLFORMATEXTPROC gl3wVertexArrayVertexAttribLFormatEXT; +PFNGLVERTEXARRAYVERTEXATTRIBBINDINGEXTPROC gl3wVertexArrayVertexAttribBindingEXT; +PFNGLVERTEXARRAYVERTEXBINDINGDIVISOREXTPROC gl3wVertexArrayVertexBindingDivisorEXT; +PFNGLFRAMEBUFFERPARAMETERIPROC gl3wFramebufferParameteri; +PFNGLGETFRAMEBUFFERPARAMETERIVPROC gl3wGetFramebufferParameteriv; +PFNGLNAMEDFRAMEBUFFERPARAMETERIEXTPROC gl3wNamedFramebufferParameteriEXT; +PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVEXTPROC gl3wGetNamedFramebufferParameterivEXT; +PFNGLGETINTERNALFORMATI64VPROC gl3wGetInternalformati64v; +PFNGLINVALIDATETEXSUBIMAGEPROC gl3wInvalidateTexSubImage; +PFNGLINVALIDATETEXIMAGEPROC gl3wInvalidateTexImage; +PFNGLINVALIDATEBUFFERSUBDATAPROC gl3wInvalidateBufferSubData; +PFNGLINVALIDATEBUFFERDATAPROC gl3wInvalidateBufferData; +PFNGLINVALIDATEFRAMEBUFFERPROC gl3wInvalidateFramebuffer; +PFNGLINVALIDATESUBFRAMEBUFFERPROC gl3wInvalidateSubFramebuffer; +PFNGLMULTIDRAWARRAYSINDIRECTPROC gl3wMultiDrawArraysIndirect; +PFNGLMULTIDRAWELEMENTSINDIRECTPROC gl3wMultiDrawElementsIndirect; +PFNGLGETPROGRAMINTERFACEIVPROC gl3wGetProgramInterfaceiv; +PFNGLGETPROGRAMRESOURCEINDEXPROC gl3wGetProgramResourceIndex; +PFNGLGETPROGRAMRESOURCENAMEPROC gl3wGetProgramResourceName; +PFNGLGETPROGRAMRESOURCEIVPROC gl3wGetProgramResourceiv; +PFNGLGETPROGRAMRESOURCELOCATIONPROC gl3wGetProgramResourceLocation; +PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC gl3wGetProgramResourceLocationIndex; +PFNGLSHADERSTORAGEBLOCKBINDINGPROC gl3wShaderStorageBlockBinding; +PFNGLTEXBUFFERRANGEPROC gl3wTexBufferRange; +PFNGLTEXTUREBUFFERRANGEEXTPROC gl3wTextureBufferRangeEXT; +PFNGLTEXSTORAGE2DMULTISAMPLEPROC gl3wTexStorage2DMultisample; +PFNGLTEXSTORAGE3DMULTISAMPLEPROC gl3wTexStorage3DMultisample; +PFNGLTEXTURESTORAGE2DMULTISAMPLEEXTPROC gl3wTextureStorage2DMultisampleEXT; +PFNGLTEXTURESTORAGE3DMULTISAMPLEEXTPROC gl3wTextureStorage3DMultisampleEXT; + +static void load_procs(void) +{ + gl3wCullFace = (PFNGLCULLFACEPROC) get_proc("glCullFace"); + gl3wFrontFace = (PFNGLFRONTFACEPROC) get_proc("glFrontFace"); + gl3wHint = (PFNGLHINTPROC) get_proc("glHint"); + gl3wLineWidth = (PFNGLLINEWIDTHPROC) get_proc("glLineWidth"); + gl3wPointSize = (PFNGLPOINTSIZEPROC) get_proc("glPointSize"); + gl3wPolygonMode = (PFNGLPOLYGONMODEPROC) get_proc("glPolygonMode"); + gl3wScissor = (PFNGLSCISSORPROC) get_proc("glScissor"); + gl3wTexParameterf = (PFNGLTEXPARAMETERFPROC) get_proc("glTexParameterf"); + gl3wTexParameterfv = (PFNGLTEXPARAMETERFVPROC) get_proc("glTexParameterfv"); + gl3wTexParameteri = (PFNGLTEXPARAMETERIPROC) get_proc("glTexParameteri"); + gl3wTexParameteriv = (PFNGLTEXPARAMETERIVPROC) get_proc("glTexParameteriv"); + gl3wTexImage1D = (PFNGLTEXIMAGE1DPROC) get_proc("glTexImage1D"); + gl3wTexImage2D = (PFNGLTEXIMAGE2DPROC) get_proc("glTexImage2D"); + gl3wDrawBuffer = (PFNGLDRAWBUFFERPROC) get_proc("glDrawBuffer"); + gl3wClear = (PFNGLCLEARPROC) get_proc("glClear"); + gl3wClearColor = (PFNGLCLEARCOLORPROC) get_proc("glClearColor"); + gl3wClearStencil = (PFNGLCLEARSTENCILPROC) get_proc("glClearStencil"); + gl3wClearDepth = (PFNGLCLEARDEPTHPROC) get_proc("glClearDepth"); + gl3wStencilMask = (PFNGLSTENCILMASKPROC) get_proc("glStencilMask"); + gl3wColorMask = (PFNGLCOLORMASKPROC) get_proc("glColorMask"); + gl3wDepthMask = (PFNGLDEPTHMASKPROC) get_proc("glDepthMask"); + gl3wDisable = (PFNGLDISABLEPROC) get_proc("glDisable"); + gl3wEnable = (PFNGLENABLEPROC) get_proc("glEnable"); + gl3wFinish = (PFNGLFINISHPROC) get_proc("glFinish"); + gl3wFlush = (PFNGLFLUSHPROC) get_proc("glFlush"); + gl3wBlendFunc = (PFNGLBLENDFUNCPROC) get_proc("glBlendFunc"); + gl3wLogicOp = (PFNGLLOGICOPPROC) get_proc("glLogicOp"); + gl3wStencilFunc = (PFNGLSTENCILFUNCPROC) get_proc("glStencilFunc"); + gl3wStencilOp = (PFNGLSTENCILOPPROC) get_proc("glStencilOp"); + gl3wDepthFunc = (PFNGLDEPTHFUNCPROC) get_proc("glDepthFunc"); + gl3wPixelStoref = (PFNGLPIXELSTOREFPROC) get_proc("glPixelStoref"); + gl3wPixelStorei = (PFNGLPIXELSTOREIPROC) get_proc("glPixelStorei"); + gl3wReadBuffer = (PFNGLREADBUFFERPROC) get_proc("glReadBuffer"); + gl3wReadPixels = (PFNGLREADPIXELSPROC) get_proc("glReadPixels"); + gl3wGetBooleanv = (PFNGLGETBOOLEANVPROC) get_proc("glGetBooleanv"); + gl3wGetDoublev = (PFNGLGETDOUBLEVPROC) get_proc("glGetDoublev"); + gl3wGetError = (PFNGLGETERRORPROC) get_proc("glGetError"); + gl3wGetFloatv = (PFNGLGETFLOATVPROC) get_proc("glGetFloatv"); + gl3wGetIntegerv = (PFNGLGETINTEGERVPROC) get_proc("glGetIntegerv"); + gl3wGetString = (PFNGLGETSTRINGPROC) get_proc("glGetString"); + gl3wGetTexImage = (PFNGLGETTEXIMAGEPROC) get_proc("glGetTexImage"); + gl3wGetTexParameterfv = (PFNGLGETTEXPARAMETERFVPROC) get_proc("glGetTexParameterfv"); + gl3wGetTexParameteriv = (PFNGLGETTEXPARAMETERIVPROC) get_proc("glGetTexParameteriv"); + gl3wGetTexLevelParameterfv = (PFNGLGETTEXLEVELPARAMETERFVPROC) get_proc("glGetTexLevelParameterfv"); + gl3wGetTexLevelParameteriv = (PFNGLGETTEXLEVELPARAMETERIVPROC) get_proc("glGetTexLevelParameteriv"); + gl3wIsEnabled = (PFNGLISENABLEDPROC) get_proc("glIsEnabled"); + gl3wDepthRange = (PFNGLDEPTHRANGEPROC) get_proc("glDepthRange"); + gl3wViewport = (PFNGLVIEWPORTPROC) get_proc("glViewport"); + gl3wDrawArrays = (PFNGLDRAWARRAYSPROC) get_proc("glDrawArrays"); + gl3wDrawElements = (PFNGLDRAWELEMENTSPROC) get_proc("glDrawElements"); + gl3wGetPointerv = (PFNGLGETPOINTERVPROC) get_proc("glGetPointerv"); + gl3wPolygonOffset = (PFNGLPOLYGONOFFSETPROC) get_proc("glPolygonOffset"); + gl3wCopyTexImage1D = (PFNGLCOPYTEXIMAGE1DPROC) get_proc("glCopyTexImage1D"); + gl3wCopyTexImage2D = (PFNGLCOPYTEXIMAGE2DPROC) get_proc("glCopyTexImage2D"); + gl3wCopyTexSubImage1D = (PFNGLCOPYTEXSUBIMAGE1DPROC) get_proc("glCopyTexSubImage1D"); + gl3wCopyTexSubImage2D = (PFNGLCOPYTEXSUBIMAGE2DPROC) get_proc("glCopyTexSubImage2D"); + gl3wTexSubImage1D = (PFNGLTEXSUBIMAGE1DPROC) get_proc("glTexSubImage1D"); + gl3wTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC) get_proc("glTexSubImage2D"); + gl3wBindTexture = (PFNGLBINDTEXTUREPROC) get_proc("glBindTexture"); + gl3wDeleteTextures = (PFNGLDELETETEXTURESPROC) get_proc("glDeleteTextures"); + gl3wGenTextures = (PFNGLGENTEXTURESPROC) get_proc("glGenTextures"); + gl3wIsTexture = (PFNGLISTEXTUREPROC) get_proc("glIsTexture"); + gl3wBlendColor = (PFNGLBLENDCOLORPROC) get_proc("glBlendColor"); + gl3wBlendEquation = (PFNGLBLENDEQUATIONPROC) get_proc("glBlendEquation"); + gl3wDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC) get_proc("glDrawRangeElements"); + gl3wTexImage3D = (PFNGLTEXIMAGE3DPROC) get_proc("glTexImage3D"); + gl3wTexSubImage3D = (PFNGLTEXSUBIMAGE3DPROC) get_proc("glTexSubImage3D"); + gl3wCopyTexSubImage3D = (PFNGLCOPYTEXSUBIMAGE3DPROC) get_proc("glCopyTexSubImage3D"); + gl3wActiveTexture = (PFNGLACTIVETEXTUREPROC) get_proc("glActiveTexture"); + gl3wSampleCoverage = (PFNGLSAMPLECOVERAGEPROC) get_proc("glSampleCoverage"); + gl3wCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC) get_proc("glCompressedTexImage3D"); + gl3wCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC) get_proc("glCompressedTexImage2D"); + gl3wCompressedTexImage1D = (PFNGLCOMPRESSEDTEXIMAGE1DPROC) get_proc("glCompressedTexImage1D"); + gl3wCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) get_proc("glCompressedTexSubImage3D"); + gl3wCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) get_proc("glCompressedTexSubImage2D"); + gl3wCompressedTexSubImage1D = (PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) get_proc("glCompressedTexSubImage1D"); + gl3wGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC) get_proc("glGetCompressedTexImage"); + gl3wBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC) get_proc("glBlendFuncSeparate"); + gl3wMultiDrawArrays = (PFNGLMULTIDRAWARRAYSPROC) get_proc("glMultiDrawArrays"); + gl3wMultiDrawElements = (PFNGLMULTIDRAWELEMENTSPROC) get_proc("glMultiDrawElements"); + gl3wPointParameterf = (PFNGLPOINTPARAMETERFPROC) get_proc("glPointParameterf"); + gl3wPointParameterfv = (PFNGLPOINTPARAMETERFVPROC) get_proc("glPointParameterfv"); + gl3wPointParameteri = (PFNGLPOINTPARAMETERIPROC) get_proc("glPointParameteri"); + gl3wPointParameteriv = (PFNGLPOINTPARAMETERIVPROC) get_proc("glPointParameteriv"); + gl3wGenQueries = (PFNGLGENQUERIESPROC) get_proc("glGenQueries"); + gl3wDeleteQueries = (PFNGLDELETEQUERIESPROC) get_proc("glDeleteQueries"); + gl3wIsQuery = (PFNGLISQUERYPROC) get_proc("glIsQuery"); + gl3wBeginQuery = (PFNGLBEGINQUERYPROC) get_proc("glBeginQuery"); + gl3wEndQuery = (PFNGLENDQUERYPROC) get_proc("glEndQuery"); + gl3wGetQueryiv = (PFNGLGETQUERYIVPROC) get_proc("glGetQueryiv"); + gl3wGetQueryObjectiv = (PFNGLGETQUERYOBJECTIVPROC) get_proc("glGetQueryObjectiv"); + gl3wGetQueryObjectuiv = (PFNGLGETQUERYOBJECTUIVPROC) get_proc("glGetQueryObjectuiv"); + gl3wBindBuffer = (PFNGLBINDBUFFERPROC) get_proc("glBindBuffer"); + gl3wDeleteBuffers = (PFNGLDELETEBUFFERSPROC) get_proc("glDeleteBuffers"); + gl3wGenBuffers = (PFNGLGENBUFFERSPROC) get_proc("glGenBuffers"); + gl3wIsBuffer = (PFNGLISBUFFERPROC) get_proc("glIsBuffer"); + gl3wBufferData = (PFNGLBUFFERDATAPROC) get_proc("glBufferData"); + gl3wBufferSubData = (PFNGLBUFFERSUBDATAPROC) get_proc("glBufferSubData"); + gl3wGetBufferSubData = (PFNGLGETBUFFERSUBDATAPROC) get_proc("glGetBufferSubData"); + gl3wMapBuffer = (PFNGLMAPBUFFERPROC) get_proc("glMapBuffer"); + gl3wUnmapBuffer = (PFNGLUNMAPBUFFERPROC) get_proc("glUnmapBuffer"); + gl3wGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC) get_proc("glGetBufferParameteriv"); + gl3wGetBufferPointerv = (PFNGLGETBUFFERPOINTERVPROC) get_proc("glGetBufferPointerv"); + gl3wBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEPROC) get_proc("glBlendEquationSeparate"); + gl3wDrawBuffers = (PFNGLDRAWBUFFERSPROC) get_proc("glDrawBuffers"); + gl3wStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC) get_proc("glStencilOpSeparate"); + gl3wStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC) get_proc("glStencilFuncSeparate"); + gl3wStencilMaskSeparate = (PFNGLSTENCILMASKSEPARATEPROC) get_proc("glStencilMaskSeparate"); + gl3wAttachShader = (PFNGLATTACHSHADERPROC) get_proc("glAttachShader"); + gl3wBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC) get_proc("glBindAttribLocation"); + gl3wCompileShader = (PFNGLCOMPILESHADERPROC) get_proc("glCompileShader"); + gl3wCreateProgram = (PFNGLCREATEPROGRAMPROC) get_proc("glCreateProgram"); + gl3wCreateShader = (PFNGLCREATESHADERPROC) get_proc("glCreateShader"); + gl3wDeleteProgram = (PFNGLDELETEPROGRAMPROC) get_proc("glDeleteProgram"); + gl3wDeleteShader = (PFNGLDELETESHADERPROC) get_proc("glDeleteShader"); + gl3wDetachShader = (PFNGLDETACHSHADERPROC) get_proc("glDetachShader"); + gl3wDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC) get_proc("glDisableVertexAttribArray"); + gl3wEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC) get_proc("glEnableVertexAttribArray"); + gl3wGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC) get_proc("glGetActiveAttrib"); + gl3wGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC) get_proc("glGetActiveUniform"); + gl3wGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC) get_proc("glGetAttachedShaders"); + gl3wGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC) get_proc("glGetAttribLocation"); + gl3wGetProgramiv = (PFNGLGETPROGRAMIVPROC) get_proc("glGetProgramiv"); + gl3wGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC) get_proc("glGetProgramInfoLog"); + gl3wGetShaderiv = (PFNGLGETSHADERIVPROC) get_proc("glGetShaderiv"); + gl3wGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC) get_proc("glGetShaderInfoLog"); + gl3wGetShaderSource = (PFNGLGETSHADERSOURCEPROC) get_proc("glGetShaderSource"); + gl3wGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC) get_proc("glGetUniformLocation"); + gl3wGetUniformfv = (PFNGLGETUNIFORMFVPROC) get_proc("glGetUniformfv"); + gl3wGetUniformiv = (PFNGLGETUNIFORMIVPROC) get_proc("glGetUniformiv"); + gl3wGetVertexAttribdv = (PFNGLGETVERTEXATTRIBDVPROC) get_proc("glGetVertexAttribdv"); + gl3wGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC) get_proc("glGetVertexAttribfv"); + gl3wGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC) get_proc("glGetVertexAttribiv"); + gl3wGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC) get_proc("glGetVertexAttribPointerv"); + gl3wIsProgram = (PFNGLISPROGRAMPROC) get_proc("glIsProgram"); + gl3wIsShader = (PFNGLISSHADERPROC) get_proc("glIsShader"); + gl3wLinkProgram = (PFNGLLINKPROGRAMPROC) get_proc("glLinkProgram"); + gl3wShaderSource = (PFNGLSHADERSOURCEPROC) get_proc("glShaderSource"); + gl3wUseProgram = (PFNGLUSEPROGRAMPROC) get_proc("glUseProgram"); + gl3wUniform1f = (PFNGLUNIFORM1FPROC) get_proc("glUniform1f"); + gl3wUniform2f = (PFNGLUNIFORM2FPROC) get_proc("glUniform2f"); + gl3wUniform3f = (PFNGLUNIFORM3FPROC) get_proc("glUniform3f"); + gl3wUniform4f = (PFNGLUNIFORM4FPROC) get_proc("glUniform4f"); + gl3wUniform1i = (PFNGLUNIFORM1IPROC) get_proc("glUniform1i"); + gl3wUniform2i = (PFNGLUNIFORM2IPROC) get_proc("glUniform2i"); + gl3wUniform3i = (PFNGLUNIFORM3IPROC) get_proc("glUniform3i"); + gl3wUniform4i = (PFNGLUNIFORM4IPROC) get_proc("glUniform4i"); + gl3wUniform1fv = (PFNGLUNIFORM1FVPROC) get_proc("glUniform1fv"); + gl3wUniform2fv = (PFNGLUNIFORM2FVPROC) get_proc("glUniform2fv"); + gl3wUniform3fv = (PFNGLUNIFORM3FVPROC) get_proc("glUniform3fv"); + gl3wUniform4fv = (PFNGLUNIFORM4FVPROC) get_proc("glUniform4fv"); + gl3wUniform1iv = (PFNGLUNIFORM1IVPROC) get_proc("glUniform1iv"); + gl3wUniform2iv = (PFNGLUNIFORM2IVPROC) get_proc("glUniform2iv"); + gl3wUniform3iv = (PFNGLUNIFORM3IVPROC) get_proc("glUniform3iv"); + gl3wUniform4iv = (PFNGLUNIFORM4IVPROC) get_proc("glUniform4iv"); + gl3wUniformMatrix2fv = (PFNGLUNIFORMMATRIX2FVPROC) get_proc("glUniformMatrix2fv"); + gl3wUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC) get_proc("glUniformMatrix3fv"); + gl3wUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC) get_proc("glUniformMatrix4fv"); + gl3wValidateProgram = (PFNGLVALIDATEPROGRAMPROC) get_proc("glValidateProgram"); + gl3wVertexAttrib1d = (PFNGLVERTEXATTRIB1DPROC) get_proc("glVertexAttrib1d"); + gl3wVertexAttrib1dv = (PFNGLVERTEXATTRIB1DVPROC) get_proc("glVertexAttrib1dv"); + gl3wVertexAttrib1f = (PFNGLVERTEXATTRIB1FPROC) get_proc("glVertexAttrib1f"); + gl3wVertexAttrib1fv = (PFNGLVERTEXATTRIB1FVPROC) get_proc("glVertexAttrib1fv"); + gl3wVertexAttrib1s = (PFNGLVERTEXATTRIB1SPROC) get_proc("glVertexAttrib1s"); + gl3wVertexAttrib1sv = (PFNGLVERTEXATTRIB1SVPROC) get_proc("glVertexAttrib1sv"); + gl3wVertexAttrib2d = (PFNGLVERTEXATTRIB2DPROC) get_proc("glVertexAttrib2d"); + gl3wVertexAttrib2dv = (PFNGLVERTEXATTRIB2DVPROC) get_proc("glVertexAttrib2dv"); + gl3wVertexAttrib2f = (PFNGLVERTEXATTRIB2FPROC) get_proc("glVertexAttrib2f"); + gl3wVertexAttrib2fv = (PFNGLVERTEXATTRIB2FVPROC) get_proc("glVertexAttrib2fv"); + gl3wVertexAttrib2s = (PFNGLVERTEXATTRIB2SPROC) get_proc("glVertexAttrib2s"); + gl3wVertexAttrib2sv = (PFNGLVERTEXATTRIB2SVPROC) get_proc("glVertexAttrib2sv"); + gl3wVertexAttrib3d = (PFNGLVERTEXATTRIB3DPROC) get_proc("glVertexAttrib3d"); + gl3wVertexAttrib3dv = (PFNGLVERTEXATTRIB3DVPROC) get_proc("glVertexAttrib3dv"); + gl3wVertexAttrib3f = (PFNGLVERTEXATTRIB3FPROC) get_proc("glVertexAttrib3f"); + gl3wVertexAttrib3fv = (PFNGLVERTEXATTRIB3FVPROC) get_proc("glVertexAttrib3fv"); + gl3wVertexAttrib3s = (PFNGLVERTEXATTRIB3SPROC) get_proc("glVertexAttrib3s"); + gl3wVertexAttrib3sv = (PFNGLVERTEXATTRIB3SVPROC) get_proc("glVertexAttrib3sv"); + gl3wVertexAttrib4Nbv = (PFNGLVERTEXATTRIB4NBVPROC) get_proc("glVertexAttrib4Nbv"); + gl3wVertexAttrib4Niv = (PFNGLVERTEXATTRIB4NIVPROC) get_proc("glVertexAttrib4Niv"); + gl3wVertexAttrib4Nsv = (PFNGLVERTEXATTRIB4NSVPROC) get_proc("glVertexAttrib4Nsv"); + gl3wVertexAttrib4Nub = (PFNGLVERTEXATTRIB4NUBPROC) get_proc("glVertexAttrib4Nub"); + gl3wVertexAttrib4Nubv = (PFNGLVERTEXATTRIB4NUBVPROC) get_proc("glVertexAttrib4Nubv"); + gl3wVertexAttrib4Nuiv = (PFNGLVERTEXATTRIB4NUIVPROC) get_proc("glVertexAttrib4Nuiv"); + gl3wVertexAttrib4Nusv = (PFNGLVERTEXATTRIB4NUSVPROC) get_proc("glVertexAttrib4Nusv"); + gl3wVertexAttrib4bv = (PFNGLVERTEXATTRIB4BVPROC) get_proc("glVertexAttrib4bv"); + gl3wVertexAttrib4d = (PFNGLVERTEXATTRIB4DPROC) get_proc("glVertexAttrib4d"); + gl3wVertexAttrib4dv = (PFNGLVERTEXATTRIB4DVPROC) get_proc("glVertexAttrib4dv"); + gl3wVertexAttrib4f = (PFNGLVERTEXATTRIB4FPROC) get_proc("glVertexAttrib4f"); + gl3wVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC) get_proc("glVertexAttrib4fv"); + gl3wVertexAttrib4iv = (PFNGLVERTEXATTRIB4IVPROC) get_proc("glVertexAttrib4iv"); + gl3wVertexAttrib4s = (PFNGLVERTEXATTRIB4SPROC) get_proc("glVertexAttrib4s"); + gl3wVertexAttrib4sv = (PFNGLVERTEXATTRIB4SVPROC) get_proc("glVertexAttrib4sv"); + gl3wVertexAttrib4ubv = (PFNGLVERTEXATTRIB4UBVPROC) get_proc("glVertexAttrib4ubv"); + gl3wVertexAttrib4uiv = (PFNGLVERTEXATTRIB4UIVPROC) get_proc("glVertexAttrib4uiv"); + gl3wVertexAttrib4usv = (PFNGLVERTEXATTRIB4USVPROC) get_proc("glVertexAttrib4usv"); + gl3wVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC) get_proc("glVertexAttribPointer"); + gl3wUniformMatrix2x3fv = (PFNGLUNIFORMMATRIX2X3FVPROC) get_proc("glUniformMatrix2x3fv"); + gl3wUniformMatrix3x2fv = (PFNGLUNIFORMMATRIX3X2FVPROC) get_proc("glUniformMatrix3x2fv"); + gl3wUniformMatrix2x4fv = (PFNGLUNIFORMMATRIX2X4FVPROC) get_proc("glUniformMatrix2x4fv"); + gl3wUniformMatrix4x2fv = (PFNGLUNIFORMMATRIX4X2FVPROC) get_proc("glUniformMatrix4x2fv"); + gl3wUniformMatrix3x4fv = (PFNGLUNIFORMMATRIX3X4FVPROC) get_proc("glUniformMatrix3x4fv"); + gl3wUniformMatrix4x3fv = (PFNGLUNIFORMMATRIX4X3FVPROC) get_proc("glUniformMatrix4x3fv"); + gl3wColorMaski = (PFNGLCOLORMASKIPROC) get_proc("glColorMaski"); + gl3wGetBooleani_v = (PFNGLGETBOOLEANI_VPROC) get_proc("glGetBooleani_v"); + gl3wGetIntegeri_v = (PFNGLGETINTEGERI_VPROC) get_proc("glGetIntegeri_v"); + gl3wEnablei = (PFNGLENABLEIPROC) get_proc("glEnablei"); + gl3wDisablei = (PFNGLDISABLEIPROC) get_proc("glDisablei"); + gl3wIsEnabledi = (PFNGLISENABLEDIPROC) get_proc("glIsEnabledi"); + gl3wBeginTransformFeedback = (PFNGLBEGINTRANSFORMFEEDBACKPROC) get_proc("glBeginTransformFeedback"); + gl3wEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC) get_proc("glEndTransformFeedback"); + gl3wBindBufferRange = (PFNGLBINDBUFFERRANGEPROC) get_proc("glBindBufferRange"); + gl3wBindBufferBase = (PFNGLBINDBUFFERBASEPROC) get_proc("glBindBufferBase"); + gl3wTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC) get_proc("glTransformFeedbackVaryings"); + gl3wGetTransformFeedbackVarying = (PFNGLGETTRANSFORMFEEDBACKVARYINGPROC) get_proc("glGetTransformFeedbackVarying"); + gl3wClampColor = (PFNGLCLAMPCOLORPROC) get_proc("glClampColor"); + gl3wBeginConditionalRender = (PFNGLBEGINCONDITIONALRENDERPROC) get_proc("glBeginConditionalRender"); + gl3wEndConditionalRender = (PFNGLENDCONDITIONALRENDERPROC) get_proc("glEndConditionalRender"); + gl3wVertexAttribIPointer = (PFNGLVERTEXATTRIBIPOINTERPROC) get_proc("glVertexAttribIPointer"); + gl3wGetVertexAttribIiv = (PFNGLGETVERTEXATTRIBIIVPROC) get_proc("glGetVertexAttribIiv"); + gl3wGetVertexAttribIuiv = (PFNGLGETVERTEXATTRIBIUIVPROC) get_proc("glGetVertexAttribIuiv"); + gl3wVertexAttribI1i = (PFNGLVERTEXATTRIBI1IPROC) get_proc("glVertexAttribI1i"); + gl3wVertexAttribI2i = (PFNGLVERTEXATTRIBI2IPROC) get_proc("glVertexAttribI2i"); + gl3wVertexAttribI3i = (PFNGLVERTEXATTRIBI3IPROC) get_proc("glVertexAttribI3i"); + gl3wVertexAttribI4i = (PFNGLVERTEXATTRIBI4IPROC) get_proc("glVertexAttribI4i"); + gl3wVertexAttribI1ui = (PFNGLVERTEXATTRIBI1UIPROC) get_proc("glVertexAttribI1ui"); + gl3wVertexAttribI2ui = (PFNGLVERTEXATTRIBI2UIPROC) get_proc("glVertexAttribI2ui"); + gl3wVertexAttribI3ui = (PFNGLVERTEXATTRIBI3UIPROC) get_proc("glVertexAttribI3ui"); + gl3wVertexAttribI4ui = (PFNGLVERTEXATTRIBI4UIPROC) get_proc("glVertexAttribI4ui"); + gl3wVertexAttribI1iv = (PFNGLVERTEXATTRIBI1IVPROC) get_proc("glVertexAttribI1iv"); + gl3wVertexAttribI2iv = (PFNGLVERTEXATTRIBI2IVPROC) get_proc("glVertexAttribI2iv"); + gl3wVertexAttribI3iv = (PFNGLVERTEXATTRIBI3IVPROC) get_proc("glVertexAttribI3iv"); + gl3wVertexAttribI4iv = (PFNGLVERTEXATTRIBI4IVPROC) get_proc("glVertexAttribI4iv"); + gl3wVertexAttribI1uiv = (PFNGLVERTEXATTRIBI1UIVPROC) get_proc("glVertexAttribI1uiv"); + gl3wVertexAttribI2uiv = (PFNGLVERTEXATTRIBI2UIVPROC) get_proc("glVertexAttribI2uiv"); + gl3wVertexAttribI3uiv = (PFNGLVERTEXATTRIBI3UIVPROC) get_proc("glVertexAttribI3uiv"); + gl3wVertexAttribI4uiv = (PFNGLVERTEXATTRIBI4UIVPROC) get_proc("glVertexAttribI4uiv"); + gl3wVertexAttribI4bv = (PFNGLVERTEXATTRIBI4BVPROC) get_proc("glVertexAttribI4bv"); + gl3wVertexAttribI4sv = (PFNGLVERTEXATTRIBI4SVPROC) get_proc("glVertexAttribI4sv"); + gl3wVertexAttribI4ubv = (PFNGLVERTEXATTRIBI4UBVPROC) get_proc("glVertexAttribI4ubv"); + gl3wVertexAttribI4usv = (PFNGLVERTEXATTRIBI4USVPROC) get_proc("glVertexAttribI4usv"); + gl3wGetUniformuiv = (PFNGLGETUNIFORMUIVPROC) get_proc("glGetUniformuiv"); + gl3wBindFragDataLocation = (PFNGLBINDFRAGDATALOCATIONPROC) get_proc("glBindFragDataLocation"); + gl3wGetFragDataLocation = (PFNGLGETFRAGDATALOCATIONPROC) get_proc("glGetFragDataLocation"); + gl3wUniform1ui = (PFNGLUNIFORM1UIPROC) get_proc("glUniform1ui"); + gl3wUniform2ui = (PFNGLUNIFORM2UIPROC) get_proc("glUniform2ui"); + gl3wUniform3ui = (PFNGLUNIFORM3UIPROC) get_proc("glUniform3ui"); + gl3wUniform4ui = (PFNGLUNIFORM4UIPROC) get_proc("glUniform4ui"); + gl3wUniform1uiv = (PFNGLUNIFORM1UIVPROC) get_proc("glUniform1uiv"); + gl3wUniform2uiv = (PFNGLUNIFORM2UIVPROC) get_proc("glUniform2uiv"); + gl3wUniform3uiv = (PFNGLUNIFORM3UIVPROC) get_proc("glUniform3uiv"); + gl3wUniform4uiv = (PFNGLUNIFORM4UIVPROC) get_proc("glUniform4uiv"); + gl3wTexParameterIiv = (PFNGLTEXPARAMETERIIVPROC) get_proc("glTexParameterIiv"); + gl3wTexParameterIuiv = (PFNGLTEXPARAMETERIUIVPROC) get_proc("glTexParameterIuiv"); + gl3wGetTexParameterIiv = (PFNGLGETTEXPARAMETERIIVPROC) get_proc("glGetTexParameterIiv"); + gl3wGetTexParameterIuiv = (PFNGLGETTEXPARAMETERIUIVPROC) get_proc("glGetTexParameterIuiv"); + gl3wClearBufferiv = (PFNGLCLEARBUFFERIVPROC) get_proc("glClearBufferiv"); + gl3wClearBufferuiv = (PFNGLCLEARBUFFERUIVPROC) get_proc("glClearBufferuiv"); + gl3wClearBufferfv = (PFNGLCLEARBUFFERFVPROC) get_proc("glClearBufferfv"); + gl3wClearBufferfi = (PFNGLCLEARBUFFERFIPROC) get_proc("glClearBufferfi"); + gl3wGetStringi = (PFNGLGETSTRINGIPROC) get_proc("glGetStringi"); + gl3wDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDPROC) get_proc("glDrawArraysInstanced"); + gl3wDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDPROC) get_proc("glDrawElementsInstanced"); + gl3wTexBuffer = (PFNGLTEXBUFFERPROC) get_proc("glTexBuffer"); + gl3wPrimitiveRestartIndex = (PFNGLPRIMITIVERESTARTINDEXPROC) get_proc("glPrimitiveRestartIndex"); + gl3wGetInteger64i_v = (PFNGLGETINTEGER64I_VPROC) get_proc("glGetInteger64i_v"); + gl3wGetBufferParameteri64v = (PFNGLGETBUFFERPARAMETERI64VPROC) get_proc("glGetBufferParameteri64v"); + gl3wFramebufferTexture = (PFNGLFRAMEBUFFERTEXTUREPROC) get_proc("glFramebufferTexture"); + gl3wVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISORPROC) get_proc("glVertexAttribDivisor"); + gl3wMinSampleShading = (PFNGLMINSAMPLESHADINGPROC) get_proc("glMinSampleShading"); + gl3wBlendEquationi = (PFNGLBLENDEQUATIONIPROC) get_proc("glBlendEquationi"); + gl3wBlendEquationSeparatei = (PFNGLBLENDEQUATIONSEPARATEIPROC) get_proc("glBlendEquationSeparatei"); + gl3wBlendFunci = (PFNGLBLENDFUNCIPROC) get_proc("glBlendFunci"); + gl3wBlendFuncSeparatei = (PFNGLBLENDFUNCSEPARATEIPROC) get_proc("glBlendFuncSeparatei"); + gl3wIsRenderbuffer = (PFNGLISRENDERBUFFERPROC) get_proc("glIsRenderbuffer"); + gl3wBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC) get_proc("glBindRenderbuffer"); + gl3wDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC) get_proc("glDeleteRenderbuffers"); + gl3wGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC) get_proc("glGenRenderbuffers"); + gl3wRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC) get_proc("glRenderbufferStorage"); + gl3wGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC) get_proc("glGetRenderbufferParameteriv"); + gl3wIsFramebuffer = (PFNGLISFRAMEBUFFERPROC) get_proc("glIsFramebuffer"); + gl3wBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC) get_proc("glBindFramebuffer"); + gl3wDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC) get_proc("glDeleteFramebuffers"); + gl3wGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC) get_proc("glGenFramebuffers"); + gl3wCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC) get_proc("glCheckFramebufferStatus"); + gl3wFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DPROC) get_proc("glFramebufferTexture1D"); + gl3wFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC) get_proc("glFramebufferTexture2D"); + gl3wFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DPROC) get_proc("glFramebufferTexture3D"); + gl3wFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC) get_proc("glFramebufferRenderbuffer"); + gl3wGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) get_proc("glGetFramebufferAttachmentParameteriv"); + gl3wGenerateMipmap = (PFNGLGENERATEMIPMAPPROC) get_proc("glGenerateMipmap"); + gl3wBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC) get_proc("glBlitFramebuffer"); + gl3wRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) get_proc("glRenderbufferStorageMultisample"); + gl3wFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC) get_proc("glFramebufferTextureLayer"); + gl3wMapBufferRange = (PFNGLMAPBUFFERRANGEPROC) get_proc("glMapBufferRange"); + gl3wFlushMappedBufferRange = (PFNGLFLUSHMAPPEDBUFFERRANGEPROC) get_proc("glFlushMappedBufferRange"); + gl3wBindVertexArray = (PFNGLBINDVERTEXARRAYPROC) get_proc("glBindVertexArray"); + gl3wDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC) get_proc("glDeleteVertexArrays"); + gl3wGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC) get_proc("glGenVertexArrays"); + gl3wIsVertexArray = (PFNGLISVERTEXARRAYPROC) get_proc("glIsVertexArray"); + gl3wGetUniformIndices = (PFNGLGETUNIFORMINDICESPROC) get_proc("glGetUniformIndices"); + gl3wGetActiveUniformsiv = (PFNGLGETACTIVEUNIFORMSIVPROC) get_proc("glGetActiveUniformsiv"); + gl3wGetActiveUniformName = (PFNGLGETACTIVEUNIFORMNAMEPROC) get_proc("glGetActiveUniformName"); + gl3wGetUniformBlockIndex = (PFNGLGETUNIFORMBLOCKINDEXPROC) get_proc("glGetUniformBlockIndex"); + gl3wGetActiveUniformBlockiv = (PFNGLGETACTIVEUNIFORMBLOCKIVPROC) get_proc("glGetActiveUniformBlockiv"); + gl3wGetActiveUniformBlockName = (PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC) get_proc("glGetActiveUniformBlockName"); + gl3wUniformBlockBinding = (PFNGLUNIFORMBLOCKBINDINGPROC) get_proc("glUniformBlockBinding"); + gl3wCopyBufferSubData = (PFNGLCOPYBUFFERSUBDATAPROC) get_proc("glCopyBufferSubData"); + gl3wDrawElementsBaseVertex = (PFNGLDRAWELEMENTSBASEVERTEXPROC) get_proc("glDrawElementsBaseVertex"); + gl3wDrawRangeElementsBaseVertex = (PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC) get_proc("glDrawRangeElementsBaseVertex"); + gl3wDrawElementsInstancedBaseVertex = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC) get_proc("glDrawElementsInstancedBaseVertex"); + gl3wMultiDrawElementsBaseVertex = (PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC) get_proc("glMultiDrawElementsBaseVertex"); + gl3wProvokingVertex = (PFNGLPROVOKINGVERTEXPROC) get_proc("glProvokingVertex"); + gl3wFenceSync = (PFNGLFENCESYNCPROC) get_proc("glFenceSync"); + gl3wIsSync = (PFNGLISSYNCPROC) get_proc("glIsSync"); + gl3wDeleteSync = (PFNGLDELETESYNCPROC) get_proc("glDeleteSync"); + gl3wClientWaitSync = (PFNGLCLIENTWAITSYNCPROC) get_proc("glClientWaitSync"); + gl3wWaitSync = (PFNGLWAITSYNCPROC) get_proc("glWaitSync"); + gl3wGetInteger64v = (PFNGLGETINTEGER64VPROC) get_proc("glGetInteger64v"); + gl3wGetSynciv = (PFNGLGETSYNCIVPROC) get_proc("glGetSynciv"); + gl3wTexImage2DMultisample = (PFNGLTEXIMAGE2DMULTISAMPLEPROC) get_proc("glTexImage2DMultisample"); + gl3wTexImage3DMultisample = (PFNGLTEXIMAGE3DMULTISAMPLEPROC) get_proc("glTexImage3DMultisample"); + gl3wGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC) get_proc("glGetMultisamplefv"); + gl3wSampleMaski = (PFNGLSAMPLEMASKIPROC) get_proc("glSampleMaski"); + gl3wBlendEquationiARB = (PFNGLBLENDEQUATIONIARBPROC) get_proc("glBlendEquationiARB"); + gl3wBlendEquationSeparateiARB = (PFNGLBLENDEQUATIONSEPARATEIARBPROC) get_proc("glBlendEquationSeparateiARB"); + gl3wBlendFunciARB = (PFNGLBLENDFUNCIARBPROC) get_proc("glBlendFunciARB"); + gl3wBlendFuncSeparateiARB = (PFNGLBLENDFUNCSEPARATEIARBPROC) get_proc("glBlendFuncSeparateiARB"); + gl3wMinSampleShadingARB = (PFNGLMINSAMPLESHADINGARBPROC) get_proc("glMinSampleShadingARB"); + gl3wNamedStringARB = (PFNGLNAMEDSTRINGARBPROC) get_proc("glNamedStringARB"); + gl3wDeleteNamedStringARB = (PFNGLDELETENAMEDSTRINGARBPROC) get_proc("glDeleteNamedStringARB"); + gl3wCompileShaderIncludeARB = (PFNGLCOMPILESHADERINCLUDEARBPROC) get_proc("glCompileShaderIncludeARB"); + gl3wIsNamedStringARB = (PFNGLISNAMEDSTRINGARBPROC) get_proc("glIsNamedStringARB"); + gl3wGetNamedStringARB = (PFNGLGETNAMEDSTRINGARBPROC) get_proc("glGetNamedStringARB"); + gl3wGetNamedStringivARB = (PFNGLGETNAMEDSTRINGIVARBPROC) get_proc("glGetNamedStringivARB"); + gl3wBindFragDataLocationIndexed = (PFNGLBINDFRAGDATALOCATIONINDEXEDPROC) get_proc("glBindFragDataLocationIndexed"); + gl3wGetFragDataIndex = (PFNGLGETFRAGDATAINDEXPROC) get_proc("glGetFragDataIndex"); + gl3wGenSamplers = (PFNGLGENSAMPLERSPROC) get_proc("glGenSamplers"); + gl3wDeleteSamplers = (PFNGLDELETESAMPLERSPROC) get_proc("glDeleteSamplers"); + gl3wIsSampler = (PFNGLISSAMPLERPROC) get_proc("glIsSampler"); + gl3wBindSampler = (PFNGLBINDSAMPLERPROC) get_proc("glBindSampler"); + gl3wSamplerParameteri = (PFNGLSAMPLERPARAMETERIPROC) get_proc("glSamplerParameteri"); + gl3wSamplerParameteriv = (PFNGLSAMPLERPARAMETERIVPROC) get_proc("glSamplerParameteriv"); + gl3wSamplerParameterf = (PFNGLSAMPLERPARAMETERFPROC) get_proc("glSamplerParameterf"); + gl3wSamplerParameterfv = (PFNGLSAMPLERPARAMETERFVPROC) get_proc("glSamplerParameterfv"); + gl3wSamplerParameterIiv = (PFNGLSAMPLERPARAMETERIIVPROC) get_proc("glSamplerParameterIiv"); + gl3wSamplerParameterIuiv = (PFNGLSAMPLERPARAMETERIUIVPROC) get_proc("glSamplerParameterIuiv"); + gl3wGetSamplerParameteriv = (PFNGLGETSAMPLERPARAMETERIVPROC) get_proc("glGetSamplerParameteriv"); + gl3wGetSamplerParameterIiv = (PFNGLGETSAMPLERPARAMETERIIVPROC) get_proc("glGetSamplerParameterIiv"); + gl3wGetSamplerParameterfv = (PFNGLGETSAMPLERPARAMETERFVPROC) get_proc("glGetSamplerParameterfv"); + gl3wGetSamplerParameterIuiv = (PFNGLGETSAMPLERPARAMETERIUIVPROC) get_proc("glGetSamplerParameterIuiv"); + gl3wQueryCounter = (PFNGLQUERYCOUNTERPROC) get_proc("glQueryCounter"); + gl3wGetQueryObjecti64v = (PFNGLGETQUERYOBJECTI64VPROC) get_proc("glGetQueryObjecti64v"); + gl3wGetQueryObjectui64v = (PFNGLGETQUERYOBJECTUI64VPROC) get_proc("glGetQueryObjectui64v"); + gl3wVertexP2ui = (PFNGLVERTEXP2UIPROC) get_proc("glVertexP2ui"); + gl3wVertexP2uiv = (PFNGLVERTEXP2UIVPROC) get_proc("glVertexP2uiv"); + gl3wVertexP3ui = (PFNGLVERTEXP3UIPROC) get_proc("glVertexP3ui"); + gl3wVertexP3uiv = (PFNGLVERTEXP3UIVPROC) get_proc("glVertexP3uiv"); + gl3wVertexP4ui = (PFNGLVERTEXP4UIPROC) get_proc("glVertexP4ui"); + gl3wVertexP4uiv = (PFNGLVERTEXP4UIVPROC) get_proc("glVertexP4uiv"); + gl3wTexCoordP1ui = (PFNGLTEXCOORDP1UIPROC) get_proc("glTexCoordP1ui"); + gl3wTexCoordP1uiv = (PFNGLTEXCOORDP1UIVPROC) get_proc("glTexCoordP1uiv"); + gl3wTexCoordP2ui = (PFNGLTEXCOORDP2UIPROC) get_proc("glTexCoordP2ui"); + gl3wTexCoordP2uiv = (PFNGLTEXCOORDP2UIVPROC) get_proc("glTexCoordP2uiv"); + gl3wTexCoordP3ui = (PFNGLTEXCOORDP3UIPROC) get_proc("glTexCoordP3ui"); + gl3wTexCoordP3uiv = (PFNGLTEXCOORDP3UIVPROC) get_proc("glTexCoordP3uiv"); + gl3wTexCoordP4ui = (PFNGLTEXCOORDP4UIPROC) get_proc("glTexCoordP4ui"); + gl3wTexCoordP4uiv = (PFNGLTEXCOORDP4UIVPROC) get_proc("glTexCoordP4uiv"); + gl3wMultiTexCoordP1ui = (PFNGLMULTITEXCOORDP1UIPROC) get_proc("glMultiTexCoordP1ui"); + gl3wMultiTexCoordP1uiv = (PFNGLMULTITEXCOORDP1UIVPROC) get_proc("glMultiTexCoordP1uiv"); + gl3wMultiTexCoordP2ui = (PFNGLMULTITEXCOORDP2UIPROC) get_proc("glMultiTexCoordP2ui"); + gl3wMultiTexCoordP2uiv = (PFNGLMULTITEXCOORDP2UIVPROC) get_proc("glMultiTexCoordP2uiv"); + gl3wMultiTexCoordP3ui = (PFNGLMULTITEXCOORDP3UIPROC) get_proc("glMultiTexCoordP3ui"); + gl3wMultiTexCoordP3uiv = (PFNGLMULTITEXCOORDP3UIVPROC) get_proc("glMultiTexCoordP3uiv"); + gl3wMultiTexCoordP4ui = (PFNGLMULTITEXCOORDP4UIPROC) get_proc("glMultiTexCoordP4ui"); + gl3wMultiTexCoordP4uiv = (PFNGLMULTITEXCOORDP4UIVPROC) get_proc("glMultiTexCoordP4uiv"); + gl3wNormalP3ui = (PFNGLNORMALP3UIPROC) get_proc("glNormalP3ui"); + gl3wNormalP3uiv = (PFNGLNORMALP3UIVPROC) get_proc("glNormalP3uiv"); + gl3wColorP3ui = (PFNGLCOLORP3UIPROC) get_proc("glColorP3ui"); + gl3wColorP3uiv = (PFNGLCOLORP3UIVPROC) get_proc("glColorP3uiv"); + gl3wColorP4ui = (PFNGLCOLORP4UIPROC) get_proc("glColorP4ui"); + gl3wColorP4uiv = (PFNGLCOLORP4UIVPROC) get_proc("glColorP4uiv"); + gl3wSecondaryColorP3ui = (PFNGLSECONDARYCOLORP3UIPROC) get_proc("glSecondaryColorP3ui"); + gl3wSecondaryColorP3uiv = (PFNGLSECONDARYCOLORP3UIVPROC) get_proc("glSecondaryColorP3uiv"); + gl3wVertexAttribP1ui = (PFNGLVERTEXATTRIBP1UIPROC) get_proc("glVertexAttribP1ui"); + gl3wVertexAttribP1uiv = (PFNGLVERTEXATTRIBP1UIVPROC) get_proc("glVertexAttribP1uiv"); + gl3wVertexAttribP2ui = (PFNGLVERTEXATTRIBP2UIPROC) get_proc("glVertexAttribP2ui"); + gl3wVertexAttribP2uiv = (PFNGLVERTEXATTRIBP2UIVPROC) get_proc("glVertexAttribP2uiv"); + gl3wVertexAttribP3ui = (PFNGLVERTEXATTRIBP3UIPROC) get_proc("glVertexAttribP3ui"); + gl3wVertexAttribP3uiv = (PFNGLVERTEXATTRIBP3UIVPROC) get_proc("glVertexAttribP3uiv"); + gl3wVertexAttribP4ui = (PFNGLVERTEXATTRIBP4UIPROC) get_proc("glVertexAttribP4ui"); + gl3wVertexAttribP4uiv = (PFNGLVERTEXATTRIBP4UIVPROC) get_proc("glVertexAttribP4uiv"); + gl3wDrawArraysIndirect = (PFNGLDRAWARRAYSINDIRECTPROC) get_proc("glDrawArraysIndirect"); + gl3wDrawElementsIndirect = (PFNGLDRAWELEMENTSINDIRECTPROC) get_proc("glDrawElementsIndirect"); + gl3wUniform1d = (PFNGLUNIFORM1DPROC) get_proc("glUniform1d"); + gl3wUniform2d = (PFNGLUNIFORM2DPROC) get_proc("glUniform2d"); + gl3wUniform3d = (PFNGLUNIFORM3DPROC) get_proc("glUniform3d"); + gl3wUniform4d = (PFNGLUNIFORM4DPROC) get_proc("glUniform4d"); + gl3wUniform1dv = (PFNGLUNIFORM1DVPROC) get_proc("glUniform1dv"); + gl3wUniform2dv = (PFNGLUNIFORM2DVPROC) get_proc("glUniform2dv"); + gl3wUniform3dv = (PFNGLUNIFORM3DVPROC) get_proc("glUniform3dv"); + gl3wUniform4dv = (PFNGLUNIFORM4DVPROC) get_proc("glUniform4dv"); + gl3wUniformMatrix2dv = (PFNGLUNIFORMMATRIX2DVPROC) get_proc("glUniformMatrix2dv"); + gl3wUniformMatrix3dv = (PFNGLUNIFORMMATRIX3DVPROC) get_proc("glUniformMatrix3dv"); + gl3wUniformMatrix4dv = (PFNGLUNIFORMMATRIX4DVPROC) get_proc("glUniformMatrix4dv"); + gl3wUniformMatrix2x3dv = (PFNGLUNIFORMMATRIX2X3DVPROC) get_proc("glUniformMatrix2x3dv"); + gl3wUniformMatrix2x4dv = (PFNGLUNIFORMMATRIX2X4DVPROC) get_proc("glUniformMatrix2x4dv"); + gl3wUniformMatrix3x2dv = (PFNGLUNIFORMMATRIX3X2DVPROC) get_proc("glUniformMatrix3x2dv"); + gl3wUniformMatrix3x4dv = (PFNGLUNIFORMMATRIX3X4DVPROC) get_proc("glUniformMatrix3x4dv"); + gl3wUniformMatrix4x2dv = (PFNGLUNIFORMMATRIX4X2DVPROC) get_proc("glUniformMatrix4x2dv"); + gl3wUniformMatrix4x3dv = (PFNGLUNIFORMMATRIX4X3DVPROC) get_proc("glUniformMatrix4x3dv"); + gl3wGetUniformdv = (PFNGLGETUNIFORMDVPROC) get_proc("glGetUniformdv"); + gl3wGetSubroutineUniformLocation = (PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC) get_proc("glGetSubroutineUniformLocation"); + gl3wGetSubroutineIndex = (PFNGLGETSUBROUTINEINDEXPROC) get_proc("glGetSubroutineIndex"); + gl3wGetActiveSubroutineUniformiv = (PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC) get_proc("glGetActiveSubroutineUniformiv"); + gl3wGetActiveSubroutineUniformName = (PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC) get_proc("glGetActiveSubroutineUniformName"); + gl3wGetActiveSubroutineName = (PFNGLGETACTIVESUBROUTINENAMEPROC) get_proc("glGetActiveSubroutineName"); + gl3wUniformSubroutinesuiv = (PFNGLUNIFORMSUBROUTINESUIVPROC) get_proc("glUniformSubroutinesuiv"); + gl3wGetUniformSubroutineuiv = (PFNGLGETUNIFORMSUBROUTINEUIVPROC) get_proc("glGetUniformSubroutineuiv"); + gl3wGetProgramStageiv = (PFNGLGETPROGRAMSTAGEIVPROC) get_proc("glGetProgramStageiv"); + gl3wPatchParameteri = (PFNGLPATCHPARAMETERIPROC) get_proc("glPatchParameteri"); + gl3wPatchParameterfv = (PFNGLPATCHPARAMETERFVPROC) get_proc("glPatchParameterfv"); + gl3wBindTransformFeedback = (PFNGLBINDTRANSFORMFEEDBACKPROC) get_proc("glBindTransformFeedback"); + gl3wDeleteTransformFeedbacks = (PFNGLDELETETRANSFORMFEEDBACKSPROC) get_proc("glDeleteTransformFeedbacks"); + gl3wGenTransformFeedbacks = (PFNGLGENTRANSFORMFEEDBACKSPROC) get_proc("glGenTransformFeedbacks"); + gl3wIsTransformFeedback = (PFNGLISTRANSFORMFEEDBACKPROC) get_proc("glIsTransformFeedback"); + gl3wPauseTransformFeedback = (PFNGLPAUSETRANSFORMFEEDBACKPROC) get_proc("glPauseTransformFeedback"); + gl3wResumeTransformFeedback = (PFNGLRESUMETRANSFORMFEEDBACKPROC) get_proc("glResumeTransformFeedback"); + gl3wDrawTransformFeedback = (PFNGLDRAWTRANSFORMFEEDBACKPROC) get_proc("glDrawTransformFeedback"); + gl3wDrawTransformFeedbackStream = (PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC) get_proc("glDrawTransformFeedbackStream"); + gl3wBeginQueryIndexed = (PFNGLBEGINQUERYINDEXEDPROC) get_proc("glBeginQueryIndexed"); + gl3wEndQueryIndexed = (PFNGLENDQUERYINDEXEDPROC) get_proc("glEndQueryIndexed"); + gl3wGetQueryIndexediv = (PFNGLGETQUERYINDEXEDIVPROC) get_proc("glGetQueryIndexediv"); + gl3wReleaseShaderCompiler = (PFNGLRELEASESHADERCOMPILERPROC) get_proc("glReleaseShaderCompiler"); + gl3wShaderBinary = (PFNGLSHADERBINARYPROC) get_proc("glShaderBinary"); + gl3wGetShaderPrecisionFormat = (PFNGLGETSHADERPRECISIONFORMATPROC) get_proc("glGetShaderPrecisionFormat"); + gl3wDepthRangef = (PFNGLDEPTHRANGEFPROC) get_proc("glDepthRangef"); + gl3wClearDepthf = (PFNGLCLEARDEPTHFPROC) get_proc("glClearDepthf"); + gl3wGetProgramBinary = (PFNGLGETPROGRAMBINARYPROC) get_proc("glGetProgramBinary"); + gl3wProgramBinary = (PFNGLPROGRAMBINARYPROC) get_proc("glProgramBinary"); + gl3wProgramParameteri = (PFNGLPROGRAMPARAMETERIPROC) get_proc("glProgramParameteri"); + gl3wUseProgramStages = (PFNGLUSEPROGRAMSTAGESPROC) get_proc("glUseProgramStages"); + gl3wActiveShaderProgram = (PFNGLACTIVESHADERPROGRAMPROC) get_proc("glActiveShaderProgram"); + gl3wCreateShaderProgramv = (PFNGLCREATESHADERPROGRAMVPROC) get_proc("glCreateShaderProgramv"); + gl3wBindProgramPipeline = (PFNGLBINDPROGRAMPIPELINEPROC) get_proc("glBindProgramPipeline"); + gl3wDeleteProgramPipelines = (PFNGLDELETEPROGRAMPIPELINESPROC) get_proc("glDeleteProgramPipelines"); + gl3wGenProgramPipelines = (PFNGLGENPROGRAMPIPELINESPROC) get_proc("glGenProgramPipelines"); + gl3wIsProgramPipeline = (PFNGLISPROGRAMPIPELINEPROC) get_proc("glIsProgramPipeline"); + gl3wGetProgramPipelineiv = (PFNGLGETPROGRAMPIPELINEIVPROC) get_proc("glGetProgramPipelineiv"); + gl3wProgramUniform1i = (PFNGLPROGRAMUNIFORM1IPROC) get_proc("glProgramUniform1i"); + gl3wProgramUniform1iv = (PFNGLPROGRAMUNIFORM1IVPROC) get_proc("glProgramUniform1iv"); + gl3wProgramUniform1f = (PFNGLPROGRAMUNIFORM1FPROC) get_proc("glProgramUniform1f"); + gl3wProgramUniform1fv = (PFNGLPROGRAMUNIFORM1FVPROC) get_proc("glProgramUniform1fv"); + gl3wProgramUniform1d = (PFNGLPROGRAMUNIFORM1DPROC) get_proc("glProgramUniform1d"); + gl3wProgramUniform1dv = (PFNGLPROGRAMUNIFORM1DVPROC) get_proc("glProgramUniform1dv"); + gl3wProgramUniform1ui = (PFNGLPROGRAMUNIFORM1UIPROC) get_proc("glProgramUniform1ui"); + gl3wProgramUniform1uiv = (PFNGLPROGRAMUNIFORM1UIVPROC) get_proc("glProgramUniform1uiv"); + gl3wProgramUniform2i = (PFNGLPROGRAMUNIFORM2IPROC) get_proc("glProgramUniform2i"); + gl3wProgramUniform2iv = (PFNGLPROGRAMUNIFORM2IVPROC) get_proc("glProgramUniform2iv"); + gl3wProgramUniform2f = (PFNGLPROGRAMUNIFORM2FPROC) get_proc("glProgramUniform2f"); + gl3wProgramUniform2fv = (PFNGLPROGRAMUNIFORM2FVPROC) get_proc("glProgramUniform2fv"); + gl3wProgramUniform2d = (PFNGLPROGRAMUNIFORM2DPROC) get_proc("glProgramUniform2d"); + gl3wProgramUniform2dv = (PFNGLPROGRAMUNIFORM2DVPROC) get_proc("glProgramUniform2dv"); + gl3wProgramUniform2ui = (PFNGLPROGRAMUNIFORM2UIPROC) get_proc("glProgramUniform2ui"); + gl3wProgramUniform2uiv = (PFNGLPROGRAMUNIFORM2UIVPROC) get_proc("glProgramUniform2uiv"); + gl3wProgramUniform3i = (PFNGLPROGRAMUNIFORM3IPROC) get_proc("glProgramUniform3i"); + gl3wProgramUniform3iv = (PFNGLPROGRAMUNIFORM3IVPROC) get_proc("glProgramUniform3iv"); + gl3wProgramUniform3f = (PFNGLPROGRAMUNIFORM3FPROC) get_proc("glProgramUniform3f"); + gl3wProgramUniform3fv = (PFNGLPROGRAMUNIFORM3FVPROC) get_proc("glProgramUniform3fv"); + gl3wProgramUniform3d = (PFNGLPROGRAMUNIFORM3DPROC) get_proc("glProgramUniform3d"); + gl3wProgramUniform3dv = (PFNGLPROGRAMUNIFORM3DVPROC) get_proc("glProgramUniform3dv"); + gl3wProgramUniform3ui = (PFNGLPROGRAMUNIFORM3UIPROC) get_proc("glProgramUniform3ui"); + gl3wProgramUniform3uiv = (PFNGLPROGRAMUNIFORM3UIVPROC) get_proc("glProgramUniform3uiv"); + gl3wProgramUniform4i = (PFNGLPROGRAMUNIFORM4IPROC) get_proc("glProgramUniform4i"); + gl3wProgramUniform4iv = (PFNGLPROGRAMUNIFORM4IVPROC) get_proc("glProgramUniform4iv"); + gl3wProgramUniform4f = (PFNGLPROGRAMUNIFORM4FPROC) get_proc("glProgramUniform4f"); + gl3wProgramUniform4fv = (PFNGLPROGRAMUNIFORM4FVPROC) get_proc("glProgramUniform4fv"); + gl3wProgramUniform4d = (PFNGLPROGRAMUNIFORM4DPROC) get_proc("glProgramUniform4d"); + gl3wProgramUniform4dv = (PFNGLPROGRAMUNIFORM4DVPROC) get_proc("glProgramUniform4dv"); + gl3wProgramUniform4ui = (PFNGLPROGRAMUNIFORM4UIPROC) get_proc("glProgramUniform4ui"); + gl3wProgramUniform4uiv = (PFNGLPROGRAMUNIFORM4UIVPROC) get_proc("glProgramUniform4uiv"); + gl3wProgramUniformMatrix2fv = (PFNGLPROGRAMUNIFORMMATRIX2FVPROC) get_proc("glProgramUniformMatrix2fv"); + gl3wProgramUniformMatrix3fv = (PFNGLPROGRAMUNIFORMMATRIX3FVPROC) get_proc("glProgramUniformMatrix3fv"); + gl3wProgramUniformMatrix4fv = (PFNGLPROGRAMUNIFORMMATRIX4FVPROC) get_proc("glProgramUniformMatrix4fv"); + gl3wProgramUniformMatrix2dv = (PFNGLPROGRAMUNIFORMMATRIX2DVPROC) get_proc("glProgramUniformMatrix2dv"); + gl3wProgramUniformMatrix3dv = (PFNGLPROGRAMUNIFORMMATRIX3DVPROC) get_proc("glProgramUniformMatrix3dv"); + gl3wProgramUniformMatrix4dv = (PFNGLPROGRAMUNIFORMMATRIX4DVPROC) get_proc("glProgramUniformMatrix4dv"); + gl3wProgramUniformMatrix2x3fv = (PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC) get_proc("glProgramUniformMatrix2x3fv"); + gl3wProgramUniformMatrix3x2fv = (PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC) get_proc("glProgramUniformMatrix3x2fv"); + gl3wProgramUniformMatrix2x4fv = (PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC) get_proc("glProgramUniformMatrix2x4fv"); + gl3wProgramUniformMatrix4x2fv = (PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC) get_proc("glProgramUniformMatrix4x2fv"); + gl3wProgramUniformMatrix3x4fv = (PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC) get_proc("glProgramUniformMatrix3x4fv"); + gl3wProgramUniformMatrix4x3fv = (PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC) get_proc("glProgramUniformMatrix4x3fv"); + gl3wProgramUniformMatrix2x3dv = (PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC) get_proc("glProgramUniformMatrix2x3dv"); + gl3wProgramUniformMatrix3x2dv = (PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC) get_proc("glProgramUniformMatrix3x2dv"); + gl3wProgramUniformMatrix2x4dv = (PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC) get_proc("glProgramUniformMatrix2x4dv"); + gl3wProgramUniformMatrix4x2dv = (PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC) get_proc("glProgramUniformMatrix4x2dv"); + gl3wProgramUniformMatrix3x4dv = (PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC) get_proc("glProgramUniformMatrix3x4dv"); + gl3wProgramUniformMatrix4x3dv = (PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC) get_proc("glProgramUniformMatrix4x3dv"); + gl3wValidateProgramPipeline = (PFNGLVALIDATEPROGRAMPIPELINEPROC) get_proc("glValidateProgramPipeline"); + gl3wGetProgramPipelineInfoLog = (PFNGLGETPROGRAMPIPELINEINFOLOGPROC) get_proc("glGetProgramPipelineInfoLog"); + gl3wVertexAttribL1d = (PFNGLVERTEXATTRIBL1DPROC) get_proc("glVertexAttribL1d"); + gl3wVertexAttribL2d = (PFNGLVERTEXATTRIBL2DPROC) get_proc("glVertexAttribL2d"); + gl3wVertexAttribL3d = (PFNGLVERTEXATTRIBL3DPROC) get_proc("glVertexAttribL3d"); + gl3wVertexAttribL4d = (PFNGLVERTEXATTRIBL4DPROC) get_proc("glVertexAttribL4d"); + gl3wVertexAttribL1dv = (PFNGLVERTEXATTRIBL1DVPROC) get_proc("glVertexAttribL1dv"); + gl3wVertexAttribL2dv = (PFNGLVERTEXATTRIBL2DVPROC) get_proc("glVertexAttribL2dv"); + gl3wVertexAttribL3dv = (PFNGLVERTEXATTRIBL3DVPROC) get_proc("glVertexAttribL3dv"); + gl3wVertexAttribL4dv = (PFNGLVERTEXATTRIBL4DVPROC) get_proc("glVertexAttribL4dv"); + gl3wVertexAttribLPointer = (PFNGLVERTEXATTRIBLPOINTERPROC) get_proc("glVertexAttribLPointer"); + gl3wGetVertexAttribLdv = (PFNGLGETVERTEXATTRIBLDVPROC) get_proc("glGetVertexAttribLdv"); + gl3wViewportArrayv = (PFNGLVIEWPORTARRAYVPROC) get_proc("glViewportArrayv"); + gl3wViewportIndexedf = (PFNGLVIEWPORTINDEXEDFPROC) get_proc("glViewportIndexedf"); + gl3wViewportIndexedfv = (PFNGLVIEWPORTINDEXEDFVPROC) get_proc("glViewportIndexedfv"); + gl3wScissorArrayv = (PFNGLSCISSORARRAYVPROC) get_proc("glScissorArrayv"); + gl3wScissorIndexed = (PFNGLSCISSORINDEXEDPROC) get_proc("glScissorIndexed"); + gl3wScissorIndexedv = (PFNGLSCISSORINDEXEDVPROC) get_proc("glScissorIndexedv"); + gl3wDepthRangeArrayv = (PFNGLDEPTHRANGEARRAYVPROC) get_proc("glDepthRangeArrayv"); + gl3wDepthRangeIndexed = (PFNGLDEPTHRANGEINDEXEDPROC) get_proc("glDepthRangeIndexed"); + gl3wGetFloati_v = (PFNGLGETFLOATI_VPROC) get_proc("glGetFloati_v"); + gl3wGetDoublei_v = (PFNGLGETDOUBLEI_VPROC) get_proc("glGetDoublei_v"); + gl3wCreateSyncFromCLeventARB = (PFNGLCREATESYNCFROMCLEVENTARBPROC) get_proc("glCreateSyncFromCLeventARB"); + gl3wDebugMessageControlARB = (PFNGLDEBUGMESSAGECONTROLARBPROC) get_proc("glDebugMessageControlARB"); + gl3wDebugMessageInsertARB = (PFNGLDEBUGMESSAGEINSERTARBPROC) get_proc("glDebugMessageInsertARB"); + gl3wDebugMessageCallbackARB = (PFNGLDEBUGMESSAGECALLBACKARBPROC) get_proc("glDebugMessageCallbackARB"); + gl3wGetDebugMessageLogARB = (PFNGLGETDEBUGMESSAGELOGARBPROC) get_proc("glGetDebugMessageLogARB"); + gl3wGetGraphicsResetStatusARB = (PFNGLGETGRAPHICSRESETSTATUSARBPROC) get_proc("glGetGraphicsResetStatusARB"); + gl3wGetnTexImageARB = (PFNGLGETNTEXIMAGEARBPROC) get_proc("glGetnTexImageARB"); + gl3wReadnPixelsARB = (PFNGLREADNPIXELSARBPROC) get_proc("glReadnPixelsARB"); + gl3wGetnCompressedTexImageARB = (PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC) get_proc("glGetnCompressedTexImageARB"); + gl3wGetnUniformfvARB = (PFNGLGETNUNIFORMFVARBPROC) get_proc("glGetnUniformfvARB"); + gl3wGetnUniformivARB = (PFNGLGETNUNIFORMIVARBPROC) get_proc("glGetnUniformivARB"); + gl3wGetnUniformuivARB = (PFNGLGETNUNIFORMUIVARBPROC) get_proc("glGetnUniformuivARB"); + gl3wGetnUniformdvARB = (PFNGLGETNUNIFORMDVARBPROC) get_proc("glGetnUniformdvARB"); + gl3wDrawArraysInstancedBaseInstance = (PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC) get_proc("glDrawArraysInstancedBaseInstance"); + gl3wDrawElementsInstancedBaseInstance = (PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC) get_proc("glDrawElementsInstancedBaseInstance"); + gl3wDrawElementsInstancedBaseVertexBaseInstance = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC) get_proc("glDrawElementsInstancedBaseVertexBaseInstance"); + gl3wDrawTransformFeedbackInstanced = (PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC) get_proc("glDrawTransformFeedbackInstanced"); + gl3wDrawTransformFeedbackStreamInstanced = (PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC) get_proc("glDrawTransformFeedbackStreamInstanced"); + gl3wGetInternalformativ = (PFNGLGETINTERNALFORMATIVPROC) get_proc("glGetInternalformativ"); + gl3wGetActiveAtomicCounterBufferiv = (PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC) get_proc("glGetActiveAtomicCounterBufferiv"); + gl3wBindImageTexture = (PFNGLBINDIMAGETEXTUREPROC) get_proc("glBindImageTexture"); + gl3wMemoryBarrier = (PFNGLMEMORYBARRIERPROC) get_proc("glMemoryBarrier"); + gl3wTexStorage1D = (PFNGLTEXSTORAGE1DPROC) get_proc("glTexStorage1D"); + gl3wTexStorage2D = (PFNGLTEXSTORAGE2DPROC) get_proc("glTexStorage2D"); + gl3wTexStorage3D = (PFNGLTEXSTORAGE3DPROC) get_proc("glTexStorage3D"); + gl3wTextureStorage1DEXT = (PFNGLTEXTURESTORAGE1DEXTPROC) get_proc("glTextureStorage1DEXT"); + gl3wTextureStorage2DEXT = (PFNGLTEXTURESTORAGE2DEXTPROC) get_proc("glTextureStorage2DEXT"); + gl3wTextureStorage3DEXT = (PFNGLTEXTURESTORAGE3DEXTPROC) get_proc("glTextureStorage3DEXT"); + gl3wDebugMessageControl = (PFNGLDEBUGMESSAGECONTROLPROC) get_proc("glDebugMessageControl"); + gl3wDebugMessageInsert = (PFNGLDEBUGMESSAGEINSERTPROC) get_proc("glDebugMessageInsert"); + gl3wDebugMessageCallback = (PFNGLDEBUGMESSAGECALLBACKPROC) get_proc("glDebugMessageCallback"); + gl3wGetDebugMessageLog = (PFNGLGETDEBUGMESSAGELOGPROC) get_proc("glGetDebugMessageLog"); + gl3wPushDebugGroup = (PFNGLPUSHDEBUGGROUPPROC) get_proc("glPushDebugGroup"); + gl3wPopDebugGroup = (PFNGLPOPDEBUGGROUPPROC) get_proc("glPopDebugGroup"); + gl3wObjectLabel = (PFNGLOBJECTLABELPROC) get_proc("glObjectLabel"); + gl3wGetObjectLabel = (PFNGLGETOBJECTLABELPROC) get_proc("glGetObjectLabel"); + gl3wObjectPtrLabel = (PFNGLOBJECTPTRLABELPROC) get_proc("glObjectPtrLabel"); + gl3wGetObjectPtrLabel = (PFNGLGETOBJECTPTRLABELPROC) get_proc("glGetObjectPtrLabel"); + gl3wClearBufferData = (PFNGLCLEARBUFFERDATAPROC) get_proc("glClearBufferData"); + gl3wClearBufferSubData = (PFNGLCLEARBUFFERSUBDATAPROC) get_proc("glClearBufferSubData"); + gl3wClearNamedBufferDataEXT = (PFNGLCLEARNAMEDBUFFERDATAEXTPROC) get_proc("glClearNamedBufferDataEXT"); + gl3wClearNamedBufferSubDataEXT = (PFNGLCLEARNAMEDBUFFERSUBDATAEXTPROC) get_proc("glClearNamedBufferSubDataEXT"); + gl3wDispatchCompute = (PFNGLDISPATCHCOMPUTEPROC) get_proc("glDispatchCompute"); + gl3wDispatchComputeIndirect = (PFNGLDISPATCHCOMPUTEINDIRECTPROC) get_proc("glDispatchComputeIndirect"); + gl3wCopyImageSubData = (PFNGLCOPYIMAGESUBDATAPROC) get_proc("glCopyImageSubData"); + gl3wTextureView = (PFNGLTEXTUREVIEWPROC) get_proc("glTextureView"); + gl3wBindVertexBuffer = (PFNGLBINDVERTEXBUFFERPROC) get_proc("glBindVertexBuffer"); + gl3wVertexAttribFormat = (PFNGLVERTEXATTRIBFORMATPROC) get_proc("glVertexAttribFormat"); + gl3wVertexAttribIFormat = (PFNGLVERTEXATTRIBIFORMATPROC) get_proc("glVertexAttribIFormat"); + gl3wVertexAttribLFormat = (PFNGLVERTEXATTRIBLFORMATPROC) get_proc("glVertexAttribLFormat"); + gl3wVertexAttribBinding = (PFNGLVERTEXATTRIBBINDINGPROC) get_proc("glVertexAttribBinding"); + gl3wVertexBindingDivisor = (PFNGLVERTEXBINDINGDIVISORPROC) get_proc("glVertexBindingDivisor"); + gl3wVertexArrayBindVertexBufferEXT = (PFNGLVERTEXARRAYBINDVERTEXBUFFEREXTPROC) get_proc("glVertexArrayBindVertexBufferEXT"); + gl3wVertexArrayVertexAttribFormatEXT = (PFNGLVERTEXARRAYVERTEXATTRIBFORMATEXTPROC) get_proc("glVertexArrayVertexAttribFormatEXT"); + gl3wVertexArrayVertexAttribIFormatEXT = (PFNGLVERTEXARRAYVERTEXATTRIBIFORMATEXTPROC) get_proc("glVertexArrayVertexAttribIFormatEXT"); + gl3wVertexArrayVertexAttribLFormatEXT = (PFNGLVERTEXARRAYVERTEXATTRIBLFORMATEXTPROC) get_proc("glVertexArrayVertexAttribLFormatEXT"); + gl3wVertexArrayVertexAttribBindingEXT = (PFNGLVERTEXARRAYVERTEXATTRIBBINDINGEXTPROC) get_proc("glVertexArrayVertexAttribBindingEXT"); + gl3wVertexArrayVertexBindingDivisorEXT = (PFNGLVERTEXARRAYVERTEXBINDINGDIVISOREXTPROC) get_proc("glVertexArrayVertexBindingDivisorEXT"); + gl3wFramebufferParameteri = (PFNGLFRAMEBUFFERPARAMETERIPROC) get_proc("glFramebufferParameteri"); + gl3wGetFramebufferParameteriv = (PFNGLGETFRAMEBUFFERPARAMETERIVPROC) get_proc("glGetFramebufferParameteriv"); + gl3wNamedFramebufferParameteriEXT = (PFNGLNAMEDFRAMEBUFFERPARAMETERIEXTPROC) get_proc("glNamedFramebufferParameteriEXT"); + gl3wGetNamedFramebufferParameterivEXT = (PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVEXTPROC) get_proc("glGetNamedFramebufferParameterivEXT"); + gl3wGetInternalformati64v = (PFNGLGETINTERNALFORMATI64VPROC) get_proc("glGetInternalformati64v"); + gl3wInvalidateTexSubImage = (PFNGLINVALIDATETEXSUBIMAGEPROC) get_proc("glInvalidateTexSubImage"); + gl3wInvalidateTexImage = (PFNGLINVALIDATETEXIMAGEPROC) get_proc("glInvalidateTexImage"); + gl3wInvalidateBufferSubData = (PFNGLINVALIDATEBUFFERSUBDATAPROC) get_proc("glInvalidateBufferSubData"); + gl3wInvalidateBufferData = (PFNGLINVALIDATEBUFFERDATAPROC) get_proc("glInvalidateBufferData"); + gl3wInvalidateFramebuffer = (PFNGLINVALIDATEFRAMEBUFFERPROC) get_proc("glInvalidateFramebuffer"); + gl3wInvalidateSubFramebuffer = (PFNGLINVALIDATESUBFRAMEBUFFERPROC) get_proc("glInvalidateSubFramebuffer"); + gl3wMultiDrawArraysIndirect = (PFNGLMULTIDRAWARRAYSINDIRECTPROC) get_proc("glMultiDrawArraysIndirect"); + gl3wMultiDrawElementsIndirect = (PFNGLMULTIDRAWELEMENTSINDIRECTPROC) get_proc("glMultiDrawElementsIndirect"); + gl3wGetProgramInterfaceiv = (PFNGLGETPROGRAMINTERFACEIVPROC) get_proc("glGetProgramInterfaceiv"); + gl3wGetProgramResourceIndex = (PFNGLGETPROGRAMRESOURCEINDEXPROC) get_proc("glGetProgramResourceIndex"); + gl3wGetProgramResourceName = (PFNGLGETPROGRAMRESOURCENAMEPROC) get_proc("glGetProgramResourceName"); + gl3wGetProgramResourceiv = (PFNGLGETPROGRAMRESOURCEIVPROC) get_proc("glGetProgramResourceiv"); + gl3wGetProgramResourceLocation = (PFNGLGETPROGRAMRESOURCELOCATIONPROC) get_proc("glGetProgramResourceLocation"); + gl3wGetProgramResourceLocationIndex = (PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC) get_proc("glGetProgramResourceLocationIndex"); + gl3wShaderStorageBlockBinding = (PFNGLSHADERSTORAGEBLOCKBINDINGPROC) get_proc("glShaderStorageBlockBinding"); + gl3wTexBufferRange = (PFNGLTEXBUFFERRANGEPROC) get_proc("glTexBufferRange"); + gl3wTextureBufferRangeEXT = (PFNGLTEXTUREBUFFERRANGEEXTPROC) get_proc("glTextureBufferRangeEXT"); + gl3wTexStorage2DMultisample = (PFNGLTEXSTORAGE2DMULTISAMPLEPROC) get_proc("glTexStorage2DMultisample"); + gl3wTexStorage3DMultisample = (PFNGLTEXSTORAGE3DMULTISAMPLEPROC) get_proc("glTexStorage3DMultisample"); + gl3wTextureStorage2DMultisampleEXT = (PFNGLTEXTURESTORAGE2DMULTISAMPLEEXTPROC) get_proc("glTextureStorage2DMultisampleEXT"); + gl3wTextureStorage3DMultisampleEXT = (PFNGLTEXTURESTORAGE3DMULTISAMPLEEXTPROC) get_proc("glTextureStorage3DMultisampleEXT"); +} diff --git a/3rdparty/imgui-node-editor/external/stb_image/CMakeLists.txt b/3rdparty/imgui-node-editor/external/stb_image/CMakeLists.txt new file mode 100644 index 0000000..bf9f44d --- /dev/null +++ b/3rdparty/imgui-node-editor/external/stb_image/CMakeLists.txt @@ -0,0 +1,12 @@ +project(stb_image) + +add_library(stb_image INTERFACE) + +set(_stb_image_Sources + ${CMAKE_CURRENT_SOURCE_DIR}/stb_image.h +) + +target_include_directories(stb_image INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) +target_sources(stb_image INTERFACE ${_stb_image_Sources}) + +source_group("ThirdParty\\stb_image" FILES ${_stb_image_Sources}) \ No newline at end of file diff --git a/3rdparty/imgui-node-editor/external/stb_image/stb_image.h b/3rdparty/imgui-node-editor/external/stb_image/stb_image.h new file mode 100644 index 0000000..571b0dc --- /dev/null +++ b/3rdparty/imgui-node-editor/external/stb_image/stb_image.h @@ -0,0 +1,7462 @@ +/* stb_image - v2.19 - public domain image loader - http://nothings.org/stb + no warranty implied; use at your own risk + + Do this: + #define STB_IMAGE_IMPLEMENTATION + before you include this file in *one* C or C++ file to create the implementation. + + // i.e. it should look like this: + #include ... + #include ... + #include ... + #define STB_IMAGE_IMPLEMENTATION + #include "stb_image.h" + + You can #define STBI_ASSERT(x) before the #include to avoid using assert.h. + And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free + + + QUICK NOTES: + Primarily of interest to game developers and other people who can + avoid problematic images and only need the trivial interface + + JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib) + PNG 1/2/4/8/16-bit-per-channel + + TGA (not sure what subset, if a subset) + BMP non-1bpp, non-RLE + PSD (composited view only, no extra channels, 8/16 bit-per-channel) + + GIF (*comp always reports as 4-channel) + HDR (radiance rgbE format) + PIC (Softimage PIC) + PNM (PPM and PGM binary only) + + Animated GIF still needs a proper API, but here's one way to do it: + http://gist.github.com/urraka/685d9a6340b26b830d49 + + - decode from memory or through FILE (define STBI_NO_STDIO to remove code) + - decode from arbitrary I/O callbacks + - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON) + + Full documentation under "DOCUMENTATION" below. + + +LICENSE + + See end of file for license information. + +RECENT REVISION HISTORY: + + 2.19 (2018-02-11) fix warning + 2.18 (2018-01-30) fix warnings + 2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings + 2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes + 2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs + 2.13 (2016-12-04) experimental 16-bit API, only for PNG so far; fixes + 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes + 2.11 (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64 + RGB-format JPEG; remove white matting in PSD; + allocate large structures on the stack; + correct channel count for PNG & BMP + 2.10 (2016-01-22) avoid warning introduced in 2.09 + 2.09 (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED + + See end of file for full revision history. + + + ============================ Contributors ========================= + + Image formats Extensions, features + Sean Barrett (jpeg, png, bmp) Jetro Lauha (stbi_info) + Nicolas Schulz (hdr, psd) Martin "SpartanJ" Golini (stbi_info) + Jonathan Dummer (tga) James "moose2000" Brown (iPhone PNG) + Jean-Marc Lienher (gif) Ben "Disch" Wenger (io callbacks) + Tom Seddon (pic) Omar Cornut (1/2/4-bit PNG) + Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip) + Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD) + github:urraka (animated gif) Junggon Kim (PNM comments) + Christopher Forseth (animated gif) Daniel Gibson (16-bit TGA) + socks-the-fox (16-bit PNG) + Jeremy Sawicki (handle all ImageNet JPGs) + Optimizations & bugfixes Mikhail Morozov (1-bit BMP) + Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query) + Arseny Kapoulkine + John-Mark Allen + + Bug & warning fixes + Marc LeBlanc David Woo Guillaume George Martins Mozeiko + Christpher Lloyd Jerry Jansson Joseph Thomson Phil Jordan + Dave Moore Roy Eltham Hayaki Saito Nathan Reed + Won Chun Luke Graham Johan Duparc Nick Verigakis + the Horde3D community Thomas Ruf Ronny Chevalier github:rlyeh + Janez Zemva John Bartholomew Michal Cichon github:romigrou + Jonathan Blow Ken Hamada Tero Hanninen github:svdijk + Laurent Gomila Cort Stratton Sergio Gonzalez github:snagar + Aruelien Pocheville Thibault Reuille Cass Everitt github:Zelex + Ryamond Barbiero Paul Du Bois Engin Manap github:grim210 + Aldo Culquicondor Philipp Wiesemann Dale Weiler github:sammyhw + Oriol Ferrer Mesia Josh Tobin Matthew Gregan github:phprus + Julian Raschke Gregory Mullen Baldur Karlsson github:poppolopoppo + Christian Floisand Kevin Schmidt github:darealshinji + Blazej Dariusz Roszkowski github:Michaelangel007 +*/ + +#ifndef STBI_INCLUDE_STB_IMAGE_H +#define STBI_INCLUDE_STB_IMAGE_H + +// DOCUMENTATION +// +// Limitations: +// - no 12-bit-per-channel JPEG +// - no JPEGs with arithmetic coding +// - GIF always returns *comp=4 +// +// Basic usage (see HDR discussion below for HDR usage): +// int x,y,n; +// unsigned char *data = stbi_load(filename, &x, &y, &n, 0); +// // ... process data if not NULL ... +// // ... x = width, y = height, n = # 8-bit components per pixel ... +// // ... replace '0' with '1'..'4' to force that many components per pixel +// // ... but 'n' will always be the number that it would have been if you said 0 +// stbi_image_free(data) +// +// Standard parameters: +// int *x -- outputs image width in pixels +// int *y -- outputs image height in pixels +// int *channels_in_file -- outputs # of image components in image file +// int desired_channels -- if non-zero, # of image components requested in result +// +// The return value from an image loader is an 'unsigned char *' which points +// to the pixel data, or NULL on an allocation failure or if the image is +// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels, +// with each pixel consisting of N interleaved 8-bit components; the first +// pixel pointed to is top-left-most in the image. There is no padding between +// image scanlines or between pixels, regardless of format. The number of +// components N is 'desired_channels' if desired_channels is non-zero, or +// *channels_in_file otherwise. If desired_channels is non-zero, +// *channels_in_file has the number of components that _would_ have been +// output otherwise. E.g. if you set desired_channels to 4, you will always +// get RGBA output, but you can check *channels_in_file to see if it's trivially +// opaque because e.g. there were only 3 channels in the source image. +// +// An output image with N components has the following components interleaved +// in this order in each pixel: +// +// N=#comp components +// 1 grey +// 2 grey, alpha +// 3 red, green, blue +// 4 red, green, blue, alpha +// +// If image loading fails for any reason, the return value will be NULL, +// and *x, *y, *channels_in_file will be unchanged. The function +// stbi_failure_reason() can be queried for an extremely brief, end-user +// unfriendly explanation of why the load failed. Define STBI_NO_FAILURE_STRINGS +// to avoid compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly +// more user-friendly ones. +// +// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. +// +// =========================================================================== +// +// Philosophy +// +// stb libraries are designed with the following priorities: +// +// 1. easy to use +// 2. easy to maintain +// 3. good performance +// +// Sometimes I let "good performance" creep up in priority over "easy to maintain", +// and for best performance I may provide less-easy-to-use APIs that give higher +// performance, in addition to the easy to use ones. Nevertheless, it's important +// to keep in mind that from the standpoint of you, a client of this library, +// all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all. +// +// Some secondary priorities arise directly from the first two, some of which +// make more explicit reasons why performance can't be emphasized. +// +// - Portable ("ease of use") +// - Small source code footprint ("easy to maintain") +// - No dependencies ("ease of use") +// +// =========================================================================== +// +// I/O callbacks +// +// I/O callbacks allow you to read from arbitrary sources, like packaged +// files or some other source. Data read from callbacks are processed +// through a small internal buffer (currently 128 bytes) to try to reduce +// overhead. +// +// The three functions you must define are "read" (reads some bytes of data), +// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end). +// +// =========================================================================== +// +// SIMD support +// +// The JPEG decoder will try to automatically use SIMD kernels on x86 when +// supported by the compiler. For ARM Neon support, you must explicitly +// request it. +// +// (The old do-it-yourself SIMD API is no longer supported in the current +// code.) +// +// On x86, SSE2 will automatically be used when available based on a run-time +// test; if not, the generic C versions are used as a fall-back. On ARM targets, +// the typical path is to have separate builds for NEON and non-NEON devices +// (at least this is true for iOS and Android). Therefore, the NEON support is +// toggled by a build flag: define STBI_NEON to get NEON loops. +// +// If for some reason you do not want to use any of SIMD code, or if +// you have issues compiling it, you can disable it entirely by +// defining STBI_NO_SIMD. +// +// =========================================================================== +// +// HDR image support (disable by defining STBI_NO_HDR) +// +// stb_image now supports loading HDR images in general, and currently +// the Radiance .HDR file format, although the support is provided +// generically. You can still load any file through the existing interface; +// if you attempt to load an HDR file, it will be automatically remapped to +// LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1; +// both of these constants can be reconfigured through this interface: +// +// stbi_hdr_to_ldr_gamma(2.2f); +// stbi_hdr_to_ldr_scale(1.0f); +// +// (note, do not use _inverse_ constants; stbi_image will invert them +// appropriately). +// +// Additionally, there is a new, parallel interface for loading files as +// (linear) floats to preserve the full dynamic range: +// +// float *data = stbi_loadf(filename, &x, &y, &n, 0); +// +// If you load LDR images through this interface, those images will +// be promoted to floating point values, run through the inverse of +// constants corresponding to the above: +// +// stbi_ldr_to_hdr_scale(1.0f); +// stbi_ldr_to_hdr_gamma(2.2f); +// +// Finally, given a filename (or an open file or memory block--see header +// file for details) containing image data, you can query for the "most +// appropriate" interface to use (that is, whether the image is HDR or +// not), using: +// +// stbi_is_hdr(char *filename); +// +// =========================================================================== +// +// iPhone PNG support: +// +// By default we convert iphone-formatted PNGs back to RGB, even though +// they are internally encoded differently. You can disable this conversion +// by by calling stbi_convert_iphone_png_to_rgb(0), in which case +// you will always just get the native iphone "format" through (which +// is BGR stored in RGB). +// +// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per +// pixel to remove any premultiplied alpha *only* if the image file explicitly +// says there's premultiplied data (currently only happens in iPhone images, +// and only if iPhone convert-to-rgb processing is on). +// +// =========================================================================== +// +// ADDITIONAL CONFIGURATION +// +// - You can suppress implementation of any of the decoders to reduce +// your code footprint by #defining one or more of the following +// symbols before creating the implementation. +// +// STBI_NO_JPEG +// STBI_NO_PNG +// STBI_NO_BMP +// STBI_NO_PSD +// STBI_NO_TGA +// STBI_NO_GIF +// STBI_NO_HDR +// STBI_NO_PIC +// STBI_NO_PNM (.ppm and .pgm) +// +// - You can request *only* certain decoders and suppress all other ones +// (this will be more forward-compatible, as addition of new decoders +// doesn't require you to disable them explicitly): +// +// STBI_ONLY_JPEG +// STBI_ONLY_PNG +// STBI_ONLY_BMP +// STBI_ONLY_PSD +// STBI_ONLY_TGA +// STBI_ONLY_GIF +// STBI_ONLY_HDR +// STBI_ONLY_PIC +// STBI_ONLY_PNM (.ppm and .pgm) +// +// - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still +// want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB +// + + +#ifndef STBI_NO_STDIO +#include +#endif // STBI_NO_STDIO + +#define STBI_VERSION 1 + +enum +{ + STBI_default = 0, // only used for desired_channels + + STBI_grey = 1, + STBI_grey_alpha = 2, + STBI_rgb = 3, + STBI_rgb_alpha = 4 +}; + +typedef unsigned char stbi_uc; +typedef unsigned short stbi_us; + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef STB_IMAGE_STATIC +#define STBIDEF static +#else +#define STBIDEF extern +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// PRIMARY API - works on images of any type +// + +// +// load image by filename, open file, or memory buffer +// + +typedef struct +{ + int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read + void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative + int (*eof) (void *user); // returns nonzero if we are at end of file/data +} stbi_io_callbacks; + +//////////////////////////////////// +// +// 8-bits-per-channel interface +// + +STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels); +#ifndef STBI_NO_GIF +STBIDEF 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); +#endif + + +#ifndef STBI_NO_STDIO +STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +// for stbi_load_from_file, file pointer is left pointing immediately after image +#endif + +//////////////////////////////////// +// +// 16-bits-per-channel interface +// + +STBIDEF stbi_us *stbi_load_16_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF 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); + +#ifndef STBI_NO_STDIO +STBIDEF stbi_us *stbi_load_16 (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +#endif + +//////////////////////////////////// +// +// float-per-channel interface +// +#ifndef STBI_NO_LINEAR + STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); + STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); + + #ifndef STBI_NO_STDIO + STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); + STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); + #endif +#endif + +#ifndef STBI_NO_HDR + STBIDEF void stbi_hdr_to_ldr_gamma(float gamma); + STBIDEF void stbi_hdr_to_ldr_scale(float scale); +#endif // STBI_NO_HDR + +#ifndef STBI_NO_LINEAR + STBIDEF void stbi_ldr_to_hdr_gamma(float gamma); + STBIDEF void stbi_ldr_to_hdr_scale(float scale); +#endif // STBI_NO_LINEAR + +// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user); +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename); +STBIDEF int stbi_is_hdr_from_file(FILE *f); +#endif // STBI_NO_STDIO + + +// get a VERY brief reason for failure +// NOT THREADSAFE +STBIDEF const char *stbi_failure_reason (void); + +// free the loaded image -- this is just free() +STBIDEF void stbi_image_free (void *retval_from_stbi_load); + +// get image dimensions & components without fully decoding +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len); +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user); + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); +STBIDEF int stbi_is_16_bit (char const *filename); +STBIDEF int stbi_is_16_bit_from_file(FILE *f); +#endif + + + +// for image formats that explicitly notate that they have premultiplied alpha, +// we just return the colors as stored in the file. set this flag to force +// unpremultiplication. results are undefined if the unpremultiply overflow. +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply); + +// indicate whether we should process iphone images back to canonical format, +// or just pass them through "as-is" +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert); + +// flip the image vertically, so the first pixel in the output array is the bottom left +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip); + +// ZLIB client - used by PNG, available for other purposes + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header); +STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + +STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + + +#ifdef __cplusplus +} +#endif + +// +// +//// end header file ///////////////////////////////////////////////////// +#endif // STBI_INCLUDE_STB_IMAGE_H + +#ifdef STB_IMAGE_IMPLEMENTATION + +#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \ + || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \ + || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \ + || defined(STBI_ONLY_ZLIB) + #ifndef STBI_ONLY_JPEG + #define STBI_NO_JPEG + #endif + #ifndef STBI_ONLY_PNG + #define STBI_NO_PNG + #endif + #ifndef STBI_ONLY_BMP + #define STBI_NO_BMP + #endif + #ifndef STBI_ONLY_PSD + #define STBI_NO_PSD + #endif + #ifndef STBI_ONLY_TGA + #define STBI_NO_TGA + #endif + #ifndef STBI_ONLY_GIF + #define STBI_NO_GIF + #endif + #ifndef STBI_ONLY_HDR + #define STBI_NO_HDR + #endif + #ifndef STBI_ONLY_PIC + #define STBI_NO_PIC + #endif + #ifndef STBI_ONLY_PNM + #define STBI_NO_PNM + #endif +#endif + +#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB) +#define STBI_NO_ZLIB +#endif + + +#include +#include // ptrdiff_t on osx +#include +#include +#include + +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +#include // ldexp, pow +#endif + +#ifndef STBI_NO_STDIO +#include +#endif + +#ifndef STBI_ASSERT +#include +#define STBI_ASSERT(x) assert(x) +#endif + + +#ifndef _MSC_VER + #ifdef __cplusplus + #define stbi_inline inline + #else + #define stbi_inline + #endif +#else + #define stbi_inline __forceinline +#endif + + +#ifdef _MSC_VER +typedef unsigned short stbi__uint16; +typedef signed short stbi__int16; +typedef unsigned int stbi__uint32; +typedef signed int stbi__int32; +#else +#include +typedef uint16_t stbi__uint16; +typedef int16_t stbi__int16; +typedef uint32_t stbi__uint32; +typedef int32_t stbi__int32; +#endif + +// should produce compiler error if size is wrong +typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; + +#ifdef _MSC_VER +#define STBI_NOTUSED(v) (void)(v) +#else +#define STBI_NOTUSED(v) (void)sizeof(v) +#endif + +#ifdef _MSC_VER +#define STBI_HAS_LROTL +#endif + +#ifdef STBI_HAS_LROTL + #define stbi_lrot(x,y) _lrotl(x,y) +#else + #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) +#endif + +#if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED)) +// ok +#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) && !defined(STBI_REALLOC_SIZED) +// ok +#else +#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC (or STBI_REALLOC_SIZED)." +#endif + +#ifndef STBI_MALLOC +#define STBI_MALLOC(sz) malloc(sz) +#define STBI_REALLOC(p,newsz) realloc(p,newsz) +#define STBI_FREE(p) free(p) +#endif + +#ifndef STBI_REALLOC_SIZED +#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz) +#endif + +// x86/x64 detection +#if defined(__x86_64__) || defined(_M_X64) +#define STBI__X64_TARGET +#elif defined(__i386) || defined(_M_IX86) +#define STBI__X86_TARGET +#endif + +#if defined(__GNUC__) && defined(STBI__X86_TARGET) && !defined(__SSE2__) && !defined(STBI_NO_SIMD) +// gcc doesn't support sse2 intrinsics unless you compile with -msse2, +// which in turn means it gets to use SSE2 everywhere. This is unfortunate, +// but previous attempts to provide the SSE2 functions with runtime +// detection caused numerous issues. The way architecture extensions are +// exposed in GCC/Clang is, sadly, not really suited for one-file libs. +// New behavior: if compiled with -msse2, we use SSE2 without any +// detection; if not, we don't use it at all. +#define STBI_NO_SIMD +#endif + +#if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD) +// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET +// +// 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the +// Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant. +// As a result, enabling SSE2 on 32-bit MinGW is dangerous when not +// simultaneously enabling "-mstackrealign". +// +// See https://github.com/nothings/stb/issues/81 for more information. +// +// So default to no SSE2 on 32-bit MinGW. If you've read this far and added +// -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2. +#define STBI_NO_SIMD +#endif + +#if !defined(STBI_NO_SIMD) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET)) +#define STBI_SSE2 +#include + +#ifdef _MSC_VER + +#if _MSC_VER >= 1400 // not VC6 +#include // __cpuid +static int stbi__cpuid3(void) +{ + int info[4]; + __cpuid(info,1); + return info[3]; +} +#else +static int stbi__cpuid3(void) +{ + int res; + __asm { + mov eax,1 + cpuid + mov res,edx + } + return res; +} +#endif + +#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name + +static int stbi__sse2_available(void) +{ + int info3 = stbi__cpuid3(); + return ((info3 >> 26) & 1) != 0; +} +#else // assume GCC-style if not VC++ +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) + +static int stbi__sse2_available(void) +{ + // If we're even attempting to compile this on GCC/Clang, that means + // -msse2 is on, which means the compiler is allowed to use SSE2 + // instructions at will, and so are we. + return 1; +} +#endif +#endif + +// ARM NEON +#if defined(STBI_NO_SIMD) && defined(STBI_NEON) +#undef STBI_NEON +#endif + +#ifdef STBI_NEON +#include +// assume GCC or Clang on ARM targets +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) +#endif + +#ifndef STBI_SIMD_ALIGN +#define STBI_SIMD_ALIGN(type, name) type name +#endif + +/////////////////////////////////////////////// +// +// stbi__context struct and start_xxx functions + +// stbi__context structure is our basic context used by all images, so it +// contains all the IO context, plus some basic image information +typedef struct +{ + stbi__uint32 img_x, img_y; + int img_n, img_out_n; + + stbi_io_callbacks io; + void *io_user_data; + + int read_from_callbacks; + int buflen; + stbi_uc buffer_start[128]; + + stbi_uc *img_buffer, *img_buffer_end; + stbi_uc *img_buffer_original, *img_buffer_original_end; +} stbi__context; + + +static void stbi__refill_buffer(stbi__context *s); + +// initialize a memory-decode context +static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len) +{ + s->io.read = NULL; + s->read_from_callbacks = 0; + s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer; + s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len; +} + +// initialize a callback-based context +static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user) +{ + s->io = *c; + s->io_user_data = user; + s->buflen = sizeof(s->buffer_start); + s->read_from_callbacks = 1; + s->img_buffer_original = s->buffer_start; + stbi__refill_buffer(s); + s->img_buffer_original_end = s->img_buffer_end; +} + +#ifndef STBI_NO_STDIO + +static int stbi__stdio_read(void *user, char *data, int size) +{ + return (int) fread(data,1,size,(FILE*) user); +} + +static void stbi__stdio_skip(void *user, int n) +{ + fseek((FILE*) user, n, SEEK_CUR); +} + +static int stbi__stdio_eof(void *user) +{ + return feof((FILE*) user); +} + +static stbi_io_callbacks stbi__stdio_callbacks = +{ + stbi__stdio_read, + stbi__stdio_skip, + stbi__stdio_eof, +}; + +static void stbi__start_file(stbi__context *s, FILE *f) +{ + stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f); +} + +//static void stop_file(stbi__context *s) { } + +#endif // !STBI_NO_STDIO + +static void stbi__rewind(stbi__context *s) +{ + // conceptually rewind SHOULD rewind to the beginning of the stream, + // but we just rewind to the beginning of the initial buffer, because + // we only use it after doing 'test', which only ever looks at at most 92 bytes + s->img_buffer = s->img_buffer_original; + s->img_buffer_end = s->img_buffer_original_end; +} + +enum +{ + STBI_ORDER_RGB, + STBI_ORDER_BGR +}; + +typedef struct +{ + int bits_per_channel; + int num_channels; + int channel_order; +} stbi__result_info; + +#ifndef STBI_NO_JPEG +static int stbi__jpeg_test(stbi__context *s); +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PNG +static int stbi__png_test(stbi__context *s); +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__png_is16(stbi__context *s); +#endif + +#ifndef STBI_NO_BMP +static int stbi__bmp_test(stbi__context *s); +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_TGA +static int stbi__tga_test(stbi__context *s); +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s); +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc); +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__psd_is16(stbi__context *s); +#endif + +#ifndef STBI_NO_HDR +static int stbi__hdr_test(stbi__context *s); +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PIC +static int stbi__pic_test(stbi__context *s); +static void *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_GIF +static int stbi__gif_test(stbi__context *s); +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PNM +static int stbi__pnm_test(stbi__context *s); +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +// this is not threadsafe +static const char *stbi__g_failure_reason; + +STBIDEF const char *stbi_failure_reason(void) +{ + return stbi__g_failure_reason; +} + +static int stbi__err(const char *str) +{ + stbi__g_failure_reason = str; + return 0; +} + +static void *stbi__malloc(size_t size) +{ + return STBI_MALLOC(size); +} + +// stb_image uses ints pervasively, including for offset calculations. +// therefore the largest decoded image size we can support with the +// current code, even on 64-bit targets, is INT_MAX. this is not a +// significant limitation for the intended use case. +// +// we do, however, need to make sure our size calculations don't +// overflow. hence a few helper functions for size calculations that +// multiply integers together, making sure that they're non-negative +// and no overflow occurs. + +// return 1 if the sum is valid, 0 on overflow. +// negative terms are considered invalid. +static int stbi__addsizes_valid(int a, int b) +{ + if (b < 0) return 0; + // now 0 <= b <= INT_MAX, hence also + // 0 <= INT_MAX - b <= INTMAX. + // And "a + b <= INT_MAX" (which might overflow) is the + // same as a <= INT_MAX - b (no overflow) + return a <= INT_MAX - b; +} + +// returns 1 if the product is valid, 0 on overflow. +// negative factors are considered invalid. +static int stbi__mul2sizes_valid(int a, int b) +{ + if (a < 0 || b < 0) return 0; + if (b == 0) return 1; // mul-by-0 is always safe + // portable way to check for no overflows in a*b + return a <= INT_MAX/b; +} + +// returns 1 if "a*b + add" has no negative terms/factors and doesn't overflow +static int stbi__mad2sizes_valid(int a, int b, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add); +} + +// returns 1 if "a*b*c + add" has no negative terms/factors and doesn't overflow +static int stbi__mad3sizes_valid(int a, int b, int c, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && + stbi__addsizes_valid(a*b*c, add); +} + +// returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && + stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add); +} +#endif + +// mallocs with size overflow checking +static void *stbi__malloc_mad2(int a, int b, int add) +{ + if (!stbi__mad2sizes_valid(a, b, add)) return NULL; + return stbi__malloc(a*b + add); +} + +static void *stbi__malloc_mad3(int a, int b, int c, int add) +{ + if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL; + return stbi__malloc(a*b*c + add); +} + +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) +{ + if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL; + return stbi__malloc(a*b*c*d + add); +} +#endif + +// stbi__err - error +// stbi__errpf - error returning pointer to float +// stbi__errpuc - error returning pointer to unsigned char + +#ifdef STBI_NO_FAILURE_STRINGS + #define stbi__err(x,y) 0 +#elif defined(STBI_FAILURE_USERMSG) + #define stbi__err(x,y) stbi__err(y) +#else + #define stbi__err(x,y) stbi__err(x) +#endif + +#define stbi__errpf(x,y) ((float *)(size_t) (stbi__err(x,y)?NULL:NULL)) +#define stbi__errpuc(x,y) ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL)) + +STBIDEF void stbi_image_free(void *retval_from_stbi_load) +{ + STBI_FREE(retval_from_stbi_load); +} + +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp); +#endif + +#ifndef STBI_NO_HDR +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp); +#endif + +static int stbi__vertically_flip_on_load = 0; + +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip) +{ + stbi__vertically_flip_on_load = flag_true_if_should_flip; +} + +static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) +{ + memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields + ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed + ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order + ri->num_channels = 0; + + #ifndef STBI_NO_JPEG + if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_PNG + if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_BMP + if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_GIF + if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_PSD + if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc); + #endif + #ifndef STBI_NO_PIC + if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_PNM + if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri); + #endif + + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + float *hdr = stbi__hdr_load(s, x,y,comp,req_comp, ri); + return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); + } + #endif + + #ifndef STBI_NO_TGA + // test tga last because it's a crappy test! + if (stbi__tga_test(s)) + return stbi__tga_load(s,x,y,comp,req_comp, ri); + #endif + + return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt"); +} + +static stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int channels) +{ + int i; + int img_len = w * h * channels; + stbi_uc *reduced; + + reduced = (stbi_uc *) stbi__malloc(img_len); + if (reduced == NULL) return stbi__errpuc("outofmem", "Out of memory"); + + for (i = 0; i < img_len; ++i) + reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling + + STBI_FREE(orig); + return reduced; +} + +static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int channels) +{ + int i; + int img_len = w * h * channels; + stbi__uint16 *enlarged; + + enlarged = (stbi__uint16 *) stbi__malloc(img_len*2); + if (enlarged == NULL) return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + + for (i = 0; i < img_len; ++i) + enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff + + STBI_FREE(orig); + return enlarged; +} + +static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel) +{ + int row; + size_t bytes_per_row = (size_t)w * bytes_per_pixel; + stbi_uc temp[2048]; + stbi_uc *bytes = (stbi_uc *)image; + + for (row = 0; row < (h>>1); row++) { + stbi_uc *row0 = bytes + row*bytes_per_row; + stbi_uc *row1 = bytes + (h - row - 1)*bytes_per_row; + // swap row0 with row1 + size_t bytes_left = bytes_per_row; + while (bytes_left) { + size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp); + memcpy(temp, row0, bytes_copy); + memcpy(row0, row1, bytes_copy); + memcpy(row1, temp, bytes_copy); + row0 += bytes_copy; + row1 += bytes_copy; + bytes_left -= bytes_copy; + } + } +} + +static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int bytes_per_pixel) +{ + int slice; + int slice_size = w * h * bytes_per_pixel; + + stbi_uc *bytes = (stbi_uc *)image; + for (slice = 0; slice < z; ++slice) { + stbi__vertical_flip(bytes, w, h, bytes_per_pixel); + bytes += slice_size; + } +} + +static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8); + + if (result == NULL) + return NULL; + + if (ri.bits_per_channel != 8) { + STBI_ASSERT(ri.bits_per_channel == 16); + result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 8; + } + + // @TODO: move stbi__convert_format to here + + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc)); + } + + return (unsigned char *) result; +} + +static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16); + + if (result == NULL) + return NULL; + + if (ri.bits_per_channel != 16) { + STBI_ASSERT(ri.bits_per_channel == 8); + result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 16; + } + + // @TODO: move stbi__convert_format16 to here + // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision + + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16)); + } + + return (stbi__uint16 *) result; +} + +#if !defined(STBI_NO_HDR) || !defined(STBI_NO_LINEAR) +static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp) +{ + if (stbi__vertically_flip_on_load && result != NULL) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(float)); + } +} +#endif + +#ifndef STBI_NO_STDIO + +static FILE *stbi__fopen(char const *filename, char const *mode) +{ + FILE *f; +#if defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != fopen_s(&f, filename, mode)) + f=0; +#else + f = fopen(filename, mode); +#endif + return f; +} + + +STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + unsigned char *result; + if (!f) return stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *result; + stbi__context s; + stbi__start_file(&s,f); + result = stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; +} + +STBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__uint16 *result; + stbi__context s; + stbi__start_file(&s,f); + result = stbi__load_and_postprocess_16bit(&s,x,y,comp,req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; +} + +STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + stbi__uint16 *result; + if (!f) return (stbi_us *) stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file_16(f,x,y,comp,req_comp); + fclose(f); + return result; +} + + +#endif //!STBI_NO_STDIO + +STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +} + +STBIDEF 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) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user); + return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +} + +STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +} + +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_GIF +STBIDEF 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) +{ + unsigned char *result; + stbi__context s; + stbi__start_mem(&s,buffer,len); + + result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp); + if (stbi__vertically_flip_on_load) { + stbi__vertical_flip_slices( result, *x, *y, *z, *comp ); + } + + return result; +} +#endif + +#ifndef STBI_NO_LINEAR +static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *data; + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + stbi__result_info ri; + float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp, &ri); + if (hdr_data) + stbi__float_postprocess(hdr_data,x,y,comp,req_comp); + return hdr_data; + } + #endif + data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp); + if (data) + return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); + return stbi__errpf("unknown image type", "Image not of any known type, or corrupt"); +} + +STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} + +STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_STDIO +STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + float *result; + FILE *f = stbi__fopen(filename, "rb"); + if (!f) return stbi__errpf("can't fopen", "Unable to open file"); + result = stbi_loadf_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_file(&s,f); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} +#endif // !STBI_NO_STDIO + +#endif // !STBI_NO_LINEAR + +// these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is +// defined, for API simplicity; if STBI_NO_LINEAR is defined, it always +// reports false! + +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(buffer); + STBI_NOTUSED(len); + return 0; + #endif +} + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result=0; + if (f) { + result = stbi_is_hdr_from_file(f); + fclose(f); + } + return result; +} + +STBIDEF int stbi_is_hdr_from_file(FILE *f) +{ + #ifndef STBI_NO_HDR + long pos = ftell(f); + int res; + stbi__context s; + stbi__start_file(&s,f); + res = stbi__hdr_test(&s); + fseek(f, pos, SEEK_SET); + return res; + #else + STBI_NOTUSED(f); + return 0; + #endif +} +#endif // !STBI_NO_STDIO + +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(clbk); + STBI_NOTUSED(user); + return 0; + #endif +} + +#ifndef STBI_NO_LINEAR +static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f; + +STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; } +STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; } +#endif + +static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f; + +STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; } +STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; } + + +////////////////////////////////////////////////////////////////////////////// +// +// Common code used by all image loaders +// + +enum +{ + STBI__SCAN_load=0, + STBI__SCAN_type, + STBI__SCAN_header +}; + +static void stbi__refill_buffer(stbi__context *s) +{ + int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen); + if (n == 0) { + // at end of file, treat same as if from memory, but need to handle case + // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file + s->read_from_callbacks = 0; + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start+1; + *s->img_buffer = 0; + } else { + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start + n; + } +} + +stbi_inline static stbi_uc stbi__get8(stbi__context *s) +{ + if (s->img_buffer < s->img_buffer_end) + return *s->img_buffer++; + if (s->read_from_callbacks) { + stbi__refill_buffer(s); + return *s->img_buffer++; + } + return 0; +} + +stbi_inline static int stbi__at_eof(stbi__context *s) +{ + if (s->io.read) { + if (!(s->io.eof)(s->io_user_data)) return 0; + // if feof() is true, check if buffer = end + // special case: we've only got the special 0 character at the end + if (s->read_from_callbacks == 0) return 1; + } + + return s->img_buffer >= s->img_buffer_end; +} + +static void stbi__skip(stbi__context *s, int n) +{ + if (n < 0) { + s->img_buffer = s->img_buffer_end; + return; + } + if (s->io.read) { + int blen = (int) (s->img_buffer_end - s->img_buffer); + if (blen < n) { + s->img_buffer = s->img_buffer_end; + (s->io.skip)(s->io_user_data, n - blen); + return; + } + } + s->img_buffer += n; +} + +static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) +{ + if (s->io.read) { + int blen = (int) (s->img_buffer_end - s->img_buffer); + if (blen < n) { + int res, count; + + memcpy(buffer, s->img_buffer, blen); + + count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen); + res = (count == (n-blen)); + s->img_buffer = s->img_buffer_end; + return res; + } + } + + if (s->img_buffer+n <= s->img_buffer_end) { + memcpy(buffer, s->img_buffer, n); + s->img_buffer += n; + return 1; + } else + return 0; +} + +static int stbi__get16be(stbi__context *s) +{ + int z = stbi__get8(s); + return (z << 8) + stbi__get8(s); +} + +static stbi__uint32 stbi__get32be(stbi__context *s) +{ + stbi__uint32 z = stbi__get16be(s); + return (z << 16) + stbi__get16be(s); +} + +#if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) +// nothing +#else +static int stbi__get16le(stbi__context *s) +{ + int z = stbi__get8(s); + return z + (stbi__get8(s) << 8); +} +#endif + +#ifndef STBI_NO_BMP +static stbi__uint32 stbi__get32le(stbi__context *s) +{ + stbi__uint32 z = stbi__get16le(s); + return z + (stbi__get16le(s) << 16); +} +#endif + +#define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings + + +////////////////////////////////////////////////////////////////////////////// +// +// generic converter from built-in img_n to req_comp +// individual types do this automatically as much as possible (e.g. jpeg +// does all cases internally since it needs to colorspace convert anyway, +// and it never has alpha, so very few cases ). png can automatically +// interleave an alpha=255 channel, but falls back to this for other cases +// +// assume data buffer is malloced, so malloc a new one and free that one +// only failure mode is malloc failing + +static stbi_uc stbi__compute_y(int r, int g, int b) +{ + return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8); +} + +static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) +{ + int i,j; + unsigned char *good; + + if (req_comp == img_n) return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0); + if (good == NULL) { + STBI_FREE(data); + return stbi__errpuc("outofmem", "Out of memory"); + } + + for (j=0; j < (int) y; ++j) { + unsigned char *src = data + j * x * img_n ; + unsigned char *dest = good + j * x * req_comp; + + #define STBI__COMBO(a,b) ((a)*8+(b)) + #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1,2) { dest[0]=src[0], dest[1]=255; } break; + STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=255; } break; + STBI__CASE(2,1) { dest[0]=src[0]; } break; + STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; } break; + STBI__CASE(3,4) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; } break; + STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = 255; } break; + STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; } break; + default: STBI_ASSERT(0); + } + #undef STBI__CASE + } + + STBI_FREE(data); + return good; +} + +static stbi__uint16 stbi__compute_y_16(int r, int g, int b) +{ + return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8); +} + +static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y) +{ + int i,j; + stbi__uint16 *good; + + if (req_comp == img_n) return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2); + if (good == NULL) { + STBI_FREE(data); + return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + } + + for (j=0; j < (int) y; ++j) { + stbi__uint16 *src = data + j * x * img_n ; + stbi__uint16 *dest = good + j * x * req_comp; + + #define STBI__COMBO(a,b) ((a)*8+(b)) + #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1,2) { dest[0]=src[0], dest[1]=0xffff; } break; + STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=0xffff; } break; + STBI__CASE(2,1) { dest[0]=src[0]; } break; + STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; } break; + STBI__CASE(3,4) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=0xffff; } break; + STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]), dest[1] = 0xffff; } break; + STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]), dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; } break; + default: STBI_ASSERT(0); + } + #undef STBI__CASE + } + + STBI_FREE(data); + return good; +} + +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) +{ + int i,k,n; + float *output; + if (!data) return NULL; + output = (float *) stbi__malloc_mad4(x, y, comp, sizeof(float), 0); + if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale); + } + if (k < comp) output[i*comp + k] = data[i*comp+k]/255.0f; + } + STBI_FREE(data); + return output; +} +#endif + +#ifndef STBI_NO_HDR +#define stbi__float2int(x) ((int) (x)) +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) +{ + int i,k,n; + stbi_uc *output; + if (!data) return NULL; + output = (stbi_uc *) stbi__malloc_mad3(x, y, comp, 0); + if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (stbi_uc) stbi__float2int(z); + } + if (k < comp) { + float z = data[i*comp+k] * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (stbi_uc) stbi__float2int(z); + } + } + STBI_FREE(data); + return output; +} +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// "baseline" JPEG/JFIF decoder +// +// simple implementation +// - doesn't support delayed output of y-dimension +// - simple interface (only one output format: 8-bit interleaved RGB) +// - doesn't try to recover corrupt jpegs +// - doesn't allow partial loading, loading multiple at once +// - still fast on x86 (copying globals into locals doesn't help x86) +// - allocates lots of intermediate memory (full size of all components) +// - non-interleaved case requires this anyway +// - allows good upsampling (see next) +// high-quality +// - upsampled channels are bilinearly interpolated, even across blocks +// - quality integer IDCT derived from IJG's 'slow' +// performance +// - fast huffman; reasonable integer IDCT +// - some SIMD kernels for common paths on targets with SSE2/NEON +// - uses a lot of intermediate memory, could cache poorly + +#ifndef STBI_NO_JPEG + +// huffman decoding acceleration +#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache + +typedef struct +{ + stbi_uc fast[1 << FAST_BITS]; + // weirdly, repacking this into AoS is a 10% speed loss, instead of a win + stbi__uint16 code[256]; + stbi_uc values[256]; + stbi_uc size[257]; + unsigned int maxcode[18]; + int delta[17]; // old 'firstsymbol' - old 'firstcode' +} stbi__huffman; + +typedef struct +{ + stbi__context *s; + stbi__huffman huff_dc[4]; + stbi__huffman huff_ac[4]; + stbi__uint16 dequant[4][64]; + stbi__int16 fast_ac[4][1 << FAST_BITS]; + +// sizes for components, interleaved MCUs + int img_h_max, img_v_max; + int img_mcu_x, img_mcu_y; + int img_mcu_w, img_mcu_h; + +// definition of jpeg image component + struct + { + int id; + int h,v; + int tq; + int hd,ha; + int dc_pred; + + int x,y,w2,h2; + stbi_uc *data; + void *raw_data, *raw_coeff; + stbi_uc *linebuf; + short *coeff; // progressive only + int coeff_w, coeff_h; // number of 8x8 coefficient blocks + } img_comp[4]; + + stbi__uint32 code_buffer; // jpeg entropy-coded buffer + int code_bits; // number of valid bits + unsigned char marker; // marker seen while filling entropy buffer + int nomore; // flag if we saw a marker so must stop + + int progressive; + int spec_start; + int spec_end; + int succ_high; + int succ_low; + int eob_run; + int jfif; + int app14_color_transform; // Adobe APP14 tag + int rgb; + + int scan_n, order[4]; + int restart_interval, todo; + +// kernels + void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]); + void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step); + stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs); +} stbi__jpeg; + +static int stbi__build_huffman(stbi__huffman *h, int *count) +{ + int i,j,k=0; + unsigned int code; + // build size list for each symbol (from JPEG spec) + for (i=0; i < 16; ++i) + for (j=0; j < count[i]; ++j) + h->size[k++] = (stbi_uc) (i+1); + h->size[k] = 0; + + // compute actual symbols (from jpeg spec) + code = 0; + k = 0; + for(j=1; j <= 16; ++j) { + // compute delta to add to code to compute symbol id + h->delta[j] = k - code; + if (h->size[k] == j) { + while (h->size[k] == j) + h->code[k++] = (stbi__uint16) (code++); + if (code-1 >= (1u << j)) return stbi__err("bad code lengths","Corrupt JPEG"); + } + // compute largest code + 1 for this size, preshifted as needed later + h->maxcode[j] = code << (16-j); + code <<= 1; + } + h->maxcode[j] = 0xffffffff; + + // build non-spec acceleration table; 255 is flag for not-accelerated + memset(h->fast, 255, 1 << FAST_BITS); + for (i=0; i < k; ++i) { + int s = h->size[i]; + if (s <= FAST_BITS) { + int c = h->code[i] << (FAST_BITS-s); + int m = 1 << (FAST_BITS-s); + for (j=0; j < m; ++j) { + h->fast[c+j] = (stbi_uc) i; + } + } + } + return 1; +} + +// build a table that decodes both magnitude and value of small ACs in +// one go. +static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h) +{ + int i; + for (i=0; i < (1 << FAST_BITS); ++i) { + stbi_uc fast = h->fast[i]; + fast_ac[i] = 0; + if (fast < 255) { + int rs = h->values[fast]; + int run = (rs >> 4) & 15; + int magbits = rs & 15; + int len = h->size[fast]; + + if (magbits && len + magbits <= FAST_BITS) { + // magnitude code followed by receive_extend code + int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits); + int m = 1 << (magbits - 1); + if (k < m) k += (~0U << magbits) + 1; + // if the result is small enough, we can fit it in fast_ac table + if (k >= -128 && k <= 127) + fast_ac[i] = (stbi__int16) ((k * 256) + (run * 16) + (len + magbits)); + } + } + } +} + +static void stbi__grow_buffer_unsafe(stbi__jpeg *j) +{ + do { + unsigned int b = j->nomore ? 0 : stbi__get8(j->s); + if (b == 0xff) { + int c = stbi__get8(j->s); + while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes + if (c != 0) { + j->marker = (unsigned char) c; + j->nomore = 1; + return; + } + } + j->code_buffer |= b << (24 - j->code_bits); + j->code_bits += 8; + } while (j->code_bits <= 24); +} + +// (1 << n) - 1 +static const stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; + +// decode a jpeg huffman value from the bitstream +stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) +{ + unsigned int temp; + int c,k; + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + // look at the top FAST_BITS and determine what symbol ID it is, + // if the code is <= FAST_BITS + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + k = h->fast[c]; + if (k < 255) { + int s = h->size[k]; + if (s > j->code_bits) + return -1; + j->code_buffer <<= s; + j->code_bits -= s; + return h->values[k]; + } + + // naive test is to shift the code_buffer down so k bits are + // valid, then test against maxcode. To speed this up, we've + // preshifted maxcode left so that it has (16-k) 0s at the + // end; in other words, regardless of the number of bits, it + // wants to be compared against something shifted to have 16; + // that way we don't need to shift inside the loop. + temp = j->code_buffer >> 16; + for (k=FAST_BITS+1 ; ; ++k) + if (temp < h->maxcode[k]) + break; + if (k == 17) { + // error! code not found + j->code_bits -= 16; + return -1; + } + + if (k > j->code_bits) + return -1; + + // convert the huffman code to the symbol id + c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; + STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); + + // convert the id to a symbol + j->code_bits -= k; + j->code_buffer <<= k; + return h->values[c]; +} + +// bias[n] = (-1<code_bits < n) stbi__grow_buffer_unsafe(j); + + sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB + k = stbi_lrot(j->code_buffer, n); + STBI_ASSERT(n >= 0 && n < (int) (sizeof(stbi__bmask)/sizeof(*stbi__bmask))); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k + (stbi__jbias[n] & ~sgn); +} + +// get some unsigned bits +stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) +{ + unsigned int k; + if (j->code_bits < n) stbi__grow_buffer_unsafe(j); + k = stbi_lrot(j->code_buffer, n); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k; +} + +stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) +{ + unsigned int k; + if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); + k = j->code_buffer; + j->code_buffer <<= 1; + --j->code_bits; + return k & 0x80000000; +} + +// given a value that's at position X in the zigzag stream, +// where does it appear in the 8x8 matrix coded as row-major? +static const stbi_uc stbi__jpeg_dezigzag[64+15] = +{ + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63, + // let corrupt input sample past end + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63 +}; + +// decode one 64-entry block-- +static 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) +{ + int diff,dc,k; + int t; + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + t = stbi__jpeg_huff_decode(j, hdc); + if (t < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + + // 0 all the ac values now so we can do it 32-bits at a time + memset(data,0,64*sizeof(data[0])); + + diff = t ? stbi__extend_receive(j, t) : 0; + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + data[0] = (short) (dc * dequant[0]); + + // decode AC components, see JPEG spec + k = 1; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + j->code_buffer <<= s; + j->code_bits -= s; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) * dequant[zig]); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (rs != 0xf0) break; // end block + k += 16; + } else { + k += r; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]); + } + } + } while (k < 64); + return 1; +} + +static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b) +{ + int diff,dc; + int t; + if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + if (j->succ_high == 0) { + // first scan for DC coefficient, must be first + memset(data,0,64*sizeof(data[0])); // 0 all the ac values now + t = stbi__jpeg_huff_decode(j, hdc); + diff = t ? stbi__extend_receive(j, t) : 0; + + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + data[0] = (short) (dc << j->succ_low); + } else { + // refinement scan for DC coefficient + if (stbi__jpeg_get_bit(j)) + data[0] += (short) (1 << j->succ_low); + } + return 1; +} + +// @OPTIMIZE: store non-zigzagged during the decode passes, +// and only de-zigzag when dequantizing +static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac) +{ + int k; + if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->succ_high == 0) { + int shift = j->succ_low; + + if (j->eob_run) { + --j->eob_run; + return 1; + } + + k = j->spec_start; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + j->code_buffer <<= s; + j->code_bits -= s; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) << shift); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r); + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + --j->eob_run; + break; + } + k += 16; + } else { + k += r; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) << shift); + } + } + } while (k <= j->spec_end); + } else { + // refinement scan for these AC coefficients + + short bit = (short) (1 << j->succ_low); + + if (j->eob_run) { + --j->eob_run; + for (k = j->spec_start; k <= j->spec_end; ++k) { + short *p = &data[stbi__jpeg_dezigzag[k]]; + if (*p != 0) + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } + } else { + k = j->spec_start; + do { + int r,s; + 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 + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r) - 1; + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + r = 64; // force end of block + } else { + // r=15 s=0 should write 16 0s, so we just do + // a run of 15 0s and then write s (which is 0), + // so we don't have to do anything special here + } + } else { + if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG"); + // sign bit + if (stbi__jpeg_get_bit(j)) + s = bit; + else + s = -bit; + } + + // advance by r + while (k <= j->spec_end) { + short *p = &data[stbi__jpeg_dezigzag[k++]]; + if (*p != 0) { + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } else { + if (r == 0) { + *p = (short) s; + break; + } + --r; + } + } + } while (k <= j->spec_end); + } + } + return 1; +} + +// take a -128..127 value and stbi__clamp it and convert to 0..255 +stbi_inline static stbi_uc stbi__clamp(int x) +{ + // trick to use a single test to catch both cases + if ((unsigned int) x > 255) { + if (x < 0) return 0; + if (x > 255) return 255; + } + return (stbi_uc) x; +} + +#define stbi__f2f(x) ((int) (((x) * 4096 + 0.5))) +#define stbi__fsh(x) ((x) * 4096) + +// derived from jidctint -- DCT_ISLOW +#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \ + int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \ + p2 = s2; \ + p3 = s6; \ + p1 = (p2+p3) * stbi__f2f(0.5411961f); \ + t2 = p1 + p3*stbi__f2f(-1.847759065f); \ + t3 = p1 + p2*stbi__f2f( 0.765366865f); \ + p2 = s0; \ + p3 = s4; \ + t0 = stbi__fsh(p2+p3); \ + t1 = stbi__fsh(p2-p3); \ + x0 = t0+t3; \ + x3 = t0-t3; \ + x1 = t1+t2; \ + x2 = t1-t2; \ + t0 = s7; \ + t1 = s5; \ + t2 = s3; \ + t3 = s1; \ + p3 = t0+t2; \ + p4 = t1+t3; \ + p1 = t0+t3; \ + p2 = t1+t2; \ + p5 = (p3+p4)*stbi__f2f( 1.175875602f); \ + t0 = t0*stbi__f2f( 0.298631336f); \ + t1 = t1*stbi__f2f( 2.053119869f); \ + t2 = t2*stbi__f2f( 3.072711026f); \ + t3 = t3*stbi__f2f( 1.501321110f); \ + p1 = p5 + p1*stbi__f2f(-0.899976223f); \ + p2 = p5 + p2*stbi__f2f(-2.562915447f); \ + p3 = p3*stbi__f2f(-1.961570560f); \ + p4 = p4*stbi__f2f(-0.390180644f); \ + t3 += p1+p4; \ + t2 += p2+p3; \ + t1 += p2+p4; \ + t0 += p1+p3; + +static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64]) +{ + int i,val[64],*v=val; + stbi_uc *o; + short *d = data; + + // columns + for (i=0; i < 8; ++i,++d, ++v) { + // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing + if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0 + && d[40]==0 && d[48]==0 && d[56]==0) { + // no shortcut 0 seconds + // (1|2|3|4|5|6|7)==0 0 seconds + // all separate -0.047 seconds + // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds + int dcterm = d[0]*4; + v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; + } else { + STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56]) + // constants scaled things up by 1<<12; let's bring them back + // down, but keep 2 extra bits of precision + x0 += 512; x1 += 512; x2 += 512; x3 += 512; + v[ 0] = (x0+t3) >> 10; + v[56] = (x0-t3) >> 10; + v[ 8] = (x1+t2) >> 10; + v[48] = (x1-t2) >> 10; + v[16] = (x2+t1) >> 10; + v[40] = (x2-t1) >> 10; + v[24] = (x3+t0) >> 10; + v[32] = (x3-t0) >> 10; + } + } + + for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) { + // no fast case since the first 1D IDCT spread components out + STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]) + // constants scaled things up by 1<<12, plus we had 1<<2 from first + // loop, plus horizontal and vertical each scale by sqrt(8) so together + // we've got an extra 1<<3, so 1<<17 total we need to remove. + // so we want to round that, which means adding 0.5 * 1<<17, + // aka 65536. Also, we'll end up with -128 to 127 that we want + // to encode as 0..255 by adding 128, so we'll add that before the shift + x0 += 65536 + (128<<17); + x1 += 65536 + (128<<17); + x2 += 65536 + (128<<17); + x3 += 65536 + (128<<17); + // tried computing the shifts into temps, or'ing the temps to see + // if any were out of range, but that was slower + o[0] = stbi__clamp((x0+t3) >> 17); + o[7] = stbi__clamp((x0-t3) >> 17); + o[1] = stbi__clamp((x1+t2) >> 17); + o[6] = stbi__clamp((x1-t2) >> 17); + o[2] = stbi__clamp((x2+t1) >> 17); + o[5] = stbi__clamp((x2-t1) >> 17); + o[3] = stbi__clamp((x3+t0) >> 17); + o[4] = stbi__clamp((x3-t0) >> 17); + } +} + +#ifdef STBI_SSE2 +// sse2 integer IDCT. not the fastest possible implementation but it +// produces bit-identical results to the generic C version so it's +// fully "transparent". +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + // This is constructed to match our regular (generic) integer IDCT exactly. + __m128i row0, row1, row2, row3, row4, row5, row6, row7; + __m128i tmp; + + // dot product constant: even elems=x, odd elems=y + #define dct_const(x,y) _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y)) + + // out(0) = c0[even]*x + c0[odd]*y (c0, x, y 16-bit, out 32-bit) + // out(1) = c1[even]*x + c1[odd]*y + #define dct_rot(out0,out1, x,y,c0,c1) \ + __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \ + __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \ + __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \ + __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \ + __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \ + __m128i out1##_h = _mm_madd_epi16(c0##hi, c1) + + // out = in << 12 (in 16-bit, out 32-bit) + #define dct_widen(out, in) \ + __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \ + __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4) + + // wide add + #define dct_wadd(out, a, b) \ + __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_add_epi32(a##_h, b##_h) + + // wide sub + #define dct_wsub(out, a, b) \ + __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_sub_epi32(a##_h, b##_h) + + // butterfly a/b, add bias, then shift by "s" and pack + #define dct_bfly32o(out0, out1, a,b,bias,s) \ + { \ + __m128i abiased_l = _mm_add_epi32(a##_l, bias); \ + __m128i abiased_h = _mm_add_epi32(a##_h, bias); \ + dct_wadd(sum, abiased, b); \ + dct_wsub(dif, abiased, b); \ + out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \ + out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \ + } + + // 8-bit interleave step (for transposes) + #define dct_interleave8(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi8(a, b); \ + b = _mm_unpackhi_epi8(tmp, b) + + // 16-bit interleave step (for transposes) + #define dct_interleave16(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi16(a, b); \ + b = _mm_unpackhi_epi16(tmp, b) + + #define dct_pass(bias,shift) \ + { \ + /* even part */ \ + dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \ + __m128i sum04 = _mm_add_epi16(row0, row4); \ + __m128i dif04 = _mm_sub_epi16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \ + dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \ + __m128i sum17 = _mm_add_epi16(row1, row7); \ + __m128i sum35 = _mm_add_epi16(row3, row5); \ + dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \ + dct_wadd(x4, y0o, y4o); \ + dct_wadd(x5, y1o, y5o); \ + dct_wadd(x6, y2o, y5o); \ + dct_wadd(x7, y3o, y4o); \ + dct_bfly32o(row0,row7, x0,x7,bias,shift); \ + dct_bfly32o(row1,row6, x1,x6,bias,shift); \ + dct_bfly32o(row2,row5, x2,x5,bias,shift); \ + dct_bfly32o(row3,row4, x3,x4,bias,shift); \ + } + + __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f)); + __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f)); + __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f)); + __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f)); + __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f)); + __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f)); + __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f)); + __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f)); + + // rounding biases in column/row passes, see stbi__idct_block for explanation. + __m128i bias_0 = _mm_set1_epi32(512); + __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17)); + + // load + row0 = _mm_load_si128((const __m128i *) (data + 0*8)); + row1 = _mm_load_si128((const __m128i *) (data + 1*8)); + row2 = _mm_load_si128((const __m128i *) (data + 2*8)); + row3 = _mm_load_si128((const __m128i *) (data + 3*8)); + row4 = _mm_load_si128((const __m128i *) (data + 4*8)); + row5 = _mm_load_si128((const __m128i *) (data + 5*8)); + row6 = _mm_load_si128((const __m128i *) (data + 6*8)); + row7 = _mm_load_si128((const __m128i *) (data + 7*8)); + + // column pass + dct_pass(bias_0, 10); + + { + // 16bit 8x8 transpose pass 1 + dct_interleave16(row0, row4); + dct_interleave16(row1, row5); + dct_interleave16(row2, row6); + dct_interleave16(row3, row7); + + // transpose pass 2 + dct_interleave16(row0, row2); + dct_interleave16(row1, row3); + dct_interleave16(row4, row6); + dct_interleave16(row5, row7); + + // transpose pass 3 + dct_interleave16(row0, row1); + dct_interleave16(row2, row3); + dct_interleave16(row4, row5); + dct_interleave16(row6, row7); + } + + // row pass + dct_pass(bias_1, 17); + + { + // pack + __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7 + __m128i p1 = _mm_packus_epi16(row2, row3); + __m128i p2 = _mm_packus_epi16(row4, row5); + __m128i p3 = _mm_packus_epi16(row6, row7); + + // 8bit 8x8 transpose pass 1 + dct_interleave8(p0, p2); // a0e0a1e1... + dct_interleave8(p1, p3); // c0g0c1g1... + + // transpose pass 2 + dct_interleave8(p0, p1); // a0c0e0g0... + dct_interleave8(p2, p3); // b0d0f0h0... + + // transpose pass 3 + dct_interleave8(p0, p2); // a0b0c0d0... + dct_interleave8(p1, p3); // a4b4c4d4... + + // store + _mm_storel_epi64((__m128i *) out, p0); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p2); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p1); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p3); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e)); + } + +#undef dct_const +#undef dct_rot +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_interleave8 +#undef dct_interleave16 +#undef dct_pass +} + +#endif // STBI_SSE2 + +#ifdef STBI_NEON + +// NEON integer IDCT. should produce bit-identical +// results to the generic C version. +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + int16x8_t row0, row1, row2, row3, row4, row5, row6, row7; + + int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f)); + int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f)); + int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f)); + int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f)); + int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f)); + int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f)); + int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f)); + int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f)); + int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f)); + int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f)); + int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f)); + int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f)); + +#define dct_long_mul(out, inq, coeff) \ + int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff) + +#define dct_long_mac(out, acc, inq, coeff) \ + int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff) + +#define dct_widen(out, inq) \ + int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \ + int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12) + +// wide add +#define dct_wadd(out, a, b) \ + int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vaddq_s32(a##_h, b##_h) + +// wide sub +#define dct_wsub(out, a, b) \ + int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vsubq_s32(a##_h, b##_h) + +// butterfly a/b, then shift using "shiftop" by "s" and pack +#define dct_bfly32o(out0,out1, a,b,shiftop,s) \ + { \ + dct_wadd(sum, a, b); \ + dct_wsub(dif, a, b); \ + out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \ + out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \ + } + +#define dct_pass(shiftop, shift) \ + { \ + /* even part */ \ + int16x8_t sum26 = vaddq_s16(row2, row6); \ + dct_long_mul(p1e, sum26, rot0_0); \ + dct_long_mac(t2e, p1e, row6, rot0_1); \ + dct_long_mac(t3e, p1e, row2, rot0_2); \ + int16x8_t sum04 = vaddq_s16(row0, row4); \ + int16x8_t dif04 = vsubq_s16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + int16x8_t sum15 = vaddq_s16(row1, row5); \ + int16x8_t sum17 = vaddq_s16(row1, row7); \ + int16x8_t sum35 = vaddq_s16(row3, row5); \ + int16x8_t sum37 = vaddq_s16(row3, row7); \ + int16x8_t sumodd = vaddq_s16(sum17, sum35); \ + dct_long_mul(p5o, sumodd, rot1_0); \ + dct_long_mac(p1o, p5o, sum17, rot1_1); \ + dct_long_mac(p2o, p5o, sum35, rot1_2); \ + dct_long_mul(p3o, sum37, rot2_0); \ + dct_long_mul(p4o, sum15, rot2_1); \ + dct_wadd(sump13o, p1o, p3o); \ + dct_wadd(sump24o, p2o, p4o); \ + dct_wadd(sump23o, p2o, p3o); \ + dct_wadd(sump14o, p1o, p4o); \ + dct_long_mac(x4, sump13o, row7, rot3_0); \ + dct_long_mac(x5, sump24o, row5, rot3_1); \ + dct_long_mac(x6, sump23o, row3, rot3_2); \ + dct_long_mac(x7, sump14o, row1, rot3_3); \ + dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \ + dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \ + dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \ + dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \ + } + + // load + row0 = vld1q_s16(data + 0*8); + row1 = vld1q_s16(data + 1*8); + row2 = vld1q_s16(data + 2*8); + row3 = vld1q_s16(data + 3*8); + row4 = vld1q_s16(data + 4*8); + row5 = vld1q_s16(data + 5*8); + row6 = vld1q_s16(data + 6*8); + row7 = vld1q_s16(data + 7*8); + + // add DC bias + row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0)); + + // column pass + dct_pass(vrshrn_n_s32, 10); + + // 16bit 8x8 transpose + { +// these three map to a single VTRN.16, VTRN.32, and VSWP, respectively. +// whether compilers actually get this is another story, sadly. +#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; } +#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]); } +#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)); } + + // pass 1 + dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6 + dct_trn16(row2, row3); + dct_trn16(row4, row5); + dct_trn16(row6, row7); + + // pass 2 + dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4 + dct_trn32(row1, row3); + dct_trn32(row4, row6); + dct_trn32(row5, row7); + + // pass 3 + dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0 + dct_trn64(row1, row5); + dct_trn64(row2, row6); + dct_trn64(row3, row7); + +#undef dct_trn16 +#undef dct_trn32 +#undef dct_trn64 + } + + // row pass + // vrshrn_n_s32 only supports shifts up to 16, we need + // 17. so do a non-rounding shift of 16 first then follow + // up with a rounding shift by 1. + dct_pass(vshrn_n_s32, 16); + + { + // pack and round + uint8x8_t p0 = vqrshrun_n_s16(row0, 1); + uint8x8_t p1 = vqrshrun_n_s16(row1, 1); + uint8x8_t p2 = vqrshrun_n_s16(row2, 1); + uint8x8_t p3 = vqrshrun_n_s16(row3, 1); + uint8x8_t p4 = vqrshrun_n_s16(row4, 1); + uint8x8_t p5 = vqrshrun_n_s16(row5, 1); + uint8x8_t p6 = vqrshrun_n_s16(row6, 1); + uint8x8_t p7 = vqrshrun_n_s16(row7, 1); + + // again, these can translate into one instruction, but often don't. +#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; } +#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]); } +#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]); } + + // sadly can't use interleaved stores here since we only write + // 8 bytes to each scan line! + + // 8x8 8-bit transpose pass 1 + dct_trn8_8(p0, p1); + dct_trn8_8(p2, p3); + dct_trn8_8(p4, p5); + dct_trn8_8(p6, p7); + + // pass 2 + dct_trn8_16(p0, p2); + dct_trn8_16(p1, p3); + dct_trn8_16(p4, p6); + dct_trn8_16(p5, p7); + + // pass 3 + dct_trn8_32(p0, p4); + dct_trn8_32(p1, p5); + dct_trn8_32(p2, p6); + dct_trn8_32(p3, p7); + + // store + vst1_u8(out, p0); out += out_stride; + vst1_u8(out, p1); out += out_stride; + vst1_u8(out, p2); out += out_stride; + vst1_u8(out, p3); out += out_stride; + vst1_u8(out, p4); out += out_stride; + vst1_u8(out, p5); out += out_stride; + vst1_u8(out, p6); out += out_stride; + vst1_u8(out, p7); + +#undef dct_trn8_8 +#undef dct_trn8_16 +#undef dct_trn8_32 + } + +#undef dct_long_mul +#undef dct_long_mac +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_pass +} + +#endif // STBI_NEON + +#define STBI__MARKER_none 0xff +// if there's a pending marker from the entropy stream, return that +// otherwise, fetch from the stream and get a marker. if there's no +// marker, return 0xff, which is never a valid marker value +static stbi_uc stbi__get_marker(stbi__jpeg *j) +{ + stbi_uc x; + if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; } + x = stbi__get8(j->s); + if (x != 0xff) return STBI__MARKER_none; + while (x == 0xff) + x = stbi__get8(j->s); // consume repeated 0xff fill bytes + return x; +} + +// in each scan, we'll have scan_n components, and the order +// of the components is specified by order[] +#define STBI__RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) + +// after a restart interval, stbi__jpeg_reset the entropy decoder and +// the dc prediction +static void stbi__jpeg_reset(stbi__jpeg *j) +{ + j->code_bits = 0; + j->code_buffer = 0; + j->nomore = 0; + 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; + j->marker = STBI__MARKER_none; + j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; + j->eob_run = 0; + // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, + // since we don't even allow 1<<30 pixels +} + +static int stbi__parse_entropy_coded_data(stbi__jpeg *z) +{ + stbi__jpeg_reset(z); + if (!z->progressive) { + if (z->scan_n == 1) { + int i,j; + STBI_SIMD_ALIGN(short, data[64]); + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + int ha = z->img_comp[n].ha; + 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; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + // if it's NOT a restart, then just bail, so we get corrupt data + // rather than no data + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + STBI_SIMD_ALIGN(short, data[64]); + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x)*8; + int y2 = (j*z->img_comp[n].v + y)*8; + int ha = z->img_comp[n].ha; + 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; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data); + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } else { + if (z->scan_n == 1) { + int i,j; + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + if (z->spec_start == 0) { + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } else { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha])) + return 0; + } + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x); + int y2 = (j*z->img_comp[n].v + y); + short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w); + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } +} + +static void stbi__jpeg_dequantize(short *data, stbi__uint16 *dequant) +{ + int i; + for (i=0; i < 64; ++i) + data[i] *= dequant[i]; +} + +static void stbi__jpeg_finish(stbi__jpeg *z) +{ + if (z->progressive) { + // dequantize and idct the data + int i,j,n; + for (n=0; n < z->s->img_n; ++n) { + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]); + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + } + } + } + } +} + +static int stbi__process_marker(stbi__jpeg *z, int m) +{ + int L; + switch (m) { + case STBI__MARKER_none: // no marker found + return stbi__err("expected marker","Corrupt JPEG"); + + case 0xDD: // DRI - specify restart interval + if (stbi__get16be(z->s) != 4) return stbi__err("bad DRI len","Corrupt JPEG"); + z->restart_interval = stbi__get16be(z->s); + return 1; + + case 0xDB: // DQT - define quantization table + L = stbi__get16be(z->s)-2; + while (L > 0) { + int q = stbi__get8(z->s); + int p = q >> 4, sixteen = (p != 0); + int t = q & 15,i; + if (p != 0 && p != 1) return stbi__err("bad DQT type","Corrupt JPEG"); + if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG"); + + for (i=0; i < 64; ++i) + z->dequant[t][stbi__jpeg_dezigzag[i]] = (stbi__uint16)(sixteen ? stbi__get16be(z->s) : stbi__get8(z->s)); + L -= (sixteen ? 129 : 65); + } + return L==0; + + case 0xC4: // DHT - define huffman table + L = stbi__get16be(z->s)-2; + while (L > 0) { + stbi_uc *v; + int sizes[16],i,n=0; + int q = stbi__get8(z->s); + int tc = q >> 4; + int th = q & 15; + if (tc > 1 || th > 3) return stbi__err("bad DHT header","Corrupt JPEG"); + for (i=0; i < 16; ++i) { + sizes[i] = stbi__get8(z->s); + n += sizes[i]; + } + L -= 17; + if (tc == 0) { + if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0; + v = z->huff_dc[th].values; + } else { + if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0; + v = z->huff_ac[th].values; + } + for (i=0; i < n; ++i) + v[i] = stbi__get8(z->s); + if (tc != 0) + stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th); + L -= n; + } + return L==0; + } + + // check for comment block or APP blocks + if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { + L = stbi__get16be(z->s); + if (L < 2) { + if (m == 0xFE) + return stbi__err("bad COM len","Corrupt JPEG"); + else + return stbi__err("bad APP len","Corrupt JPEG"); + } + L -= 2; + + if (m == 0xE0 && L >= 5) { // JFIF APP0 segment + static const unsigned char tag[5] = {'J','F','I','F','\0'}; + int ok = 1; + int i; + for (i=0; i < 5; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 5; + if (ok) + z->jfif = 1; + } else if (m == 0xEE && L >= 12) { // Adobe APP14 segment + static const unsigned char tag[6] = {'A','d','o','b','e','\0'}; + int ok = 1; + int i; + for (i=0; i < 6; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 6; + if (ok) { + stbi__get8(z->s); // version + stbi__get16be(z->s); // flags0 + stbi__get16be(z->s); // flags1 + z->app14_color_transform = stbi__get8(z->s); // color transform + L -= 6; + } + } + + stbi__skip(z->s, L); + return 1; + } + + return stbi__err("unknown marker","Corrupt JPEG"); +} + +// after we see SOS +static int stbi__process_scan_header(stbi__jpeg *z) +{ + int i; + int Ls = stbi__get16be(z->s); + z->scan_n = stbi__get8(z->s); + 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"); + if (Ls != 6+2*z->scan_n) return stbi__err("bad SOS len","Corrupt JPEG"); + for (i=0; i < z->scan_n; ++i) { + int id = stbi__get8(z->s), which; + int q = stbi__get8(z->s); + for (which = 0; which < z->s->img_n; ++which) + if (z->img_comp[which].id == id) + break; + if (which == z->s->img_n) return 0; // no match + z->img_comp[which].hd = q >> 4; if (z->img_comp[which].hd > 3) return stbi__err("bad DC huff","Corrupt JPEG"); + z->img_comp[which].ha = q & 15; if (z->img_comp[which].ha > 3) return stbi__err("bad AC huff","Corrupt JPEG"); + z->order[i] = which; + } + + { + int aa; + z->spec_start = stbi__get8(z->s); + z->spec_end = stbi__get8(z->s); // should be 63, but might be 0 + aa = stbi__get8(z->s); + z->succ_high = (aa >> 4); + z->succ_low = (aa & 15); + if (z->progressive) { + if (z->spec_start > 63 || z->spec_end > 63 || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13) + return stbi__err("bad SOS", "Corrupt JPEG"); + } else { + if (z->spec_start != 0) return stbi__err("bad SOS","Corrupt JPEG"); + if (z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS","Corrupt JPEG"); + z->spec_end = 63; + } + } + + return 1; +} + +static int stbi__free_jpeg_components(stbi__jpeg *z, int ncomp, int why) +{ + int i; + for (i=0; i < ncomp; ++i) { + if (z->img_comp[i].raw_data) { + STBI_FREE(z->img_comp[i].raw_data); + z->img_comp[i].raw_data = NULL; + z->img_comp[i].data = NULL; + } + if (z->img_comp[i].raw_coeff) { + STBI_FREE(z->img_comp[i].raw_coeff); + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].coeff = 0; + } + if (z->img_comp[i].linebuf) { + STBI_FREE(z->img_comp[i].linebuf); + z->img_comp[i].linebuf = NULL; + } + } + return why; +} + +static int stbi__process_frame_header(stbi__jpeg *z, int scan) +{ + stbi__context *s = z->s; + int Lf,p,i,q, h_max=1,v_max=1,c; + Lf = stbi__get16be(s); if (Lf < 11) return stbi__err("bad SOF len","Corrupt JPEG"); // JPEG + p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline + 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 + s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires + c = stbi__get8(s); + if (c != 3 && c != 1 && c != 4) return stbi__err("bad component count","Corrupt JPEG"); + s->img_n = c; + for (i=0; i < c; ++i) { + z->img_comp[i].data = NULL; + z->img_comp[i].linebuf = NULL; + } + + if (Lf != 8+3*s->img_n) return stbi__err("bad SOF len","Corrupt JPEG"); + + z->rgb = 0; + for (i=0; i < s->img_n; ++i) { + static const unsigned char rgb[3] = { 'R', 'G', 'B' }; + z->img_comp[i].id = stbi__get8(s); + if (s->img_n == 3 && z->img_comp[i].id == rgb[i]) + ++z->rgb; + q = stbi__get8(s); + 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"); + 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"); + z->img_comp[i].tq = stbi__get8(s); if (z->img_comp[i].tq > 3) return stbi__err("bad TQ","Corrupt JPEG"); + } + + if (scan != STBI__SCAN_load) return 1; + + if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) return stbi__err("too large", "Image too large to decode"); + + for (i=0; i < s->img_n; ++i) { + if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h; + if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; + } + + // compute interleaved mcu info + z->img_h_max = h_max; + z->img_v_max = v_max; + z->img_mcu_w = h_max * 8; + z->img_mcu_h = v_max * 8; + // these sizes can't be more than 17 bits + z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w; + z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h; + + for (i=0; i < s->img_n; ++i) { + // number of effective pixels (e.g. for non-interleaved MCU) + z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max; + z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max; + // to simplify generation, we'll allocate enough memory to decode + // the bogus oversized data from using interleaved MCUs and their + // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't + // discard the extra data until colorspace conversion + // + // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked earlier) + // so these muls can't overflow with 32-bit ints (which we require) + z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; + z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; + z->img_comp[i].coeff = 0; + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].linebuf = NULL; + z->img_comp[i].raw_data = stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15); + if (z->img_comp[i].raw_data == NULL) + return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); + // align blocks for idct using mmx/sse + z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15); + if (z->progressive) { + // w2, h2 are multiples of 8 (see above) + z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8; + z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8; + z->img_comp[i].raw_coeff = stbi__malloc_mad3(z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15); + if (z->img_comp[i].raw_coeff == NULL) + return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); + z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15); + } + } + + return 1; +} + +// use comparisons since in some cases we handle more than one case (e.g. SOF) +#define stbi__DNL(x) ((x) == 0xdc) +#define stbi__SOI(x) ((x) == 0xd8) +#define stbi__EOI(x) ((x) == 0xd9) +#define stbi__SOF(x) ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2) +#define stbi__SOS(x) ((x) == 0xda) + +#define stbi__SOF_progressive(x) ((x) == 0xc2) + +static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) +{ + int m; + z->jfif = 0; + z->app14_color_transform = -1; // valid values are 0,1,2 + z->marker = STBI__MARKER_none; // initialize cached marker to empty + m = stbi__get_marker(z); + if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG"); + if (scan == STBI__SCAN_type) return 1; + m = stbi__get_marker(z); + while (!stbi__SOF(m)) { + if (!stbi__process_marker(z,m)) return 0; + m = stbi__get_marker(z); + while (m == STBI__MARKER_none) { + // some files have extra padding after their blocks, so ok, we'll scan + if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG"); + m = stbi__get_marker(z); + } + } + z->progressive = stbi__SOF_progressive(m); + if (!stbi__process_frame_header(z, scan)) return 0; + return 1; +} + +// decode image to YCbCr format +static int stbi__decode_jpeg_image(stbi__jpeg *j) +{ + int m; + for (m = 0; m < 4; m++) { + j->img_comp[m].raw_data = NULL; + j->img_comp[m].raw_coeff = NULL; + } + j->restart_interval = 0; + if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0; + m = stbi__get_marker(j); + while (!stbi__EOI(m)) { + if (stbi__SOS(m)) { + if (!stbi__process_scan_header(j)) return 0; + if (!stbi__parse_entropy_coded_data(j)) return 0; + if (j->marker == STBI__MARKER_none ) { + // handle 0s at the end of image data from IP Kamera 9060 + while (!stbi__at_eof(j->s)) { + int x = stbi__get8(j->s); + if (x == 255) { + j->marker = stbi__get8(j->s); + break; + } + } + // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 + } + } else if (stbi__DNL(m)) { + int Ld = stbi__get16be(j->s); + stbi__uint32 NL = stbi__get16be(j->s); + if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG"); + if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG"); + } else { + if (!stbi__process_marker(j, m)) return 0; + } + m = stbi__get_marker(j); + } + if (j->progressive) + stbi__jpeg_finish(j); + return 1; +} + +// static jfif-centered resampling (across block boundaries) + +typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1, + int w, int hs); + +#define stbi__div4(x) ((stbi_uc) ((x) >> 2)) + +static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + STBI_NOTUSED(out); + STBI_NOTUSED(in_far); + STBI_NOTUSED(w); + STBI_NOTUSED(hs); + return in_near; +} + +static stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate two samples vertically for every one in input + int i; + STBI_NOTUSED(hs); + for (i=0; i < w; ++i) + out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2); + return out; +} + +static stbi_uc* stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate two samples horizontally for every one in input + int i; + stbi_uc *input = in_near; + + if (w == 1) { + // if only one sample, can't do any interpolation + out[0] = out[1] = input[0]; + return out; + } + + out[0] = input[0]; + out[1] = stbi__div4(input[0]*3 + input[1] + 2); + for (i=1; i < w-1; ++i) { + int n = 3*input[i]+2; + out[i*2+0] = stbi__div4(n+input[i-1]); + out[i*2+1] = stbi__div4(n+input[i+1]); + } + out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2); + out[i*2+1] = input[w-1]; + + STBI_NOTUSED(in_far); + STBI_NOTUSED(hs); + + return out; +} + +#define stbi__div16(x) ((stbi_uc) ((x) >> 4)) + +static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i,t0,t1; + if (w == 1) { + out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + out[0] = stbi__div4(t1+2); + for (i=1; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i=0,t0,t1; + + if (w == 1) { + out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + // process groups of 8 pixels for as long as we can. + // note we can't handle the last pixel in a row in this loop + // because we need to handle the filter boundary conditions. + for (; i < ((w-1) & ~7); i += 8) { +#if defined(STBI_SSE2) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + __m128i zero = _mm_setzero_si128(); + __m128i farb = _mm_loadl_epi64((__m128i *) (in_far + i)); + __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i)); + __m128i farw = _mm_unpacklo_epi8(farb, zero); + __m128i nearw = _mm_unpacklo_epi8(nearb, zero); + __m128i diff = _mm_sub_epi16(farw, nearw); + __m128i nears = _mm_slli_epi16(nearw, 2); + __m128i curr = _mm_add_epi16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + __m128i prv0 = _mm_slli_si128(curr, 2); + __m128i nxt0 = _mm_srli_si128(curr, 2); + __m128i prev = _mm_insert_epi16(prv0, t1, 0); + __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + __m128i bias = _mm_set1_epi16(8); + __m128i curs = _mm_slli_epi16(curr, 2); + __m128i prvd = _mm_sub_epi16(prev, curr); + __m128i nxtd = _mm_sub_epi16(next, curr); + __m128i curb = _mm_add_epi16(curs, bias); + __m128i even = _mm_add_epi16(prvd, curb); + __m128i odd = _mm_add_epi16(nxtd, curb); + + // interleave even and odd pixels, then undo scaling. + __m128i int0 = _mm_unpacklo_epi16(even, odd); + __m128i int1 = _mm_unpackhi_epi16(even, odd); + __m128i de0 = _mm_srli_epi16(int0, 4); + __m128i de1 = _mm_srli_epi16(int1, 4); + + // pack and write output + __m128i outv = _mm_packus_epi16(de0, de1); + _mm_storeu_si128((__m128i *) (out + i*2), outv); +#elif defined(STBI_NEON) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + uint8x8_t farb = vld1_u8(in_far + i); + uint8x8_t nearb = vld1_u8(in_near + i); + int16x8_t diff = vreinterpretq_s16_u16(vsubl_u8(farb, nearb)); + int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2)); + int16x8_t curr = vaddq_s16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + int16x8_t prv0 = vextq_s16(curr, curr, 7); + int16x8_t nxt0 = vextq_s16(curr, curr, 1); + int16x8_t prev = vsetq_lane_s16(t1, prv0, 0); + int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + int16x8_t curs = vshlq_n_s16(curr, 2); + int16x8_t prvd = vsubq_s16(prev, curr); + int16x8_t nxtd = vsubq_s16(next, curr); + int16x8_t even = vaddq_s16(curs, prvd); + int16x8_t odd = vaddq_s16(curs, nxtd); + + // undo scaling and round, then store with even/odd phases interleaved + uint8x8x2_t o; + o.val[0] = vqrshrun_n_s16(even, 4); + o.val[1] = vqrshrun_n_s16(odd, 4); + vst2_u8(out + i*2, o); +#endif + + // "previous" value for next iter + t1 = 3*in_near[i+7] + in_far[i+7]; + } + + t0 = t1; + t1 = 3*in_near[i] + in_far[i]; + out[i*2] = stbi__div16(3*t1 + t0 + 8); + + for (++i; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} +#endif + +static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // resample with nearest-neighbor + int i,j; + STBI_NOTUSED(in_far); + for (i=0; i < w; ++i) + for (j=0; j < hs; ++j) + out[i*hs+j] = in_near[i]; + return out; +} + +// this is a reduced-precision calculation of YCbCr-to-RGB introduced +// to make sure the code produces the same results in both SIMD and scalar +#define stbi__float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8) +static 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) +{ + int i; + for (i=0; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* stbi__float2fixed(1.40200f); + g = y_fixed + (cr*-stbi__float2fixed(0.71414f)) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static 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) +{ + int i = 0; + +#ifdef STBI_SSE2 + // step == 3 is pretty ugly on the final interleave, and i'm not convinced + // it's useful in practice (you wouldn't use it for textures, for example). + // so just accelerate step == 4 case. + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + __m128i signflip = _mm_set1_epi8(-0x80); + __m128i cr_const0 = _mm_set1_epi16( (short) ( 1.40200f*4096.0f+0.5f)); + __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f)); + __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f)); + __m128i cb_const1 = _mm_set1_epi16( (short) ( 1.77200f*4096.0f+0.5f)); + __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128); + __m128i xw = _mm_set1_epi16(255); // alpha channel + + for (; i+7 < count; i += 8) { + // load + __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i)); + __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i)); + __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i)); + __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128 + __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128 + + // unpack to short (and left-shift cr, cb by 8) + __m128i yw = _mm_unpacklo_epi8(y_bias, y_bytes); + __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased); + __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased); + + // color transform + __m128i yws = _mm_srli_epi16(yw, 4); + __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw); + __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw); + __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1); + __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1); + __m128i rws = _mm_add_epi16(cr0, yws); + __m128i gwt = _mm_add_epi16(cb0, yws); + __m128i bws = _mm_add_epi16(yws, cb1); + __m128i gws = _mm_add_epi16(gwt, cr1); + + // descale + __m128i rw = _mm_srai_epi16(rws, 4); + __m128i bw = _mm_srai_epi16(bws, 4); + __m128i gw = _mm_srai_epi16(gws, 4); + + // back to byte, set up for transpose + __m128i brb = _mm_packus_epi16(rw, bw); + __m128i gxb = _mm_packus_epi16(gw, xw); + + // transpose to interleave channels + __m128i t0 = _mm_unpacklo_epi8(brb, gxb); + __m128i t1 = _mm_unpackhi_epi8(brb, gxb); + __m128i o0 = _mm_unpacklo_epi16(t0, t1); + __m128i o1 = _mm_unpackhi_epi16(t0, t1); + + // store + _mm_storeu_si128((__m128i *) (out + 0), o0); + _mm_storeu_si128((__m128i *) (out + 16), o1); + out += 32; + } + } +#endif + +#ifdef STBI_NEON + // in this version, step=3 support would be easy to add. but is there demand? + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + uint8x8_t signflip = vdup_n_u8(0x80); + int16x8_t cr_const0 = vdupq_n_s16( (short) ( 1.40200f*4096.0f+0.5f)); + int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f)); + int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f)); + int16x8_t cb_const1 = vdupq_n_s16( (short) ( 1.77200f*4096.0f+0.5f)); + + for (; i+7 < count; i += 8) { + // load + uint8x8_t y_bytes = vld1_u8(y + i); + uint8x8_t cr_bytes = vld1_u8(pcr + i); + uint8x8_t cb_bytes = vld1_u8(pcb + i); + int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip)); + int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip)); + + // expand to s16 + int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4)); + int16x8_t crw = vshll_n_s8(cr_biased, 7); + int16x8_t cbw = vshll_n_s8(cb_biased, 7); + + // color transform + int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0); + int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0); + int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1); + int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1); + int16x8_t rws = vaddq_s16(yws, cr0); + int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1); + int16x8_t bws = vaddq_s16(yws, cb1); + + // undo scaling, round, convert to byte + uint8x8x4_t o; + o.val[0] = vqrshrun_n_s16(rws, 4); + o.val[1] = vqrshrun_n_s16(gws, 4); + o.val[2] = vqrshrun_n_s16(bws, 4); + o.val[3] = vdup_n_u8(255); + + // store, interleaving r/g/b/a + vst4_u8(out, o); + out += 8*4; + } + } +#endif + + for (; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* stbi__float2fixed(1.40200f); + g = y_fixed + cr*-stbi__float2fixed(0.71414f) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} +#endif + +// set up the kernels +static void stbi__setup_jpeg(stbi__jpeg *j) +{ + j->idct_block_kernel = stbi__idct_block; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2; + +#ifdef STBI_SSE2 + if (stbi__sse2_available()) { + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; + } +#endif + +#ifdef STBI_NEON + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; +#endif +} + +// clean up the temporary component buffers +static void stbi__cleanup_jpeg(stbi__jpeg *j) +{ + stbi__free_jpeg_components(j, j->s->img_n, 0); +} + +typedef struct +{ + resample_row_func resample; + stbi_uc *line0,*line1; + int hs,vs; // expansion factor in each axis + int w_lores; // horizontal pixels pre-expansion + int ystep; // how far through vertical expansion we are + int ypos; // which pre-expansion row we're on +} stbi__resample; + +// fast 0..255 * 0..255 => 0..255 rounded multiplication +static stbi_uc stbi__blinn_8x8(stbi_uc x, stbi_uc y) +{ + unsigned int t = x*y + 128; + return (stbi_uc) ((t + (t >>8)) >> 8); +} + +static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp) +{ + int n, decode_n, is_rgb; + z->s->img_n = 0; // make stbi__cleanup_jpeg safe + + // validate req_comp + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + + // load a jpeg image from whichever source, but leave in YCbCr format + if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; } + + // determine actual number of components to generate + n = req_comp ? req_comp : z->s->img_n >= 3 ? 3 : 1; + + is_rgb = z->s->img_n == 3 && (z->rgb == 3 || (z->app14_color_transform == 0 && !z->jfif)); + + if (z->s->img_n == 3 && n < 3 && !is_rgb) + decode_n = 1; + else + decode_n = z->s->img_n; + + // resample and color-convert + { + int k; + unsigned int i,j; + stbi_uc *output; + stbi_uc *coutput[4]; + + stbi__resample res_comp[4]; + + for (k=0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + + // allocate line buffer big enough for upsampling off the edges + // with upsample factor of 4 + z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3); + if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + + r->hs = z->img_h_max / z->img_comp[k].h; + r->vs = z->img_v_max / z->img_comp[k].v; + r->ystep = r->vs >> 1; + r->w_lores = (z->s->img_x + r->hs-1) / r->hs; + r->ypos = 0; + r->line0 = r->line1 = z->img_comp[k].data; + + if (r->hs == 1 && r->vs == 1) r->resample = resample_row_1; + else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2; + else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2; + else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel; + else r->resample = stbi__resample_row_generic; + } + + // can't error after this so, this is safe + output = (stbi_uc *) stbi__malloc_mad3(n, z->s->img_x, z->s->img_y, 1); + if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + + // now go ahead and resample + for (j=0; j < z->s->img_y; ++j) { + stbi_uc *out = output + n * z->s->img_x * j; + for (k=0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + int y_bot = r->ystep >= (r->vs >> 1); + coutput[k] = r->resample(z->img_comp[k].linebuf, + y_bot ? r->line1 : r->line0, + y_bot ? r->line0 : r->line1, + r->w_lores, r->hs); + if (++r->ystep >= r->vs) { + r->ystep = 0; + r->line0 = r->line1; + if (++r->ypos < z->img_comp[k].y) + r->line1 += z->img_comp[k].w2; + } + } + if (n >= 3) { + stbi_uc *y = coutput[0]; + if (z->s->img_n == 3) { + if (is_rgb) { + for (i=0; i < z->s->img_x; ++i) { + out[0] = y[i]; + out[1] = coutput[1][i]; + out[2] = coutput[2][i]; + out[3] = 255; + out += n; + } + } else { + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } else if (z->s->img_n == 4) { + if (z->app14_color_transform == 0) { // CMYK + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(coutput[0][i], m); + out[1] = stbi__blinn_8x8(coutput[1][i], m); + out[2] = stbi__blinn_8x8(coutput[2][i], m); + out[3] = 255; + out += n; + } + } else if (z->app14_color_transform == 2) { // YCCK + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(255 - out[0], m); + out[1] = stbi__blinn_8x8(255 - out[1], m); + out[2] = stbi__blinn_8x8(255 - out[2], m); + out += n; + } + } else { // YCbCr + alpha? Ignore the fourth channel for now + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } else + for (i=0; i < z->s->img_x; ++i) { + out[0] = out[1] = out[2] = y[i]; + out[3] = 255; // not used if n==3 + out += n; + } + } else { + if (is_rgb) { + if (n == 1) + for (i=0; i < z->s->img_x; ++i) + *out++ = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + else { + for (i=0; i < z->s->img_x; ++i, out += 2) { + out[0] = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + out[1] = 255; + } + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 0) { + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + stbi_uc r = stbi__blinn_8x8(coutput[0][i], m); + stbi_uc g = stbi__blinn_8x8(coutput[1][i], m); + stbi_uc b = stbi__blinn_8x8(coutput[2][i], m); + out[0] = stbi__compute_y(r, g, b); + out[1] = 255; + out += n; + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 2) { + for (i=0; i < z->s->img_x; ++i) { + out[0] = stbi__blinn_8x8(255 - coutput[0][i], coutput[3][i]); + out[1] = 255; + out += n; + } + } else { + stbi_uc *y = coutput[0]; + if (n == 1) + for (i=0; i < z->s->img_x; ++i) out[i] = y[i]; + else + for (i=0; i < z->s->img_x; ++i) *out++ = y[i], *out++ = 255; + } + } + } + stbi__cleanup_jpeg(z); + *out_x = z->s->img_x; + *out_y = z->s->img_y; + if (comp) *comp = z->s->img_n >= 3 ? 3 : 1; // report original components, not output + return output; + } +} + +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + unsigned char* result; + stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg)); + STBI_NOTUSED(ri); + j->s = s; + stbi__setup_jpeg(j); + result = load_jpeg_image(j, x,y,comp,req_comp); + STBI_FREE(j); + return result; +} + +static int stbi__jpeg_test(stbi__context *s) +{ + int r; + stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg)); + j->s = s; + stbi__setup_jpeg(j); + r = stbi__decode_jpeg_header(j, STBI__SCAN_type); + stbi__rewind(s); + STBI_FREE(j); + return r; +} + +static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp) +{ + if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) { + stbi__rewind( j->s ); + return 0; + } + if (x) *x = j->s->img_x; + if (y) *y = j->s->img_y; + if (comp) *comp = j->s->img_n >= 3 ? 3 : 1; + return 1; +} + +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) +{ + int result; + stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg))); + j->s = s; + result = stbi__jpeg_info_raw(j, x, y, comp); + STBI_FREE(j); + return result; +} +#endif + +// public domain zlib decode v0.2 Sean Barrett 2006-11-18 +// simple implementation +// - all input must be provided in an upfront buffer +// - all output is written to a single output buffer (can malloc/realloc) +// performance +// - fast huffman + +#ifndef STBI_NO_ZLIB + +// fast-way is faster to check than jpeg huffman, but slow way is slower +#define STBI__ZFAST_BITS 9 // accelerate all cases in default tables +#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) + +// zlib-style huffman encoding +// (jpegs packs from left, zlib from right, so can't share code) +typedef struct +{ + stbi__uint16 fast[1 << STBI__ZFAST_BITS]; + stbi__uint16 firstcode[16]; + int maxcode[17]; + stbi__uint16 firstsymbol[16]; + stbi_uc size[288]; + stbi__uint16 value[288]; +} stbi__zhuffman; + +stbi_inline static int stbi__bitreverse16(int n) +{ + n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); + n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); + n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); + n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); + return n; +} + +stbi_inline static int stbi__bit_reverse(int v, int bits) +{ + STBI_ASSERT(bits <= 16); + // to bit reverse n bits, reverse 16 and shift + // e.g. 11 bits, bit reverse and shift away 5 + return stbi__bitreverse16(v) >> (16-bits); +} + +static int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int num) +{ + int i,k=0; + int code, next_code[16], sizes[17]; + + // DEFLATE spec for generating codes + memset(sizes, 0, sizeof(sizes)); + memset(z->fast, 0, sizeof(z->fast)); + for (i=0; i < num; ++i) + ++sizes[sizelist[i]]; + sizes[0] = 0; + for (i=1; i < 16; ++i) + if (sizes[i] > (1 << i)) + return stbi__err("bad sizes", "Corrupt PNG"); + code = 0; + for (i=1; i < 16; ++i) { + next_code[i] = code; + z->firstcode[i] = (stbi__uint16) code; + z->firstsymbol[i] = (stbi__uint16) k; + code = (code + sizes[i]); + if (sizes[i]) + if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt PNG"); + z->maxcode[i] = code << (16-i); // preshift for inner loop + code <<= 1; + k += sizes[i]; + } + z->maxcode[16] = 0x10000; // sentinel + for (i=0; i < num; ++i) { + int s = sizelist[i]; + if (s) { + int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; + stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i); + z->size [c] = (stbi_uc ) s; + z->value[c] = (stbi__uint16) i; + if (s <= STBI__ZFAST_BITS) { + int j = stbi__bit_reverse(next_code[s],s); + while (j < (1 << STBI__ZFAST_BITS)) { + z->fast[j] = fastv; + j += (1 << s); + } + } + ++next_code[s]; + } + } + return 1; +} + +// zlib-from-memory implementation for PNG reading +// because PNG allows splitting the zlib stream arbitrarily, +// and it's annoying structurally to have PNG call ZLIB call PNG, +// we require PNG read all the IDATs and combine them into a single +// memory buffer + +typedef struct +{ + stbi_uc *zbuffer, *zbuffer_end; + int num_bits; + stbi__uint32 code_buffer; + + char *zout; + char *zout_start; + char *zout_end; + int z_expandable; + + stbi__zhuffman z_length, z_distance; +} stbi__zbuf; + +stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z) +{ + if (z->zbuffer >= z->zbuffer_end) return 0; + return *z->zbuffer++; +} + +static void stbi__fill_bits(stbi__zbuf *z) +{ + do { + STBI_ASSERT(z->code_buffer < (1U << z->num_bits)); + z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits; + z->num_bits += 8; + } while (z->num_bits <= 24); +} + +stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n) +{ + unsigned int k; + if (z->num_bits < n) stbi__fill_bits(z); + k = z->code_buffer & ((1 << n) - 1); + z->code_buffer >>= n; + z->num_bits -= n; + return k; +} + +static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s,k; + // not resolved by fast table, so compute it the slow way + // use jpeg approach, which requires MSbits at top + k = stbi__bit_reverse(a->code_buffer, 16); + for (s=STBI__ZFAST_BITS+1; ; ++s) + if (k < z->maxcode[s]) + break; + if (s == 16) return -1; // invalid code! + // code size is s, so: + b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; + STBI_ASSERT(z->size[b] == s); + a->code_buffer >>= s; + a->num_bits -= s; + return z->value[b]; +} + +stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s; + if (a->num_bits < 16) stbi__fill_bits(a); + b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; + if (b) { + s = b >> 9; + a->code_buffer >>= s; + a->num_bits -= s; + return b & 511; + } + return stbi__zhuffman_decode_slowpath(a, z); +} + +static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes +{ + char *q; + int cur, limit, old_limit; + z->zout = zout; + if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); + cur = (int) (z->zout - z->zout_start); + limit = old_limit = (int) (z->zout_end - z->zout_start); + while (cur + n > limit) + limit *= 2; + q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit); + STBI_NOTUSED(old_limit); + if (q == NULL) return stbi__err("outofmem", "Out of memory"); + z->zout_start = q; + z->zout = q + cur; + z->zout_end = q + limit; + return 1; +} + +static const int stbi__zlength_base[31] = { + 3,4,5,6,7,8,9,10,11,13, + 15,17,19,23,27,31,35,43,51,59, + 67,83,99,115,131,163,195,227,258,0,0 }; + +static const int stbi__zlength_extra[31]= +{ 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 }; + +static const int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, +257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; + +static const int stbi__zdist_extra[32] = +{ 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}; + +static int stbi__parse_huffman_block(stbi__zbuf *a) +{ + char *zout = a->zout; + for(;;) { + int z = stbi__zhuffman_decode(a, &a->z_length); + if (z < 256) { + if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); // error in huffman codes + if (zout >= a->zout_end) { + if (!stbi__zexpand(a, zout, 1)) return 0; + zout = a->zout; + } + *zout++ = (char) z; + } else { + stbi_uc *p; + int len,dist; + if (z == 256) { + a->zout = zout; + return 1; + } + z -= 257; + len = stbi__zlength_base[z]; + if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); + z = stbi__zhuffman_decode(a, &a->z_distance); + if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); + dist = stbi__zdist_base[z]; + if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); + if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); + if (zout + len > a->zout_end) { + if (!stbi__zexpand(a, zout, len)) return 0; + zout = a->zout; + } + p = (stbi_uc *) (zout - dist); + if (dist == 1) { // run of one byte; common in images. + stbi_uc v = *p; + if (len) { do *zout++ = v; while (--len); } + } else { + if (len) { do *zout++ = *p++; while (--len); } + } + } + } +} + +static int stbi__compute_huffman_codes(stbi__zbuf *a) +{ + 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 }; + stbi__zhuffman z_codelength; + stbi_uc lencodes[286+32+137];//padding for maximum single op + stbi_uc codelength_sizes[19]; + int i,n; + + int hlit = stbi__zreceive(a,5) + 257; + int hdist = stbi__zreceive(a,5) + 1; + int hclen = stbi__zreceive(a,4) + 4; + int ntot = hlit + hdist; + + memset(codelength_sizes, 0, sizeof(codelength_sizes)); + for (i=0; i < hclen; ++i) { + int s = stbi__zreceive(a,3); + codelength_sizes[length_dezigzag[i]] = (stbi_uc) s; + } + if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; + + n = 0; + while (n < ntot) { + int c = stbi__zhuffman_decode(a, &z_codelength); + if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG"); + if (c < 16) + lencodes[n++] = (stbi_uc) c; + else { + stbi_uc fill = 0; + if (c == 16) { + c = stbi__zreceive(a,2)+3; + if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG"); + fill = lencodes[n-1]; + } else if (c == 17) + c = stbi__zreceive(a,3)+3; + else { + STBI_ASSERT(c == 18); + c = stbi__zreceive(a,7)+11; + } + if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG"); + memset(lencodes+n, fill, c); + n += c; + } + } + if (n != ntot) return stbi__err("bad codelengths","Corrupt PNG"); + if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; + return 1; +} + +static int stbi__parse_uncompressed_block(stbi__zbuf *a) +{ + stbi_uc header[4]; + int len,nlen,k; + if (a->num_bits & 7) + stbi__zreceive(a, a->num_bits & 7); // discard + // drain the bit-packed data into header + k = 0; + while (a->num_bits > 0) { + header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check + a->code_buffer >>= 8; + a->num_bits -= 8; + } + STBI_ASSERT(a->num_bits == 0); + // now fill header the normal way + while (k < 4) + header[k++] = stbi__zget8(a); + len = header[1] * 256 + header[0]; + nlen = header[3] * 256 + header[2]; + if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG"); + if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG"); + if (a->zout + len > a->zout_end) + if (!stbi__zexpand(a, a->zout, len)) return 0; + memcpy(a->zout, a->zbuffer, len); + a->zbuffer += len; + a->zout += len; + return 1; +} + +static int stbi__parse_zlib_header(stbi__zbuf *a) +{ + int cmf = stbi__zget8(a); + int cm = cmf & 15; + /* int cinfo = cmf >> 4; */ + int flg = stbi__zget8(a); + if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec + if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png + if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png + // window = 1 << (8 + cinfo)... but who cares, we fully buffer output + return 1; +} + +static const stbi_uc stbi__zdefault_length[288] = +{ + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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 +}; +static const stbi_uc stbi__zdefault_distance[32] = +{ + 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 +}; +/* +Init algorithm: +{ + int i; // use <= to match clearly with spec + for (i=0; i <= 143; ++i) stbi__zdefault_length[i] = 8; + for ( ; i <= 255; ++i) stbi__zdefault_length[i] = 9; + for ( ; i <= 279; ++i) stbi__zdefault_length[i] = 7; + for ( ; i <= 287; ++i) stbi__zdefault_length[i] = 8; + + for (i=0; i <= 31; ++i) stbi__zdefault_distance[i] = 5; +} +*/ + +static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) +{ + int final, type; + if (parse_header) + if (!stbi__parse_zlib_header(a)) return 0; + a->num_bits = 0; + a->code_buffer = 0; + do { + final = stbi__zreceive(a,1); + type = stbi__zreceive(a,2); + if (type == 0) { + if (!stbi__parse_uncompressed_block(a)) return 0; + } else if (type == 3) { + return 0; + } else { + if (type == 1) { + // use fixed code lengths + if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , 288)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; + } else { + if (!stbi__compute_huffman_codes(a)) return 0; + } + if (!stbi__parse_huffman_block(a)) return 0; + } + } while (!final); + return 1; +} + +static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header) +{ + a->zout_start = obuf; + a->zout = obuf; + a->zout_end = obuf + olen; + a->z_expandable = exp; + + return stbi__parse_zlib(a, parse_header); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, 1)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen) +{ + return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 1)) + return (int) (a.zout - a.zout_start); + else + return -1; +} + +STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(16384); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer+len; + if (stbi__do_zlib(&a, p, 16384, 1, 0)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 0)) + return (int) (a.zout - a.zout_start); + else + return -1; +} +#endif + +// public domain "baseline" PNG decoder v0.10 Sean Barrett 2006-11-18 +// simple implementation +// - only 8-bit samples +// - no CRC checking +// - allocates lots of intermediate memory +// - avoids problem of streaming data between subsystems +// - avoids explicit window management +// performance +// - uses stb_zlib, a PD zlib implementation with fast huffman decoding + +#ifndef STBI_NO_PNG +typedef struct +{ + stbi__uint32 length; + stbi__uint32 type; +} stbi__pngchunk; + +static stbi__pngchunk stbi__get_chunk_header(stbi__context *s) +{ + stbi__pngchunk c; + c.length = stbi__get32be(s); + c.type = stbi__get32be(s); + return c; +} + +static int stbi__check_png_header(stbi__context *s) +{ + static const stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 }; + int i; + for (i=0; i < 8; ++i) + if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG"); + return 1; +} + +typedef struct +{ + stbi__context *s; + stbi_uc *idata, *expanded, *out; + int depth; +} stbi__png; + + +enum { + STBI__F_none=0, + STBI__F_sub=1, + STBI__F_up=2, + STBI__F_avg=3, + STBI__F_paeth=4, + // synthetic filters used for first scanline to avoid needing a dummy row of 0s + STBI__F_avg_first, + STBI__F_paeth_first +}; + +static stbi_uc first_row_filter[5] = +{ + STBI__F_none, + STBI__F_sub, + STBI__F_none, + STBI__F_avg_first, + STBI__F_paeth_first +}; + +static int stbi__paeth(int a, int b, int c) +{ + int p = a + b - c; + int pa = abs(p-a); + int pb = abs(p-b); + int pc = abs(p-c); + if (pa <= pb && pa <= pc) return a; + if (pb <= pc) return b; + return c; +} + +static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; + +// create the png data from post-deflated data +static 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) +{ + int bytes = (depth == 16? 2 : 1); + stbi__context *s = a->s; + stbi__uint32 i,j,stride = x*out_n*bytes; + stbi__uint32 img_len, img_width_bytes; + int k; + int img_n = s->img_n; // copy it into a local for later + + int output_bytes = out_n*bytes; + int filter_bytes = img_n*bytes; + int width = x; + + STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); + a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into + if (!a->out) return stbi__err("outofmem", "Out of memory"); + + if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG"); + img_width_bytes = (((img_n * x * depth) + 7) >> 3); + img_len = (img_width_bytes + 1) * y; + + // we used to check for exact match between raw_len and img_len on non-interlaced PNGs, + // but issue #276 reported a PNG in the wild that had extra data at the end (all zeros), + // so just check for raw_len < img_len always. + if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); + + for (j=0; j < y; ++j) { + stbi_uc *cur = a->out + stride*j; + stbi_uc *prior; + int filter = *raw++; + + if (filter > 4) + return stbi__err("invalid filter","Corrupt PNG"); + + if (depth < 8) { + STBI_ASSERT(img_width_bytes <= x); + cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place + filter_bytes = 1; + width = img_width_bytes; + } + prior = cur - stride; // bugfix: need to compute this after 'cur +=' computation above + + // if first row, use special filter that doesn't sample previous row + if (j == 0) filter = first_row_filter[filter]; + + // handle first byte explicitly + for (k=0; k < filter_bytes; ++k) { + switch (filter) { + case STBI__F_none : cur[k] = raw[k]; break; + case STBI__F_sub : cur[k] = raw[k]; break; + case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; + case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break; + case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break; + case STBI__F_avg_first : cur[k] = raw[k]; break; + case STBI__F_paeth_first: cur[k] = raw[k]; break; + } + } + + if (depth == 8) { + if (img_n != out_n) + cur[img_n] = 255; // first pixel + raw += img_n; + cur += out_n; + prior += out_n; + } else if (depth == 16) { + if (img_n != out_n) { + cur[filter_bytes] = 255; // first pixel top byte + cur[filter_bytes+1] = 255; // first pixel bottom byte + } + raw += filter_bytes; + cur += output_bytes; + prior += output_bytes; + } else { + raw += 1; + cur += 1; + prior += 1; + } + + // this is a little gross, so that we don't switch per-pixel or per-component + if (depth < 8 || img_n == out_n) { + int nk = (width - 1)*filter_bytes; + #define STBI__CASE(f) \ + case f: \ + for (k=0; k < nk; ++k) + switch (filter) { + // "none" filter turns into a memcpy here; make that explicit. + case STBI__F_none: memcpy(cur, raw, nk); break; + STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break; + STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; + STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break; + STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break; + STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break; + STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break; + } + #undef STBI__CASE + raw += nk; + } else { + STBI_ASSERT(img_n+1 == out_n); + #define STBI__CASE(f) \ + case f: \ + for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \ + for (k=0; k < filter_bytes; ++k) + switch (filter) { + STBI__CASE(STBI__F_none) { cur[k] = raw[k]; } break; + STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break; + STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; + STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break; + STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break; + STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break; + STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break; + } + #undef STBI__CASE + + // the loop above sets the high byte of the pixels' alpha, but for + // 16 bit png files we also need the low byte set. we'll do that here. + if (depth == 16) { + cur = a->out + stride*j; // start at the beginning of the row again + for (i=0; i < x; ++i,cur+=output_bytes) { + cur[filter_bytes+1] = 255; + } + } + } + } + + // we make a separate pass to expand bits to pixels; for performance, + // this could run two scanlines behind the above code, so it won't + // intefere with filtering but will still be in the cache. + if (depth < 8) { + for (j=0; j < y; ++j) { + stbi_uc *cur = a->out + stride*j; + stbi_uc *in = a->out + stride*j + x*out_n - img_width_bytes; + // 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 + // 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 + stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range + + // note that the final byte might overshoot and write more data than desired. + // we can allocate enough data that this never writes out of memory, but it + // could also overwrite the next scanline. can it overwrite non-empty data + // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel. + // so we need to explicitly clamp the final ones + + if (depth == 4) { + for (k=x*img_n; k >= 2; k-=2, ++in) { + *cur++ = scale * ((*in >> 4) ); + *cur++ = scale * ((*in ) & 0x0f); + } + if (k > 0) *cur++ = scale * ((*in >> 4) ); + } else if (depth == 2) { + for (k=x*img_n; k >= 4; k-=4, ++in) { + *cur++ = scale * ((*in >> 6) ); + *cur++ = scale * ((*in >> 4) & 0x03); + *cur++ = scale * ((*in >> 2) & 0x03); + *cur++ = scale * ((*in ) & 0x03); + } + if (k > 0) *cur++ = scale * ((*in >> 6) ); + if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03); + if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03); + } else if (depth == 1) { + for (k=x*img_n; k >= 8; k-=8, ++in) { + *cur++ = scale * ((*in >> 7) ); + *cur++ = scale * ((*in >> 6) & 0x01); + *cur++ = scale * ((*in >> 5) & 0x01); + *cur++ = scale * ((*in >> 4) & 0x01); + *cur++ = scale * ((*in >> 3) & 0x01); + *cur++ = scale * ((*in >> 2) & 0x01); + *cur++ = scale * ((*in >> 1) & 0x01); + *cur++ = scale * ((*in ) & 0x01); + } + if (k > 0) *cur++ = scale * ((*in >> 7) ); + if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01); + if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01); + if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01); + if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01); + if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01); + if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01); + } + if (img_n != out_n) { + int q; + // insert alpha = 255 + cur = a->out + stride*j; + if (img_n == 1) { + for (q=x-1; q >= 0; --q) { + cur[q*2+1] = 255; + cur[q*2+0] = cur[q]; + } + } else { + STBI_ASSERT(img_n == 3); + for (q=x-1; q >= 0; --q) { + cur[q*4+3] = 255; + cur[q*4+2] = cur[q*3+2]; + cur[q*4+1] = cur[q*3+1]; + cur[q*4+0] = cur[q*3+0]; + } + } + } + } + } else if (depth == 16) { + // force the image data from big-endian to platform-native. + // this is done in a separate pass due to the decoding relying + // on the data being untouched, but could probably be done + // per-line during decode if care is taken. + stbi_uc *cur = a->out; + stbi__uint16 *cur16 = (stbi__uint16*)cur; + + for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) { + *cur16 = (cur[0] << 8) | cur[1]; + } + } + + return 1; +} + +static 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) +{ + int bytes = (depth == 16 ? 2 : 1); + int out_bytes = out_n * bytes; + stbi_uc *final; + int p; + if (!interlaced) + return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); + + // de-interlacing + final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); + for (p=0; p < 7; ++p) { + int xorig[] = { 0,4,0,2,0,1,0 }; + int yorig[] = { 0,0,4,0,2,0,1 }; + int xspc[] = { 8,8,4,4,2,2,1 }; + int yspc[] = { 8,8,8,4,4,2,2 }; + int i,j,x,y; + // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1 + x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; + y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; + if (x && y) { + stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; + if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { + STBI_FREE(final); + return 0; + } + for (j=0; j < y; ++j) { + for (i=0; i < x; ++i) { + int out_y = j*yspc[p]+yorig[p]; + int out_x = i*xspc[p]+xorig[p]; + memcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes, + a->out + (j*x+i)*out_bytes, out_bytes); + } + } + STBI_FREE(a->out); + image_data += img_len; + image_data_len -= img_len; + } + } + a->out = final; + + return 1; +} + +static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + // compute color-based transparency, assuming we've + // already got 255 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); + + if (out_n == 2) { + for (i=0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 255); + p += 2; + } + } else { + for (i=0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi__uint16 *p = (stbi__uint16*) z->out; + + // compute color-based transparency, assuming we've + // already got 65535 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); + + if (out_n == 2) { + for (i = 0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 65535); + p += 2; + } + } else { + for (i = 0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n) +{ + stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; + stbi_uc *p, *temp_out, *orig = a->out; + + p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0); + if (p == NULL) return stbi__err("outofmem", "Out of memory"); + + // between here and free(out) below, exitting would leak + temp_out = p; + + if (pal_img_n == 3) { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p += 3; + } + } else { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p[3] = palette[n+3]; + p += 4; + } + } + STBI_FREE(a->out); + a->out = temp_out; + + STBI_NOTUSED(len); + + return 1; +} + +static int stbi__unpremultiply_on_load = 0; +static int stbi__de_iphone_flag = 0; + +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) +{ + stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply; +} + +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) +{ + stbi__de_iphone_flag = flag_true_if_should_convert; +} + +static void stbi__de_iphone(stbi__png *z) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + if (s->img_out_n == 3) { // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 3; + } + } else { + STBI_ASSERT(s->img_out_n == 4); + if (stbi__unpremultiply_on_load) { + // convert bgr to rgb and unpremultiply + for (i=0; i < pixel_count; ++i) { + stbi_uc a = p[3]; + stbi_uc t = p[0]; + if (a) { + stbi_uc half = a / 2; + p[0] = (p[2] * 255 + half) / a; + p[1] = (p[1] * 255 + half) / a; + p[2] = ( t * 255 + half) / a; + } else { + p[0] = p[2]; + p[2] = t; + } + p += 4; + } + } else { + // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 4; + } + } + } +} + +#define STBI__PNG_TYPE(a,b,c,d) (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d)) + +static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) +{ + stbi_uc palette[1024], pal_img_n=0; + stbi_uc has_trans=0, tc[3]; + stbi__uint16 tc16[3]; + stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; + int first=1,k,interlace=0, color=0, is_iphone=0; + stbi__context *s = z->s; + + z->expanded = NULL; + z->idata = NULL; + z->out = NULL; + + if (!stbi__check_png_header(s)) return 0; + + if (scan == STBI__SCAN_type) return 1; + + for (;;) { + stbi__pngchunk c = stbi__get_chunk_header(s); + switch (c.type) { + case STBI__PNG_TYPE('C','g','B','I'): + is_iphone = 1; + stbi__skip(s, c.length); + break; + case STBI__PNG_TYPE('I','H','D','R'): { + int comp,filter; + if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); + first = 0; + if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); + s->img_x = stbi__get32be(s); if (s->img_x > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); + s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); + 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"); + color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG"); + comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG"); + filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG"); + interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG"); + if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG"); + if (!pal_img_n) { + s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); + if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); + if (scan == STBI__SCAN_header) return 1; + } else { + // if paletted, then pal_n is our final components, and + // img_n is # components to decompress/filter. + s->img_n = 1; + if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); + // if SCAN_header, have to scan to see if we have a tRNS + } + break; + } + + case STBI__PNG_TYPE('P','L','T','E'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG"); + pal_len = c.length / 3; + if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG"); + for (i=0; i < pal_len; ++i) { + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + } + break; + } + + case STBI__PNG_TYPE('t','R','N','S'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG"); + if (pal_img_n) { + if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; } + if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG"); + if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG"); + pal_img_n = 4; + for (i=0; i < c.length; ++i) + palette[i*4+3] = stbi__get8(s); + } else { + if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); + if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); + has_trans = 1; + if (z->depth == 16) { + for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is + } else { + 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 + } + } + break; + } + + case STBI__PNG_TYPE('I','D','A','T'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); + if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; } + if ((int)(ioff + c.length) < (int)ioff) return 0; + if (ioff + c.length > idata_limit) { + stbi__uint32 idata_limit_old = idata_limit; + stbi_uc *p; + if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; + while (ioff + c.length > idata_limit) + idata_limit *= 2; + STBI_NOTUSED(idata_limit_old); + p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory"); + z->idata = p; + } + if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG"); + ioff += c.length; + break; + } + + case STBI__PNG_TYPE('I','E','N','D'): { + stbi__uint32 raw_len, bpl; + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (scan != STBI__SCAN_load) return 1; + if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG"); + // initial guess for decoded data size to avoid unnecessary reallocs + bpl = (s->img_x * z->depth + 7) / 8; // bytes per line, per component + raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; + z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone); + if (z->expanded == NULL) return 0; // zlib should set error + STBI_FREE(z->idata); z->idata = NULL; + if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) + s->img_out_n = s->img_n+1; + else + s->img_out_n = s->img_n; + if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0; + if (has_trans) { + if (z->depth == 16) { + if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0; + } else { + if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0; + } + } + if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2) + stbi__de_iphone(z); + if (pal_img_n) { + // pal_img_n == 3 or 4 + s->img_n = pal_img_n; // record the actual colors we had + s->img_out_n = pal_img_n; + if (req_comp >= 3) s->img_out_n = req_comp; + if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) + return 0; + } else if (has_trans) { + // non-paletted image with tRNS -> source image has (constant) alpha + ++s->img_n; + } + STBI_FREE(z->expanded); z->expanded = NULL; + return 1; + } + + default: + // if critical, fail + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if ((c.type & (1 << 29)) == 0) { + #ifndef STBI_NO_FAILURE_STRINGS + // not threadsafe + static char invalid_chunk[] = "XXXX PNG chunk not known"; + invalid_chunk[0] = STBI__BYTECAST(c.type >> 24); + invalid_chunk[1] = STBI__BYTECAST(c.type >> 16); + invalid_chunk[2] = STBI__BYTECAST(c.type >> 8); + invalid_chunk[3] = STBI__BYTECAST(c.type >> 0); + #endif + return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type"); + } + stbi__skip(s, c.length); + break; + } + // end of PNG chunk, read and skip CRC + stbi__get32be(s); + } +} + +static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri) +{ + void *result=NULL; + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { + if (p->depth < 8) + ri->bits_per_channel = 8; + else + ri->bits_per_channel = p->depth; + result = p->out; + p->out = NULL; + if (req_comp && req_comp != p->s->img_out_n) { + if (ri->bits_per_channel == 8) + result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + else + result = stbi__convert_format16((stbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + p->s->img_out_n = req_comp; + if (result == NULL) return result; + } + *x = p->s->img_x; + *y = p->s->img_y; + if (n) *n = p->s->img_n; + } + STBI_FREE(p->out); p->out = NULL; + STBI_FREE(p->expanded); p->expanded = NULL; + STBI_FREE(p->idata); p->idata = NULL; + + return result; +} + +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi__png p; + p.s = s; + return stbi__do_png(&p, x,y,comp,req_comp, ri); +} + +static int stbi__png_test(stbi__context *s) +{ + int r; + r = stbi__check_png_header(s); + stbi__rewind(s); + return r; +} + +static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp) +{ + if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) { + stbi__rewind( p->s ); + return 0; + } + if (x) *x = p->s->img_x; + if (y) *y = p->s->img_y; + if (comp) *comp = p->s->img_n; + return 1; +} + +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__png p; + p.s = s; + return stbi__png_info_raw(&p, x, y, comp); +} + +static int stbi__png_is16(stbi__context *s) +{ + stbi__png p; + p.s = s; + if (!stbi__png_info_raw(&p, NULL, NULL, NULL)) + return 0; + if (p.depth != 16) { + stbi__rewind(p.s); + return 0; + } + return 1; +} +#endif + +// Microsoft/Windows BMP image + +#ifndef STBI_NO_BMP +static int stbi__bmp_test_raw(stbi__context *s) +{ + int r; + int sz; + if (stbi__get8(s) != 'B') return 0; + if (stbi__get8(s) != 'M') return 0; + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + stbi__get32le(s); // discard data offset + sz = stbi__get32le(s); + r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124); + return r; +} + +static int stbi__bmp_test(stbi__context *s) +{ + int r = stbi__bmp_test_raw(s); + stbi__rewind(s); + return r; +} + + +// returns 0..31 for the highest set bit +static int stbi__high_bit(unsigned int z) +{ + int n=0; + if (z == 0) return -1; + if (z >= 0x10000) n += 16, z >>= 16; + if (z >= 0x00100) n += 8, z >>= 8; + if (z >= 0x00010) n += 4, z >>= 4; + if (z >= 0x00004) n += 2, z >>= 2; + if (z >= 0x00002) n += 1, z >>= 1; + return n; +} + +static int stbi__bitcount(unsigned int a) +{ + a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 + a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 + a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits + a = (a + (a >> 8)); // max 16 per 8 bits + a = (a + (a >> 16)); // max 32 per 8 bits + return a & 0xff; +} + +// extract an arbitrarily-aligned N-bit value (N=bits) +// from v, and then make it 8-bits long and fractionally +// extend it to full full range. +static int stbi__shiftsigned(int v, int shift, int bits) +{ + static unsigned int mul_table[9] = { + 0, + 0xff/*0b11111111*/, 0x55/*0b01010101*/, 0x49/*0b01001001*/, 0x11/*0b00010001*/, + 0x21/*0b00100001*/, 0x41/*0b01000001*/, 0x81/*0b10000001*/, 0x01/*0b00000001*/, + }; + static unsigned int shift_table[9] = { + 0, 0,0,1,0,2,4,6,0, + }; + if (shift < 0) + v <<= -shift; + else + v >>= shift; + STBI_ASSERT(v >= 0 && v < 256); + v >>= (8-bits); + STBI_ASSERT(bits >= 0 && bits <= 8); + return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits]; +} + +typedef struct +{ + int bpp, offset, hsz; + unsigned int mr,mg,mb,ma, all_a; +} stbi__bmp_data; + +static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) +{ + int hsz; + if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP"); + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + info->offset = stbi__get32le(s); + info->hsz = hsz = stbi__get32le(s); + info->mr = info->mg = info->mb = info->ma = 0; + + if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); + if (hsz == 12) { + s->img_x = stbi__get16le(s); + s->img_y = stbi__get16le(s); + } else { + s->img_x = stbi__get32le(s); + s->img_y = stbi__get32le(s); + } + if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP"); + info->bpp = stbi__get16le(s); + if (hsz != 12) { + int compress = stbi__get32le(s); + if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); + stbi__get32le(s); // discard sizeof + stbi__get32le(s); // discard hres + stbi__get32le(s); // discard vres + stbi__get32le(s); // discard colorsused + stbi__get32le(s); // discard max important + if (hsz == 40 || hsz == 56) { + if (hsz == 56) { + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + } + if (info->bpp == 16 || info->bpp == 32) { + if (compress == 0) { + if (info->bpp == 32) { + info->mr = 0xffu << 16; + info->mg = 0xffu << 8; + info->mb = 0xffu << 0; + info->ma = 0xffu << 24; + info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 + } else { + info->mr = 31u << 10; + info->mg = 31u << 5; + info->mb = 31u << 0; + } + } else if (compress == 3) { + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + // not documented, but generated by photoshop and handled by mspaint + if (info->mr == info->mg && info->mg == info->mb) { + // ?!?!? + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else { + int i; + if (hsz != 108 && hsz != 124) + return stbi__errpuc("bad BMP", "bad BMP"); + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + info->ma = stbi__get32le(s); + stbi__get32le(s); // discard color space + for (i=0; i < 12; ++i) + stbi__get32le(s); // discard color space parameters + if (hsz == 124) { + stbi__get32le(s); // discard rendering intent + stbi__get32le(s); // discard offset of profile data + stbi__get32le(s); // discard size of profile data + stbi__get32le(s); // discard reserved + } + } + } + return (void *) 1; +} + + +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *out; + unsigned int mr=0,mg=0,mb=0,ma=0, all_a; + stbi_uc pal[256][4]; + int psize=0,i,j,width; + int flip_vertically, pad, target; + stbi__bmp_data info; + STBI_NOTUSED(ri); + + info.all_a = 255; + if (stbi__bmp_parse_header(s, &info) == NULL) + return NULL; // error code already set + + flip_vertically = ((int) s->img_y) > 0; + s->img_y = abs((int) s->img_y); + + mr = info.mr; + mg = info.mg; + mb = info.mb; + ma = info.ma; + all_a = info.all_a; + + if (info.hsz == 12) { + if (info.bpp < 24) + psize = (info.offset - 14 - 24) / 3; + } else { + if (info.bpp < 16) + psize = (info.offset - 14 - info.hsz) >> 2; + } + + s->img_n = ma ? 4 : 3; + if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 + target = req_comp; + else + target = s->img_n; // if they want monochrome, we'll post-convert + + // sanity-check size + if (!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0)) + return stbi__errpuc("too large", "Corrupt BMP"); + + out = (stbi_uc *) stbi__malloc_mad3(target, s->img_x, s->img_y, 0); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + if (info.bpp < 16) { + int z=0; + if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); } + for (i=0; i < psize; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + if (info.hsz != 12) stbi__get8(s); + pal[i][3] = 255; + } + stbi__skip(s, info.offset - 14 - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); + if (info.bpp == 1) width = (s->img_x + 7) >> 3; + else if (info.bpp == 4) width = (s->img_x + 1) >> 1; + else if (info.bpp == 8) width = s->img_x; + else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); } + pad = (-width)&3; + if (info.bpp == 1) { + for (j=0; j < (int) s->img_y; ++j) { + int bit_offset = 7, v = stbi__get8(s); + for (i=0; i < (int) s->img_x; ++i) { + int color = (v>>bit_offset)&0x1; + out[z++] = pal[color][0]; + out[z++] = pal[color][1]; + out[z++] = pal[color][2]; + if((--bit_offset) < 0) { + bit_offset = 7; + v = stbi__get8(s); + } + } + stbi__skip(s, pad); + } + } else { + for (j=0; j < (int) s->img_y; ++j) { + for (i=0; i < (int) s->img_x; i += 2) { + int v=stbi__get8(s),v2=0; + if (info.bpp == 4) { + v2 = v & 15; + v >>= 4; + } + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + if (i+1 == (int) s->img_x) break; + v = (info.bpp == 8) ? stbi__get8(s) : v2; + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + } + stbi__skip(s, pad); + } + } + } else { + int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; + int z = 0; + int easy=0; + stbi__skip(s, info.offset - 14 - info.hsz); + if (info.bpp == 24) width = 3 * s->img_x; + else if (info.bpp == 16) width = 2*s->img_x; + else /* bpp = 32 and pad = 0 */ width=0; + pad = (-width) & 3; + if (info.bpp == 24) { + easy = 1; + } else if (info.bpp == 32) { + if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) + easy = 2; + } + if (!easy) { + if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } + // right shift amt to put high bit in position #7 + rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr); + gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg); + bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb); + ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma); + } + for (j=0; j < (int) s->img_y; ++j) { + if (easy) { + for (i=0; i < (int) s->img_x; ++i) { + unsigned char a; + out[z+2] = stbi__get8(s); + out[z+1] = stbi__get8(s); + out[z+0] = stbi__get8(s); + z += 3; + a = (easy == 2 ? stbi__get8(s) : 255); + all_a |= a; + if (target == 4) out[z++] = a; + } + } else { + int bpp = info.bpp; + for (i=0; i < (int) s->img_x; ++i) { + stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s)); + unsigned int a; + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount)); + a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255); + all_a |= a; + if (target == 4) out[z++] = STBI__BYTECAST(a); + } + } + stbi__skip(s, pad); + } + } + + // if alpha channel is all 0s, replace with all 255s + if (target == 4 && all_a == 0) + for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4) + out[i] = 255; + + if (flip_vertically) { + stbi_uc t; + for (j=0; j < (int) s->img_y>>1; ++j) { + stbi_uc *p1 = out + j *s->img_x*target; + stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target; + for (i=0; i < (int) s->img_x*target; ++i) { + t = p1[i], p1[i] = p2[i], p2[i] = t; + } + } + } + + if (req_comp && req_comp != target) { + out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + *x = s->img_x; + *y = s->img_y; + if (comp) *comp = s->img_n; + return out; +} +#endif + +// Targa Truevision - TGA +// by Jonathan Dummer +#ifndef STBI_NO_TGA +// returns STBI_rgb or whatever, 0 on error +static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16) +{ + // only RGB or RGBA (incl. 16bit) or grey allowed + if (is_rgb16) *is_rgb16 = 0; + switch(bits_per_pixel) { + case 8: return STBI_grey; + case 16: if(is_grey) return STBI_grey_alpha; + // fallthrough + case 15: if(is_rgb16) *is_rgb16 = 1; + return STBI_rgb; + case 24: // fallthrough + case 32: return bits_per_pixel/8; + default: return 0; + } +} + +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) +{ + int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp; + int sz, tga_colormap_type; + stbi__get8(s); // discard Offset + tga_colormap_type = stbi__get8(s); // colormap type + if( tga_colormap_type > 1 ) { + stbi__rewind(s); + return 0; // only RGB or indexed allowed + } + tga_image_type = stbi__get8(s); // image type + if ( tga_colormap_type == 1 ) { // colormapped (paletted) image + if (tga_image_type != 1 && tga_image_type != 9) { + stbi__rewind(s); + return 0; + } + stbi__skip(s,4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) { + stbi__rewind(s); + return 0; + } + stbi__skip(s,4); // skip image x and y origin + tga_colormap_bpp = sz; + } else { // "normal" image w/o colormap - only RGB or grey allowed, +/- RLE + if ( (tga_image_type != 2) && (tga_image_type != 3) && (tga_image_type != 10) && (tga_image_type != 11) ) { + stbi__rewind(s); + return 0; // only RGB or grey allowed, +/- RLE + } + stbi__skip(s,9); // skip colormap specification and image x/y origin + tga_colormap_bpp = 0; + } + tga_w = stbi__get16le(s); + if( tga_w < 1 ) { + stbi__rewind(s); + return 0; // test width + } + tga_h = stbi__get16le(s); + if( tga_h < 1 ) { + stbi__rewind(s); + return 0; // test height + } + tga_bits_per_pixel = stbi__get8(s); // bits per pixel + stbi__get8(s); // ignore alpha bits + if (tga_colormap_bpp != 0) { + if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) { + // when using a colormap, tga_bits_per_pixel is the size of the indexes + // I don't think anything but 8 or 16bit indexes makes sense + stbi__rewind(s); + return 0; + } + tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL); + } else { + tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), NULL); + } + if(!tga_comp) { + stbi__rewind(s); + return 0; + } + if (x) *x = tga_w; + if (y) *y = tga_h; + if (comp) *comp = tga_comp; + return 1; // seems to have passed everything +} + +static int stbi__tga_test(stbi__context *s) +{ + int res = 0; + int sz, tga_color_type; + stbi__get8(s); // discard Offset + tga_color_type = stbi__get8(s); // color type + if ( tga_color_type > 1 ) goto errorEnd; // only RGB or indexed allowed + sz = stbi__get8(s); // image type + if ( tga_color_type == 1 ) { // colormapped (paletted) image + if (sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9 + stbi__skip(s,4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; + stbi__skip(s,4); // skip image x and y origin + } else { // "normal" image w/o colormap + if ( (sz != 2) && (sz != 3) && (sz != 10) && (sz != 11) ) goto errorEnd; // only RGB or grey allowed, +/- RLE + stbi__skip(s,9); // skip colormap specification and image x/y origin + } + if ( stbi__get16le(s) < 1 ) goto errorEnd; // test width + if ( stbi__get16le(s) < 1 ) goto errorEnd; // test height + sz = stbi__get8(s); // bits per pixel + if ( (tga_color_type == 1) && (sz != 8) && (sz != 16) ) goto errorEnd; // for colormapped images, bpp is size of an index + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; + + res = 1; // if we got this far, everything's good and we can return 1 instead of 0 + +errorEnd: + stbi__rewind(s); + return res; +} + +// read 16bit value and convert to 24bit RGB +static void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out) +{ + stbi__uint16 px = (stbi__uint16)stbi__get16le(s); + stbi__uint16 fiveBitMask = 31; + // we have 3 channels with 5bits each + int r = (px >> 10) & fiveBitMask; + int g = (px >> 5) & fiveBitMask; + int b = px & fiveBitMask; + // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later + out[0] = (stbi_uc)((r * 255)/31); + out[1] = (stbi_uc)((g * 255)/31); + out[2] = (stbi_uc)((b * 255)/31); + + // some people claim that the most significant bit might be used for alpha + // (possibly if an alpha-bit is set in the "image descriptor byte") + // but that only made 16bit test images completely translucent.. + // so let's treat all 15 and 16bit TGAs as RGB with no alpha. +} + +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + // read in the TGA header stuff + int tga_offset = stbi__get8(s); + int tga_indexed = stbi__get8(s); + int tga_image_type = stbi__get8(s); + int tga_is_RLE = 0; + int tga_palette_start = stbi__get16le(s); + int tga_palette_len = stbi__get16le(s); + int tga_palette_bits = stbi__get8(s); + int tga_x_origin = stbi__get16le(s); + int tga_y_origin = stbi__get16le(s); + int tga_width = stbi__get16le(s); + int tga_height = stbi__get16le(s); + int tga_bits_per_pixel = stbi__get8(s); + int tga_comp, tga_rgb16=0; + int tga_inverted = stbi__get8(s); + // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?) + // image data + unsigned char *tga_data; + unsigned char *tga_palette = NULL; + int i, j; + unsigned char raw_data[4] = {0}; + int RLE_count = 0; + int RLE_repeating = 0; + int read_next_pixel = 1; + STBI_NOTUSED(ri); + + // do a tiny bit of precessing + if ( tga_image_type >= 8 ) + { + tga_image_type -= 8; + tga_is_RLE = 1; + } + tga_inverted = 1 - ((tga_inverted >> 5) & 1); + + // If I'm paletted, then I'll use the number of bits from the palette + if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16); + else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16); + + if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency + return stbi__errpuc("bad format", "Can't find out TGA pixelformat"); + + // tga info + *x = tga_width; + *y = tga_height; + if (comp) *comp = tga_comp; + + if (!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0)) + return stbi__errpuc("too large", "Corrupt TGA"); + + tga_data = (unsigned char*)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0); + if (!tga_data) return stbi__errpuc("outofmem", "Out of memory"); + + // skip to the data's starting position (offset usually = 0) + stbi__skip(s, tga_offset ); + + if ( !tga_indexed && !tga_is_RLE && !tga_rgb16 ) { + for (i=0; i < tga_height; ++i) { + int row = tga_inverted ? tga_height -i - 1 : i; + stbi_uc *tga_row = tga_data + row*tga_width*tga_comp; + stbi__getn(s, tga_row, tga_width * tga_comp); + } + } else { + // do I need to load a palette? + if ( tga_indexed) + { + // any data to skip? (offset usually = 0) + stbi__skip(s, tga_palette_start ); + // load the palette + tga_palette = (unsigned char*)stbi__malloc_mad2(tga_palette_len, tga_comp, 0); + if (!tga_palette) { + STBI_FREE(tga_data); + return stbi__errpuc("outofmem", "Out of memory"); + } + if (tga_rgb16) { + stbi_uc *pal_entry = tga_palette; + STBI_ASSERT(tga_comp == STBI_rgb); + for (i=0; i < tga_palette_len; ++i) { + stbi__tga_read_rgb16(s, pal_entry); + pal_entry += tga_comp; + } + } else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) { + STBI_FREE(tga_data); + STBI_FREE(tga_palette); + return stbi__errpuc("bad palette", "Corrupt TGA"); + } + } + // load the data + for (i=0; i < tga_width * tga_height; ++i) + { + // if I'm in RLE mode, do I need to get a RLE stbi__pngchunk? + if ( tga_is_RLE ) + { + if ( RLE_count == 0 ) + { + // yep, get the next byte as a RLE command + int RLE_cmd = stbi__get8(s); + RLE_count = 1 + (RLE_cmd & 127); + RLE_repeating = RLE_cmd >> 7; + read_next_pixel = 1; + } else if ( !RLE_repeating ) + { + read_next_pixel = 1; + } + } else + { + read_next_pixel = 1; + } + // OK, if I need to read a pixel, do it now + if ( read_next_pixel ) + { + // load however much data we did have + if ( tga_indexed ) + { + // read in index, then perform the lookup + int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s); + if ( pal_idx >= tga_palette_len ) { + // invalid index + pal_idx = 0; + } + pal_idx *= tga_comp; + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = tga_palette[pal_idx+j]; + } + } else if(tga_rgb16) { + STBI_ASSERT(tga_comp == STBI_rgb); + stbi__tga_read_rgb16(s, raw_data); + } else { + // read in the data raw + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = stbi__get8(s); + } + } + // clear the reading flag for the next pixel + read_next_pixel = 0; + } // end of reading a pixel + + // copy data + for (j = 0; j < tga_comp; ++j) + tga_data[i*tga_comp+j] = raw_data[j]; + + // in case we're in RLE mode, keep counting down + --RLE_count; + } + // do I need to invert the image? + if ( tga_inverted ) + { + for (j = 0; j*2 < tga_height; ++j) + { + int index1 = j * tga_width * tga_comp; + int index2 = (tga_height - 1 - j) * tga_width * tga_comp; + for (i = tga_width * tga_comp; i > 0; --i) + { + unsigned char temp = tga_data[index1]; + tga_data[index1] = tga_data[index2]; + tga_data[index2] = temp; + ++index1; + ++index2; + } + } + } + // clear my palette, if I had one + if ( tga_palette != NULL ) + { + STBI_FREE( tga_palette ); + } + } + + // swap RGB - if the source data was RGB16, it already is in the right order + if (tga_comp >= 3 && !tga_rgb16) + { + unsigned char* tga_pixel = tga_data; + for (i=0; i < tga_width * tga_height; ++i) + { + unsigned char temp = tga_pixel[0]; + tga_pixel[0] = tga_pixel[2]; + tga_pixel[2] = temp; + tga_pixel += tga_comp; + } + } + + // convert to target component count + if (req_comp && req_comp != tga_comp) + tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height); + + // the things I do to get rid of an error message, and yet keep + // Microsoft's C compilers happy... [8^( + tga_palette_start = tga_palette_len = tga_palette_bits = + tga_x_origin = tga_y_origin = 0; + // OK, done + return tga_data; +} +#endif + +// ************************************************************************************************* +// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB + +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s) +{ + int r = (stbi__get32be(s) == 0x38425053); + stbi__rewind(s); + return r; +} + +static int stbi__psd_decode_rle(stbi__context *s, stbi_uc *p, int pixelCount) +{ + int count, nleft, len; + + count = 0; + while ((nleft = pixelCount - count) > 0) { + len = stbi__get8(s); + if (len == 128) { + // No-op. + } else if (len < 128) { + // Copy next len+1 bytes literally. + len++; + if (len > nleft) return 0; // corrupt data + count += len; + while (len) { + *p = stbi__get8(s); + p += 4; + len--; + } + } else if (len > 128) { + stbi_uc val; + // Next -len+1 bytes in the dest are replicated from next source byte. + // (Interpret len as a negative 8-bit int.) + len = 257 - len; + if (len > nleft) return 0; // corrupt data + val = stbi__get8(s); + count += len; + while (len) { + *p = val; + p += 4; + len--; + } + } + } + + return 1; +} + +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) +{ + int pixelCount; + int channelCount, compression; + int channel, i; + int bitdepth; + int w,h; + stbi_uc *out; + STBI_NOTUSED(ri); + + // Check identifier + if (stbi__get32be(s) != 0x38425053) // "8BPS" + return stbi__errpuc("not PSD", "Corrupt PSD image"); + + // Check file type version. + if (stbi__get16be(s) != 1) + return stbi__errpuc("wrong version", "Unsupported version of PSD image"); + + // Skip 6 reserved bytes. + stbi__skip(s, 6 ); + + // Read the number of channels (R, G, B, A, etc). + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) + return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image"); + + // Read the rows and columns of the image. + h = stbi__get32be(s); + w = stbi__get32be(s); + + // Make sure the depth is 8 bits. + bitdepth = stbi__get16be(s); + if (bitdepth != 8 && bitdepth != 16) + return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 or 16 bit"); + + // Make sure the color mode is RGB. + // Valid options are: + // 0: Bitmap + // 1: Grayscale + // 2: Indexed color + // 3: RGB color + // 4: CMYK color + // 7: Multichannel + // 8: Duotone + // 9: Lab color + if (stbi__get16be(s) != 3) + return stbi__errpuc("wrong color format", "PSD is not in RGB color format"); + + // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.) + stbi__skip(s,stbi__get32be(s) ); + + // Skip the image resources. (resolution, pen tool paths, etc) + stbi__skip(s, stbi__get32be(s) ); + + // Skip the reserved data. + stbi__skip(s, stbi__get32be(s) ); + + // Find out if the data is compressed. + // Known values: + // 0: no compression + // 1: RLE compressed + compression = stbi__get16be(s); + if (compression > 1) + return stbi__errpuc("bad compression", "PSD has an unknown compression format"); + + // Check size + if (!stbi__mad3sizes_valid(4, w, h, 0)) + return stbi__errpuc("too large", "Corrupt PSD"); + + // Create the destination image. + + if (!compression && bitdepth == 16 && bpc == 16) { + out = (stbi_uc *) stbi__malloc_mad3(8, w, h, 0); + ri->bits_per_channel = 16; + } else + out = (stbi_uc *) stbi__malloc(4 * w*h); + + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + pixelCount = w*h; + + // Initialize the data to zero. + //memset( out, 0, pixelCount * 4 ); + + // Finally, the image data. + if (compression) { + // RLE as used by .PSD and .TIFF + // Loop until you get the number of unpacked bytes you are expecting: + // Read the next source byte into n. + // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. + // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. + // Else if n is 128, noop. + // Endloop + + // The RLE-compressed data is preceeded by a 2-byte data count for each row in the data, + // which we're going to just skip. + stbi__skip(s, h * channelCount * 2 ); + + // Read the RLE data by channel. + for (channel = 0; channel < 4; channel++) { + stbi_uc *p; + + p = out+channel; + if (channel >= channelCount) { + // Fill this channel with default data. + for (i = 0; i < pixelCount; i++, p += 4) + *p = (channel == 3 ? 255 : 0); + } else { + // Read the RLE data. + if (!stbi__psd_decode_rle(s, p, pixelCount)) { + STBI_FREE(out); + return stbi__errpuc("corrupt", "bad RLE data"); + } + } + } + + } else { + // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) + // where each channel consists of an 8-bit (or 16-bit) value for each pixel in the image. + + // Read the data by channel. + for (channel = 0; channel < 4; channel++) { + if (channel >= channelCount) { + // Fill this channel with default data. + if (bitdepth == 16 && bpc == 16) { + stbi__uint16 *q = ((stbi__uint16 *) out) + channel; + stbi__uint16 val = channel == 3 ? 65535 : 0; + for (i = 0; i < pixelCount; i++, q += 4) + *q = val; + } else { + stbi_uc *p = out+channel; + stbi_uc val = channel == 3 ? 255 : 0; + for (i = 0; i < pixelCount; i++, p += 4) + *p = val; + } + } else { + if (ri->bits_per_channel == 16) { // output bpc + stbi__uint16 *q = ((stbi__uint16 *) out) + channel; + for (i = 0; i < pixelCount; i++, q += 4) + *q = (stbi__uint16) stbi__get16be(s); + } else { + stbi_uc *p = out+channel; + if (bitdepth == 16) { // input bpc + for (i = 0; i < pixelCount; i++, p += 4) + *p = (stbi_uc) (stbi__get16be(s) >> 8); + } else { + for (i = 0; i < pixelCount; i++, p += 4) + *p = stbi__get8(s); + } + } + } + } + } + + // remove weird white matte from PSD + if (channelCount >= 4) { + if (ri->bits_per_channel == 16) { + for (i=0; i < w*h; ++i) { + stbi__uint16 *pixel = (stbi__uint16 *) out + 4*i; + if (pixel[3] != 0 && pixel[3] != 65535) { + float a = pixel[3] / 65535.0f; + float ra = 1.0f / a; + float inv_a = 65535.0f * (1 - ra); + pixel[0] = (stbi__uint16) (pixel[0]*ra + inv_a); + pixel[1] = (stbi__uint16) (pixel[1]*ra + inv_a); + pixel[2] = (stbi__uint16) (pixel[2]*ra + inv_a); + } + } + } else { + for (i=0; i < w*h; ++i) { + unsigned char *pixel = out + 4*i; + if (pixel[3] != 0 && pixel[3] != 255) { + float a = pixel[3] / 255.0f; + float ra = 1.0f / a; + float inv_a = 255.0f * (1 - ra); + pixel[0] = (unsigned char) (pixel[0]*ra + inv_a); + pixel[1] = (unsigned char) (pixel[1]*ra + inv_a); + pixel[2] = (unsigned char) (pixel[2]*ra + inv_a); + } + } + } + } + + // convert to desired output format + if (req_comp && req_comp != 4) { + if (ri->bits_per_channel == 16) + out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, 4, req_comp, w, h); + else + out = stbi__convert_format(out, 4, req_comp, w, h); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + if (comp) *comp = 4; + *y = h; + *x = w; + + return out; +} +#endif + +// ************************************************************************************************* +// Softimage PIC loader +// by Tom Seddon +// +// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format +// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/ + +#ifndef STBI_NO_PIC +static int stbi__pic_is4(stbi__context *s,const char *str) +{ + int i; + for (i=0; i<4; ++i) + if (stbi__get8(s) != (stbi_uc)str[i]) + return 0; + + return 1; +} + +static int stbi__pic_test_core(stbi__context *s) +{ + int i; + + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) + return 0; + + for(i=0;i<84;++i) + stbi__get8(s); + + if (!stbi__pic_is4(s,"PICT")) + return 0; + + return 1; +} + +typedef struct +{ + stbi_uc size,type,channel; +} stbi__pic_packet; + +static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest) +{ + int mask=0x80, i; + + for (i=0; i<4; ++i, mask>>=1) { + if (channel & mask) { + if (stbi__at_eof(s)) return stbi__errpuc("bad file","PIC file too short"); + dest[i]=stbi__get8(s); + } + } + + return dest; +} + +static void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src) +{ + int mask=0x80,i; + + for (i=0;i<4; ++i, mask>>=1) + if (channel&mask) + dest[i]=src[i]; +} + +static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result) +{ + int act_comp=0,num_packets=0,y,chained; + stbi__pic_packet packets[10]; + + // this will (should...) cater for even some bizarre stuff like having data + // for the same channel in multiple packets. + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return stbi__errpuc("bad format","too many packets"); + + packet = &packets[num_packets++]; + + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + + act_comp |= packet->channel; + + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (reading packets)"); + if (packet->size != 8) return stbi__errpuc("bad format","packet isn't 8bpp"); + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel? + + for(y=0; ytype) { + default: + return stbi__errpuc("bad format","packet has bad compression type"); + + case 0: {//uncompressed + int x; + + for(x=0;xchannel,dest)) + return 0; + break; + } + + case 1://Pure RLE + { + int left=width, i; + + while (left>0) { + stbi_uc count,value[4]; + + count=stbi__get8(s); + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pure read count)"); + + if (count > left) + count = (stbi_uc) left; + + if (!stbi__readval(s,packet->channel,value)) return 0; + + for(i=0; ichannel,dest,value); + left -= count; + } + } + break; + + case 2: {//Mixed RLE + int left=width; + while (left>0) { + int count = stbi__get8(s), i; + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (mixed read count)"); + + if (count >= 128) { // Repeated + stbi_uc value[4]; + + if (count==128) + count = stbi__get16be(s); + else + count -= 127; + if (count > left) + return stbi__errpuc("bad file","scanline overrun"); + + if (!stbi__readval(s,packet->channel,value)) + return 0; + + for(i=0;ichannel,dest,value); + } else { // Raw + ++count; + if (count>left) return stbi__errpuc("bad file","scanline overrun"); + + for(i=0;ichannel,dest)) + return 0; + } + left-=count; + } + break; + } + } + } + } + + return result; +} + +static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp, stbi__result_info *ri) +{ + stbi_uc *result; + int i, x,y, internal_comp; + STBI_NOTUSED(ri); + + if (!comp) comp = &internal_comp; + + for (i=0; i<92; ++i) + stbi__get8(s); + + x = stbi__get16be(s); + y = stbi__get16be(s); + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)"); + if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode"); + + stbi__get32be(s); //skip `ratio' + stbi__get16be(s); //skip `fields' + stbi__get16be(s); //skip `pad' + + // intermediate buffer is RGBA + result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0); + memset(result, 0xff, x*y*4); + + if (!stbi__pic_load_core(s,x,y,comp, result)) { + STBI_FREE(result); + result=0; + } + *px = x; + *py = y; + if (req_comp == 0) req_comp = *comp; + result=stbi__convert_format(result,4,req_comp,x,y); + + return result; +} + +static int stbi__pic_test(stbi__context *s) +{ + int r = stbi__pic_test_core(s); + stbi__rewind(s); + return r; +} +#endif + +// ************************************************************************************************* +// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb + +#ifndef STBI_NO_GIF +typedef struct +{ + stbi__int16 prefix; + stbi_uc first; + stbi_uc suffix; +} stbi__gif_lzw; + +typedef struct +{ + int w,h; + stbi_uc *out; // output buffer (always 4 components) + stbi_uc *background; // The current "background" as far as a gif is concerned + stbi_uc *history; + int flags, bgindex, ratio, transparent, eflags; + stbi_uc pal[256][4]; + stbi_uc lpal[256][4]; + stbi__gif_lzw codes[8192]; + stbi_uc *color_table; + int parse, step; + int lflags; + int start_x, start_y; + int max_x, max_y; + int cur_x, cur_y; + int line_size; + int delay; +} stbi__gif; + +static int stbi__gif_test_raw(stbi__context *s) +{ + int sz; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0; + sz = stbi__get8(s); + if (sz != '9' && sz != '7') return 0; + if (stbi__get8(s) != 'a') return 0; + return 1; +} + +static int stbi__gif_test(stbi__context *s) +{ + int r = stbi__gif_test_raw(s); + stbi__rewind(s); + return r; +} + +static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp) +{ + int i; + for (i=0; i < num_entries; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + pal[i][3] = transp == i ? 0 : 255; + } +} + +static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info) +{ + stbi_uc version; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') + return stbi__err("not GIF", "Corrupt GIF"); + + version = stbi__get8(s); + if (version != '7' && version != '9') return stbi__err("not GIF", "Corrupt GIF"); + if (stbi__get8(s) != 'a') return stbi__err("not GIF", "Corrupt GIF"); + + stbi__g_failure_reason = ""; + g->w = stbi__get16le(s); + g->h = stbi__get16le(s); + g->flags = stbi__get8(s); + g->bgindex = stbi__get8(s); + g->ratio = stbi__get8(s); + g->transparent = -1; + + if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments + + if (is_info) return 1; + + if (g->flags & 0x80) + stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1); + + return 1; +} + +static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif)); + if (!stbi__gif_header(s, g, comp, 1)) { + STBI_FREE(g); + stbi__rewind( s ); + return 0; + } + if (x) *x = g->w; + if (y) *y = g->h; + STBI_FREE(g); + return 1; +} + +static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) +{ + stbi_uc *p, *c; + int idx; + + // recurse to decode the prefixes, since the linked-list is backwards, + // and working backwards through an interleaved image would be nasty + if (g->codes[code].prefix >= 0) + stbi__out_gif_code(g, g->codes[code].prefix); + + if (g->cur_y >= g->max_y) return; + + idx = g->cur_x + g->cur_y; + p = &g->out[idx]; + g->history[idx / 4] = 1; + + c = &g->color_table[g->codes[code].suffix * 4]; + if (c[3] > 128) { // don't render transparent pixels; + p[0] = c[2]; + p[1] = c[1]; + p[2] = c[0]; + p[3] = c[3]; + } + g->cur_x += 4; + + if (g->cur_x >= g->max_x) { + g->cur_x = g->start_x; + g->cur_y += g->step; + + while (g->cur_y >= g->max_y && g->parse > 0) { + g->step = (1 << g->parse) * g->line_size; + g->cur_y = g->start_y + (g->step >> 1); + --g->parse; + } + } +} + +static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) +{ + stbi_uc lzw_cs; + stbi__int32 len, init_code; + stbi__uint32 first; + stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear; + stbi__gif_lzw *p; + + lzw_cs = stbi__get8(s); + if (lzw_cs > 12) return NULL; + clear = 1 << lzw_cs; + first = 1; + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + bits = 0; + valid_bits = 0; + for (init_code = 0; init_code < clear; init_code++) { + g->codes[init_code].prefix = -1; + g->codes[init_code].first = (stbi_uc) init_code; + g->codes[init_code].suffix = (stbi_uc) init_code; + } + + // support no starting clear code + avail = clear+2; + oldcode = -1; + + len = 0; + for(;;) { + if (valid_bits < codesize) { + if (len == 0) { + len = stbi__get8(s); // start new block + if (len == 0) + return g->out; + } + --len; + bits |= (stbi__int32) stbi__get8(s) << valid_bits; + valid_bits += 8; + } else { + stbi__int32 code = bits & codemask; + bits >>= codesize; + valid_bits -= codesize; + // @OPTIMIZE: is there some way we can accelerate the non-clear path? + if (code == clear) { // clear code + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + avail = clear + 2; + oldcode = -1; + first = 0; + } else if (code == clear + 1) { // end of stream code + stbi__skip(s, len); + while ((len = stbi__get8(s)) > 0) + stbi__skip(s,len); + return g->out; + } else if (code <= avail) { + if (first) { + return stbi__errpuc("no clear code", "Corrupt GIF"); + } + + if (oldcode >= 0) { + p = &g->codes[avail++]; + if (avail > 8192) { + return stbi__errpuc("too many codes", "Corrupt GIF"); + } + + p->prefix = (stbi__int16) oldcode; + p->first = g->codes[oldcode].first; + p->suffix = (code == avail) ? p->first : g->codes[code].first; + } else if (code == avail) + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + + stbi__out_gif_code(g, (stbi__uint16) code); + + if ((avail & codemask) == 0 && avail <= 0x0FFF) { + codesize++; + codemask = (1 << codesize) - 1; + } + + oldcode = code; + } else { + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + } + } + } +} + +// this function is designed to support animated gifs, although stb_image doesn't support it +// two back is the image from two frames ago, used for a very specific disposal format +static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back) +{ + int dispose; + int first_frame; + int pi; + int pcount; + + // on first frame, any non-written pixels get the background colour (non-transparent) + first_frame = 0; + if (g->out == 0) { + if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header + g->out = (stbi_uc *) stbi__malloc(4 * g->w * g->h); + g->background = (stbi_uc *) stbi__malloc(4 * g->w * g->h); + g->history = (stbi_uc *) stbi__malloc(g->w * g->h); + if (g->out == 0) return stbi__errpuc("outofmem", "Out of memory"); + + // image is treated as "tranparent" at the start - ie, nothing overwrites the current background; + // background colour is only used for pixels that are not rendered first frame, after that "background" + // color refers to teh color that was there the previous frame. + memset( g->out, 0x00, 4 * g->w * g->h ); + memset( g->background, 0x00, 4 * g->w * g->h ); // state of the background (starts transparent) + memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame + first_frame = 1; + } else { + // second frame - how do we dispoase of the previous one? + dispose = (g->eflags & 0x1C) >> 2; + pcount = g->w * g->h; + + if ((dispose == 3) && (two_back == 0)) { + dispose = 2; // if I don't have an image to revert back to, default to the old background + } + + if (dispose == 3) { // use previous graphic + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 ); + } + } + } else if (dispose == 2) { + // restore what was changed last frame to background before that frame; + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 ); + } + } + } else { + // This is a non-disposal case eithe way, so just + // leave the pixels as is, and they will become the new background + // 1: do not dispose + // 0: not specified. + } + + // background is what out is after the undoing of the previou frame; + memcpy( g->background, g->out, 4 * g->w * g->h ); + } + + // clear my history; + memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame + + for (;;) { + int tag = stbi__get8(s); + switch (tag) { + case 0x2C: /* Image Descriptor */ + { + stbi__int32 x, y, w, h; + stbi_uc *o; + + x = stbi__get16le(s); + y = stbi__get16le(s); + w = stbi__get16le(s); + h = stbi__get16le(s); + if (((x + w) > (g->w)) || ((y + h) > (g->h))) + return stbi__errpuc("bad Image Descriptor", "Corrupt GIF"); + + g->line_size = g->w * 4; + g->start_x = x * 4; + g->start_y = y * g->line_size; + g->max_x = g->start_x + w * 4; + g->max_y = g->start_y + h * g->line_size; + g->cur_x = g->start_x; + g->cur_y = g->start_y; + + g->lflags = stbi__get8(s); + + if (g->lflags & 0x40) { + g->step = 8 * g->line_size; // first interlaced spacing + g->parse = 3; + } else { + g->step = g->line_size; + g->parse = 0; + } + + if (g->lflags & 0x80) { + stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); + g->color_table = (stbi_uc *) g->lpal; + } else if (g->flags & 0x80) { + g->color_table = (stbi_uc *) g->pal; + } else + return stbi__errpuc("missing color table", "Corrupt GIF"); + + o = stbi__process_gif_raster(s, g); + if (o == NULL) return NULL; + + // if this was the first frame, + pcount = g->w * g->h; + if (first_frame && (g->bgindex > 0)) { + // if first frame, any pixel not drawn to gets the background color + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi] == 0) { + g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be; + memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 ); + } + } + } + + return o; + } + + case 0x21: // Comment Extension. + { + int len; + int ext = stbi__get8(s); + if (ext == 0xF9) { // Graphic Control Extension. + len = stbi__get8(s); + if (len == 4) { + g->eflags = stbi__get8(s); + g->delay = 10 * stbi__get16le(s); // delay - 1/100th of a second, saving as 1/1000ths. + + // unset old transparent + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 255; + } + if (g->eflags & 0x01) { + g->transparent = stbi__get8(s); + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 0; + } + } else { + // don't need transparent + stbi__skip(s, 1); + g->transparent = -1; + } + } else { + stbi__skip(s, len); + break; + } + } + while ((len = stbi__get8(s)) != 0) { + stbi__skip(s, len); + } + break; + } + + case 0x3B: // gif stream termination code + return (stbi_uc *) s; // using '1' causes warning on some compilers + + default: + return stbi__errpuc("unknown code", "Corrupt GIF"); + } + } +} + +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp) +{ + if (stbi__gif_test(s)) { + int layers = 0; + stbi_uc *u = 0; + stbi_uc *out = 0; + stbi_uc *two_back = 0; + stbi__gif g; + int stride; + memset(&g, 0, sizeof(g)); + if (delays) { + *delays = 0; + } + + do { + u = stbi__gif_load_next(s, &g, comp, req_comp, two_back); + if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + + if (u) { + *x = g.w; + *y = g.h; + ++layers; + stride = g.w * g.h * 4; + + if (out) { + out = (stbi_uc*) STBI_REALLOC( out, layers * stride ); + if (delays) { + *delays = (int*) STBI_REALLOC( *delays, sizeof(int) * layers ); + } + } else { + out = (stbi_uc*)stbi__malloc( layers * stride ); + if (delays) { + *delays = (int*) stbi__malloc( layers * sizeof(int) ); + } + } + memcpy( out + ((layers - 1) * stride), u, stride ); + if (layers >= 2) { + two_back = out - 2 * stride; + } + + if (delays) { + (*delays)[layers - 1U] = g.delay; + } + } + } while (u != 0); + + // free temp buffer; + STBI_FREE(g.out); + STBI_FREE(g.history); + STBI_FREE(g.background); + + // do the final conversion after loading everything; + if (req_comp && req_comp != 4) + out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h); + + *z = layers; + return out; + } else { + return stbi__errpuc("not GIF", "Image was not as a gif type."); + } +} + +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *u = 0; + stbi__gif g; + memset(&g, 0, sizeof(g)); + + u = stbi__gif_load_next(s, &g, comp, req_comp, 0); + if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + if (u) { + *x = g.w; + *y = g.h; + + // moved conversion to after successful load so that the same + // can be done for multiple frames. + if (req_comp && req_comp != 4) + u = stbi__convert_format(u, 4, req_comp, g.w, g.h); + } + + // free buffers needed for multiple frame loading; + STBI_FREE(g.history); + STBI_FREE(g.background); + + return u; +} + +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp) +{ + return stbi__gif_info_raw(s,x,y,comp); +} +#endif + +// ************************************************************************************************* +// Radiance RGBE HDR loader +// originally by Nicolas Schulz +#ifndef STBI_NO_HDR +static int stbi__hdr_test_core(stbi__context *s, const char *signature) +{ + int i; + for (i=0; signature[i]; ++i) + if (stbi__get8(s) != signature[i]) + return 0; + stbi__rewind(s); + return 1; +} + +static int stbi__hdr_test(stbi__context* s) +{ + int r = stbi__hdr_test_core(s, "#?RADIANCE\n"); + stbi__rewind(s); + if(!r) { + r = stbi__hdr_test_core(s, "#?RGBE\n"); + stbi__rewind(s); + } + return r; +} + +#define STBI__HDR_BUFLEN 1024 +static char *stbi__hdr_gettoken(stbi__context *z, char *buffer) +{ + int len=0; + char c = '\0'; + + c = (char) stbi__get8(z); + + while (!stbi__at_eof(z) && c != '\n') { + buffer[len++] = c; + if (len == STBI__HDR_BUFLEN-1) { + // flush to end of line + while (!stbi__at_eof(z) && stbi__get8(z) != '\n') + ; + break; + } + c = (char) stbi__get8(z); + } + + buffer[len] = 0; + return buffer; +} + +static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp) +{ + if ( input[3] != 0 ) { + float f1; + // Exponent + f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8)); + if (req_comp <= 2) + output[0] = (input[0] + input[1] + input[2]) * f1 / 3; + else { + output[0] = input[0] * f1; + output[1] = input[1] * f1; + output[2] = input[2] * f1; + } + if (req_comp == 2) output[1] = 1; + if (req_comp == 4) output[3] = 1; + } else { + switch (req_comp) { + case 4: output[3] = 1; /* fallthrough */ + case 3: output[0] = output[1] = output[2] = 0; + break; + case 2: output[1] = 1; /* fallthrough */ + case 1: output[0] = 0; + break; + } + } +} + +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int width, height; + stbi_uc *scanline; + float *hdr_data; + int len; + unsigned char count, value; + int i, j, k, c1,c2, z; + const char *headerToken; + STBI_NOTUSED(ri); + + // Check identifier + headerToken = stbi__hdr_gettoken(s,buffer); + if (strcmp(headerToken, "#?RADIANCE") != 0 && strcmp(headerToken, "#?RGBE") != 0) + return stbi__errpf("not HDR", "Corrupt HDR image"); + + // Parse header + for(;;) { + token = stbi__hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) return stbi__errpf("unsupported format", "Unsupported HDR format"); + + // Parse width and height + // can't use sscanf() if we're not using stdio! + token = stbi__hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + height = (int) strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + width = (int) strtol(token, NULL, 10); + + *x = width; + *y = height; + + if (comp) *comp = 3; + if (req_comp == 0) req_comp = 3; + + if (!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0)) + return stbi__errpf("too large", "HDR image is too large"); + + // Read data + hdr_data = (float *) stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0); + if (!hdr_data) + return stbi__errpf("outofmem", "Out of memory"); + + // Load image data + // image data is stored as some number of sca + if ( width < 8 || width >= 32768) { + // Read flat data + for (j=0; j < height; ++j) { + for (i=0; i < width; ++i) { + stbi_uc rgbe[4]; + main_decode_loop: + stbi__getn(s, rgbe, 4); + stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp); + } + } + } else { + // Read RLE-encoded data + scanline = NULL; + + for (j = 0; j < height; ++j) { + c1 = stbi__get8(s); + c2 = stbi__get8(s); + len = stbi__get8(s); + if (c1 != 2 || c2 != 2 || (len & 0x80)) { + // not run-length encoded, so we have to actually use THIS data as a decoded + // pixel (note this can't be a valid pixel--one of RGB must be >= 128) + stbi_uc rgbe[4]; + rgbe[0] = (stbi_uc) c1; + rgbe[1] = (stbi_uc) c2; + rgbe[2] = (stbi_uc) len; + rgbe[3] = (stbi_uc) stbi__get8(s); + stbi__hdr_convert(hdr_data, rgbe, req_comp); + i = 1; + j = 0; + STBI_FREE(scanline); + goto main_decode_loop; // yes, this makes no sense + } + len <<= 8; + len |= stbi__get8(s); + if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); } + if (scanline == NULL) { + scanline = (stbi_uc *) stbi__malloc_mad2(width, 4, 0); + if (!scanline) { + STBI_FREE(hdr_data); + return stbi__errpf("outofmem", "Out of memory"); + } + } + + for (k = 0; k < 4; ++k) { + int nleft; + i = 0; + while ((nleft = width - i) > 0) { + count = stbi__get8(s); + if (count > 128) { + // Run + value = stbi__get8(s); + count -= 128; + if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = value; + } else { + // Dump + if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = stbi__get8(s); + } + } + } + for (i=0; i < width; ++i) + stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); + } + if (scanline) + STBI_FREE(scanline); + } + + return hdr_data; +} + +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp) +{ + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int dummy; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + if (stbi__hdr_test(s) == 0) { + stbi__rewind( s ); + return 0; + } + + for(;;) { + token = stbi__hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) { + stbi__rewind( s ); + return 0; + } + token = stbi__hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) { + stbi__rewind( s ); + return 0; + } + token += 3; + *y = (int) strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) { + stbi__rewind( s ); + return 0; + } + token += 3; + *x = (int) strtol(token, NULL, 10); + *comp = 3; + return 1; +} +#endif // STBI_NO_HDR + +#ifndef STBI_NO_BMP +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) +{ + void *p; + stbi__bmp_data info; + + info.all_a = 255; + p = stbi__bmp_parse_header(s, &info); + stbi__rewind( s ); + if (p == NULL) + return 0; + if (x) *x = s->img_x; + if (y) *y = s->img_y; + if (comp) *comp = info.ma ? 4 : 3; + return 1; +} +#endif + +#ifndef STBI_NO_PSD +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) +{ + int channelCount, dummy, depth; + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind( s ); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind( s ); + return 0; + } + *y = stbi__get32be(s); + *x = stbi__get32be(s); + depth = stbi__get16be(s); + if (depth != 8 && depth != 16) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 3) { + stbi__rewind( s ); + return 0; + } + *comp = 4; + return 1; +} + +static int stbi__psd_is16(stbi__context *s) +{ + int channelCount, depth; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind( s ); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind( s ); + return 0; + } + (void) stbi__get32be(s); + (void) stbi__get32be(s); + depth = stbi__get16be(s); + if (depth != 16) { + stbi__rewind( s ); + return 0; + } + return 1; +} +#endif + +#ifndef STBI_NO_PIC +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) +{ + int act_comp=0,num_packets=0,chained,dummy; + stbi__pic_packet packets[10]; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) { + stbi__rewind(s); + return 0; + } + + stbi__skip(s, 88); + + *x = stbi__get16be(s); + *y = stbi__get16be(s); + if (stbi__at_eof(s)) { + stbi__rewind( s); + return 0; + } + if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) { + stbi__rewind( s ); + return 0; + } + + stbi__skip(s, 8); + + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return 0; + + packet = &packets[num_packets++]; + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + act_comp |= packet->channel; + + if (stbi__at_eof(s)) { + stbi__rewind( s ); + return 0; + } + if (packet->size != 8) { + stbi__rewind( s ); + return 0; + } + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); + + return 1; +} +#endif + +// ************************************************************************************************* +// Portable Gray Map and Portable Pixel Map loader +// by Ken Miller +// +// PGM: http://netpbm.sourceforge.net/doc/pgm.html +// PPM: http://netpbm.sourceforge.net/doc/ppm.html +// +// Known limitations: +// Does not support comments in the header section +// Does not support ASCII image data (formats P2 and P3) +// Does not support 16-bit-per-channel + +#ifndef STBI_NO_PNM + +static int stbi__pnm_test(stbi__context *s) +{ + char p, t; + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind( s ); + return 0; + } + return 1; +} + +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *out; + STBI_NOTUSED(ri); + + if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n)) + return 0; + + *x = s->img_x; + *y = s->img_y; + if (comp) *comp = s->img_n; + + if (!stbi__mad3sizes_valid(s->img_n, s->img_x, s->img_y, 0)) + return stbi__errpuc("too large", "PNM too large"); + + out = (stbi_uc *) stbi__malloc_mad3(s->img_n, s->img_x, s->img_y, 0); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + stbi__getn(s, out, s->img_n * s->img_x * s->img_y); + + if (req_comp && req_comp != s->img_n) { + out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + return out; +} + +static int stbi__pnm_isspace(char c) +{ + return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; +} + +static void stbi__pnm_skip_whitespace(stbi__context *s, char *c) +{ + for (;;) { + while (!stbi__at_eof(s) && stbi__pnm_isspace(*c)) + *c = (char) stbi__get8(s); + + if (stbi__at_eof(s) || *c != '#') + break; + + while (!stbi__at_eof(s) && *c != '\n' && *c != '\r' ) + *c = (char) stbi__get8(s); + } +} + +static int stbi__pnm_isdigit(char c) +{ + return c >= '0' && c <= '9'; +} + +static int stbi__pnm_getinteger(stbi__context *s, char *c) +{ + int value = 0; + + while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { + value = value*10 + (*c - '0'); + *c = (char) stbi__get8(s); + } + + return value; +} + +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) +{ + int maxv, dummy; + char c, p, t; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + stbi__rewind(s); + + // Get identifier + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind(s); + return 0; + } + + *comp = (t == '6') ? 3 : 1; // '5' is 1-component .pgm; '6' is 3-component .ppm + + c = (char) stbi__get8(s); + stbi__pnm_skip_whitespace(s, &c); + + *x = stbi__pnm_getinteger(s, &c); // read width + stbi__pnm_skip_whitespace(s, &c); + + *y = stbi__pnm_getinteger(s, &c); // read height + stbi__pnm_skip_whitespace(s, &c); + + maxv = stbi__pnm_getinteger(s, &c); // read max value + + if (maxv > 255) + return stbi__err("max value > 255", "PPM image not 8-bit"); + else + return 1; +} +#endif + +static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) +{ + #ifndef STBI_NO_JPEG + if (stbi__jpeg_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNG + if (stbi__png_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_GIF + if (stbi__gif_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_BMP + if (stbi__bmp_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PSD + if (stbi__psd_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PIC + if (stbi__pic_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNM + if (stbi__pnm_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_HDR + if (stbi__hdr_info(s, x, y, comp)) return 1; + #endif + + // test tga last because it's a crappy test! + #ifndef STBI_NO_TGA + if (stbi__tga_info(s, x, y, comp)) + return 1; + #endif + return stbi__err("unknown image type", "Image not of any known type, or corrupt"); +} + +static int stbi__is_16_main(stbi__context *s) +{ + #ifndef STBI_NO_PNG + if (stbi__png_is16(s)) return 1; + #endif + + #ifndef STBI_NO_PSD + if (stbi__psd_is16(s)) return 1; + #endif + + return 0; +} + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) return stbi__err("can't fopen", "Unable to open file"); + result = stbi_info_from_file(f, x, y, comp); + fclose(f); + return result; +} + +STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) +{ + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__info_main(&s,x,y,comp); + fseek(f,pos,SEEK_SET); + return r; +} + +STBIDEF int stbi_is_16_bit(char const *filename) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) return stbi__err("can't fopen", "Unable to open file"); + result = stbi_is_16_bit_from_file(f); + fclose(f); + return result; +} + +STBIDEF int stbi_is_16_bit_from_file(FILE *f) +{ + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__is_16_main(&s); + fseek(f,pos,SEEK_SET); + return r; +} +#endif // !STBI_NO_STDIO + +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__info_main(&s,x,y,comp); +} + +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); + return stbi__info_main(&s,x,y,comp); +} + +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__is_16_main(&s); +} + +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); + return stbi__is_16_main(&s); +} + +#endif // STB_IMAGE_IMPLEMENTATION + +/* + revision history: + 2.19 (2018-02-11) fix warning + 2.18 (2018-01-30) fix warnings + 2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug + 1-bit BMP + *_is_16_bit api + avoid warnings + 2.16 (2017-07-23) all functions have 16-bit variants; + STBI_NO_STDIO works again; + compilation fixes; + fix rounding in unpremultiply; + optimize vertical flip; + disable raw_len validation; + documentation fixes + 2.15 (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode; + warning fixes; disable run-time SSE detection on gcc; + uniform handling of optional "return" values; + thread-safe initialization of zlib tables + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs + 2.13 (2016-11-29) add 16-bit API, only supported for PNG right now + 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes + 2.11 (2016-04-02) allocate large structures on the stack + remove white matting for transparent PSD + fix reported channel count for PNG & BMP + re-enable SSE2 in non-gcc 64-bit + support RGB-formatted JPEG + read 16-bit PNGs (only as 8-bit) + 2.10 (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED + 2.09 (2016-01-16) allow comments in PNM files + 16-bit-per-pixel TGA (not bit-per-component) + info() for TGA could break due to .hdr handling + info() for BMP to shares code instead of sloppy parse + can use STBI_REALLOC_SIZED if allocator doesn't support realloc + code cleanup + 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA + 2.07 (2015-09-13) fix compiler warnings + partial animated GIF support + limited 16-bpc PSD support + #ifdef unused functions + bug with < 92 byte PIC,PNM,HDR,TGA + 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value + 2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning + 2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit + 2.03 (2015-04-12) extra corruption checking (mmozeiko) + stbi_set_flip_vertically_on_load (nguillemot) + fix NEON support; fix mingw support + 2.02 (2015-01-19) fix incorrect assert, fix warning + 2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2 + 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG + 2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg) + progressive JPEG (stb) + PGM/PPM support (Ken Miller) + STBI_MALLOC,STBI_REALLOC,STBI_FREE + GIF bugfix -- seemingly never worked + STBI_NO_*, STBI_ONLY_* + 1.48 (2014-12-14) fix incorrectly-named assert() + 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb) + optimize PNG (ryg) + fix bug in interlaced PNG with user-specified channel count (stb) + 1.46 (2014-08-26) + fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG + 1.45 (2014-08-16) + fix MSVC-ARM internal compiler error by wrapping malloc + 1.44 (2014-08-07) + various warning fixes from Ronny Chevalier + 1.43 (2014-07-15) + fix MSVC-only compiler problem in code changed in 1.42 + 1.42 (2014-07-09) + don't define _CRT_SECURE_NO_WARNINGS (affects user code) + fixes to stbi__cleanup_jpeg path + added STBI_ASSERT to avoid requiring assert.h + 1.41 (2014-06-25) + fix search&replace from 1.36 that messed up comments/error messages + 1.40 (2014-06-22) + fix gcc struct-initialization warning + 1.39 (2014-06-15) + fix to TGA optimization when req_comp != number of components in TGA; + fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite) + add support for BMP version 5 (more ignored fields) + 1.38 (2014-06-06) + suppress MSVC warnings on integer casts truncating values + fix accidental rename of 'skip' field of I/O + 1.37 (2014-06-04) + remove duplicate typedef + 1.36 (2014-06-03) + convert to header file single-file library + if de-iphone isn't set, load iphone images color-swapped instead of returning NULL + 1.35 (2014-05-27) + various warnings + fix broken STBI_SIMD path + fix bug where stbi_load_from_file no longer left file pointer in correct place + fix broken non-easy path for 32-bit BMP (possibly never used) + TGA optimization by Arseny Kapoulkine + 1.34 (unknown) + use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case + 1.33 (2011-07-14) + make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements + 1.32 (2011-07-13) + support for "info" function for all supported filetypes (SpartanJ) + 1.31 (2011-06-20) + a few more leak fixes, bug in PNG handling (SpartanJ) + 1.30 (2011-06-11) + added ability to load files via callbacks to accomidate custom input streams (Ben Wenger) + removed deprecated format-specific test/load functions + removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway + error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha) + fix inefficiency in decoding 32-bit BMP (David Woo) + 1.29 (2010-08-16) + various warning fixes from Aurelien Pocheville + 1.28 (2010-08-01) + fix bug in GIF palette transparency (SpartanJ) + 1.27 (2010-08-01) + cast-to-stbi_uc to fix warnings + 1.26 (2010-07-24) + fix bug in file buffering for PNG reported by SpartanJ + 1.25 (2010-07-17) + refix trans_data warning (Won Chun) + 1.24 (2010-07-12) + perf improvements reading from files on platforms with lock-heavy fgetc() + minor perf improvements for jpeg + deprecated type-specific functions so we'll get feedback if they're needed + attempt to fix trans_data warning (Won Chun) + 1.23 fixed bug in iPhone support + 1.22 (2010-07-10) + removed image *writing* support + stbi_info support from Jetro Lauha + GIF support from Jean-Marc Lienher + iPhone PNG-extensions from James Brown + warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva) + 1.21 fix use of 'stbi_uc' in header (reported by jon blow) + 1.20 added support for Softimage PIC, by Tom Seddon + 1.19 bug in interlaced PNG corruption check (found by ryg) + 1.18 (2008-08-02) + fix a threading bug (local mutable static) + 1.17 support interlaced PNG + 1.16 major bugfix - stbi__convert_format converted one too many pixels + 1.15 initialize some fields for thread safety + 1.14 fix threadsafe conversion bug + header-file-only version (#define STBI_HEADER_FILE_ONLY before including) + 1.13 threadsafe + 1.12 const qualifiers in the API + 1.11 Support installable IDCT, colorspace conversion routines + 1.10 Fixes for 64-bit (don't use "unsigned long") + optimized upsampling by Fabian "ryg" Giesen + 1.09 Fix format-conversion for PSD code (bad global variables!) + 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz + 1.07 attempt to fix C++ warning/errors again + 1.06 attempt to fix C++ warning/errors again + 1.05 fix TGA loading to return correct *comp and use good luminance calc + 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free + 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR + 1.02 support for (subset of) HDR files, float interface for preferred access to them + 1.01 fix bug: possible bug in handling right-side up bmps... not sure + fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all + 1.00 interface to zlib that skips zlib header + 0.99 correct handling of alpha in palette + 0.98 TGA loader by lonesock; dynamically add loaders (untested) + 0.97 jpeg errors on too large a file; also catch another malloc failure + 0.96 fix detection of invalid v value - particleman@mollyrocket forum + 0.95 during header scan, seek to markers in case of padding + 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same + 0.93 handle jpegtran output; verbose errors + 0.92 read 4,8,16,24,32-bit BMP files of several formats + 0.91 output 24-bit Windows 3.0 BMP files + 0.90 fix a few more warnings; bump version number to approach 1.0 + 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd + 0.60 fix compiling as c++ + 0.59 fix warnings: merge Dave Moore's -Wall fixes + 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian + 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available + 0.56 fix bug: zlib uncompressed mode len vs. nlen + 0.55 fix bug: restart_interval not initialized to 0 + 0.54 allow NULL for 'int *comp' + 0.53 fix bug in png 3->4; speedup png decoding + 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments + 0.51 obey req_comp requests, 1-component jpegs return as 1-component, + on 'test' only check type, not whether we support this variant + 0.50 (2006-11-19) + first released version +*/ + + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ \ No newline at end of file diff --git a/3rdparty/imgui-node-editor/imgui_bezier_math.h b/3rdparty/imgui-node-editor/imgui_bezier_math.h new file mode 100644 index 0000000..85ead39 --- /dev/null +++ b/3rdparty/imgui-node-editor/imgui_bezier_math.h @@ -0,0 +1,144 @@ +//------------------------------------------------------------------------------ +// VERSION 0.1 +// +// LICENSE +// This software is dual-licensed to the public domain and under the following +// license: you are granted a perpetual, irrevocable license to copy, modify, +// publish, and distribute this file as you see fit. +// +// CREDITS +// Written by Michal Cichon +//------------------------------------------------------------------------------ +# ifndef __IMGUI_BEZIER_MATH_H__ +# define __IMGUI_BEZIER_MATH_H__ +# pragma once + + +//------------------------------------------------------------------------------ +# include "imgui_extra_math.h" + + +//------------------------------------------------------------------------------ +template +struct ImCubicBezierPointsT +{ + T P0; + T P1; + T P2; + T P3; +}; +using ImCubicBezierPoints = ImCubicBezierPointsT; + + +//------------------------------------------------------------------------------ +// Low-level Bezier curve sampling. +template inline T ImLinearBezier(const T& p0, const T& p1, float t); +template inline T ImLinearBezierDt(const T& p0, const T& p1, float t); +template inline T ImQuadraticBezier(const T& p0, const T& p1, const T& p2, float t); +template inline T ImQuadraticBezierDt(const T& p0, const T& p1, const T& p2, float t); +template inline T ImCubicBezier(const T& p0, const T& p1, const T& p2, const T& p3, float t); +template inline T ImCubicBezierDt(const T& p0, const T& p1, const T& p2, const T& p3, float t); + + +// High-level Bezier sampling, automatically collapse to lower level Bezier curves if control points overlap. +template inline T ImCubicBezierSample(const T& p0, const T& p1, const T& p2, const T& p3, float t); +template inline T ImCubicBezierSample(const ImCubicBezierPointsT& curve, float t); +template inline T ImCubicBezierTangent(const T& p0, const T& p1, const T& p2, const T& p3, float t); +template inline T ImCubicBezierTangent(const ImCubicBezierPointsT& curve, float t); + + +// Calculate approximate length of Cubic Bezier curve. +template inline float ImCubicBezierLength(const T& p0, const T& p1, const T& p2, const T& p3); +template inline float ImCubicBezierLength(const ImCubicBezierPointsT& curve); + + +// Splits Cubic Bezier curve into two curves. +template +struct ImCubicBezierSplitResultT +{ + ImCubicBezierPointsT Left; + ImCubicBezierPointsT Right; +}; +using ImCubicBezierSplitResult = ImCubicBezierSplitResultT; + +template inline ImCubicBezierSplitResultT ImCubicBezierSplit(const T& p0, const T& p1, const T& p2, const T& p3, float t); +template inline ImCubicBezierSplitResultT ImCubicBezierSplit(const ImCubicBezierPointsT& curve, float t); + + +// Returns bounding rectangle of Cubic Bezier curve. +inline ImRect ImCubicBezierBoundingRect(const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3); +inline ImRect ImCubicBezierBoundingRect(const ImCubicBezierPoints& curve); + + +// Project point on Cubic Bezier curve. +struct ImProjectResult +{ + ImVec2 Point; // Point on curve + float Time; // [0 - 1] + float Distance; // Distance to curve +}; + +inline ImProjectResult ImProjectOnCubicBezier(const ImVec2& p, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const int subdivisions = 100); +inline ImProjectResult ImProjectOnCubicBezier(const ImVec2& p, const ImCubicBezierPoints& curve, const int subdivisions = 100); + + +// Calculate intersection between line and a Cubic Bezier curve. +struct ImCubicBezierIntersectResult +{ + int Count; + ImVec2 Points[3]; +}; + +inline ImCubicBezierIntersectResult ImCubicBezierLineIntersect(const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& a0, const ImVec2& a1); +inline ImCubicBezierIntersectResult ImCubicBezierLineIntersect(const ImCubicBezierPoints& curve, const ImLine& line); + + +// Adaptive Cubic Bezier subdivision. +enum ImCubicBezierSubdivideFlags +{ + ImCubicBezierSubdivide_None = 0, + ImCubicBezierSubdivide_SkipFirst = 1 +}; + +struct ImCubicBezierSubdivideSample +{ + ImVec2 Point; + ImVec2 Tangent; +}; + +using ImCubicBezierSubdivideCallback = void (*)(const ImCubicBezierSubdivideSample& p, void* user_pointer); + +inline void ImCubicBezierSubdivide(ImCubicBezierSubdivideCallback callback, void* user_pointer, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float tess_tol = -1.0f, ImCubicBezierSubdivideFlags flags = ImCubicBezierSubdivide_None); +inline void ImCubicBezierSubdivide(ImCubicBezierSubdivideCallback callback, void* user_pointer, const ImCubicBezierPoints& curve, float tess_tol = -1.0f, ImCubicBezierSubdivideFlags flags = ImCubicBezierSubdivide_None); + + +// F has signature void(const ImCubicBezierSubdivideSample& p) +template inline void ImCubicBezierSubdivide(F& callback, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float tess_tol = -1.0f, ImCubicBezierSubdivideFlags flags = ImCubicBezierSubdivide_None); +template inline void ImCubicBezierSubdivide(F& callback, const ImCubicBezierPoints& curve, float tess_tol = -1.0f, ImCubicBezierSubdivideFlags flags = ImCubicBezierSubdivide_None); + +// Fixed step Cubic Bezier subdivision. +struct ImCubicBezierFixedStepSample +{ + float T; + float Length; + ImVec2 Point; + bool BreakSearch; +}; + +using ImCubicBezierFixedStepCallback = void (*)(ImCubicBezierFixedStepSample& sample, void* user_pointer); + +inline void ImCubicBezierFixedStep(ImCubicBezierFixedStepCallback callback, void* user_pointer, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float step, bool overshoot = false, float max_value_error = 1e-3f, float max_t_error = 1e-5f); +inline void ImCubicBezierFixedStep(ImCubicBezierFixedStepCallback callback, void* user_pointer, const ImCubicBezierPoints& curve, float step, bool overshoot = false, float max_value_error = 1e-3f, float max_t_error = 1e-5f); + + +// F has signature void(const ImCubicBezierFixedStepSample& p) +template inline void ImCubicBezierFixedStep(F& callback, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float step, bool overshoot = false, float max_value_error = 1e-3f, float max_t_error = 1e-5f); +template inline void ImCubicBezierFixedStep(F& callback, const ImCubicBezierPoints& curve, float step, bool overshoot = false, float max_value_error = 1e-3f, float max_t_error = 1e-5f); + + +//------------------------------------------------------------------------------ +# include "imgui_bezier_math.inl" + + +//------------------------------------------------------------------------------ +# endif // __IMGUI_BEZIER_MATH_H__ diff --git a/3rdparty/imgui-node-editor/imgui_bezier_math.inl b/3rdparty/imgui-node-editor/imgui_bezier_math.inl new file mode 100644 index 0000000..9f497f6 --- /dev/null +++ b/3rdparty/imgui-node-editor/imgui_bezier_math.inl @@ -0,0 +1,689 @@ +//Disable a bunch of warnings for now +#ifndef _MSC_VER +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wshadow" +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//------------------------------------------------------------------------------ +// VERSION 0.1 +// +// LICENSE +// This software is dual-licensed to the public domain and under the following +// license: you are granted a perpetual, irrevocable license to copy, modify, +// publish, and distribute this file as you see fit. +// +// CREDITS +// Written by Michal Cichon +//------------------------------------------------------------------------------ +# ifndef __IMGUI_BEZIER_MATH_INL__ +# define __IMGUI_BEZIER_MATH_INL__ +# pragma once + + +//------------------------------------------------------------------------------ +# include "imgui_bezier_math.h" +# include // used in ImCubicBezierFixedStep + + +//------------------------------------------------------------------------------ +template +inline T ImLinearBezier(const T& p0, const T& p1, float t) +{ + return p0 + t * (p1 - p0); +} + +template +inline T ImLinearBezierDt(const T& p0, const T& p1, float t) +{ + IM_UNUSED(t); + + return p1 - p0; +} + +template +inline T ImQuadraticBezier(const T& p0, const T& p1, const T& p2, float t) +{ + const auto a = 1 - t; + + return a * a * p0 + 2 * t * a * p1 + t * t * p2; +} + +template +inline T ImQuadraticBezierDt(const T& p0, const T& p1, const T& p2, float t) +{ + return 2 * (1 - t) * (p1 - p0) + 2 * t * (p2 - p1); +} + +template +inline T ImCubicBezier(const T& p0, const T& p1, const T& p2, const T& p3, float t) +{ + const auto a = 1 - t; + const auto b = a * a * a; + const auto c = t * t * t; + + return b * p0 + 3 * t * a * a * p1 + 3 * t * t * a * p2 + c * p3; +} + +template +inline T ImCubicBezierDt(const T& p0, const T& p1, const T& p2, const T& p3, float t) +{ + const auto a = 1 - t; + const auto b = a * a; + const auto c = t * t; + const auto d = 2 * t * a; + + return -3 * p0 * b + 3 * p1 * (b - d) + 3 * p2 * (d - c) + 3 * p3 * c; +} + +template +inline T ImCubicBezierSample(const T& p0, const T& p1, const T& p2, const T& p3, float t) +{ + const auto cp0_zero = ImLengthSqr(p1 - p0) < 1e-5f; + const auto cp1_zero = ImLengthSqr(p3 - p2) < 1e-5f; + + if (cp0_zero && cp1_zero) + return ImLinearBezier(p0, p3, t); + else if (cp0_zero) + return ImQuadraticBezier(p0, p2, p3, t); + else if (cp1_zero) + return ImQuadraticBezier(p0, p1, p3, t); + else + return ImCubicBezier(p0, p1, p2, p3, t); +} + +template +inline T ImCubicBezierSample(const ImCubicBezierPointsT& curve, float t) +{ + return ImCubicBezierSample(curve.P0, curve.P1, curve.P2, curve.P3, t); +} + +template +inline T ImCubicBezierTangent(const T& p0, const T& p1, const T& p2, const T& p3, float t) +{ + const auto cp0_zero = ImLengthSqr(p1 - p0) < 1e-5f; + const auto cp1_zero = ImLengthSqr(p3 - p2) < 1e-5f; + + if (cp0_zero && cp1_zero) + return ImLinearBezierDt(p0, p3, t); + else if (cp0_zero) + return ImQuadraticBezierDt(p0, p2, p3, t); + else if (cp1_zero) + return ImQuadraticBezierDt(p0, p1, p3, t); + else + return ImCubicBezierDt(p0, p1, p2, p3, t); +} + +template +inline T ImCubicBezierTangent(const ImCubicBezierPointsT& curve, float t) +{ + return ImCubicBezierTangent(curve.P0, curve.P1, curve.P2, curve.P3, t); +} + +template +inline float ImCubicBezierLength(const T& p0, const T& p1, const T& p2, const T& p3) +{ + // Legendre-Gauss abscissae with n=24 (x_i values, defined at i=n as the roots of the nth order Legendre polynomial Pn(x)) + static const float t_values[] = + { + -0.0640568928626056260850430826247450385909f, + 0.0640568928626056260850430826247450385909f, + -0.1911188674736163091586398207570696318404f, + 0.1911188674736163091586398207570696318404f, + -0.3150426796961633743867932913198102407864f, + 0.3150426796961633743867932913198102407864f, + -0.4337935076260451384870842319133497124524f, + 0.4337935076260451384870842319133497124524f, + -0.5454214713888395356583756172183723700107f, + 0.5454214713888395356583756172183723700107f, + -0.6480936519369755692524957869107476266696f, + 0.6480936519369755692524957869107476266696f, + -0.7401241915785543642438281030999784255232f, + 0.7401241915785543642438281030999784255232f, + -0.8200019859739029219539498726697452080761f, + 0.8200019859739029219539498726697452080761f, + -0.8864155270044010342131543419821967550873f, + 0.8864155270044010342131543419821967550873f, + -0.9382745520027327585236490017087214496548f, + 0.9382745520027327585236490017087214496548f, + -0.9747285559713094981983919930081690617411f, + 0.9747285559713094981983919930081690617411f, + -0.9951872199970213601799974097007368118745f, + 0.9951872199970213601799974097007368118745f + }; + + // Legendre-Gauss weights with n=24 (w_i values, defined by a function linked to in the Bezier primer article) + static const float c_values[] = + { + 0.1279381953467521569740561652246953718517f, + 0.1279381953467521569740561652246953718517f, + 0.1258374563468282961213753825111836887264f, + 0.1258374563468282961213753825111836887264f, + 0.1216704729278033912044631534762624256070f, + 0.1216704729278033912044631534762624256070f, + 0.1155056680537256013533444839067835598622f, + 0.1155056680537256013533444839067835598622f, + 0.1074442701159656347825773424466062227946f, + 0.1074442701159656347825773424466062227946f, + 0.0976186521041138882698806644642471544279f, + 0.0976186521041138882698806644642471544279f, + 0.0861901615319532759171852029837426671850f, + 0.0861901615319532759171852029837426671850f, + 0.0733464814110803057340336152531165181193f, + 0.0733464814110803057340336152531165181193f, + 0.0592985849154367807463677585001085845412f, + 0.0592985849154367807463677585001085845412f, + 0.0442774388174198061686027482113382288593f, + 0.0442774388174198061686027482113382288593f, + 0.0285313886289336631813078159518782864491f, + 0.0285313886289336631813078159518782864491f, + 0.0123412297999871995468056670700372915759f, + 0.0123412297999871995468056670700372915759f + }; + + static_assert(sizeof(t_values) / sizeof(*t_values) == sizeof(c_values) / sizeof(*c_values), ""); + + auto arc = [p0, p1, p2, p3](float t) + { + const auto p = ImCubicBezierDt(p0, p1, p2, p3, t); + const auto l = ImLength(p); + return l; + }; + + const auto z = 0.5f; + const auto n = sizeof(t_values) / sizeof(*t_values); + + auto accumulator = 0.0f; + for (size_t i = 0; i < n; ++i) + { + const auto t = z * t_values[i] + z; + accumulator += c_values[i] * arc(t); + } + + return z * accumulator; +} + +template +inline float ImCubicBezierLength(const ImCubicBezierPointsT& curve) +{ + return ImCubicBezierLength(curve.P0, curve.P1, curve.P2, curve.P3); +} + +template +inline ImCubicBezierSplitResultT ImCubicBezierSplit(const T& p0, const T& p1, const T& p2, const T& p3, float t) +{ + const auto z1 = t; + const auto z2 = z1 * z1; + const auto z3 = z1 * z1 * z1; + const auto s1 = z1 - 1; + const auto s2 = s1 * s1; + const auto s3 = s1 * s1 * s1; + + return ImCubicBezierSplitResultT + { + ImCubicBezierPointsT + { + p0, + z1 * p1 - s1 * p0, + z2 * p2 - 2 * z1 * s1 * p1 + s2 * p0, + z3 * p3 - 3 * z2 * s1 * p2 + 3 * z1 * s2 * p1 - s3 * p0 + }, + ImCubicBezierPointsT + { + z3 * p0 - 3 * z2 * s1 * p1 + 3 * z1 * s2 * p2 - s3 * p3, + z2 * p1 - 2 * z1 * s1 * p2 + s2 * p3, + z1 * p2 - s1 * p3, + p3, + } + }; +} + +template +inline ImCubicBezierSplitResultT ImCubicBezierSplit(const ImCubicBezierPointsT& curve, float t) +{ + return ImCubicBezierSplit(curve.P0, curve.P1, curve.P2, curve.P3, t); +} + +inline ImRect ImCubicBezierBoundingRect(const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3) +{ + auto a = 3 * p3 - 9 * p2 + 9 * p1 - 3 * p0; + auto b = 6 * p0 - 12 * p1 + 6 * p2; + auto c = 3 * p1 - 3 * p0; + auto delta_squared = ImMul(b, b) - 4 * ImMul(a, c); + + auto tl = ImMin(p0, p3); + auto rb = ImMax(p0, p3); + +# define IM_VEC2_INDEX(v, i) *(&v.x + i) + + for (int i = 0; i < 2; ++i) + { + if (IM_VEC2_INDEX(a, i) == 0.0f) + continue; + + if (IM_VEC2_INDEX(delta_squared, i) >= 0) + { + auto delta = ImSqrt(IM_VEC2_INDEX(delta_squared, i)); + + auto t0 = (-IM_VEC2_INDEX(b, i) + delta) / (2 * IM_VEC2_INDEX(a, i)); + if (t0 > 0 && t0 < 1) + { + auto p = ImCubicBezier(IM_VEC2_INDEX(p0, i), IM_VEC2_INDEX(p1, i), IM_VEC2_INDEX(p2, i), IM_VEC2_INDEX(p3, i), t0); + IM_VEC2_INDEX(tl, i) = ImMin(IM_VEC2_INDEX(tl, i), p); + IM_VEC2_INDEX(rb, i) = ImMax(IM_VEC2_INDEX(rb, i), p); + } + + auto t1 = (-IM_VEC2_INDEX(b, i) - delta) / (2 * IM_VEC2_INDEX(a, i)); + if (t1 > 0 && t1 < 1) + { + auto p = ImCubicBezier(IM_VEC2_INDEX(p0, i), IM_VEC2_INDEX(p1, i), IM_VEC2_INDEX(p2, i), IM_VEC2_INDEX(p3, i), t1); + IM_VEC2_INDEX(tl, i) = ImMin(IM_VEC2_INDEX(tl, i), p); + IM_VEC2_INDEX(rb, i) = ImMax(IM_VEC2_INDEX(rb, i), p); + } + } + } + +# undef IM_VEC2_INDEX + + return ImRect(tl, rb); +} + +inline ImRect ImCubicBezierBoundingRect(const ImCubicBezierPoints& curve) +{ + return ImCubicBezierBoundingRect(curve.P0, curve.P1, curve.P2, curve.P3); +} + +inline ImProjectResult ImProjectOnCubicBezier(const ImVec2& point, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const int subdivisions) +{ + // http://pomax.github.io/bezierinfo/#projections + + const float epsilon = 1e-5f; + const float fixed_step = 1.0f / static_cast(subdivisions - 1); + + ImProjectResult result; + result.Point = point; + result.Time = 0.0f; + result.Distance = FLT_MAX; + + // Step 1: Coarse check + for (int i = 0; i < subdivisions; ++i) + { + auto t = i * fixed_step; + auto p = ImCubicBezier(p0, p1, p2, p3, t); + auto s = point - p; + auto d = ImDot(s, s); + + if (d < result.Distance) + { + result.Point = p; + result.Time = t; + result.Distance = d; + } + } + + if (result.Time == 0.0f || ImFabs(result.Time - 1.0f) <= epsilon) + { + result.Distance = ImSqrt(result.Distance); + return result; + } + + // Step 2: Fine check + auto left = result.Time - fixed_step; + auto right = result.Time + fixed_step; + auto step = fixed_step * 0.1f; + + for (auto t = left; t < right + step; t += step) + { + auto p = ImCubicBezier(p0, p1, p2, p3, t); + auto s = point - p; + auto d = ImDot(s, s); + + if (d < result.Distance) + { + result.Point = p; + result.Time = t; + result.Distance = d; + } + } + + result.Distance = ImSqrt(result.Distance); + + return result; +} + +inline ImProjectResult ImProjectOnCubicBezier(const ImVec2& p, const ImCubicBezierPoints& curve, const int subdivisions) +{ + return ImProjectOnCubicBezier(p, curve.P0, curve.P1, curve.P2, curve.P3, subdivisions); +} + +inline ImCubicBezierIntersectResult ImCubicBezierLineIntersect(const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& a0, const ImVec2& a1) +{ + auto cubic_roots = [](float a, float b, float c, float d, float* roots) -> int + { + int count = 0; + + auto sign = [](float x) -> float { return x < 0 ? -1.0f : 1.0f; }; + + auto A = b / a; + auto B = c / a; + auto C = d / a; + + auto Q = (3 * B - ImPow(A, 2)) / 9; + auto R = (9 * A * B - 27 * C - 2 * ImPow(A, 3)) / 54; + auto D = ImPow(Q, 3) + ImPow(R, 2); // polynomial discriminant + + if (D >= 0) // complex or duplicate roots + { + auto S = sign(R + ImSqrt(D)) * ImPow(ImFabs(R + ImSqrt(D)), (1.0f / 3.0f)); + auto T = sign(R - ImSqrt(D)) * ImPow(ImFabs(R - ImSqrt(D)), (1.0f / 3.0f)); + + roots[0] = -A / 3 + (S + T); // real root + roots[1] = -A / 3 - (S + T) / 2; // real part of complex root + roots[2] = -A / 3 - (S + T) / 2; // real part of complex root + auto Im = ImFabs(ImSqrt(3) * (S - T) / 2); // complex part of root pair + + // discard complex roots + if (Im != 0) + count = 1; + else + count = 3; + } + else // distinct real roots + { + auto th = ImAcos(R / ImSqrt(-ImPow(Q, 3))); + + roots[0] = 2 * ImSqrt(-Q) * ImCos(th / 3) - A / 3; + roots[1] = 2 * ImSqrt(-Q) * ImCos((th + 2 * IM_PI) / 3) - A / 3; + roots[2] = 2 * ImSqrt(-Q) * ImCos((th + 4 * IM_PI) / 3) - A / 3; + + count = 3; + } + + return count; + }; + + /* + https://github.com/kaishiqi/Geometric-Bezier/blob/master/GeometricBezier/src/kaishiqi/geometric/intersection/Intersection.as + + Start with Bezier using Bernstein polynomials for weighting functions: + (1-t^3)P0 + 3t(1-t)^2P1 + 3t^2(1-t)P2 + t^3P3 + + Expand and collect terms to form linear combinations of original Bezier + controls. This ends up with a vector cubic in t: + (-P0+3P1-3P2+P3)t^3 + (3P0-6P1+3P2)t^2 + (-3P0+3P1)t + P0 + /\ /\ /\ /\ + || || || || + c3 c2 c1 c0 + */ + + // Calculate the coefficients + auto c3 = -p0 + 3 * p1 - 3 * p2 + p3; + auto c2 = 3 * p0 - 6 * p1 + 3 * p2; + auto c1 = -3 * p0 + 3 * p1; + auto c0 = p0; + + // Convert line to normal form: ax + by + c = 0 + auto a = a1.y - a0.y; + auto b = a0.x - a1.x; + auto c = a0.x * (a0.y - a1.y) + a0.y * (a1.x - a0.x); + + // Rotate each cubic coefficient using line for new coordinate system? + // Find roots of rotated cubic + float roots[3]; + auto rootCount = cubic_roots( + a * c3.x + b * c3.y, + a * c2.x + b * c2.y, + a * c1.x + b * c1.y, + a * c0.x + b * c0.y + c, + roots); + + // Any roots in closed interval [0,1] are intersections on Bezier, but + // might not be on the line segment. + // Find intersections and calculate point coordinates + + auto min = ImMin(a0, a1); + auto max = ImMax(a0, a1); + + ImCubicBezierIntersectResult result; + auto points = result.Points; + + for (int i = 0; i < rootCount; ++i) + { + auto root = roots[i]; + + if (0 <= root && root <= 1) + { + // We're within the Bezier curve + // Find point on Bezier + auto p = ImCubicBezier(p0, p1, p2, p3, root); + + // See if point is on line segment + // Had to make special cases for vertical and horizontal lines due + // to slight errors in calculation of p00 + if (a0.x == a1.x) + { + if (min.y <= p.y && p.y <= max.y) + *points++ = p; + } + else if (a0.y == a1.y) + { + if (min.x <= p.x && p.x <= max.x) + *points++ = p; + } + else if (p.x >= min.x && p.y >= min.y && p.x <= max.x && p.y <= max.y) + { + *points++ = p; + } + } + } + + result.Count = static_cast(points - result.Points); + + return result; +} + +inline ImCubicBezierIntersectResult ImCubicBezierLineIntersect(const ImCubicBezierPoints& curve, const ImLine& line) +{ + return ImCubicBezierLineIntersect(curve.P0, curve.P1, curve.P2, curve.P3, line.A, line.B); +} + +inline void ImCubicBezierSubdivide(ImCubicBezierSubdivideCallback callback, void* user_pointer, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float tess_tol, ImCubicBezierSubdivideFlags flags) +{ + return ImCubicBezierSubdivide(callback, user_pointer, ImCubicBezierPoints{ p0, p1, p2, p3 }, tess_tol, flags); +} + +inline void ImCubicBezierSubdivide(ImCubicBezierSubdivideCallback callback, void* user_pointer, const ImCubicBezierPoints& curve, float tess_tol, ImCubicBezierSubdivideFlags flags) +{ + struct Tesselator + { + ImCubicBezierSubdivideCallback Callback; + void* UserPointer; + float TesselationTollerance; + ImCubicBezierSubdivideFlags Flags; + + void Commit(const ImVec2& p, const ImVec2& t) + { + ImCubicBezierSubdivideSample sample; + sample.Point = p; + sample.Tangent = t; + Callback(sample, UserPointer); + } + + void Subdivide(const ImCubicBezierPoints& curve, int level = 0) + { + float dx = curve.P3.x - curve.P0.x; + float dy = curve.P3.y - curve.P0.y; + float d2 = ((curve.P1.x - curve.P3.x) * dy - (curve.P1.y - curve.P3.y) * dx); + float d3 = ((curve.P2.x - curve.P3.x) * dy - (curve.P2.y - curve.P3.y) * dx); + d2 = (d2 >= 0) ? d2 : -d2; + d3 = (d3 >= 0) ? d3 : -d3; + if ((d2 + d3) * (d2 + d3) < TesselationTollerance * (dx * dx + dy * dy)) + { + Commit(curve.P3, ImCubicBezierTangent(curve, 1.0f)); + } + else if (level < 10) + { + const auto p12 = (curve.P0 + curve.P1) * 0.5f; + const auto p23 = (curve.P1 + curve.P2) * 0.5f; + const auto p34 = (curve.P2 + curve.P3) * 0.5f; + const auto p123 = (p12 + p23) * 0.5f; + const auto p234 = (p23 + p34) * 0.5f; + const auto p1234 = (p123 + p234) * 0.5f; + + Subdivide(ImCubicBezierPoints { curve.P0, p12, p123, p1234 }, level + 1); + Subdivide(ImCubicBezierPoints { p1234, p234, p34, curve.P3 }, level + 1); + } + } + }; + + if (tess_tol < 0) + tess_tol = 1.118f; // sqrtf(1.25f) + + Tesselator tesselator; + tesselator.Callback = callback; + tesselator.UserPointer = user_pointer; + tesselator.TesselationTollerance = tess_tol * tess_tol; + tesselator.Flags = flags; + + if (!(tesselator.Flags & ImCubicBezierSubdivide_SkipFirst)) + tesselator.Commit(curve.P0, ImCubicBezierTangent(curve, 0.0f)); + + tesselator.Subdivide(curve, 0); +} + +template inline void ImCubicBezierSubdivide(F& callback, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float tess_tol, ImCubicBezierSubdivideFlags flags) +{ + auto handler = [](const ImCubicBezierSubdivideSample& p, void* user_pointer) + { + auto& callback = *reinterpret_cast(user_pointer); + callback(p); + }; + + ImCubicBezierSubdivide(handler, &callback, ImCubicBezierPoints{ p0, p1, p2, p3 }, tess_tol, flags); +} + +template inline void ImCubicBezierSubdivide(F& callback, const ImCubicBezierPoints& curve, float tess_tol, ImCubicBezierSubdivideFlags flags) +{ + auto handler = [](const ImCubicBezierSubdivideSample& p, void* user_pointer) + { + auto& callback = *reinterpret_cast(user_pointer); + callback(p); + }; + + ImCubicBezierSubdivide(handler, &callback, curve, tess_tol, flags); +} + +inline void ImCubicBezierFixedStep(ImCubicBezierFixedStepCallback callback, void* user_pointer, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float step, bool overshoot, float max_value_error, float max_t_error) +{ + if (step <= 0.0f || !callback || max_value_error <= 0 || max_t_error <= 0) + return; + + ImCubicBezierFixedStepSample sample; + sample.T = 0.0f; + sample.Length = 0.0f; + sample.Point = p0; + sample.BreakSearch = false; + + callback(sample, user_pointer); + if (sample.BreakSearch) + return; + + const auto total_length = ImCubicBezierLength(p0, p1, p2, p3); + const auto point_count = static_cast(total_length / step) + (overshoot ? 2 : 1); + const auto t_min = 0.0f; + const auto t_max = step * point_count / total_length; + const auto t_0 = (t_min + t_max) * 0.5f; + + // #todo: replace map with ImVector + binary search + std::map cache; + for (int point_index = 1; point_index < point_count; ++point_index) + { + const auto targetLength = point_index * step; + + float t_start = t_min; + float t_end = t_max; + float t = t_0; + + float t_best = t; + float error_best = total_length; + + while (true) + { + auto cacheIt = cache.find(t); + if (cacheIt == cache.end()) + { + const auto front = ImCubicBezierSplit(p0, p1, p2, p3, t).Left; + const auto split_length = ImCubicBezierLength(front); + + cacheIt = cache.emplace(t, split_length).first; + } + + const auto length = cacheIt->second; + const auto error = targetLength - length; + + if (error < error_best) + { + error_best = error; + t_best = t; + } + + if (ImFabs(error) <= max_value_error || ImFabs(t_start - t_end) <= max_t_error) + { + sample.T = t; + sample.Length = length; + sample.Point = ImCubicBezier(p0, p1, p2, p3, t); + + callback(sample, user_pointer); + if (sample.BreakSearch) + return; + + break; + } + else if (error < 0.0f) + t_end = t; + else // if (error > 0.0f) + t_start = t; + + t = (t_start + t_end) * 0.5f; + } + } +} + +inline void ImCubicBezierFixedStep(ImCubicBezierFixedStepCallback callback, void* user_pointer, const ImCubicBezierPoints& curve, float step, bool overshoot, float max_value_error, float max_t_error) +{ + ImCubicBezierFixedStep(callback, user_pointer, curve.P0, curve.P1, curve.P2, curve.P3, step, overshoot, max_value_error, max_t_error); +} + +// F has signature void(const ImCubicBezierFixedStepSample& p) +template +inline void ImCubicBezierFixedStep(F& callback, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float step, bool overshoot, float max_value_error, float max_t_error) +{ + auto handler = [](ImCubicBezierFixedStepSample& sample, void* user_pointer) + { + auto& callback = *reinterpret_cast(user_pointer); + callback(sample); + }; + + ImCubicBezierFixedStep(handler, &callback, p0, p1, p2, p3, step, overshoot, max_value_error, max_t_error); +} + +template +inline void ImCubicBezierFixedStep(F& callback, const ImCubicBezierPoints& curve, float step, bool overshoot, float max_value_error, float max_t_error) +{ + auto handler = [](ImCubicBezierFixedStepSample& sample, void* user_pointer) + { + auto& callback = *reinterpret_cast(user_pointer); + callback(sample); + }; + + ImCubicBezierFixedStep(handler, &callback, curve.P0, curve.P1, curve.P2, curve.P3, step, overshoot, max_value_error, max_t_error); +} + + +//------------------------------------------------------------------------------ +# endif // __IMGUI_BEZIER_MATH_INL__ + +#ifndef _MSC_VER +#pragma GCC diagnostic pop +#endif diff --git a/3rdparty/imgui-node-editor/imgui_canvas.cpp b/3rdparty/imgui-node-editor/imgui_canvas.cpp new file mode 100644 index 0000000..c58c8ed --- /dev/null +++ b/3rdparty/imgui-node-editor/imgui_canvas.cpp @@ -0,0 +1,550 @@ +# define IMGUI_DEFINE_MATH_OPERATORS +# include "imgui_canvas.h" +# include + +// https://stackoverflow.com/a/36079786 +# define DECLARE_HAS_MEMBER(__trait_name__, __member_name__) \ + \ + template \ + class __trait_name__ \ + { \ + using check_type = ::std::remove_const_t<__boost_has_member_T__>; \ + struct no_type {char x[2];}; \ + using yes_type = char; \ + \ + struct base { void __member_name__() {}}; \ + struct mixin : public base, public check_type {}; \ + \ + template struct aux {}; \ + \ + template static no_type test(aux<&U::__member_name__>*); \ + template static yes_type test(...); \ + \ + public: \ + \ + static constexpr bool value = (sizeof(yes_type) == sizeof(test(0))); \ + } + +namespace ImCanvasDetails { + +DECLARE_HAS_MEMBER(HasFringeScale, _FringeScale); + +struct FringeScaleRef +{ + // Overload is present when ImDrawList does have _FringeScale member variable. + template + static float& Get(typename std::enable_if::value, T>::type* drawList) + { + return drawList->_FringeScale; + } + + // Overload is present when ImDrawList does not have _FringeScale member variable. + template + static float& Get(typename std::enable_if::value, T>::type*) + { + static float placeholder = 1.0f; + return placeholder; + } +}; + +DECLARE_HAS_MEMBER(HasVtxCurrentOffset, _VtxCurrentOffset); + +struct VtxCurrentOffsetRef +{ + // Overload is present when ImDrawList does have _FringeScale member variable. + template + static unsigned int& Get(typename std::enable_if::value, T>::type* drawList) + { + return drawList->_VtxCurrentOffset; + } + + // Overload is present when ImDrawList does not have _FringeScale member variable. + template + static unsigned int& Get(typename std::enable_if::value, T>::type* drawList) + { + return drawList->_CmdHeader.VtxOffset; + } +}; + +} // namespace ImCanvasDetails + +// Returns a reference to _FringeScale extension to ImDrawList +// +// If ImDrawList does not have _FringeScale a placeholder is returned. +static inline float& ImFringeScaleRef(ImDrawList* drawList) +{ + using namespace ImCanvasDetails; + return FringeScaleRef::Get(drawList); +} + +static inline unsigned int& ImVtxOffsetRef(ImDrawList* drawList) +{ + using namespace ImCanvasDetails; + return VtxCurrentOffsetRef::Get(drawList); +} + +static inline ImVec2 ImSelectPositive(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x > 0.0f ? lhs.x : rhs.x, lhs.y > 0.0f ? lhs.y : rhs.y); } + +bool ImGuiEx::Canvas::Begin(const char* id, const ImVec2& size) +{ + return Begin(ImGui::GetID(id), size); +} + +bool ImGuiEx::Canvas::Begin(ImGuiID id, const ImVec2& size) +{ + IM_ASSERT(m_InBeginEnd == false); + + m_WidgetPosition = ImGui::GetCursorScreenPos(); + m_WidgetSize = ImSelectPositive(size, ImGui::GetContentRegionAvail()); + m_WidgetRect = ImRect(m_WidgetPosition, m_WidgetPosition + m_WidgetSize); + m_DrawList = ImGui::GetWindowDrawList(); + + UpdateViewTransformPosition(); + +# if IMGUI_VERSION_NUM > 18415 + if (ImGui::IsClippedEx(m_WidgetRect, id)) + return false; +# else + if (ImGui::IsClippedEx(m_WidgetRect, id, false)) + return false; +# endif + + // Save current channel, so we can assert when user + // call canvas API with different one. + m_ExpectedChannel = m_DrawList->_Splitter._Current; + + // #debug: Canvas content. + //m_DrawList->AddRectFilled(m_StartPos, m_StartPos + m_CurrentSize, IM_COL32(0, 0, 0, 64)); + m_DrawList->AddRect(m_WidgetRect.Min, m_WidgetRect.Max, IM_COL32(255, 0, 255, 64)); + + ImGui::SetCursorScreenPos(ImVec2(0.0f, 0.0f)); + +# if IMGUI_EX_CANVAS_DEFERED() + m_Ranges.resize(0); +# endif + + SaveInputState(); + SaveViewportState(); + + // Record cursor max to prevent scrollbars from appearing. + m_WindowCursorMaxBackup = ImGui::GetCurrentWindow()->DC.CursorMaxPos; + + EnterLocalSpace(); + + // Emit dummy widget matching bounds of the canvas. + ImGui::SetCursorScreenPos(m_ViewRect.Min); + ImGui::Dummy(m_ViewRect.GetSize()); + + ImGui::SetCursorScreenPos(ImVec2(0.0f, 0.0f)); + + m_InBeginEnd = true; + + return true; +} + +void ImGuiEx::Canvas::End() +{ + // If you're here your call to Begin() returned false, + // or Begin() wasn't called at all. + IM_ASSERT(m_InBeginEnd == true); + + // If you're here, please make sure you do not interleave + // channel splitter with canvas. + // Always call canvas function with using same channel. + IM_ASSERT(m_DrawList->_Splitter._Current == m_ExpectedChannel); + + //auto& io = ImGui::GetIO(); + + // Check: Unmatched calls to Suspend() / Resume(). Please check your code. + IM_ASSERT(m_SuspendCounter == 0); + + LeaveLocalSpace(); + + ImGui::GetCurrentWindow()->DC.CursorMaxPos = m_WindowCursorMaxBackup; + + ImGui::SetItemAllowOverlap(); + + // Emit dummy widget matching bounds of the canvas. + ImGui::SetCursorScreenPos(m_WidgetPosition); + ImGui::Dummy(m_WidgetSize); + + // #debug: Rect around canvas. Content should be inside these bounds. + //m_DrawList->AddRect(m_WidgetPosition - ImVec2(1.0f, 1.0f), m_WidgetPosition + m_WidgetSize + ImVec2(1.0f, 1.0f), IM_COL32(196, 0, 0, 255)); + + m_InBeginEnd = false; +} + +void ImGuiEx::Canvas::SetView(const ImVec2& origin, float scale) +{ + SetView(CanvasView(origin, scale)); +} + +void ImGuiEx::Canvas::SetView(const CanvasView& view) +{ + if (m_InBeginEnd) + LeaveLocalSpace(); + + if (m_View.Origin.x != view.Origin.x || m_View.Origin.y != view.Origin.y) + { + m_View.Origin = view.Origin; + + UpdateViewTransformPosition(); + } + + if (m_View.Scale != view.Scale) + { + m_View.Scale = view.Scale; + m_View.InvScale = view.InvScale; + } + + if (m_InBeginEnd) + EnterLocalSpace(); +} + +void ImGuiEx::Canvas::CenterView(const ImVec2& canvasPoint) +{ + auto view = CalcCenterView(canvasPoint); + SetView(view); +} + +ImGuiEx::CanvasView ImGuiEx::Canvas::CalcCenterView(const ImVec2& canvasPoint) const +{ + auto localCenter = ToLocal(m_WidgetPosition + m_WidgetSize * 0.5f); + auto localOffset = canvasPoint - localCenter; + auto offset = FromLocalV(localOffset); + + return CanvasView{ m_View.Origin - offset, m_View.Scale }; +} + +void ImGuiEx::Canvas::CenterView(const ImRect& canvasRect) +{ + auto view = CalcCenterView(canvasRect); + + SetView(view); +} + +ImGuiEx::CanvasView ImGuiEx::Canvas::CalcCenterView(const ImRect& canvasRect) const +{ + auto canvasRectSize = canvasRect.GetSize(); + + if (canvasRectSize.x <= 0.0f || canvasRectSize.y <= 0.0f) + return View(); + + auto widgetAspectRatio = m_WidgetSize.y > 0.0f ? m_WidgetSize.x / m_WidgetSize.y : 0.0f; + auto canvasRectAspectRatio = canvasRectSize.y > 0.0f ? canvasRectSize.x / canvasRectSize.y : 0.0f; + + if (widgetAspectRatio <= 0.0f || canvasRectAspectRatio <= 0.0f) + return View(); + + auto newOrigin = m_View.Origin; + auto newScale = m_View.Scale; + if (canvasRectAspectRatio > widgetAspectRatio) + { + // width span across view + newScale = m_WidgetSize.x / canvasRectSize.x; + newOrigin = canvasRect.Min * -newScale; + newOrigin.y += (m_WidgetSize.y - canvasRectSize.y * newScale) * 0.5f; + } + else + { + // height span across view + newScale = m_WidgetSize.y / canvasRectSize.y; + newOrigin = canvasRect.Min * -newScale; + newOrigin.x += (m_WidgetSize.x - canvasRectSize.x * newScale) * 0.5f; + } + + return CanvasView{ newOrigin, newScale }; +} + +void ImGuiEx::Canvas::Suspend() +{ + // If you're here, please make sure you do not interleave + // channel splitter with canvas. + // Always call canvas function with using same channel. + IM_ASSERT(m_DrawList->_Splitter._Current == m_ExpectedChannel); + + if (m_SuspendCounter == 0) + LeaveLocalSpace(); + + ++m_SuspendCounter; +} + +void ImGuiEx::Canvas::Resume() +{ + // If you're here, please make sure you do not interleave + // channel splitter with canvas. + // Always call canvas function with using same channel. + IM_ASSERT(m_DrawList->_Splitter._Current == m_ExpectedChannel); + + // Check: Number of calls to Resume() do not match calls to Suspend(). Please check your code. + IM_ASSERT(m_SuspendCounter > 0); + if (--m_SuspendCounter == 0) + EnterLocalSpace(); +} + +ImVec2 ImGuiEx::Canvas::FromLocal(const ImVec2& point) const +{ + return point * m_View.Scale + m_ViewTransformPosition; +} + +ImVec2 ImGuiEx::Canvas::FromLocal(const ImVec2& point, const CanvasView& view) const +{ + return point * view.Scale + view.Origin + m_WidgetPosition; +} + +ImVec2 ImGuiEx::Canvas::FromLocalV(const ImVec2& vector) const +{ + return vector * m_View.Scale; +} + +ImVec2 ImGuiEx::Canvas::FromLocalV(const ImVec2& vector, const CanvasView& view) const +{ + return vector * view.Scale; +} + +ImVec2 ImGuiEx::Canvas::ToLocal(const ImVec2& point) const +{ + return (point - m_ViewTransformPosition) * m_View.InvScale; +} + +ImVec2 ImGuiEx::Canvas::ToLocal(const ImVec2& point, const CanvasView& view) const +{ + return (point - view.Origin - m_WidgetPosition) * view.InvScale; +} + +ImVec2 ImGuiEx::Canvas::ToLocalV(const ImVec2& vector) const +{ + return vector * m_View.InvScale; +} + +ImVec2 ImGuiEx::Canvas::ToLocalV(const ImVec2& vector, const CanvasView& view) const +{ + return vector * view.InvScale; +} + +ImRect ImGuiEx::Canvas::CalcViewRect(const CanvasView& view) const +{ + ImRect result; + result.Min = ImVec2(-view.Origin.x, -view.Origin.y) * view.InvScale; + result.Max = (m_WidgetSize - view.Origin) * view.InvScale; + return result; +} + +void ImGuiEx::Canvas::UpdateViewTransformPosition() +{ + m_ViewTransformPosition = m_View.Origin + m_WidgetPosition; +} + +void ImGuiEx::Canvas::SaveInputState() +{ + auto& io = ImGui::GetIO(); + m_MousePosBackup = io.MousePos; + m_MousePosPrevBackup = io.MousePosPrev; + for (auto i = 0; i < IM_ARRAYSIZE(m_MouseClickedPosBackup); ++i) + m_MouseClickedPosBackup[i] = io.MouseClickedPos[i]; +} + +void ImGuiEx::Canvas::RestoreInputState() +{ + auto& io = ImGui::GetIO(); + io.MousePos = m_MousePosBackup; + io.MousePosPrev = m_MousePosPrevBackup; + for (auto i = 0; i < IM_ARRAYSIZE(m_MouseClickedPosBackup); ++i) + io.MouseClickedPos[i] = m_MouseClickedPosBackup[i]; +} + +void ImGuiEx::Canvas::SaveViewportState() +{ +# if defined(IMGUI_HAS_VIEWPORT) + auto window = ImGui::GetCurrentWindow(); + auto viewport = ImGui::GetWindowViewport(); + + m_WindowPosBackup = window->Pos; + m_ViewportPosBackup = viewport->Pos; + m_ViewportSizeBackup = viewport->Size; +# if IMGUI_VERSION_NUM > 18002 + m_ViewportWorkPosBackup = viewport->WorkPos; + m_ViewportWorkSizeBackup = viewport->WorkSize; +# else + m_ViewportWorkOffsetMinBackup = viewport->WorkOffsetMin; + m_ViewportWorkOffsetMaxBackup = viewport->WorkOffsetMax; +# endif +# endif +} + +void ImGuiEx::Canvas::RestoreViewportState() +{ +# if defined(IMGUI_HAS_VIEWPORT) + auto window = ImGui::GetCurrentWindow(); + auto viewport = ImGui::GetWindowViewport(); + + window->Pos = m_WindowPosBackup; + viewport->Pos = m_ViewportPosBackup; + viewport->Size = m_ViewportSizeBackup; +# if IMGUI_VERSION_NUM > 18002 + viewport->WorkPos = m_ViewportWorkPosBackup; + viewport->WorkSize = m_ViewportWorkSizeBackup; +# else + viewport->WorkOffsetMin = m_ViewportWorkOffsetMinBackup; + viewport->WorkOffsetMax = m_ViewportWorkOffsetMaxBackup; +# endif +# endif +} + +void ImGuiEx::Canvas::EnterLocalSpace() +{ + // Prepare ImDrawList for drawing in local coordinate system: + // - determine visible part of the canvas + // - start unique draw command + // - add clip rect matching canvas size + // - record current command index + // - record current vertex write index + + // Determine visible part of the canvas. Make it before + // adding new command, to avoid round rip where command + // is removed in PopClipRect() and added again next PushClipRect(). + ImGui::PushClipRect(m_WidgetPosition, m_WidgetPosition + m_WidgetSize, true); + auto clipped_clip_rect = m_DrawList->_ClipRectStack.back(); + ImGui::PopClipRect(); + + // Make sure we do not share draw command with anyone. We don't want to mess + // with someones clip rectangle. + + // #FIXME: + // This condition is not enough to avoid when user choose + // to use channel splitter. + // + // To deal with Suspend()/Resume() calls empty draw command + // is always added then splitter is active. Otherwise + // channel merger will collapse our draw command one with + // different clip rectangle. + // + // More investigation is needed. To get to the bottom of this. + if ((!m_DrawList->CmdBuffer.empty() && m_DrawList->CmdBuffer.back().ElemCount > 0) || m_DrawList->_Splitter._Count > 1) + m_DrawList->AddDrawCmd(); + +# if IMGUI_EX_CANVAS_DEFERED() + m_Ranges.resize(m_Ranges.Size + 1); + m_CurrentRange = &m_Ranges.back(); + m_CurrentRange->BeginComandIndex = ImMax(m_DrawList->CmdBuffer.Size - 1, 0); + m_CurrentRange->BeginVertexIndex = m_DrawList->_VtxCurrentIdx + ImVtxOffsetRef(m_DrawList); +# endif + m_DrawListCommadBufferSize = ImMax(m_DrawList->CmdBuffer.Size - 1, 0); + m_DrawListStartVertexIndex = m_DrawList->_VtxCurrentIdx + ImVtxOffsetRef(m_DrawList); + +# if defined(IMGUI_HAS_VIEWPORT) + auto window = ImGui::GetCurrentWindow(); + window->Pos = ImVec2(0.0f, 0.0f); + + auto viewport_min = m_ViewportPosBackup; + auto viewport_max = m_ViewportPosBackup + m_ViewportSizeBackup; + + viewport_min.x = (viewport_min.x - m_ViewTransformPosition.x) * m_View.InvScale; + viewport_min.y = (viewport_min.y - m_ViewTransformPosition.y) * m_View.InvScale; + viewport_max.x = (viewport_max.x - m_ViewTransformPosition.x) * m_View.InvScale; + viewport_max.y = (viewport_max.y - m_ViewTransformPosition.y) * m_View.InvScale; + + auto viewport = ImGui::GetWindowViewport(); + viewport->Pos = viewport_min; + viewport->Size = viewport_max - viewport_min; + +# if IMGUI_VERSION_NUM > 18002 + viewport->WorkPos = m_ViewportWorkPosBackup * m_View.InvScale; + viewport->WorkSize = m_ViewportWorkSizeBackup * m_View.InvScale; +# else + viewport->WorkOffsetMin = m_ViewportWorkOffsetMinBackup * m_View.InvScale; + viewport->WorkOffsetMax = m_ViewportWorkOffsetMaxBackup * m_View.InvScale; +# endif +# endif + + // Clip rectangle in parent canvas space and move it to local space. + clipped_clip_rect.x = (clipped_clip_rect.x - m_ViewTransformPosition.x) * m_View.InvScale; + clipped_clip_rect.y = (clipped_clip_rect.y - m_ViewTransformPosition.y) * m_View.InvScale; + clipped_clip_rect.z = (clipped_clip_rect.z - m_ViewTransformPosition.x) * m_View.InvScale; + clipped_clip_rect.w = (clipped_clip_rect.w - m_ViewTransformPosition.y) * m_View.InvScale; + ImGui::PushClipRect(ImVec2(clipped_clip_rect.x, clipped_clip_rect.y), ImVec2(clipped_clip_rect.z, clipped_clip_rect.w), false); + + // Transform mouse position to local space. + auto& io = ImGui::GetIO(); + io.MousePos = (m_MousePosBackup - m_ViewTransformPosition) * m_View.InvScale; + io.MousePosPrev = (m_MousePosPrevBackup - m_ViewTransformPosition) * m_View.InvScale; + for (auto i = 0; i < IM_ARRAYSIZE(m_MouseClickedPosBackup); ++i) + io.MouseClickedPos[i] = (m_MouseClickedPosBackup[i] - m_ViewTransformPosition) * m_View.InvScale; + + m_ViewRect = CalcViewRect(m_View);; + + auto& fringeScale = ImFringeScaleRef(m_DrawList); + m_LastFringeScale = fringeScale; + fringeScale *= m_View.InvScale; +} + +void ImGuiEx::Canvas::LeaveLocalSpace() +{ + IM_ASSERT(m_DrawList->_Splitter._Current == m_ExpectedChannel); + +# if IMGUI_EX_CANVAS_DEFERED() + IM_ASSERT(m_CurrentRange != nullptr); + + m_CurrentRange->EndVertexIndex = m_DrawList->_VtxCurrentIdx + ImVtxOffsetRef(m_DrawList); + m_CurrentRange->EndCommandIndex = m_DrawList->CmdBuffer.size(); + if (m_CurrentRange->BeginVertexIndex == m_CurrentRange->EndVertexIndex) + { + // Drop empty range + m_Ranges.resize(m_Ranges.Size - 1); + } + m_CurrentRange = nullptr; +# endif + + // Move vertices to screen space. + auto vertex = m_DrawList->VtxBuffer.Data + m_DrawListStartVertexIndex; + auto vertexEnd = m_DrawList->VtxBuffer.Data + m_DrawList->_VtxCurrentIdx + ImVtxOffsetRef(m_DrawList); + + // If canvas view is not scaled take a faster path. + if (m_View.Scale != 1.0f) + { + while (vertex < vertexEnd) + { + vertex->pos.x = vertex->pos.x * m_View.Scale + m_ViewTransformPosition.x; + vertex->pos.y = vertex->pos.y * m_View.Scale + m_ViewTransformPosition.y; + ++vertex; + } + + // Move clip rectangles to screen space. + for (int i = m_DrawListCommadBufferSize; i < m_DrawList->CmdBuffer.size(); ++i) + { + auto& command = m_DrawList->CmdBuffer[i]; + command.ClipRect.x = command.ClipRect.x * m_View.Scale + m_ViewTransformPosition.x; + command.ClipRect.y = command.ClipRect.y * m_View.Scale + m_ViewTransformPosition.y; + command.ClipRect.z = command.ClipRect.z * m_View.Scale + m_ViewTransformPosition.x; + command.ClipRect.w = command.ClipRect.w * m_View.Scale + m_ViewTransformPosition.y; + } + } + else + { + while (vertex < vertexEnd) + { + vertex->pos.x = vertex->pos.x + m_ViewTransformPosition.x; + vertex->pos.y = vertex->pos.y + m_ViewTransformPosition.y; + ++vertex; + } + + // Move clip rectangles to screen space. + for (int i = m_DrawListCommadBufferSize; i < m_DrawList->CmdBuffer.size(); ++i) + { + auto& command = m_DrawList->CmdBuffer[i]; + command.ClipRect.x = command.ClipRect.x + m_ViewTransformPosition.x; + command.ClipRect.y = command.ClipRect.y + m_ViewTransformPosition.y; + command.ClipRect.z = command.ClipRect.z + m_ViewTransformPosition.x; + command.ClipRect.w = command.ClipRect.w + m_ViewTransformPosition.y; + } + } + + auto& fringeScale = ImFringeScaleRef(m_DrawList); + fringeScale = m_LastFringeScale; + + // And pop \o/ + ImGui::PopClipRect(); + + RestoreInputState(); + RestoreViewportState(); +} diff --git a/3rdparty/imgui-node-editor/imgui_canvas.h b/3rdparty/imgui-node-editor/imgui_canvas.h new file mode 100644 index 0000000..e5e4959 --- /dev/null +++ b/3rdparty/imgui-node-editor/imgui_canvas.h @@ -0,0 +1,268 @@ +// Canvas widget - view over infinite virtual space. +// +// Canvas allows you to draw your widgets anywhere over infinite space and provide +// view over it with support for panning and scaling. +// +// When you enter a canvas ImGui is moved to virtual space which mean: +// - ImGui::GetCursorScreenPos() return (0, 0) and which correspond to top left corner +// of the canvas on the screen (this can be changed using CanvasView()). +// - Mouse input is brought to canvas space, so widgets works as usual. +// - Everything you draw with ImDrawList will be in virtual space. +// +// By default origin point is on top left corner of canvas widget. It can be +// changed with call to CanvasView() where you can specify what part of space +// should be viewed by setting viewport origin point and scale. Current state +// can be queried with CanvasViewOrigin() and CanvasViewScale(). +// +// Viewport size is controlled by 'size' parameter in BeginCanvas(). You can query +// it using CanvasContentMin/Max/Size functions. They are useful if you to not specify +// canvas size in which case all free space is used. +// +// Bounds of visible region of infinite space can be queried using CanvasViewMin/Max/Size +// functions. Everything that is drawn outside of this region will be clipped +// as usual in ImGui. +// +// While drawing inside canvas you can translate position from world (usual ImGui space) +// to virtual space and back using CanvasFromWorld()/CanvasToWorld(). +// +// Canvas can be nested in each other (they are regular widgets after all). There +// is a way to transform position between current and parent canvas with +// CanvasFromParent()/CanvasToParent(). +// +// Sometimes in more elaborate scenarios you want to move out canvas virtual space, +// do something and came back. You can do that with SuspendCanvas() and ResumeCanvas(). +// +// Note: +// It is not valid to call canvas API outside of BeginCanvas() / EndCanvas() scope. +// +// VERSION 0.1 +// +// LICENSE +// This software is dual-licensed to the public domain and under the following +// license: you are granted a perpetual, irrevocable license to copy, modify, +// publish, and distribute this file as you see fit. +// +// CREDITS +// Written by Michal Cichon +# ifndef __IMGUI_EX_CANVAS_H__ +# define __IMGUI_EX_CANVAS_H__ +# pragma once + +# include +# include // ImRect, ImFloor + +namespace ImGuiEx { + +struct CanvasView +{ + ImVec2 Origin; + float Scale = 1.0f; + float InvScale = 1.0f; + + CanvasView() = default; + CanvasView(const ImVec2& origin, float scale) + : Origin(origin) + , Scale(scale) + , InvScale(scale ? 1.0f / scale : 0.0f) + { + } + + void Set(const ImVec2& origin, float scale) + { + *this = CanvasView(origin, scale); + } +}; + +// Canvas widget represent view over infinite plane. +// +// It acts like a child window without scroll bars with +// ability to zoom to specific part of canvas plane. +// +// Widgets are clipped according to current view exactly +// same way ImGui do. To avoid `missing widgets` artifacts first +// setup visible region with SetView() then draw content. +// +// Everything drawn with ImDrawList betwen calls to Begin()/End() +// will be drawn on canvas plane. This behavior can be suspended +// by calling Suspend() and resumed by calling Resume(). +// +// Warning: +// Please do not interleave canvas with use of channel splitter. +// Keep channel splitter contained inside canvas or always +// call canvas functions from same channel. +struct Canvas +{ + // Begins drawing content of canvas plane. + // + // When false is returned that mean canvas is not visible to the + // user can drawing should be skipped and End() not called. + // When true is returned drawing must be ended with call to End(). + // + // If any size component is equal to zero or less canvas will + // automatically expand to all available area on that axis. + // So (0, 300) will take horizontal space and have height + // of 300 points. (0, 0) will take all remaining space of + // the window. + // + // You can query size of the canvas while it is being drawn + // by calling Rect(). + bool Begin(const char* id, const ImVec2& size); + bool Begin(ImGuiID id, const ImVec2& size); + + // Ends interaction with canvas plane. + // + // Must be called only when Begin() retuned true. + void End(); + + // Sets visible region of canvas plane. + // + // Origin is an offset of infinite plane origin from top left + // corner of the canvas. + // + // Scale greater than 1 make canvas content be bigger, less than 1 smaller. + void SetView(const ImVec2& origin, float scale); + void SetView(const CanvasView& view); + + // Centers view over specific point on canvas plane. + // + // View will be centered on specific point by changing origin + // but not scale. + void CenterView(const ImVec2& canvasPoint); + + // Calculates view over specific point on canvas plane. + CanvasView CalcCenterView(const ImVec2& canvasPoint) const; + + // Centers view over specific rectangle on canvas plane. + // + // Whole rectangle will fit in canvas view. This will affect both + // origin and scale. + void CenterView(const ImRect& canvasRect); + + // Calculates view over specific rectangle on canvas plane. + CanvasView CalcCenterView(const ImRect& canvasRect) const; + + // Suspends canvas by returning to normal ImGui transformation space. + // While suspended UI will not be drawn on canvas plane. + // + // Calls to Suspend()/Resume() are symetrical. Each call to Suspend() + // must be matched with call to Resume(). + void Suspend(); + void Resume(); + + // Transforms point from canvas plane to ImGui. + ImVec2 FromLocal(const ImVec2& point) const; + ImVec2 FromLocal(const ImVec2& point, const CanvasView& view) const; + + // Transforms vector from canvas plant to ImGui. + ImVec2 FromLocalV(const ImVec2& vector) const; + ImVec2 FromLocalV(const ImVec2& vector, const CanvasView& view) const; + + // Transforms point from ImGui to canvas plane. + ImVec2 ToLocal(const ImVec2& point) const; + ImVec2 ToLocal(const ImVec2& point, const CanvasView& view) const; + + // Transforms vector from ImGui to canvas plane. + ImVec2 ToLocalV(const ImVec2& vector) const; + ImVec2 ToLocalV(const ImVec2& vector, const CanvasView& view) const; + + // Returns widget bounds. + // + // Note: + // Rect is valid after call to Begin(). + const ImRect& Rect() const { return m_WidgetRect; } + + // Returns visible region on canvas plane (in canvas plane coordinates). + const ImRect& ViewRect() const { return m_ViewRect; } + + // Calculates visible region for view. + ImRect CalcViewRect(const CanvasView& view) const; + + // Returns current view. + const CanvasView& View() const { return m_View; } + + // Returns origin of the view. + // + // Origin is an offset of infinite plane origin from top left + // corner of the canvas. + const ImVec2& ViewOrigin() const { return m_View.Origin; } + + // Returns scale of the view. + float ViewScale() const { return m_View.Scale; } + + // Returns true if canvas is suspended. + // + // See: Suspend()/Resume() + bool IsSuspended() const { return m_SuspendCounter > 0; } + +private: +# define IMGUI_EX_CANVAS_DEFERED() 0 + +# if IMGUI_EX_CANVAS_DEFERED() + struct Range + { + int BeginVertexIndex = 0; + int EndVertexIndex = 0; + int BeginComandIndex = 0; + int EndCommandIndex = 0; + }; +# endif + + void UpdateViewTransformPosition(); + + void SaveInputState(); + void RestoreInputState(); + + void SaveViewportState(); + void RestoreViewportState(); + + void EnterLocalSpace(); + void LeaveLocalSpace(); + + bool m_InBeginEnd = false; + + ImVec2 m_WidgetPosition; + ImVec2 m_WidgetSize; + ImRect m_WidgetRect; + + ImDrawList* m_DrawList = nullptr; + int m_ExpectedChannel = 0; + +# if IMGUI_EX_CANVAS_DEFERED() + ImVector m_Ranges; + Range* m_CurrentRange = nullptr; +# endif + + int m_DrawListCommadBufferSize = 0; + int m_DrawListStartVertexIndex = 0; + + CanvasView m_View; + ImRect m_ViewRect; + + ImVec2 m_ViewTransformPosition; + + int m_SuspendCounter = 0; + + float m_LastFringeScale = 1.0f; + + ImVec2 m_MousePosBackup; + ImVec2 m_MousePosPrevBackup; + ImVec2 m_MouseClickedPosBackup[IM_ARRAYSIZE(ImGuiIO::MouseClickedPos)]; + ImVec2 m_WindowCursorMaxBackup; + +# if defined(IMGUI_HAS_VIEWPORT) + ImVec2 m_WindowPosBackup; + ImVec2 m_ViewportPosBackup; + ImVec2 m_ViewportSizeBackup; +# if IMGUI_VERSION_NUM > 18002 + ImVec2 m_ViewportWorkPosBackup; + ImVec2 m_ViewportWorkSizeBackup; +# else + ImVec2 m_ViewportWorkOffsetMinBackup; + ImVec2 m_ViewportWorkOffsetMaxBackup; +# endif +# endif +}; + +} // namespace ImGuiEx + +# endif // __IMGUI_EX_CANVAS_H__ \ No newline at end of file diff --git a/3rdparty/imgui-node-editor/imgui_extra_math.h b/3rdparty/imgui-node-editor/imgui_extra_math.h new file mode 100644 index 0000000..3022055 --- /dev/null +++ b/3rdparty/imgui-node-editor/imgui_extra_math.h @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// VERSION 0.9.1 +// +// LICENSE +// This software is dual-licensed to the public domain and under the following +// license: you are granted a perpetual, irrevocable license to copy, modify, +// publish, and distribute this file as you see fit. +// +// CREDITS +// Written by Michal Cichon +//------------------------------------------------------------------------------ +# ifndef __IMGUI_EXTRA_MATH_H__ +# define __IMGUI_EXTRA_MATH_H__ +# pragma once + + +//------------------------------------------------------------------------------ +# include +# ifndef IMGUI_DEFINE_MATH_OPERATORS +# define IMGUI_DEFINE_MATH_OPERATORS +# endif +# include + + +//------------------------------------------------------------------------------ +struct ImLine +{ + ImVec2 A, B; +}; + + +//------------------------------------------------------------------------------ +inline bool operator==(const ImVec2& lhs, const ImVec2& rhs); +inline bool operator!=(const ImVec2& lhs, const ImVec2& rhs); +inline ImVec2 operator*(const float lhs, const ImVec2& rhs); +inline ImVec2 operator-(const ImVec2& lhs); + + +//------------------------------------------------------------------------------ +inline float ImLength(float v); +inline float ImLength(const ImVec2& v); +inline float ImLengthSqr(float v); +inline ImVec2 ImNormalized(const ImVec2& v); + + +//------------------------------------------------------------------------------ +inline bool ImRect_IsEmpty(const ImRect& rect); +inline ImVec2 ImRect_ClosestPoint(const ImRect& rect, const ImVec2& p, bool snap_to_edge); +inline ImVec2 ImRect_ClosestPoint(const ImRect& rect, const ImVec2& p, bool snap_to_edge, float radius); +inline ImVec2 ImRect_ClosestPoint(const ImRect& rect, const ImRect& b); +inline ImLine ImRect_ClosestLine(const ImRect& rect_a, const ImRect& rect_b); +inline ImLine ImRect_ClosestLine(const ImRect& rect_a, const ImRect& rect_b, float radius_a, float radius_b); + + + +//------------------------------------------------------------------------------ +namespace ImEasing { + +template +inline V EaseOutQuad(V b, V c, T t) +{ + return b - c * (t * (t - 2)); +} + +} // namespace ImEasing + + +//------------------------------------------------------------------------------ +# include "imgui_extra_math.inl" + + +//------------------------------------------------------------------------------ +# endif // __IMGUI_EXTRA_MATH_H__ diff --git a/3rdparty/imgui-node-editor/imgui_extra_math.inl b/3rdparty/imgui-node-editor/imgui_extra_math.inl new file mode 100644 index 0000000..13cf990 --- /dev/null +++ b/3rdparty/imgui-node-editor/imgui_extra_math.inl @@ -0,0 +1,189 @@ +//------------------------------------------------------------------------------ +// VERSION 0.9.1 +// +// LICENSE +// This software is dual-licensed to the public domain and under the following +// license: you are granted a perpetual, irrevocable license to copy, modify, +// publish, and distribute this file as you see fit. +// +// CREDITS +// Written by Michal Cichon +//------------------------------------------------------------------------------ +# ifndef __IMGUI_EXTRA_MATH_INL__ +# define __IMGUI_EXTRA_MATH_INL__ +# pragma once + + +//------------------------------------------------------------------------------ +# include "imgui_extra_math.h" + + +//------------------------------------------------------------------------------ +inline bool operator==(const ImVec2& lhs, const ImVec2& rhs) +{ + return lhs.x == rhs.x && lhs.y == rhs.y; +} + +inline bool operator!=(const ImVec2& lhs, const ImVec2& rhs) +{ + return lhs.x != rhs.x || lhs.y != rhs.y; +} + +inline ImVec2 operator*(const float lhs, const ImVec2& rhs) +{ + return ImVec2(lhs * rhs.x, lhs * rhs.y); +} + +inline ImVec2 operator-(const ImVec2& lhs) +{ + return ImVec2(-lhs.x, -lhs.y); +} + + +//------------------------------------------------------------------------------ +inline float ImLength(float v) +{ + return v; +} + +inline float ImLength(const ImVec2& v) +{ + return ImSqrt(ImLengthSqr(v)); +} + +inline float ImLengthSqr(float v) +{ + return v * v; +} + +inline ImVec2 ImNormalized(const ImVec2& v) +{ + return v * ImInvLength(v, 0.0f); +} + + + + +//------------------------------------------------------------------------------ +inline bool ImRect_IsEmpty(const ImRect& rect) +{ + return rect.Min.x >= rect.Max.x + || rect.Min.y >= rect.Max.y; +} + +inline ImVec2 ImRect_ClosestPoint(const ImRect& rect, const ImVec2& p, bool snap_to_edge) +{ + if (!snap_to_edge && rect.Contains(p)) + return p; + + return ImVec2( + (p.x > rect.Max.x) ? rect.Max.x : (p.x < rect.Min.x ? rect.Min.x : p.x), + (p.y > rect.Max.y) ? rect.Max.y : (p.y < rect.Min.y ? rect.Min.y : p.y) + ); +} + +inline ImVec2 ImRect_ClosestPoint(const ImRect& rect, const ImVec2& p, bool snap_to_edge, float radius) +{ + auto point = ImRect_ClosestPoint(rect, p, snap_to_edge); + + const auto offset = p - point; + const auto distance_sq = offset.x * offset.x + offset.y * offset.y; + if (distance_sq <= 0) + return point; + + const auto distance = ImSqrt(distance_sq); + + return point + offset * (ImMin(distance, radius) * (1.0f / distance)); +} + +inline ImVec2 ImRect_ClosestPoint(const ImRect& rect, const ImRect& other) +{ + ImVec2 result; + if (other.Min.x >= rect.Max.x) + result.x = rect.Max.x; + else if (other.Max.x <= rect.Min.x) + result.x = rect.Min.x; + else + result.x = (ImMax(rect.Min.x, other.Min.x) + ImMin(rect.Max.x, other.Max.x)) / 2; + + if (other.Min.y >= rect.Max.y) + result.y = rect.Max.y; + else if (other.Max.y <= rect.Min.y) + result.y = rect.Min.y; + else + result.y = (ImMax(rect.Min.y, other.Min.y) + ImMin(rect.Max.y, other.Max.y)) / 2; + + return result; +} + +inline ImLine ImRect_ClosestLine(const ImRect& rect_a, const ImRect& rect_b) +{ + ImLine result; + result.A = ImRect_ClosestPoint(rect_a, rect_b); + result.B = ImRect_ClosestPoint(rect_b, rect_a); + + auto distribute = [](float& a, float& b, float a0, float a1, float b0, float b1) + { + if (a0 >= b1 || a1 <= b0) + return; + + const auto aw = a1 - a0; + const auto bw = b1 - b0; + + if (aw > bw) + { + b = b0 + bw - bw * (a - a0) / aw; + a = b; + } + else if (aw < bw) + { + a = a0 + aw - aw * (b - b0) / bw; + b = a; + } + }; + + distribute(result.A.x, result.B.x, rect_a.Min.x, rect_a.Max.x, rect_b.Min.x, rect_b.Max.x); + distribute(result.A.y, result.B.y, rect_a.Min.y, rect_a.Max.y, rect_b.Min.y, rect_b.Max.y); + + return result; +} + +inline ImLine ImRect_ClosestLine(const ImRect& rect_a, const ImRect& rect_b, float radius_a, float radius_b) +{ + auto line = ImRect_ClosestLine(rect_a, rect_b); + if (radius_a < 0) + radius_a = 0; + if (radius_b < 0) + radius_b = 0; + + if (radius_a == 0 && radius_b == 0) + return line; + + const auto offset = line.B - line.A; + const auto length_sq = offset.x * offset.x + offset.y * offset.y; + const auto radius_a_sq = radius_a * radius_a; + const auto radius_b_sq = radius_b * radius_b; + + if (length_sq <= 0) + return line; + + const auto length = ImSqrt(length_sq); + const auto direction = ImVec2(offset.x / length, offset.y / length); + + const auto total_radius_sq = radius_a_sq + radius_b_sq; + if (total_radius_sq > length_sq) + { + const auto scale = length / (radius_a + radius_b); + radius_a *= scale; + radius_b *= scale; + } + + line.A = line.A + (direction * radius_a); + line.B = line.B - (direction * radius_b); + + return line; +} + + +//------------------------------------------------------------------------------ +# endif // __IMGUI_EXTRA_MATH_INL__ diff --git a/3rdparty/imgui-node-editor/imgui_node_editor.cpp b/3rdparty/imgui-node-editor/imgui_node_editor.cpp new file mode 100644 index 0000000..cd18324 --- /dev/null +++ b/3rdparty/imgui-node-editor/imgui_node_editor.cpp @@ -0,0 +1,5780 @@ +//Disable a bunch of warnings for now +#ifndef _MSC_VER +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wshadow" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//------------------------------------------------------------------------------ +// VERSION 0.9.1 +// +// LICENSE +// This software is dual-licensed to the public domain and under the following +// license: you are granted a perpetual, irrevocable license to copy, modify, +// publish, and distribute this file as you see fit. +// +// CREDITS +// Written by Michal Cichon +//------------------------------------------------------------------------------ +# include "imgui_node_editor_internal.h" +# include // snprintf +# include +# include +# include +# include +# include +# include +# include +# include + +// https://stackoverflow.com/a/8597498 +# define DECLARE_HAS_NESTED(Name, Member) \ + \ + template \ + struct has_nested_ ## Name \ + { \ + typedef char yes; \ + typedef yes(&no)[2]; \ + \ + template static yes test(decltype(U::Member)*); \ + template static no test(...); \ + \ + static bool const value = sizeof(test(0)) == sizeof(yes); \ + }; + +//------------------------------------------------------------------------------ +namespace ed = ax::NodeEditor::Detail; + + +//------------------------------------------------------------------------------ +static const int c_BackgroundChannelCount = 1; +static const int c_LinkChannelCount = 4; +static const int c_UserLayersCount = 5; + +static const int c_UserLayerChannelStart = 0; +static const int c_BackgroundChannelStart = c_UserLayerChannelStart + c_UserLayersCount; +static const int c_LinkStartChannel = c_BackgroundChannelStart + c_BackgroundChannelCount; +static const int c_NodeStartChannel = c_LinkStartChannel + c_LinkChannelCount; + +static const int c_BackgroundChannel_SelectionRect = c_BackgroundChannelStart + 0; + +static const int c_UserChannel_Content = c_UserLayerChannelStart + 1; +static const int c_UserChannel_Grid = c_UserLayerChannelStart + 2; +static const int c_UserChannel_HintsBackground = c_UserLayerChannelStart + 3; +static const int c_UserChannel_Hints = c_UserLayerChannelStart + 4; + +static const int c_LinkChannel_Selection = c_LinkStartChannel + 0; +static const int c_LinkChannel_Links = c_LinkStartChannel + 1; +static const int c_LinkChannel_Flow = c_LinkStartChannel + 2; +static const int c_LinkChannel_NewLink = c_LinkStartChannel + 3; + +static const int c_ChannelsPerNode = 5; +static const int c_NodeBaseChannel = 0; +static const int c_NodeBackgroundChannel = 1; +static const int c_NodeUserBackgroundChannel = 2; +static const int c_NodePinChannel = 3; +static const int c_NodeContentChannel = 4; + +static const float c_GroupSelectThickness = 6.0f; // canvas pixels +static const float c_LinkSelectThickness = 5.0f; // canvas pixels +static const float c_NavigationZoomMargin = 0.1f; // percentage of visible bounds +static const float c_MouseZoomDuration = 0.15f; // seconds +static const float c_SelectionFadeOutDuration = 0.15f; // seconds + +static const auto c_MaxMoveOverEdgeSpeed = 10.0f; +static const auto c_MaxMoveOverEdgeDistance = 300.0f; + +#if IMGUI_VERSION_NUM > 18101 +static const auto c_AllRoundCornersFlags = ImDrawFlags_RoundCornersAll; +#else +static const auto c_AllRoundCornersFlags = 15; +#endif + + +//------------------------------------------------------------------------------ +# if defined(_DEBUG) && defined(_WIN32) +extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA(const char* string); + +static void LogV(const char* fmt, va_list args) +{ + const int buffer_size = 1024; + static char buffer[1024]; + + vsnprintf(buffer, buffer_size - 1, fmt, args); + buffer[buffer_size - 1] = 0; + + ImGui::LogText("\nNode Editor: %s", buffer); + + OutputDebugStringA("NodeEditor: "); + OutputDebugStringA(buffer); + OutputDebugStringA("\n"); +} +# endif + +void ed::Log(const char* fmt, ...) +{ +# if defined(_DEBUG) && defined(_WIN32) + va_list args; + va_start(args, fmt); + LogV(fmt, args); + va_end(args); +# endif +} + + +//------------------------------------------------------------------------------ +static bool IsGroup(const ed::Node* node) +{ + if (node && node->m_Type == ed::NodeType::Group) + return true; + else + return false; +} + + +//------------------------------------------------------------------------------ +static void ImDrawListSplitter_Grow(ImDrawList* draw_list, ImDrawListSplitter* splitter, int channels_count) +{ + IM_ASSERT(splitter != nullptr); + IM_ASSERT(splitter->_Count <= channels_count); + + if (splitter->_Count == 1) + { + splitter->Split(draw_list, channels_count); + return; + } + + int old_channels_count = splitter->_Channels.Size; + if (old_channels_count < channels_count) + { + splitter->_Channels.reserve(channels_count); + splitter->_Channels.resize(channels_count); + } + int old_used_channels_count = splitter->_Count; + splitter->_Count = channels_count; + + for (int i = old_used_channels_count; i < channels_count; i++) + { + if (i >= old_channels_count) + { + IM_PLACEMENT_NEW(&splitter->_Channels[i]) ImDrawChannel(); + } + else + { + splitter->_Channels[i]._CmdBuffer.resize(0); + splitter->_Channels[i]._IdxBuffer.resize(0); + } + } +} + +static void ImDrawList_ChannelsGrow(ImDrawList* draw_list, int channels_count) +{ + ImDrawListSplitter_Grow(draw_list, &draw_list->_Splitter, channels_count); +} + +static void ImDrawListSplitter_SwapChannels(ImDrawListSplitter* splitter, int left, int right) +{ + IM_ASSERT(left < splitter->_Count && right < splitter->_Count); + if (left == right) + return; + + auto currentChannel = splitter->_Current; + + auto* leftCmdBuffer = &splitter->_Channels[left]._CmdBuffer; + auto* leftIdxBuffer = &splitter->_Channels[left]._IdxBuffer; + auto* rightCmdBuffer = &splitter->_Channels[right]._CmdBuffer; + auto* rightIdxBuffer = &splitter->_Channels[right]._IdxBuffer; + + leftCmdBuffer->swap(*rightCmdBuffer); + leftIdxBuffer->swap(*rightIdxBuffer); + + if (currentChannel == left) + splitter->_Current = right; + else if (currentChannel == right) + splitter->_Current = left; +} + +static void ImDrawList_SwapChannels(ImDrawList* drawList, int left, int right) +{ + ImDrawListSplitter_SwapChannels(&drawList->_Splitter, left, right); +} + +static void ImDrawList_SwapSplitter(ImDrawList* drawList, ImDrawListSplitter& splitter) +{ + auto& currentSplitter = drawList->_Splitter; + + std::swap(currentSplitter._Current, splitter._Current); + std::swap(currentSplitter._Count, splitter._Count); + currentSplitter._Channels.swap(splitter._Channels); +} + +//static void ImDrawList_TransformChannel_Inner(ImVector& vtxBuffer, const ImVector& idxBuffer, const ImVector& cmdBuffer, const ImVec2& preOffset, const ImVec2& scale, const ImVec2& postOffset) +//{ +// auto idxRead = idxBuffer.Data; +// +// int indexOffset = 0; +// for (auto& cmd : cmdBuffer) +// { +// auto idxCount = cmd.ElemCount; +// +// if (idxCount == 0) continue; +// +// auto minIndex = idxRead[indexOffset]; +// auto maxIndex = idxRead[indexOffset]; +// +// for (auto i = 1u; i < idxCount; ++i) +// { +// auto idx = idxRead[indexOffset + i]; +// minIndex = std::min(minIndex, idx); +// maxIndex = ImMax(maxIndex, idx); +// } +// +// for (auto vtx = vtxBuffer.Data + minIndex, vtxEnd = vtxBuffer.Data + maxIndex + 1; vtx < vtxEnd; ++vtx) +// { +// vtx->pos.x = (vtx->pos.x + preOffset.x) * scale.x + postOffset.x; +// vtx->pos.y = (vtx->pos.y + preOffset.y) * scale.y + postOffset.y; +// } +// +// indexOffset += idxCount; +// } +//} + +//static void ImDrawList_TransformChannels(ImDrawList* drawList, int begin, int end, const ImVec2& preOffset, const ImVec2& scale, const ImVec2& postOffset) +//{ +// int lastCurrentChannel = drawList->_ChannelsCurrent; +// if (lastCurrentChannel != 0) +// drawList->ChannelsSetCurrent(0); +// +// auto& vtxBuffer = drawList->VtxBuffer; +// +// if (begin == 0 && begin != end) +// { +// ImDrawList_TransformChannel_Inner(vtxBuffer, drawList->IdxBuffer, drawList->CmdBuffer, preOffset, scale, postOffset); +// ++begin; +// } +// +// for (int channelIndex = begin; channelIndex < end; ++channelIndex) +// { +// auto& channel = drawList->_Channels[channelIndex]; +// ImDrawList_TransformChannel_Inner(vtxBuffer, channel.IdxBuffer, channel.CmdBuffer, preOffset, scale, postOffset); +// } +// +// if (lastCurrentChannel != 0) +// drawList->ChannelsSetCurrent(lastCurrentChannel); +//} + +//static void ImDrawList_ClampClipRects_Inner(ImVector& cmdBuffer, const ImVec4& clipRect, const ImVec2& offset) +//{ +// for (auto& cmd : cmdBuffer) +// { +// cmd.ClipRect.x = ImMax(cmd.ClipRect.x + offset.x, clipRect.x); +// cmd.ClipRect.y = ImMax(cmd.ClipRect.y + offset.y, clipRect.y); +// cmd.ClipRect.z = std::min(cmd.ClipRect.z + offset.x, clipRect.z); +// cmd.ClipRect.w = std::min(cmd.ClipRect.w + offset.y, clipRect.w); +// } +//} + +//static void ImDrawList_TranslateAndClampClipRects(ImDrawList* drawList, int begin, int end, const ImVec2& offset) +//{ +// int lastCurrentChannel = drawList->_ChannelsCurrent; +// if (lastCurrentChannel != 0) +// drawList->ChannelsSetCurrent(0); +// +// auto clipRect = drawList->_ClipRectStack.back(); +// +// if (begin == 0 && begin != end) +// { +// ImDrawList_ClampClipRects_Inner(drawList->CmdBuffer, clipRect, offset); +// ++begin; +// } +// +// for (int channelIndex = begin; channelIndex < end; ++channelIndex) +// { +// auto& channel = drawList->_Channels[channelIndex]; +// ImDrawList_ClampClipRects_Inner(channel.CmdBuffer, clipRect, offset); +// } +// +// if (lastCurrentChannel != 0) +// drawList->ChannelsSetCurrent(lastCurrentChannel); +//} + +static void ImDrawList_PathBezierOffset(ImDrawList* drawList, float offset, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3) +{ + using namespace ed; + + auto acceptPoint = [drawList, offset](const ImCubicBezierSubdivideSample& r) + { + drawList->PathLineTo(r.Point + ImNormalized(ImVec2(-r.Tangent.y, r.Tangent.x)) * offset); + }; + + ImCubicBezierSubdivide(acceptPoint, p0, p1, p2, p3); +} + +/* +static void ImDrawList_PolyFillScanFlood(ImDrawList *draw, std::vector* poly, ImColor color, int gap = 1, float strokeWidth = 1.0f) +{ + std::vector scanHits; + ImVec2 min, max; // polygon min/max points + auto io = ImGui::GetIO(); + float y; + bool isMinMaxDone = false; + unsigned int polysize = poly->size(); + + // find the orthagonal bounding box + // probably can put this as a predefined + if (!isMinMaxDone) + { + min.x = min.y = FLT_MAX; + max.x = max.y = FLT_MIN; + for (auto p : *poly) + { + if (p.x < min.x) min.x = p.x; + if (p.y < min.y) min.y = p.y; + if (p.x > max.x) max.x = p.x; + if (p.y > max.y) max.y = p.y; + } + isMinMaxDone = true; + } + + // Bounds check + if ((max.x < 0) || (min.x > io.DisplaySize.x) || (max.y < 0) || (min.y > io.DisplaySize.y)) return; + + // Vertically clip + if (min.y < 0) min.y = 0; + if (max.y > io.DisplaySize.y) max.y = io.DisplaySize.y; + + // so we know we start on the outside of the object we step out by 1. + min.x -= 1; + max.x += 1; + + // Initialise our starting conditions + y = min.y; + + // Go through each scan line iteratively, jumping by 'gap' pixels each time + while (y < max.y) + { + scanHits.clear(); + + { + int jump = 1; + ImVec2 fp = poly->at(0); + + for (size_t i = 0; i < polysize - 1; i++) + { + ImVec2 pa = poly->at(i); + ImVec2 pb = poly->at(i + 1); + + // jump double/dud points + if (pa.x == pb.x && pa.y == pb.y) continue; + + // if we encounter our hull/poly start point, then we've now created the + // closed + // hull, jump the next segment and reset the first-point + if ((!jump) && (fp.x == pb.x) && (fp.y == pb.y)) + { + if (i < polysize - 2) + { + fp = poly->at(i + 2); + jump = 1; + i++; + } + } + else + { + jump = 0; + } + + // test to see if this segment makes the scan-cut. + if ((pa.y > pb.y && y < pa.y && y > pb.y) || (pa.y < pb.y && y > pa.y && y < pb.y)) + { + ImVec2 intersect; + + intersect.y = y; + if (pa.x == pb.x) + { + intersect.x = pa.x; + } + else + { + intersect.x = (pb.x - pa.x) / (pb.y - pa.y) * (y - pa.y) + pa.x; + } + scanHits.push_back(intersect); + } + } + + // Sort the scan hits by X, so we have a proper left->right ordering + sort(scanHits.begin(), scanHits.end(), [](ImVec2 const &a, ImVec2 const &b) { return a.x < b.x; }); + + // generate the line segments. + { + int i = 0; + int l = scanHits.size() - 1; // we need pairs of points, this prevents segfault. + for (i = 0; i < l; i += 2) + { + draw->AddLine(scanHits[i], scanHits[i + 1], color, strokeWidth); + } + } + } + y += gap; + } // for each scan line + scanHits.clear(); +} +*/ + +static void ImDrawList_AddBezierWithArrows(ImDrawList* drawList, const ImCubicBezierPoints& curve, float thickness, + float startArrowSize, float startArrowWidth, float endArrowSize, float endArrowWidth, + bool fill, ImU32 color, float strokeThickness, const ImVec2* startDirHint = nullptr, const ImVec2* endDirHint = nullptr) +{ + using namespace ax; + + if ((color >> 24) == 0) + return; + + const auto half_thickness = thickness * 0.5f; + + if (fill) + { + drawList->AddBezierCubic(curve.P0, curve.P1, curve.P2, curve.P3, color, thickness); + + if (startArrowSize > 0.0f) + { + const auto start_dir = ImNormalized(startDirHint ? *startDirHint : ImCubicBezierTangent(curve.P0, curve.P1, curve.P2, curve.P3, 0.0f)); + const auto start_n = ImVec2(-start_dir.y, start_dir.x); + const auto half_width = startArrowWidth * 0.5f; + const auto tip = curve.P0 - start_dir * startArrowSize; + + drawList->PathLineTo(curve.P0 - start_n * ImMax(half_width, half_thickness)); + drawList->PathLineTo(curve.P0 + start_n * ImMax(half_width, half_thickness)); + drawList->PathLineTo(tip); + drawList->PathFillConvex(color); + } + + if (endArrowSize > 0.0f) + { + const auto end_dir = ImNormalized(endDirHint ? -*endDirHint : ImCubicBezierTangent(curve.P0, curve.P1, curve.P2, curve.P3, 1.0f)); + const auto end_n = ImVec2( -end_dir.y, end_dir.x); + const auto half_width = endArrowWidth * 0.5f; + const auto tip = curve.P3 + end_dir * endArrowSize; + + drawList->PathLineTo(curve.P3 + end_n * ImMax(half_width, half_thickness)); + drawList->PathLineTo(curve.P3 - end_n * ImMax(half_width, half_thickness)); + drawList->PathLineTo(tip); + drawList->PathFillConvex(color); + } + } + else + { + if (startArrowSize > 0.0f) + { + const auto start_dir = ImNormalized(ImCubicBezierTangent(curve.P0, curve.P1, curve.P2, curve.P3, 0.0f)); + const auto start_n = ImVec2(-start_dir.y, start_dir.x); + const auto half_width = startArrowWidth * 0.5f; + const auto tip = curve.P0 - start_dir * startArrowSize; + + if (half_width > half_thickness) + drawList->PathLineTo(curve.P0 - start_n * half_width); + drawList->PathLineTo(tip); + if (half_width > half_thickness) + drawList->PathLineTo(curve.P0 + start_n * half_width); + } + + ImDrawList_PathBezierOffset(drawList, half_thickness, curve.P0, curve.P1, curve.P2, curve.P3); + + if (endArrowSize > 0.0f) + { + const auto end_dir = ImNormalized(ImCubicBezierTangent(curve.P0, curve.P1, curve.P2, curve.P3, 1.0f)); + const auto end_n = ImVec2( -end_dir.y, end_dir.x); + const auto half_width = endArrowWidth * 0.5f; + const auto tip = curve.P3 + end_dir * endArrowSize; + + if (half_width > half_thickness) + drawList->PathLineTo(curve.P3 + end_n * half_width); + drawList->PathLineTo(tip); + if (half_width > half_thickness) + drawList->PathLineTo(curve.P3 - end_n * half_width); + } + + ImDrawList_PathBezierOffset(drawList, half_thickness, curve.P3, curve.P2, curve.P1, curve.P0); + + drawList->PathStroke(color, true, strokeThickness); + } +} + + + + +//------------------------------------------------------------------------------ +// +// Pin +// +//------------------------------------------------------------------------------ +void ed::Pin::Draw(ImDrawList* drawList, DrawFlags flags) +{ + if (flags & Hovered) + { + drawList->ChannelsSetCurrent(m_Node->m_Channel + c_NodePinChannel); + + drawList->AddRectFilled(m_Bounds.Min, m_Bounds.Max, + m_Color, m_Rounding, m_Corners); + + if (m_BorderWidth > 0.0f) + { + FringeScaleScope fringe(1.0f); + drawList->AddRect(m_Bounds.Min, m_Bounds.Max, + m_BorderColor, m_Rounding, m_Corners, m_BorderWidth); + } + + if (!Editor->IsSelected(m_Node)) + m_Node->Draw(drawList, flags); + } +} + +ImVec2 ed::Pin::GetClosestPoint(const ImVec2& p) const +{ + auto pivot = m_Pivot; + auto extent = m_Radius + m_ArrowSize; + + if (m_SnapLinkToDir && extent > 0.0f) + { + pivot.Min += m_Dir * extent; + pivot.Max += m_Dir * extent; + + extent = 0; + } + + return ImRect_ClosestPoint(pivot, p, true, extent); +} + +ImLine ed::Pin::GetClosestLine(const Pin* pin) const +{ + auto pivotA = m_Pivot; + auto pivotB = pin->m_Pivot; + auto extentA = m_Radius + m_ArrowSize; + auto extentB = pin->m_Radius + pin->m_ArrowSize; + + if (m_SnapLinkToDir && extentA > 0.0f) + { + pivotA.Min += m_Dir * extentA; + pivotA.Max += m_Dir * extentA; + + extentA = 0; + } + + if (pin->m_SnapLinkToDir && extentB > 0.0f) + { + pivotB.Min += pin->m_Dir * extentB; + pivotB.Max += pin->m_Dir * extentB; + + extentB = 0; + } + + return ImRect_ClosestLine(pivotA, pivotB, extentA, extentB); +} + + + + +//------------------------------------------------------------------------------ +// +// Node +// +//------------------------------------------------------------------------------ +bool ed::Node::AcceptDrag() +{ + m_DragStart = m_Bounds.Min; + return true; +} + +void ed::Node::UpdateDrag(const ImVec2& offset) +{ + auto size = m_Bounds.GetSize(); + m_Bounds.Min = ImFloor(m_DragStart + offset); + m_Bounds.Max = m_Bounds.Min + size; +} + +bool ed::Node::EndDrag() +{ + return m_Bounds.Min != m_DragStart; +} + +void ed::Node::Draw(ImDrawList* drawList, DrawFlags flags) +{ + if (flags == Detail::Object::None) + { + drawList->ChannelsSetCurrent(m_Channel + c_NodeBackgroundChannel); + + drawList->AddRectFilled( + m_Bounds.Min, + m_Bounds.Max, + m_Color, m_Rounding); + + if (IsGroup(this)) + { + drawList->AddRectFilled( + m_GroupBounds.Min, + m_GroupBounds.Max, + m_GroupColor, m_GroupRounding); + + if (m_GroupBorderWidth > 0.0f) + { + FringeScaleScope fringe(1.0f); + + drawList->AddRect( + m_GroupBounds.Min, + m_GroupBounds.Max, + m_GroupBorderColor, m_GroupRounding, c_AllRoundCornersFlags, m_GroupBorderWidth); + } + } + +# if 0 + // #debug: highlight group regions + auto drawRect = [drawList](const ImRect& rect, ImU32 color) + { + if (ImRect_IsEmpty(rect)) return; + drawList->AddRectFilled(rect.Min, rect.Max, color); + }; + + drawRect(GetRegionBounds(NodeRegion::Top), IM_COL32(255, 0, 0, 64)); + drawRect(GetRegionBounds(NodeRegion::Bottom), IM_COL32(255, 0, 0, 64)); + drawRect(GetRegionBounds(NodeRegion::Left), IM_COL32(0, 255, 0, 64)); + drawRect(GetRegionBounds(NodeRegion::Right), IM_COL32(0, 255, 0, 64)); + drawRect(GetRegionBounds(NodeRegion::TopLeft), IM_COL32(255, 0, 255, 64)); + drawRect(GetRegionBounds(NodeRegion::TopRight), IM_COL32(255, 0, 255, 64)); + drawRect(GetRegionBounds(NodeRegion::BottomLeft), IM_COL32(255, 0, 255, 64)); + drawRect(GetRegionBounds(NodeRegion::BottomRight), IM_COL32(255, 0, 255, 64)); + drawRect(GetRegionBounds(NodeRegion::Center), IM_COL32(0, 0, 255, 64)); + drawRect(GetRegionBounds(NodeRegion::Header), IM_COL32(0, 255, 255, 64)); +# endif + + DrawBorder(drawList, m_BorderColor, m_BorderWidth); + } + else if (flags & Selected) + { + const auto borderColor = Editor->GetColor(StyleColor_SelNodeBorder); + const auto& editorStyle = Editor->GetStyle(); + + drawList->ChannelsSetCurrent(m_Channel + c_NodeBaseChannel); + + DrawBorder(drawList, borderColor, editorStyle.SelectedNodeBorderWidth); + } + else if (!IsGroup(this) && (flags & Hovered)) + { + const auto borderColor = Editor->GetColor(StyleColor_HovNodeBorder); + const auto& editorStyle = Editor->GetStyle(); + + drawList->ChannelsSetCurrent(m_Channel + c_NodeBaseChannel); + + DrawBorder(drawList, borderColor, editorStyle.HoveredNodeBorderWidth); + } +} + +void ed::Node::DrawBorder(ImDrawList* drawList, ImU32 color, float thickness) +{ + if (thickness > 0.0f) + { + drawList->AddRect(m_Bounds.Min, m_Bounds.Max, + color, m_Rounding, c_AllRoundCornersFlags, thickness); + } +} + +void ed::Node::GetGroupedNodes(std::vector& result, bool append) +{ + if (!append) + result.resize(0); + + if (!IsGroup(this)) + return; + + const auto firstNodeIndex = result.size(); + Editor->FindNodesInRect(m_GroupBounds, result, true, false); + + for (auto index = firstNodeIndex; index < result.size(); ++index) + result[index]->GetGroupedNodes(result, true); +} + +ImRect ed::Node::GetRegionBounds(NodeRegion region) const +{ + if (m_Type == NodeType::Node) + { + if (region == NodeRegion::Header) + return m_Bounds; + } + else if (m_Type == NodeType::Group) + { + const float activeAreaMinimumSize = ImMax(ImMax( + Editor->GetView().InvScale * c_GroupSelectThickness, + m_GroupBorderWidth), c_GroupSelectThickness); + const float minimumSize = activeAreaMinimumSize * 5; + + auto bounds = m_Bounds; + if (bounds.GetWidth() < minimumSize) + bounds.Expand(ImVec2(minimumSize - bounds.GetWidth(), 0.0f)); + if (bounds.GetHeight() < minimumSize) + bounds.Expand(ImVec2(0.0f, minimumSize - bounds.GetHeight())); + + if (region == NodeRegion::Top) + { + bounds.Max.y = bounds.Min.y + activeAreaMinimumSize; + bounds.Min.x += activeAreaMinimumSize; + bounds.Max.x -= activeAreaMinimumSize; + return bounds; + } + else if (region == NodeRegion::Bottom) + { + bounds.Min.y = bounds.Max.y - activeAreaMinimumSize; + bounds.Min.x += activeAreaMinimumSize; + bounds.Max.x -= activeAreaMinimumSize; + return bounds; + } + else if (region == NodeRegion::Left) + { + bounds.Max.x = bounds.Min.x + activeAreaMinimumSize; + bounds.Min.y += activeAreaMinimumSize; + bounds.Max.y -= activeAreaMinimumSize; + return bounds; + } + else if (region == NodeRegion::Right) + { + bounds.Min.x = bounds.Max.x - activeAreaMinimumSize; + bounds.Min.y += activeAreaMinimumSize; + bounds.Max.y -= activeAreaMinimumSize; + return bounds; + } + else if (region == NodeRegion::TopLeft) + { + bounds.Max.x = bounds.Min.x + activeAreaMinimumSize * 2; + bounds.Max.y = bounds.Min.y + activeAreaMinimumSize * 2; + return bounds; + } + else if (region == NodeRegion::TopRight) + { + bounds.Min.x = bounds.Max.x - activeAreaMinimumSize * 2; + bounds.Max.y = bounds.Min.y + activeAreaMinimumSize * 2; + return bounds; + } + else if (region == NodeRegion::BottomRight) + { + bounds.Min.x = bounds.Max.x - activeAreaMinimumSize * 2; + bounds.Min.y = bounds.Max.y - activeAreaMinimumSize * 2; + return bounds; + } + else if (region == NodeRegion::BottomLeft) + { + bounds.Max.x = bounds.Min.x + activeAreaMinimumSize * 2; + bounds.Min.y = bounds.Max.y - activeAreaMinimumSize * 2; + return bounds; + } + else if (region == NodeRegion::Header) + { + bounds.Min.x += activeAreaMinimumSize; + bounds.Max.x -= activeAreaMinimumSize; + bounds.Min.y += activeAreaMinimumSize; + bounds.Max.y = ImMax(bounds.Min.y + activeAreaMinimumSize, m_GroupBounds.Min.y); + return bounds; + } + else if (region == NodeRegion::Center) + { + bounds.Max.x -= activeAreaMinimumSize; + bounds.Min.y = ImMax(bounds.Min.y + activeAreaMinimumSize, m_GroupBounds.Min.y); + bounds.Min.x += activeAreaMinimumSize; + bounds.Max.y -= activeAreaMinimumSize; + return bounds; + } + } + + return ImRect(); +} + +ed::NodeRegion ed::Node::GetRegion(const ImVec2& point) const +{ + if (m_Type == NodeType::Node) + { + if (m_Bounds.Contains(point)) + return NodeRegion::Header; + else + return NodeRegion::None; + } + else if (m_Type == NodeType::Group) + { + static const NodeRegion c_Regions[] = + { + // Corners first, they may overlap other regions. + NodeRegion::TopLeft, + NodeRegion::TopRight, + NodeRegion::BottomLeft, + NodeRegion::BottomRight, + NodeRegion::Header, + NodeRegion::Top, + NodeRegion::Bottom, + NodeRegion::Left, + NodeRegion::Right, + NodeRegion::Center + }; + + for (auto region : c_Regions) + { + auto bounds = GetRegionBounds(region); + if (bounds.Contains(point)) + return region; + } + } + + return NodeRegion::None; +} + + + + +//------------------------------------------------------------------------------ +// +// Link +// +//------------------------------------------------------------------------------ +void ed::Link::Draw(ImDrawList* drawList, DrawFlags flags) +{ + if (flags == None) + { + drawList->ChannelsSetCurrent(c_LinkChannel_Links); + + Draw(drawList, m_Color, 0.0f); + } + else if (flags & Selected) + { + const auto borderColor = Editor->GetColor(StyleColor_SelLinkBorder); + + drawList->ChannelsSetCurrent(c_LinkChannel_Selection); + + Draw(drawList, borderColor, 4.5f); + } + else if (flags & Hovered) + { + const auto borderColor = Editor->GetColor(StyleColor_HovLinkBorder); + + drawList->ChannelsSetCurrent(c_LinkChannel_Selection); + + Draw(drawList, borderColor, 2.0f); + } + else if (flags & Highlighted) + { + drawList->ChannelsSetCurrent(c_LinkChannel_Selection); + + Draw(drawList, m_HighlightColor, 3.5f); + } +} + +void ed::Link::Draw(ImDrawList* drawList, ImU32 color, float extraThickness) const +{ + if (!m_IsLive) + return; + + const auto curve = GetCurve(); + + ImDrawList_AddBezierWithArrows(drawList, curve, m_Thickness + extraThickness, + m_StartPin && m_StartPin->m_ArrowSize > 0.0f ? m_StartPin->m_ArrowSize + extraThickness : 0.0f, + m_StartPin && m_StartPin->m_ArrowWidth > 0.0f ? m_StartPin->m_ArrowWidth + extraThickness : 0.0f, + m_EndPin && m_EndPin->m_ArrowSize > 0.0f ? m_EndPin->m_ArrowSize + extraThickness : 0.0f, + m_EndPin && m_EndPin->m_ArrowWidth > 0.0f ? m_EndPin->m_ArrowWidth + extraThickness : 0.0f, + true, color, 1.0f, + m_StartPin && m_StartPin->m_SnapLinkToDir ? &m_StartPin->m_Dir : nullptr, + m_EndPin && m_EndPin->m_SnapLinkToDir ? &m_EndPin->m_Dir : nullptr); +} + +void ed::Link::UpdateEndpoints() +{ + const auto line = m_StartPin->GetClosestLine(m_EndPin); + m_Start = line.A; + m_End = line.B; +} + +ImCubicBezierPoints ed::Link::GetCurve() const +{ + auto easeLinkStrength = [](const ImVec2& a, const ImVec2& b, float strength) + { + const auto distanceX = b.x - a.x; + const auto distanceY = b.y - a.y; + const auto distance = ImSqrt(distanceX * distanceX + distanceY * distanceY); + const auto halfDistance = distance * 0.5f; + + if (halfDistance < strength) + strength = strength * ImSin(IM_PI * 0.5f * halfDistance / strength); + + return strength; + }; + + const auto startStrength = easeLinkStrength(m_Start, m_End, m_StartPin->m_Strength); + const auto endStrength = easeLinkStrength(m_Start, m_End, m_EndPin->m_Strength); + const auto cp0 = m_Start + m_StartPin->m_Dir * startStrength; + const auto cp1 = m_End + m_EndPin->m_Dir * endStrength; + + ImCubicBezierPoints result; + result.P0 = m_Start; + result.P1 = cp0; + result.P2 = cp1; + result.P3 = m_End; + + return result; +} + +bool ed::Link::TestHit(const ImVec2& point, float extraThickness) const +{ + if (!m_IsLive) + return false; + + auto bounds = GetBounds(); + if (extraThickness > 0.0f) + bounds.Expand(extraThickness); + + if (!bounds.Contains(point)) + return false; + + const auto bezier = GetCurve(); + const auto result = ImProjectOnCubicBezier(point, bezier.P0, bezier.P1, bezier.P2, bezier.P3, 50); + + return result.Distance <= m_Thickness + extraThickness; +} + +bool ed::Link::TestHit(const ImRect& rect, bool allowIntersect) const +{ + if (!m_IsLive) + return false; + + const auto bounds = GetBounds(); + + if (rect.Contains(bounds)) + return true; + + if (!allowIntersect || !rect.Overlaps(bounds)) + return false; + + const auto bezier = GetCurve(); + + const auto p0 = rect.GetTL(); + const auto p1 = rect.GetTR(); + const auto p2 = rect.GetBR(); + const auto p3 = rect.GetBL(); + + if (ImCubicBezierLineIntersect(bezier.P0, bezier.P1, bezier.P2, bezier.P3, p0, p1).Count > 0) + return true; + if (ImCubicBezierLineIntersect(bezier.P0, bezier.P1, bezier.P2, bezier.P3, p1, p2).Count > 0) + return true; + if (ImCubicBezierLineIntersect(bezier.P0, bezier.P1, bezier.P2, bezier.P3, p2, p3).Count > 0) + return true; + if (ImCubicBezierLineIntersect(bezier.P0, bezier.P1, bezier.P2, bezier.P3, p3, p0).Count > 0) + return true; + + return false; +} + +ImRect ed::Link::GetBounds() const +{ + if (m_IsLive) + { + const auto curve = GetCurve(); + auto bounds = ImCubicBezierBoundingRect(curve.P0, curve.P1, curve.P2, curve.P3); + + if (bounds.GetWidth() == 0.0f) + { + bounds.Min.x -= 0.5f; + bounds.Max.x += 0.5f; + } + + if (bounds.GetHeight() == 0.0f) + { + bounds.Min.y -= 0.5f; + bounds.Max.y += 0.5f; + } + + if (m_StartPin->m_ArrowSize) + { + const auto start_dir = ImNormalized(ImCubicBezierTangent(curve.P0, curve.P1, curve.P2, curve.P3, 0.0f)); + const auto p0 = curve.P0; + const auto p1 = curve.P0 - start_dir * m_StartPin->m_ArrowSize; + const auto min = ImMin(p0, p1); + const auto max = ImMax(p0, p1); + auto arrowBounds = ImRect(min, ImMax(max, min + ImVec2(1, 1))); + bounds.Add(arrowBounds); + } + + if (m_EndPin->m_ArrowSize) + { + const auto end_dir = ImNormalized(ImCubicBezierTangent(curve.P0, curve.P1, curve.P2, curve.P3, 1.0f)); + const auto p0 = curve.P3; + const auto p1 = curve.P3 + end_dir * m_EndPin->m_ArrowSize; + const auto min = ImMin(p0, p1); + const auto max = ImMax(p0, p1); + auto arrowBounds = ImRect(min, ImMax(max, min + ImVec2(1, 1))); + bounds.Add(arrowBounds); + } + + return bounds; + } + else + return ImRect(); +} + + + + +//------------------------------------------------------------------------------ +// +// Editor Context +// +//------------------------------------------------------------------------------ +ed::EditorContext::EditorContext(const ax::NodeEditor::Config* config) + : m_Config(config) + , m_EditorActiveId(0) + , m_IsFirstFrame(true) + , m_IsFocused(false) + , m_IsHovered(false) + , m_IsHoveredWithoutOverlapp(false) + , m_ShortcutsEnabled(true) + , m_Style() + , m_Nodes() + , m_Pins() + , m_Links() + , m_SelectionId(1) + , m_LastActiveLink(nullptr) + , m_Canvas() + , m_IsCanvasVisible(false) + , m_NodeBuilder(this) + , m_HintBuilder(this) + , m_CurrentAction(nullptr) + , m_NavigateAction(this, m_Canvas) + , m_SizeAction(this) + , m_DragAction(this) + , m_SelectAction(this) + , m_ContextMenuAction(this) + , m_ShortcutAction(this) + , m_CreateItemAction(this) + , m_DeleteItemsAction(this) + , m_AnimationControllers{ &m_FlowAnimationController } + , m_FlowAnimationController(this) + , m_HoveredNode(0) + , m_HoveredPin(0) + , m_HoveredLink(0) + , m_DoubleClickedNode(0) + , m_DoubleClickedPin(0) + , m_DoubleClickedLink(0) + , m_BackgroundClickButtonIndex(-1) + , m_BackgroundDoubleClickButtonIndex(-1) + , m_IsInitialized(false) + , m_Settings() + , m_DrawList(nullptr) + , m_ExternalChannel(0) +{ +} + +ed::EditorContext::~EditorContext() +{ + if (m_IsInitialized) + SaveSettings(); + + for (auto link : m_Links) delete link.m_Object; + for (auto pin : m_Pins) delete pin.m_Object; + for (auto node : m_Nodes) delete node.m_Object; + + m_Splitter.ClearFreeMemory(); +} + +void ed::EditorContext::Begin(const char* id, const ImVec2& size) +{ + m_EditorActiveId = ImGui::GetID(id); + ImGui::PushID(id); + + auto availableContentSize = ImGui::GetContentRegionAvail(); + ImVec2 canvasSize = ImFloor(size); + if (canvasSize.x <= 0.0f) + canvasSize.x = ImMax(4.0f, availableContentSize.x); + if (canvasSize.y <= 0.0f) + canvasSize.y = ImMax(4.0f, availableContentSize.y); + + if (!m_IsInitialized) + { + // Cycle canvas so it has a change to setup its size before settings are loaded + m_Canvas.Begin(id, canvasSize); + m_Canvas.End(); + + LoadSettings(); + m_IsInitialized = true; + } + + //ImGui::LogToClipboard(); + //Log("---- begin ----"); + + static auto resetAndCollect = [](auto& objects) + { + objects.erase(std::remove_if(objects.begin(), objects.end(), [](auto objectWrapper) + { + if (objectWrapper->m_DeleteOnNewFrame) + { + delete objectWrapper.m_Object; + return true; + } + else + { + objectWrapper->Reset(); + return false; + } + }), objects.end()); + }; + + resetAndCollect(m_Nodes); + resetAndCollect(m_Pins); + resetAndCollect(m_Links); + + m_DrawList = ImGui::GetWindowDrawList(); + + ImDrawList_SwapSplitter(m_DrawList, m_Splitter); + m_ExternalChannel = m_DrawList->_Splitter._Current; + + if (m_CurrentAction && m_CurrentAction->IsDragging() && m_NavigateAction.MoveOverEdge(canvasSize)) + { + auto& io = ImGui::GetIO(); + auto offset = m_NavigateAction.GetMoveScreenOffset(); + for (int i = 0; i < 5; ++i) + io.MouseClickedPos[i] = io.MouseClickedPos[i] - offset; + } + else + m_NavigateAction.StopMoveOverEdge(); + + auto previousSize = m_Canvas.Rect().GetSize(); + auto previousVisibleRect = m_Canvas.ViewRect(); + m_IsCanvasVisible = m_Canvas.Begin(id, canvasSize); + + //ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0, 0, 0, 0)); + //ImGui::BeginChild(id, size, false, + // ImGuiWindowFlags_NoMove | + // ImGuiWindowFlags_NoScrollbar | + // ImGuiWindowFlags_NoScrollWithMouse); + + m_IsFocused = ImGui::IsWindowFocused(); + + // + m_NavigateAction.SetWindow(m_Canvas.ViewRect().Min, m_Canvas.ViewRect().GetSize()); + + // Handle canvas size change. Scale to Y axis, center on X. + if (!ImRect_IsEmpty(previousVisibleRect) && previousSize != canvasSize) + { + m_NavigateAction.FinishNavigation(); + + auto centerX = (previousVisibleRect.Max.x + previousVisibleRect.Min.x) * 0.5f; + auto centerY = (previousVisibleRect.Max.y + previousVisibleRect.Min.y) * 0.5f; + auto currentVisibleRect = m_Canvas.ViewRect(); + auto currentAspectRatio = currentVisibleRect.GetHeight() ? (currentVisibleRect.GetWidth() / currentVisibleRect.GetHeight()) : 0.0f; + auto width = previousVisibleRect.GetHeight(); + auto height = previousVisibleRect.GetHeight(); + + if (m_Config.CanvasSizeMode == ax::NodeEditor::CanvasSizeMode::FitVerticalView) + { + height = previousVisibleRect.GetHeight(); + width = height * currentAspectRatio; + } + else if (m_Config.CanvasSizeMode == ax::NodeEditor::CanvasSizeMode::FitHorizontalView) + { + width = previousVisibleRect.GetWidth(); + height = width / currentAspectRatio; + } + else if (m_Config.CanvasSizeMode == ax::NodeEditor::CanvasSizeMode::CenterOnly) + { + width = currentVisibleRect.GetWidth(); + height = currentVisibleRect.GetHeight(); + } + + previousVisibleRect.Min.x = centerX - 0.5f * width; + previousVisibleRect.Max.x = centerX + 0.5f * width; + previousVisibleRect.Min.y = centerY - 0.5f * height; + previousVisibleRect.Max.y = centerY + 0.5f * height; + + m_NavigateAction.NavigateTo(previousVisibleRect, Detail::NavigateAction::ZoomMode::Exact, 0.0f); + } + + m_Canvas.SetView(m_NavigateAction.GetView()); + + // #debug #clip + //ImGui::Text("CLIP = { x=%g y=%g w=%g h=%g r=%g b=%g }", + // clipMin.x, clipMin.y, clipMax.x - clipMin.x, clipMax.y - clipMin.y, clipMax.x, clipMax.y); + + // Reserve channels for background and links + ImDrawList_ChannelsGrow(m_DrawList, c_NodeStartChannel); + + if (HasSelectionChanged()) + ++m_SelectionId; + + m_LastSelectedObjects = m_SelectedObjects; +} + +void ed::EditorContext::End() +{ + //auto& io = ImGui::GetIO(); + auto control = BuildControl(m_CurrentAction && m_CurrentAction->IsDragging()); // NavigateAction.IsMovingOverEdge() + //auto& editorStyle = GetStyle(); + + m_HoveredNode = control.HotNode && m_CurrentAction == nullptr ? control.HotNode->m_ID : 0; + m_HoveredPin = control.HotPin && m_CurrentAction == nullptr ? control.HotPin->m_ID : 0; + m_HoveredLink = control.HotLink && m_CurrentAction == nullptr ? control.HotLink->m_ID : 0; + m_DoubleClickedNode = control.DoubleClickedNode ? control.DoubleClickedNode->m_ID : 0; + m_DoubleClickedPin = control.DoubleClickedPin ? control.DoubleClickedPin->m_ID : 0; + m_DoubleClickedLink = control.DoubleClickedLink ? control.DoubleClickedLink->m_ID : 0; + m_BackgroundClickButtonIndex = control.BackgroundClickButtonIndex; + m_BackgroundDoubleClickButtonIndex = control.BackgroundDoubleClickButtonIndex; + + //if (DoubleClickedNode) LOG_TRACE(0, "DOUBLE CLICK NODE: %d", DoubleClickedNode); + //if (DoubleClickedPin) LOG_TRACE(0, "DOUBLE CLICK PIN: %d", DoubleClickedPin); + //if (DoubleClickedLink) LOG_TRACE(0, "DOUBLE CLICK LINK: %d", DoubleClickedLink); + //if (BackgroundDoubleClicked) LOG_TRACE(0, "DOUBLE CLICK BACKGROUND", DoubleClickedLink); + + const bool isSelecting = m_CurrentAction && m_CurrentAction->AsSelect() != nullptr; + const bool isDragging = m_CurrentAction && m_CurrentAction->AsDrag() != nullptr; + //const bool isSizing = CurrentAction && CurrentAction->AsSize() != nullptr; + + // Draw nodes + for (auto node : m_Nodes) + if (node->m_IsLive && node->IsVisible()) + node->Draw(m_DrawList); + + // Draw links + for (auto link : m_Links) + if (link->m_IsLive && link->IsVisible()) + link->Draw(m_DrawList); + + // Highlight selected objects + { + auto selectedObjects = &m_SelectedObjects; + if (auto selectAction = m_CurrentAction ? m_CurrentAction->AsSelect() : nullptr) + selectedObjects = &selectAction->m_CandidateObjects; + + for (auto selectedObject : *selectedObjects) + { + if (selectedObject->IsVisible()) + selectedObject->Draw(m_DrawList, Object::Selected); + } + + // Highlight adjacent links + static auto isLinkHighlightedForPin = [](const Pin& pin) + { + return pin.m_Node->m_HighlightConnectedLinks && pin.m_Node->m_IsSelected; + }; + + for (auto& link : m_Links) + { + if (!link->m_IsLive || !link->IsVisible()) + continue; + + auto isLinkHighlighted = isLinkHighlightedForPin(*link->m_StartPin) || isLinkHighlightedForPin(*link->m_EndPin); + if (!isLinkHighlighted) + continue; + + link->Draw(m_DrawList, Object::Highlighted); + } + } + + if (!isSelecting) + { + auto hoveredObject = control.HotObject; + if (auto dragAction = m_CurrentAction ? m_CurrentAction->AsDrag() : nullptr) + hoveredObject = dragAction->m_DraggedObject; + if (auto sizeAction = m_CurrentAction ? m_CurrentAction->AsSize() : nullptr) + hoveredObject = sizeAction->m_SizedNode; + + if (hoveredObject && !IsSelected(hoveredObject) && hoveredObject->IsVisible()) + hoveredObject->Draw(m_DrawList, Object::Hovered); + } + + // Draw animations + for (auto controller : m_AnimationControllers) + controller->Draw(m_DrawList); + + if (m_CurrentAction && !m_CurrentAction->Process(control)) + m_CurrentAction = nullptr; + + if (m_NavigateAction.m_IsActive) + m_NavigateAction.Process(control); + else + m_NavigateAction.Accept(control); + + if (nullptr == m_CurrentAction) + { + EditorAction* possibleAction = nullptr; + + auto accept = [&possibleAction, &control](EditorAction& action) + { + auto result = action.Accept(control); + + if (result == EditorAction::True) + return true; + else if (/*!possibleAction &&*/ result == EditorAction::Possible) + possibleAction = &action; + else if (result == EditorAction::Possible) + action.Reject(); + + return false; + }; + + if (accept(m_ContextMenuAction)) + m_CurrentAction = &m_ContextMenuAction; + else if (accept(m_ShortcutAction)) + m_CurrentAction = &m_ShortcutAction; + else if (accept(m_SizeAction)) + m_CurrentAction = &m_SizeAction; + else if (accept(m_DragAction)) + m_CurrentAction = &m_DragAction; + else if (accept(m_CreateItemAction)) + m_CurrentAction = &m_CreateItemAction; + else if (accept(m_DeleteItemsAction)) + m_CurrentAction = &m_DeleteItemsAction; + else if (accept(m_SelectAction)) + m_CurrentAction = &m_SelectAction; + + if (possibleAction) + ImGui::SetMouseCursor(possibleAction->GetCursor()); + + if (m_CurrentAction && possibleAction) + possibleAction->Reject(); + } + + if (m_CurrentAction) + ImGui::SetMouseCursor(m_CurrentAction->GetCursor()); + + // Draw selection rectangle + m_SelectAction.Draw(m_DrawList); + + bool sortGroups = false; + if (control.ActiveNode) + { + if (!IsGroup(control.ActiveNode)) + { + // Bring active node to front + auto activeNodeIt = std::find(m_Nodes.begin(), m_Nodes.end(), control.ActiveNode); + std::rotate(activeNodeIt, activeNodeIt + 1, m_Nodes.end()); + } + else if (!isDragging && m_CurrentAction && m_CurrentAction->AsDrag()) + { + // Bring content of dragged group to front + std::vector nodes; + control.ActiveNode->GetGroupedNodes(nodes); + + std::stable_partition(m_Nodes.begin(), m_Nodes.end(), [&nodes](Node* node) + { + return std::find(nodes.begin(), nodes.end(), node) == nodes.end(); + }); + + sortGroups = true; + } + } + + // Sort nodes if bounds of node changed + if (sortGroups || ((m_Settings.m_DirtyReason & (SaveReasonFlags::Position | SaveReasonFlags::Size)) != SaveReasonFlags::None)) + { + // Bring all groups before regular nodes + auto groupsItEnd = std::stable_partition(m_Nodes.begin(), m_Nodes.end(), IsGroup); + + // Sort groups by area + std::sort(m_Nodes.begin(), groupsItEnd, [this](Node* lhs, Node* rhs) + { + const auto& lhsSize = lhs == m_SizeAction.m_SizedNode ? m_SizeAction.GetStartGroupBounds().GetSize() : lhs->m_GroupBounds.GetSize(); + const auto& rhsSize = rhs == m_SizeAction.m_SizedNode ? m_SizeAction.GetStartGroupBounds().GetSize() : rhs->m_GroupBounds.GetSize(); + + const auto lhsArea = lhsSize.x * lhsSize.y; + const auto rhsArea = rhsSize.x * rhsSize.y; + + return lhsArea > rhsArea; + }); + } + + // Apply Z order + std::stable_sort(m_Nodes.begin(), m_Nodes.end(), [](const auto& lhs, const auto& rhs) + { + return lhs->m_ZPosition < rhs->m_ZPosition; + }); + +# if 1 + // Every node has few channels assigned. Grow channel list + // to hold twice as much of channels and place them in + // node drawing order. + { + // Copy group nodes + auto liveNodeCount = static_cast(std::count_if(m_Nodes.begin(), m_Nodes.end(), [](Node* node) { return node->m_IsLive; })); + + // Reserve two additional channels for sorted list of channels + auto nodeChannelCount = m_DrawList->_Splitter._Count; + ImDrawList_ChannelsGrow(m_DrawList, m_DrawList->_Splitter._Count + c_ChannelsPerNode * liveNodeCount + c_LinkChannelCount); + + int targetChannel = nodeChannelCount; + + auto copyNode = [this, &targetChannel](Node* node) + { + if (!node->m_IsLive) + return; + + for (int i = 0; i < c_ChannelsPerNode; ++i) + ImDrawList_SwapChannels(m_DrawList, node->m_Channel + i, targetChannel + i); + + node->m_Channel = targetChannel; + targetChannel += c_ChannelsPerNode; + }; + + auto groupsItEnd = std::find_if(m_Nodes.begin(), m_Nodes.end(), [](Node* node) { return !IsGroup(node); }); + + // Copy group nodes + std::for_each(m_Nodes.begin(), groupsItEnd, copyNode); + + // Copy links + for (int i = 0; i < c_LinkChannelCount; ++i, ++targetChannel) + ImDrawList_SwapChannels(m_DrawList, c_LinkStartChannel + i, targetChannel); + + // Copy normal nodes + std::for_each(groupsItEnd, m_Nodes.end(), copyNode); + } +# endif + + // ImGui::PopClipRect(); + + // Draw grid +# if 1 // #FIXME + { + //auto& style = ImGui::GetStyle(); + + m_DrawList->ChannelsSetCurrent(c_UserChannel_Grid); + + ImVec2 offset = m_Canvas.ViewOrigin() * (1.0f / m_Canvas.ViewScale()); + ImU32 GRID_COLOR = GetColor(StyleColor_Grid, ImClamp(m_Canvas.ViewScale() * m_Canvas.ViewScale(), 0.0f, 1.0f)); + float GRID_SX = 32.0f;// * m_Canvas.ViewScale(); + float GRID_SY = 32.0f;// * m_Canvas.ViewScale(); + ImVec2 VIEW_POS = m_Canvas.ViewRect().Min; + ImVec2 VIEW_SIZE = m_Canvas.ViewRect().GetSize(); + + m_DrawList->AddRectFilled(VIEW_POS, VIEW_POS + VIEW_SIZE, GetColor(StyleColor_Bg)); + + for (float x = fmodf(offset.x, GRID_SX); x < VIEW_SIZE.x; x += GRID_SX) + m_DrawList->AddLine(ImVec2(x, 0.0f) + VIEW_POS, ImVec2(x, VIEW_SIZE.y) + VIEW_POS, GRID_COLOR); + for (float y = fmodf(offset.y, GRID_SY); y < VIEW_SIZE.y; y += GRID_SY) + m_DrawList->AddLine(ImVec2(0.0f, y) + VIEW_POS, ImVec2(VIEW_SIZE.x, y) + VIEW_POS, GRID_COLOR); + } +# endif + +# if 0 + { + auto userChannel = drawList->_Splitter._Count; + auto channelsToCopy = c_UserLayersCount; + ImDrawList_ChannelsGrow(drawList, userChannel + channelsToCopy); + for (int i = 0; i < channelsToCopy; ++i) + ImDrawList_SwapChannels(drawList, userChannel + i, c_UserLayerChannelStart + i); + } +# endif + +# if 0 + { + auto preOffset = ImVec2(0, 0); + auto postOffset = m_OldCanvas.WindowScreenPos + m_OldCanvas.ClientOrigin; + auto scale = m_OldCanvas.Zoom; + + ImDrawList_TransformChannels(drawList, 0, 1, preOffset, scale, postOffset); + ImDrawList_TransformChannels(drawList, c_BackgroundChannelStart, drawList->_ChannelsCount - 1, preOffset, scale, postOffset); + + auto clipTranslation = m_OldCanvas.WindowScreenPos - m_OldCanvas.FromScreen(m_OldCanvas.WindowScreenPos); + ImGui::PushClipRect(m_OldCanvas.WindowScreenPos + ImVec2(1, 1), m_OldCanvas.WindowScreenPos + m_OldCanvas.WindowScreenSize - ImVec2(1, 1), false); + ImDrawList_TranslateAndClampClipRects(drawList, 0, 1, clipTranslation); + ImDrawList_TranslateAndClampClipRects(drawList, c_BackgroundChannelStart, drawList->_ChannelsCount - 1, clipTranslation); + ImGui::PopClipRect(); + + // #debug: Static grid in local space + //for (float x = 0; x < Canvas.WindowScreenSize.x; x += 100) + // drawList->AddLine(ImVec2(x, 0.0f) + Canvas.WindowScreenPos, ImVec2(x, Canvas.WindowScreenSize.y) + Canvas.WindowScreenPos, IM_COL32(255, 0, 0, 128)); + //for (float y = 0; y < Canvas.WindowScreenSize.y; y += 100) + // drawList->AddLine(ImVec2(0.0f, y) + Canvas.WindowScreenPos, ImVec2(Canvas.WindowScreenSize.x, y) + Canvas.WindowScreenPos, IM_COL32(255, 0, 0, 128)); + } +# endif + +# if 1 + // Move user and hint channels to top + { + // Clip plane is transformed to global space. + // These channels already have clip planes in global space, so + // we move them to clip plane. Batch transformation in canvas + // will bring them back to global space. + auto preTransformClipRect = [this](int channelIndex) + { + ImDrawChannel& channel = m_DrawList->_Splitter._Channels[channelIndex]; + for (ImDrawCmd& cmd : channel._CmdBuffer) + { + auto a = ToCanvas(ImVec2(cmd.ClipRect.x, cmd.ClipRect.y)); + auto b = ToCanvas(ImVec2(cmd.ClipRect.z, cmd.ClipRect.w)); + cmd.ClipRect = ImVec4(a.x, a.y, b.x, b.y); + } + }; + + m_DrawList->ChannelsSetCurrent(0); + + auto channelCount = m_DrawList->_Splitter._Count; + ImDrawList_ChannelsGrow(m_DrawList, channelCount + 3); + ImDrawList_SwapChannels(m_DrawList, c_UserChannel_HintsBackground, channelCount + 0); + ImDrawList_SwapChannels(m_DrawList, c_UserChannel_Hints, channelCount + 1); + ImDrawList_SwapChannels(m_DrawList, c_UserChannel_Content, channelCount + 2); + + preTransformClipRect(channelCount + 0); + preTransformClipRect(channelCount + 1); + preTransformClipRect(channelCount + 2); + } +# endif + + UpdateAnimations(); + + m_DrawList->ChannelsMerge(); + + // #debug + // drawList->AddRectFilled(ImVec2(-10.0f, -10.0f), ImVec2(10.0f, 10.0f), IM_COL32(255, 0, 255, 255)); + + // ImGui::EndChild(); + // ImGui::PopStyleColor(); + if (m_IsCanvasVisible) + m_Canvas.End(); + + ImDrawList_SwapSplitter(m_DrawList, m_Splitter); + + // Draw border + { + auto& style = ImGui::GetStyle(); + auto borderShadoColor = style.Colors[ImGuiCol_BorderShadow]; + auto borderColor = style.Colors[ImGuiCol_Border]; + m_DrawList->AddRect(m_Canvas.Rect().Min + ImVec2(1, 1), m_Canvas.Rect().Max - ImVec2(1, 1), ImColor(borderShadoColor)); + m_DrawList->AddRect(m_Canvas.Rect().Min, m_Canvas.Rect().Max, ImColor(borderColor)); + } + + // #metrics + // ShowMetrics(control); + + ImGui::PopID(); + + if (!m_CurrentAction && m_IsFirstFrame && !m_Settings.m_Selection.empty()) + { + ClearSelection(); + for (auto id : m_Settings.m_Selection) + if (auto object = FindObject(id)) + SelectObject(object); + } + + if (HasSelectionChanged()) + MakeDirty(SaveReasonFlags::Selection); + + if (m_Settings.m_IsDirty && !m_CurrentAction) + SaveSettings(); + + m_DrawList = nullptr; + m_IsFirstFrame = false; +} + +bool ed::EditorContext::DoLink(LinkId id, PinId startPinId, PinId endPinId, ImU32 color, float thickness) +{ + //auto& editorStyle = GetStyle(); + + auto startPin = FindPin(startPinId); + auto endPin = FindPin(endPinId); + + if (!startPin || !startPin->m_IsLive || !endPin || !endPin->m_IsLive) + return false; + + startPin->m_HasConnection = true; + endPin->m_HasConnection = true; + + auto link = GetLink(id); + link->m_StartPin = startPin; + link->m_EndPin = endPin; + link->m_Color = color; + link->m_HighlightColor= GetColor(StyleColor_HighlightLinkBorder); + link->m_Thickness = thickness; + link->m_IsLive = true; + + link->UpdateEndpoints(); + + return true; +} + +void ed::EditorContext::SetNodePosition(NodeId nodeId, const ImVec2& position) +{ + auto node = FindNode(nodeId); + if (!node) + { + node = CreateNode(nodeId); + node->m_IsLive = false; + } + + if (node->m_Bounds.Min != position) + { + node->m_Bounds.Translate(position - node->m_Bounds.Min); + node->m_Bounds.Floor(); + MakeDirty(NodeEditor::SaveReasonFlags::Position, node); + } +} + +void ed::EditorContext::SetGroupSize(NodeId nodeId, const ImVec2& size) +{ + auto node = FindNode(nodeId); + if (!node) + { + node = CreateNode(nodeId); + node->m_IsLive = false; + } + + node->m_Type = NodeType::Group; + + if (node->m_GroupBounds.GetSize() != size) + { + node->m_GroupBounds.Min = node->m_Bounds.Min; + node->m_GroupBounds.Max = node->m_Bounds.Min + size; + node->m_GroupBounds.Floor(); + MakeDirty(NodeEditor::SaveReasonFlags::Size, node); + } +} + +ImVec2 ed::EditorContext::GetNodePosition(NodeId nodeId) +{ + auto node = FindNode(nodeId); + if (!node) + return ImVec2(FLT_MAX, FLT_MAX); + + return node->m_Bounds.Min; +} + +ImVec2 ed::EditorContext::GetNodeSize(NodeId nodeId) +{ + auto node = FindNode(nodeId); + if (!node) + return ImVec2(0, 0); + + return node->m_Bounds.GetSize(); +} + +void ed::EditorContext::SetNodeZPosition(NodeId nodeId, float z) +{ + auto node = FindNode(nodeId); + if (!node) + { + node = CreateNode(nodeId); + node->m_IsLive = false; + } + + node->m_ZPosition = z; +} + +float ed::EditorContext::GetNodeZPosition(NodeId nodeId) +{ + auto node = FindNode(nodeId); + if (!node) + return 0.0f; + + return node->m_ZPosition; +} + +void ed::EditorContext::MarkNodeToRestoreState(Node* node) +{ + node->m_RestoreState = true; +} + +void ed::EditorContext::UpdateNodeState(Node* node) +{ + bool tryLoadState = node->m_RestoreState; + + node->m_RestoreState = false; + + auto settings = m_Settings.FindNode(node->m_ID); + if (!settings) + return; + + if (!tryLoadState && settings->m_WasUsed) + return; + + if (!settings->m_WasUsed) + { + MakeDirty(SaveReasonFlags::AddNode, node); + settings->m_WasUsed = true; + } + + // Load state from config (if possible) + if (tryLoadState) + { + NodeSettings newSettings = *settings; + if (NodeSettings::Parse(m_Config.LoadNode(node->m_ID), newSettings)) + *settings = newSettings; + } + + node->m_Bounds.Min = settings->m_Location; + node->m_Bounds.Max = node->m_Bounds.Min + settings->m_Size; + node->m_Bounds.Floor(); + node->m_GroupBounds.Min = settings->m_Location; + node->m_GroupBounds.Max = node->m_GroupBounds.Min + settings->m_GroupSize; + node->m_GroupBounds.Floor(); +} + +void ed::EditorContext::RemoveSettings(Object* object) +{ + if (auto node = object->AsNode()) + { + m_Settings.RemoveNode(node->m_ID); + MakeDirty(SaveReasonFlags::RemoveNode, node); + } +} + +void ed::EditorContext::ClearSelection() +{ + for (auto& object : m_SelectedObjects) + object->m_IsSelected = false; + + m_SelectedObjects.clear(); +} + +void ed::EditorContext::SelectObject(Object* object) +{ + m_SelectedObjects.push_back(object); + object->m_IsSelected = true; +} + +void ed::EditorContext::DeselectObject(Object* object) +{ + auto objectIt = std::find(m_SelectedObjects.begin(), m_SelectedObjects.end(), object); + if (objectIt == m_SelectedObjects.end()) + return; + + object->m_IsSelected = false; + m_SelectedObjects.erase(objectIt); +} + +void ed::EditorContext::SetSelectedObject(Object* object) +{ + ClearSelection(); + SelectObject(object); +} + +void ed::EditorContext::ToggleObjectSelection(Object* object) +{ + if (IsSelected(object)) + DeselectObject(object); + else + SelectObject(object); +} + +bool ed::EditorContext::IsSelected(Object* object) +{ + return object && object->m_IsSelected; + // return std::find(m_SelectedObjects.begin(), m_SelectedObjects.end(), object) != m_SelectedObjects.end(); +} + +const ed::vector& ed::EditorContext::GetSelectedObjects() +{ + return m_SelectedObjects; +} + +bool ed::EditorContext::IsAnyNodeSelected() +{ + for (auto object : m_SelectedObjects) + if (object->AsNode()) + return true; + + return false; +} + +bool ed::EditorContext::IsAnyLinkSelected() +{ + for (auto object : m_SelectedObjects) + if (object->AsLink()) + return true; + + return false; +} + +bool ed::EditorContext::HasSelectionChanged() +{ + return m_LastSelectedObjects != m_SelectedObjects; +} + +ed::Node* ed::EditorContext::FindNodeAt(const ImVec2& p) +{ + for (auto node : m_Nodes) + if (node->TestHit(p)) + return node; + + return nullptr; +} + +void ed::EditorContext::FindNodesInRect(const ImRect& r, vector& result, bool append, bool includeIntersecting) +{ + if (!append) + result.resize(0); + + if (ImRect_IsEmpty(r)) + return; + + for (auto node : m_Nodes) + if (node->TestHit(r, includeIntersecting)) + result.push_back(node); +} + +void ed::EditorContext::FindLinksInRect(const ImRect& r, vector& result, bool append) +{ + if (!append) + result.resize(0); + + if (ImRect_IsEmpty(r)) + return; + + for (auto link : m_Links) + if (link->TestHit(r)) + result.push_back(link); +} + +bool ed::EditorContext::HasAnyLinks(NodeId nodeId) const +{ + for (auto link : m_Links) + { + if (!link->m_IsLive) + continue; + + if (link->m_StartPin->m_Node->m_ID == nodeId || link->m_EndPin->m_Node->m_ID == nodeId) + return true; + } + + return false; +} + +bool ed::EditorContext::HasAnyLinks(PinId pinId) const +{ + for (auto link : m_Links) + { + if (!link->m_IsLive) + continue; + + if (link->m_StartPin->m_ID == pinId || link->m_EndPin->m_ID == pinId) + return true; + } + + return false; +} + +int ed::EditorContext::BreakLinks(NodeId nodeId) +{ + int result = 0; + for (auto link : m_Links) + { + if (!link->m_IsLive) + continue; + + if (link->m_StartPin->m_Node->m_ID == nodeId || link->m_EndPin->m_Node->m_ID == nodeId) + { + if (GetItemDeleter().Add(link)) + ++result; + } + } + return result; +} + +int ed::EditorContext::BreakLinks(PinId pinId) +{ + int result = 0; + for (auto link : m_Links) + { + if (!link->m_IsLive) + continue; + + if (link->m_StartPin->m_ID == pinId || link->m_EndPin->m_ID == pinId) + { + if (GetItemDeleter().Add(link)) + ++result; + } + } + return result; +} + +void ed::EditorContext::FindLinksForNode(NodeId nodeId, vector& result, bool add) +{ + if (!add) + result.clear(); + + for (auto link : m_Links) + { + if (!link->m_IsLive) + continue; + + if (link->m_StartPin->m_Node->m_ID == nodeId || link->m_EndPin->m_Node->m_ID == nodeId) + result.push_back(link); + } +} + +bool ed::EditorContext::PinHadAnyLinks(PinId pinId) +{ + auto pin = FindPin(pinId); + if (!pin || !pin->m_IsLive) + return false; + + return pin->m_HasConnection || pin->m_HadConnection; +} + +void ed::EditorContext::NotifyLinkDeleted(Link* link) +{ + if (m_LastActiveLink == link) + m_LastActiveLink = nullptr; +} + +void ed::EditorContext::Suspend(SuspendFlags flags) +{ + IM_ASSERT(m_DrawList != nullptr && "Suspend was called outiside of Begin/End."); + auto lastChannel = m_DrawList->_Splitter._Current; + m_DrawList->ChannelsSetCurrent(m_ExternalChannel); + m_Canvas.Suspend(); + m_DrawList->ChannelsSetCurrent(lastChannel); + if ((flags & SuspendFlags::KeepSplitter) != SuspendFlags::KeepSplitter) + ImDrawList_SwapSplitter(m_DrawList, m_Splitter); +} + +void ed::EditorContext::Resume(SuspendFlags flags) +{ + IM_ASSERT(m_DrawList != nullptr && "Reasume was called outiside of Begin/End."); + if ((flags & SuspendFlags::KeepSplitter) != SuspendFlags::KeepSplitter) + ImDrawList_SwapSplitter(m_DrawList, m_Splitter); + auto lastChannel = m_DrawList->_Splitter._Current; + m_DrawList->ChannelsSetCurrent(m_ExternalChannel); + m_Canvas.Resume(); + m_DrawList->ChannelsSetCurrent(lastChannel); +} + +bool ed::EditorContext::IsSuspended() +{ + return m_Canvas.IsSuspended(); +} + +bool ed::EditorContext::IsFocused() +{ + return m_IsFocused; +} + +bool ed::EditorContext::IsHovered() const +{ + return m_IsHovered; +} + +bool ed::EditorContext::IsHoveredWithoutOverlapp() const +{ + return m_IsHoveredWithoutOverlapp; +} + +bool ed::EditorContext::CanAcceptUserInput() const +{ + return m_IsFocused && m_IsHovered; +} + +int ed::EditorContext::CountLiveNodes() const +{ + return (int)std::count_if(m_Nodes.begin(), m_Nodes.end(), [](const Node* node) { return node->m_IsLive; }); +} + +int ed::EditorContext::CountLivePins() const +{ + return (int)std::count_if(m_Pins.begin(), m_Pins.end(), [](const Pin* pin) { return pin->m_IsLive; }); +} + +int ed::EditorContext::CountLiveLinks() const +{ + return (int)std::count_if(m_Links.begin(), m_Links.end(), [](const Link* link) { return link->m_IsLive; }); +} + +ed::Pin* ed::EditorContext::CreatePin(PinId id, PinKind kind) +{ + IM_ASSERT(nullptr == FindObject(id)); + auto pin = new Pin(this, id, kind); + m_Pins.push_back({id, pin}); + std::sort(m_Pins.begin(), m_Pins.end()); + return pin; +} + +ed::Node* ed::EditorContext::CreateNode(NodeId id) +{ + IM_ASSERT(nullptr == FindObject(id)); + auto node = new Node(this, id); + m_Nodes.push_back({id, node}); + //std::sort(Nodes.begin(), Nodes.end()); + + auto settings = m_Settings.FindNode(id); + if (!settings) + settings = m_Settings.AddNode(id); + + UpdateNodeState(node); + + if (settings->m_GroupSize.x > 0 || settings->m_GroupSize.y > 0) + node->m_Type = NodeType::Group; + + node->m_IsLive = false; + + return node; +} + +ed::Link* ed::EditorContext::CreateLink(LinkId id) +{ + IM_ASSERT(nullptr == FindObject(id)); + auto link = new Link(this, id); + m_Links.push_back({id, link}); + std::sort(m_Links.begin(), m_Links.end()); + + return link; +} + +template +static inline auto FindItemInLinear(C& container, Id id) +{ +# if defined(_DEBUG) + auto start = container.data(); + auto end = container.data() + container.size(); + for (auto it = start; it < end; ++it) + if ((*it).m_ID == id) + return it->m_Object; +# else + for (auto item : container) + if (item.m_ID == id) + return item.m_Object; +# endif + + return static_cast(nullptr); +} + +template +static inline auto FindItemIn(C& container, Id id) +{ +//# if defined(_DEBUG) +// auto start = container.data(); +// auto end = container.data() + container.size(); +// for (auto it = start; it < end; ++it) +// if ((*it)->ID == id) +// return *it; +//# else +// for (auto item : container) +// if (item->ID == id) +// return item; +//# endif + auto key = typename C::value_type{ id, nullptr }; + auto first = container.cbegin(); + auto last = container.cend(); + auto it = std::lower_bound(first, last, key); + if (it != last && (key.m_ID == it->m_ID)) + return it->m_Object; + else + return static_castm_Object)>(nullptr); +} + +ed::Node* ed::EditorContext::FindNode(NodeId id) +{ + return FindItemInLinear(m_Nodes, id); +} + +ed::Pin* ed::EditorContext::FindPin(PinId id) +{ + return FindItemIn(m_Pins, id); +} + +ed::Link* ed::EditorContext::FindLink(LinkId id) +{ + return FindItemIn(m_Links, id); +} + +ed::Object* ed::EditorContext::FindObject(ObjectId id) +{ + if (id.IsNodeId()) + return FindNode(id.AsNodeId()); + else if (id.IsLinkId()) + return FindLink(id.AsLinkId()); + else if (id.IsPinId()) + return FindPin(id.AsPinId()); + else + return nullptr; +} + +ed::Node* ed::EditorContext::GetNode(NodeId id) +{ + auto node = FindNode(id); + if (!node) + node = CreateNode(id); + return node; +} + +ed::Pin* ed::EditorContext::GetPin(PinId id, PinKind kind) +{ + if (auto pin = FindPin(id)) + { + pin->m_Kind = kind; + return pin; + } + else + return CreatePin(id, kind); +} + +ed::Link* ed::EditorContext::GetLink(LinkId id) +{ + if (auto link = FindLink(id)) + return link; + else + return CreateLink(id); +} + +void ed::EditorContext::LoadSettings() +{ + ed::Settings::Parse(m_Config.Load(), m_Settings); + + if (ImRect_IsEmpty(m_Settings.m_VisibleRect)) + { + m_NavigateAction.m_Scroll = m_Settings.m_ViewScroll; + m_NavigateAction.m_Zoom = m_Settings.m_ViewZoom; + } + else + { + m_NavigateAction.NavigateTo(m_Settings.m_VisibleRect, NavigateAction::ZoomMode::Exact, 0.0f); + } +} + +void ed::EditorContext::SaveSettings() +{ + m_Config.BeginSave(); + + for (auto& node : m_Nodes) + { + auto settings = m_Settings.FindNode(node->m_ID); + settings->m_Location = node->m_Bounds.Min; + settings->m_Size = node->m_Bounds.GetSize(); + if (IsGroup(node)) + settings->m_GroupSize = node->m_GroupBounds.GetSize(); + + if (!node->m_RestoreState && settings->m_IsDirty && m_Config.SaveNodeSettings) + { + if (m_Config.SaveNode(node->m_ID, settings->Serialize().dump(), settings->m_DirtyReason)) + settings->ClearDirty(); + } + } + + m_Settings.m_Selection.resize(0); + for (auto& object : m_SelectedObjects) + m_Settings.m_Selection.push_back(object->ID()); + + m_Settings.m_ViewScroll = m_NavigateAction.m_Scroll; + m_Settings.m_ViewZoom = m_NavigateAction.m_Zoom; + m_Settings.m_VisibleRect = m_NavigateAction.m_VisibleRect; + + if (m_Config.Save(m_Settings.Serialize(), m_Settings.m_DirtyReason)) + m_Settings.ClearDirty(); + + m_Config.EndSave(); +} + +void ed::EditorContext::MakeDirty(SaveReasonFlags reason) +{ + m_Settings.MakeDirty(reason); +} + +void ed::EditorContext::MakeDirty(SaveReasonFlags reason, Node* node) +{ + m_Settings.MakeDirty(reason, node); +} + +ed::Link* ed::EditorContext::FindLinkAt(const ImVec2& p) +{ + for (auto& link : m_Links) + if (link->TestHit(p, c_LinkSelectThickness)) + return link; + + return nullptr; +} + +ImU32 ed::EditorContext::GetColor(StyleColor colorIndex) const +{ + return ImColor(m_Style.Colors[colorIndex]); +} + +ImU32 ed::EditorContext::GetColor(StyleColor colorIndex, float alpha) const +{ + auto color = m_Style.Colors[colorIndex]; + return ImColor(color.x, color.y, color.z, color.w * alpha); +} + +int ed::EditorContext::GetNodeIds(NodeId* nodes, int size) const +{ + if (size <= 0) + return 0; + + int result = 0; + for (auto node : m_Nodes) + { + if (!node->m_IsLive) + continue; + + *nodes++ = node->m_ID; + ++result; + if (--size == 0) + break; + } + + return result; +} + +void ed::EditorContext::RegisterAnimation(Animation* animation) +{ + m_LiveAnimations.push_back(animation); +} + +void ed::EditorContext::UnregisterAnimation(Animation* animation) +{ + auto it = std::find(m_LiveAnimations.begin(), m_LiveAnimations.end(), animation); + if (it != m_LiveAnimations.end()) + m_LiveAnimations.erase(it); +} + +void ed::EditorContext::UpdateAnimations() +{ + m_LastLiveAnimations = m_LiveAnimations; + + for (auto animation : m_LastLiveAnimations) + { + const bool isLive = (std::find(m_LiveAnimations.begin(), m_LiveAnimations.end(), animation) != m_LiveAnimations.end()); + + if (isLive) + animation->Update(); + } +} + +void ed::EditorContext::Flow(Link* link, FlowDirection direction) +{ + m_FlowAnimationController.Flow(link, direction); +} + +void ed::EditorContext::SetUserContext(bool globalSpace) +{ + const auto mousePos = ImGui::GetMousePos(); + + // Move drawing cursor to mouse location and prepare layer for + // content added by user. + if (globalSpace) + ImGui::SetCursorScreenPos(m_Canvas.FromLocal(mousePos)); + else + ImGui::SetCursorScreenPos(m_Canvas.FromLocal(mousePos)); + //ImGui::SetCursorScreenPos(ImFloor(mousePos)); + //ImGui::SetCursorScreenPos(ImVec2(floorf(mousePos.x), floorf(mousePos.y))); + + if (!IsSuspended()) + { + m_DrawList->ChannelsSetCurrent(c_UserChannel_Content); + } + + // #debug + // drawList->AddCircleFilled(ImGui::GetMousePos(), 4, IM_COL32(0, 255, 0, 255)); +} + +void ed::EditorContext::EnableShortcuts(bool enable) +{ + m_ShortcutsEnabled = enable; +} + +bool ed::EditorContext::AreShortcutsEnabled() +{ + return m_ShortcutsEnabled; +} + +ed::Control ed::EditorContext::BuildControl(bool allowOffscreen) +{ + m_IsHovered = false; + m_IsHoveredWithoutOverlapp = false; + + const auto windowHovered = ImGui::IsWindowHovered(); + const auto widgetHovered = ImGui::IsMouseHoveringRect(m_Canvas.ViewRect().Min, m_Canvas.ViewRect().Max, true); + + if (!allowOffscreen && !windowHovered && !widgetHovered) + return Control(); + + const auto mousePos = ImGui::GetMousePos(); + + // Expand clip rectangle to always contain cursor + auto editorRect = m_Canvas.ViewRect(); + auto isMouseOffscreen = allowOffscreen && !editorRect.Contains(mousePos); + if (isMouseOffscreen) + { + // Extend clip rect to capture off-screen mouse cursor + editorRect.Add(ImFloor(mousePos)); + editorRect.Add(ImVec2(ImCeil(mousePos.x), ImCeil(mousePos.y))); + + ImGui::PushClipRect(editorRect.Min, editorRect.Max, false); + } + + ImGuiID activeId = 0; + Object* hotObject = nullptr; + Object* activeObject = nullptr; + Object* clickedObject = nullptr; + Object* doubleClickedObject = nullptr; + + ImGuiButtonFlags extraFlags = ImGuiButtonFlags_None; + extraFlags |= ImGuiButtonFlags_MouseButtonLeft; + extraFlags |= ImGuiButtonFlags_MouseButtonRight; + extraFlags |= ImGuiButtonFlags_MouseButtonMiddle; + + static auto invisibleButtonEx = [](const char* str_id, const ImVec2& size_arg, ImGuiButtonFlags extraFlags) -> int + { + using namespace ImGui; + + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return -1; + + if (size_arg.x == 0.0f || size_arg.y == 0.0f) + return false; + + const ImGuiID id = window->GetID(str_id); + ImVec2 size = CalcItemSize(size_arg, 0.0f, 0.0f); + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); + ItemSize(size); + if (!ItemAdd(bb, id)) + return -1; + + auto buttonIndex = ImGui::GetCurrentContext()->ActiveIdMouseButton; + + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held, extraFlags); + + return pressed ? buttonIndex : -1; + }; + + // Emits invisible button and returns true if it is clicked. + auto emitInteractiveAreaEx = [&activeId](ObjectId id, const ImRect& rect, ImGuiButtonFlags extraFlags) -> int + { + char idString[33] = { 0 }; // itoa can output 33 bytes maximum + snprintf(idString, 32, "%p", id.AsPointer()); + ImGui::SetCursorScreenPos(rect.Min); + + // debug + //if (id < 0) return ImGui::Button(idString, to_imvec(rect.size)); + + auto buttonIndex = invisibleButtonEx(idString, rect.GetSize(), extraFlags); + + // #debug + //ImGui::GetWindowDrawList()->AddRectFilled(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(0, 255, 0, 64)); + + if (ImGui::IsItemActive()) + activeId = ImGui::GetActiveID(); + + return buttonIndex; + }; + + auto emitInteractiveArea = [&emitInteractiveAreaEx, extraFlags](ObjectId id, const ImRect& rect) + { + return emitInteractiveAreaEx(id, rect, extraFlags); + }; + + // Check input interactions over area. + auto checkInteractionsInArea = [this, &emitInteractiveArea, &hotObject, &activeObject, &clickedObject, &doubleClickedObject](ObjectId id, const ImRect& rect, Object* object) + { + if (emitInteractiveArea(id, rect) >= 0) + clickedObject = object; + if (!doubleClickedObject && ImGui::IsMouseDoubleClicked(m_Config.DragButtonIndex) && ImGui::IsItemHovered()) + doubleClickedObject = object; + + if (!hotObject && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) + hotObject = object; + + if (ImGui::IsItemActive()) + activeObject = object; + }; + + // Process live nodes and pins. + for (auto nodeIt = m_Nodes.rbegin(), nodeItEnd = m_Nodes.rend(); nodeIt != nodeItEnd; ++nodeIt) + { + auto node = *nodeIt; + + if (!node->m_IsLive) continue; + + // Check for interactions with live pins in node before + // processing node itself. Pins does not overlap each other + // and all are within node bounds. + for (auto pin = node->m_LastPin; pin; pin = pin->m_PreviousPin) + { + if (!pin->m_IsLive) continue; + + checkInteractionsInArea(pin->m_ID, pin->m_Bounds, pin); + } + + // Check for interactions with node. + if (node->m_Type == NodeType::Group) + { + // Node with a hole + ImGui::PushID(node->m_ID.AsPointer()); + + static const NodeRegion c_Regions[] = + { + NodeRegion::TopLeft, + NodeRegion::TopRight, + NodeRegion::BottomLeft, + NodeRegion::BottomRight, + NodeRegion::Top, + NodeRegion::Bottom, + NodeRegion::Left, + NodeRegion::Right, + NodeRegion::Header, + }; + + for (auto region : c_Regions) + { + auto bounds = node->GetRegionBounds(region); + if (ImRect_IsEmpty(bounds)) + continue; + checkInteractionsInArea(NodeId(static_cast(region)), bounds, node); + } + + ImGui::PopID(); + } + else + checkInteractionsInArea(node->m_ID, node->m_Bounds, node); + } + + // Links are not regular widgets and must be done manually since + // ImGui does not support interactive elements with custom hit maps. + // + // Links can steal input from background. + + // Links are just over background. So if anything else + // is hovered we can skip them. + if (nullptr == hotObject) + hotObject = FindLinkAt(mousePos); + + ImGuiButtonFlags backgroundExtraFlags = ImGuiButtonFlags_None; + if (m_Config.DragButtonIndex == 0 || m_Config.SelectButtonIndex == 0 || m_Config.NavigateButtonIndex == 0) + backgroundExtraFlags |= ImGuiButtonFlags_MouseButtonLeft; + if (m_Config.DragButtonIndex == 1 || m_Config.SelectButtonIndex == 1 || m_Config.NavigateButtonIndex == 1) + backgroundExtraFlags |= ImGuiButtonFlags_MouseButtonRight; + if (m_Config.DragButtonIndex == 2 || m_Config.SelectButtonIndex == 2 || m_Config.NavigateButtonIndex == 2) + backgroundExtraFlags |= ImGuiButtonFlags_MouseButtonMiddle; + + auto isMouseDoubleClickOverBackground = [doubleClickedObject, backgroundExtraFlags]() -> int + { + if (doubleClickedObject) + return -1; + + if (!ImGui::IsItemHovered()) + return -1; + + if ((backgroundExtraFlags & ImGuiButtonFlags_MouseButtonLeft) && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) + return ImGuiButtonFlags_MouseButtonLeft; + if ((backgroundExtraFlags & ImGuiButtonFlags_MouseButtonRight) && ImGui::IsMouseDoubleClicked(ImGuiButtonFlags_MouseButtonRight)) + return ImGuiButtonFlags_MouseButtonRight; + if ((backgroundExtraFlags & ImGuiButtonFlags_MouseButtonMiddle) && ImGui::IsMouseDoubleClicked(ImGuiButtonFlags_MouseButtonMiddle)) + return ImGuiButtonFlags_MouseButtonMiddle; + + return -1; + }; + + // Check for interaction with background. + auto backgroundClickButonIndex = emitInteractiveAreaEx(NodeId(0), editorRect, backgroundExtraFlags); + auto backgroundDoubleClickButtonIndex = isMouseDoubleClickOverBackground(); + auto isBackgroundActive = ImGui::IsItemActive(); + auto isBackgroundHot = !hotObject; + auto isDragging = ImGui::IsMouseDragging(0, 1) || ImGui::IsMouseDragging(1, 1) || ImGui::IsMouseDragging(2, 1); + + if (backgroundDoubleClickButtonIndex >= 0) + backgroundClickButonIndex = -1; + + if (isMouseOffscreen) + ImGui::PopClipRect(); + + // Process link input using background interactions. + auto hotLink = hotObject ? hotObject->AsLink() : nullptr; + + // ImGui take care of tracking active items. With link + // we must do this ourself. + if (!isDragging && isBackgroundActive && hotLink && !m_LastActiveLink) + m_LastActiveLink = hotLink; + if (isBackgroundActive && m_LastActiveLink) + { + activeObject = m_LastActiveLink; + isBackgroundActive = false; + } + else if (!isBackgroundActive && m_LastActiveLink) + m_LastActiveLink = nullptr; + + // Steal click from backgrounds if link is hovered. + if (!isDragging && backgroundClickButonIndex >= 0 && hotLink) + { + clickedObject = hotLink; + backgroundClickButonIndex = -1; + } + + // Steal double-click from backgrounds if link is hovered. + if (!isDragging && backgroundDoubleClickButtonIndex >= 0 && hotLink) + { + doubleClickedObject = hotLink; + backgroundDoubleClickButtonIndex = -1; + } + + if (activeId) + m_EditorActiveId = activeId; + + if (ImGui::IsAnyItemActive() && ImGui::GetActiveID() != m_EditorActiveId) + return Control(); + + m_IsHovered = ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly); + m_IsHoveredWithoutOverlapp = ImGui::IsItemHovered(); + if (!allowOffscreen && !m_IsHovered) + return Control(); + +# if IMGUI_VERSION_NUM >= 17909 + if (m_IsHoveredWithoutOverlapp) + ImGui::SetItemKeyOwner(ImGuiKey_MouseWheelY); +# endif + + return Control(hotObject, activeObject, clickedObject, doubleClickedObject, + isBackgroundHot, isBackgroundActive, backgroundClickButonIndex, backgroundDoubleClickButtonIndex); +} + +void ed::EditorContext::ShowMetrics(const Control& control) +{ + auto& io = ImGui::GetIO(); + + auto getObjectName = [](Object* object) + { + if (!object) return ""; + else if (object->AsNode()) return "Node"; + else if (object->AsPin()) return "Pin"; + else if (object->AsLink()) return "Link"; + else return ""; + }; + + auto getHotObjectName = [&control, &getObjectName]() + { + if (control.HotObject) + return getObjectName(control.HotObject); + else if (control.BackgroundHot) + return "Background"; + else + return ""; + }; + + auto getActiveObjectName = [&control, &getObjectName]() + { + if (control.ActiveObject) + return getObjectName(control.ActiveObject); + else if (control.BackgroundActive) + return "Background"; + else + return ""; + }; + + auto liveNodeCount = CountLiveNodes(); + auto livePinCount = CountLivePins(); + auto liveLinkCount = CountLiveLinks(); + + auto canvasRect = m_Canvas.Rect(); + auto viewRect = m_Canvas.ViewRect(); + auto localMousePos = m_Canvas.ToLocal(io.MousePos); + auto globalMousePos = io.MousePos; + + ImGui::SetCursorScreenPos(canvasRect.Min + ImVec2(5, 5)); + ImGui::BeginGroup(); + ImGui::Text("Is Focused: %s", m_IsFocused ? "true" : "false"); + ImGui::Text("Is Hovered: %s", m_IsHovered ? "true" : "false"); + ImGui::Text("Is Hovered (without overlapp): %s", m_IsHoveredWithoutOverlapp ? "true" : "false"); + ImGui::Text("Accept Input: %s", CanAcceptUserInput() ? "true" : "false"); + ImGui::Text("View Position: { x=%g y=%g }", viewRect.Min.x, viewRect.Min.y); + ImGui::Text("View Size: { w=%g h=%g }", viewRect.GetWidth(), viewRect.GetHeight()); + ImGui::Text("Canvas Size: { w=%g h=%g }", canvasRect.GetWidth(), canvasRect.GetHeight()); + ImGui::Text("Mouse: { x=%.0f y=%.0f } global: { x=%g y=%g }", localMousePos.x, localMousePos.y, globalMousePos.x, globalMousePos.y); + ImGui::Text("Live Nodes: %d", liveNodeCount); + ImGui::Text("Live Pins: %d", livePinCount); + ImGui::Text("Live Links: %d", liveLinkCount); + ImGui::Text("Hot Object: %s (%p)", getHotObjectName(), control.HotObject ? control.HotObject->ID().AsPointer() : nullptr); + if (auto node = control.HotObject ? control.HotObject->AsNode() : nullptr) + { + ImGui::SameLine(); + ImGui::Text("{ x=%g y=%g w=%g h=%g }", node->m_Bounds.Min.x, node->m_Bounds.Min.y, node->m_Bounds.GetWidth(), node->m_Bounds.GetHeight()); + } + ImGui::Text("Active Object: %s (%p)", getActiveObjectName(), control.ActiveObject ? control.ActiveObject->ID().AsPointer() : nullptr); + if (auto node = control.ActiveObject ? control.ActiveObject->AsNode() : nullptr) + { + ImGui::SameLine(); + ImGui::Text("{ x=%g y=%g w=%g h=%g }", node->m_Bounds.Min.x, node->m_Bounds.Min.y, node->m_Bounds.GetWidth(), node->m_Bounds.GetHeight()); + } + ImGui::Text("Action: %s", m_CurrentAction ? m_CurrentAction->GetName() : ""); + ImGui::Text("Action Is Dragging: %s", m_CurrentAction && m_CurrentAction->IsDragging() ? "Yes" : "No"); + m_NavigateAction.ShowMetrics(); + m_SizeAction.ShowMetrics(); + m_DragAction.ShowMetrics(); + m_SelectAction.ShowMetrics(); + m_ContextMenuAction.ShowMetrics(); + m_CreateItemAction.ShowMetrics(); + m_DeleteItemsAction.ShowMetrics(); + ImGui::EndGroup(); +} + + + + +//------------------------------------------------------------------------------ +// +// Node Settings +// +//------------------------------------------------------------------------------ +void ed::NodeSettings::ClearDirty() +{ + m_IsDirty = false; + m_DirtyReason = SaveReasonFlags::None; +} + +void ed::NodeSettings::MakeDirty(SaveReasonFlags reason) +{ + m_IsDirty = true; + m_DirtyReason = m_DirtyReason | reason; +} + +ed::json::value ed::NodeSettings::Serialize() +{ + json::value result; + result["location"]["x"] = m_Location.x; + result["location"]["y"] = m_Location.y; + + if (m_GroupSize.x > 0 || m_GroupSize.y > 0) + { + result["group_size"]["x"] = m_GroupSize.x; + result["group_size"]["y"] = m_GroupSize.y; + } + + return result; +} + +bool ed::NodeSettings::Parse(const std::string& string, NodeSettings& settings) +{ + auto settingsValue = json::value::parse(string); + if (settingsValue.is_discarded()) + return false; + + return Parse(settingsValue, settings); +} + +bool ed::NodeSettings::Parse(const json::value& data, NodeSettings& result) +{ + if (!data.is_object()) + return false; + + auto tryParseVector = [](const json::value& v, ImVec2& result) -> bool + { + if (v.is_object()) + { + auto xValue = v["x"]; + auto yValue = v["y"]; + + if (xValue.is_number() && yValue.is_number()) + { + result.x = static_cast(xValue.get()); + result.y = static_cast(yValue.get()); + + return true; + } + } + + return false; + }; + + if (!tryParseVector(data["location"], result.m_Location)) + return false; + + if (data.contains("group_size") && !tryParseVector(data["group_size"], result.m_GroupSize)) + return false; + + return true; +} + + + + +//------------------------------------------------------------------------------ +// +// Settings +// +//------------------------------------------------------------------------------ +ed::NodeSettings* ed::Settings::AddNode(NodeId id) +{ + m_Nodes.push_back(NodeSettings(id)); + return &m_Nodes.back(); +} + +ed::NodeSettings* ed::Settings::FindNode(NodeId id) +{ + for (auto& settings : m_Nodes) + if (settings.m_ID == id) + return &settings; + + return nullptr; +} + +void ed::Settings::RemoveNode(NodeId id) +{ + auto node = FindNode(id); + if (!node) + return; + + *node = NodeSettings(id); +} + +void ed::Settings::ClearDirty(Node* node) +{ + if (node) + { + auto settings = FindNode(node->m_ID); + IM_ASSERT(settings); + settings->ClearDirty(); + } + else + { + m_IsDirty = false; + m_DirtyReason = SaveReasonFlags::None; + + for (auto& knownNode : m_Nodes) + knownNode.ClearDirty(); + } +} + +void ed::Settings::MakeDirty(SaveReasonFlags reason, Node* node) +{ + m_IsDirty = true; + m_DirtyReason = m_DirtyReason | reason; + + if (node) + { + auto settings = FindNode(node->m_ID); + IM_ASSERT(settings); + + settings->MakeDirty(reason); + } +} + +std::string ed::Settings::Serialize() +{ + json::value result; + + auto serializeObjectId = [](ObjectId id) + { + auto value = std::to_string(reinterpret_cast(id.AsPointer())); + switch (id.Type()) + { + default: + case NodeEditor::Detail::ObjectType::None: return value; + case NodeEditor::Detail::ObjectType::Node: return "node:" + value; + case NodeEditor::Detail::ObjectType::Link: return "link:" + value; + case NodeEditor::Detail::ObjectType::Pin: return "pin:" + value; + } + }; + + auto& nodes = result["nodes"]; + for (auto& node : m_Nodes) + { + if (node.m_WasUsed) + nodes[serializeObjectId(node.m_ID)] = node.Serialize(); + } + + auto& selection = result["selection"]; + for (auto& id : m_Selection) + selection.push_back(serializeObjectId(id)); + + auto& view = result["view"]; + view["scroll"]["x"] = m_ViewScroll.x; + view["scroll"]["y"] = m_ViewScroll.y; + view["zoom"] = m_ViewZoom; + view["visible_rect"]["min"]["x"] = m_VisibleRect.Min.x; + view["visible_rect"]["min"]["y"] = m_VisibleRect.Min.y; + view["visible_rect"]["max"]["x"] = m_VisibleRect.Max.x; + view["visible_rect"]["max"]["y"] = m_VisibleRect.Max.y; + + return result.dump(); +} + +bool ed::Settings::Parse(const std::string& string, Settings& settings) +{ + Settings result = settings; + + auto settingsValue = json::value::parse(string); + if (settingsValue.is_discarded()) + return false; + + if (!settingsValue.is_object()) + return false; + + auto tryParseVector = [](const json::value& v, ImVec2& result) -> bool + { + if (v.is_object() && v.contains("x") && v.contains("y")) + { + auto xValue = v["x"]; + auto yValue = v["y"]; + + if (xValue.is_number() && yValue.is_number()) + { + result.x = static_cast(xValue.get()); + result.y = static_cast(yValue.get()); + + return true; + } + } + + return false; + }; + + auto deserializeObjectId = [](const std::string& str) + { + auto separator = str.find_first_of(':'); + auto idStart = str.c_str() + ((separator != std::string::npos) ? separator + 1 : 0); + auto id = reinterpret_cast(strtoull(idStart, nullptr, 10)); + if (str.compare(0, separator, "node") == 0) + return ObjectId(NodeId(id)); + else if (str.compare(0, separator, "link") == 0) + return ObjectId(LinkId(id)); + else if (str.compare(0, separator, "pin") == 0) + return ObjectId(PinId(id)); + else + // fallback to old format + return ObjectId(NodeId(id)); //return ObjectId(); + }; + + //auto& settingsObject = settingsValue.get(); + + auto& nodesValue = settingsValue["nodes"]; + if (nodesValue.is_object()) + { + for (auto& node : nodesValue.get()) + { + auto id = deserializeObjectId(node.first.c_str()).AsNodeId(); + + auto nodeSettings = result.FindNode(id); + if (!nodeSettings) + nodeSettings = result.AddNode(id); + + NodeSettings::Parse(node.second, *nodeSettings); + } + } + + auto& selectionValue = settingsValue["selection"]; + if (selectionValue.is_array()) + { + const auto selectionArray = selectionValue.get(); + + result.m_Selection.reserve(selectionArray.size()); + result.m_Selection.resize(0); + for (auto& selection : selectionArray) + { + if (selection.is_string()) + result.m_Selection.push_back(deserializeObjectId(selection.get())); + } + } + + auto& viewValue = settingsValue["view"]; + if (viewValue.is_object()) + { + auto& viewScrollValue = viewValue["scroll"]; + auto& viewZoomValue = viewValue["zoom"]; + + if (!tryParseVector(viewScrollValue, result.m_ViewScroll)) + result.m_ViewScroll = ImVec2(0, 0); + + result.m_ViewZoom = viewZoomValue.is_number() ? static_cast(viewZoomValue.get()) : 1.0f; + + if (!viewValue.contains("visible_rect") || !tryParseVector(viewValue["visible_rect"]["min"], result.m_VisibleRect.Min) || !tryParseVector(viewValue["visible_rect"]["max"], result.m_VisibleRect.Max)) + result.m_VisibleRect = {}; + } + + settings = std::move(result); + + return true; +} + + + +//------------------------------------------------------------------------------ +// +// Animation +// +//------------------------------------------------------------------------------ +ed::Animation::Animation(EditorContext* editor): + Editor(editor), + m_State(Stopped), + m_Time(0.0f), + m_Duration(0.0f) +{ +} + +ed::Animation::~Animation() +{ + Stop(); +} + +void ed::Animation::Play(float duration) +{ + if (IsPlaying()) + Stop(); + + m_State = Playing; + if (duration < 0) + duration = 0.0f; + + m_Time = 0.0f; + m_Duration = duration; + + OnPlay(); + + Editor->RegisterAnimation(this); + + if (duration == 0.0f) + Finish(); +} + +void ed::Animation::Stop() +{ + if (!IsPlaying()) + return; + + m_State = Stopped; + + Editor->UnregisterAnimation(this); + + OnStop(); +} + +void ed::Animation::Finish() +{ + if (!IsPlaying()) + return; + + OnFinish(); + + Stop(); +} + +void ed::Animation::Update() +{ + if (!IsPlaying()) + return; + + m_Time += ImMax(0.0f, ImGui::GetIO().DeltaTime); + if (m_Time < m_Duration) + { + const float progress = GetProgress(); + OnUpdate(progress); + } + else + { + OnFinish(); + Stop(); + } +} + + + + +//------------------------------------------------------------------------------ +// +// Navigate Animation +// +//------------------------------------------------------------------------------ +ed::NavigateAnimation::NavigateAnimation(EditorContext* editor, NavigateAction& scrollAction): + Animation(editor), + Action(scrollAction) +{ +} + +void ed::NavigateAnimation::NavigateTo(const ImRect& target, float duration) +{ + Stop(); + + m_Start = Action.GetViewRect(); + m_Target = target; + + // Skip tiny animations + auto minoffset = m_Target.Min - m_Start.Min; + auto maxOffset = m_Target.Max - m_Start.Max; + auto epsilon = 1e-4f; + if (ImFabs(minoffset.x) < epsilon && ImFabs(minoffset.y) < epsilon && + ImFabs(maxOffset.x) < epsilon && ImFabs(maxOffset.y) < epsilon) + { + duration = 0; + } + + Play(duration); +} + +void ed::NavigateAnimation::OnUpdate(float progress) +{ + ImRect current; + current.Min = ImEasing::EaseOutQuad(m_Start.Min, m_Target.Min - m_Start.Min, progress); + current.Max = ImEasing::EaseOutQuad(m_Start.Max, m_Target.Max - m_Start.Max, progress); + Action.SetViewRect(current); +} + +void ed::NavigateAnimation::OnStop() +{ + Editor->MakeDirty(SaveReasonFlags::Navigation); +} + +void ed::NavigateAnimation::OnFinish() +{ + Action.SetViewRect(m_Target); + + Editor->MakeDirty(SaveReasonFlags::Navigation); +} + + + + +//------------------------------------------------------------------------------ +// +// Flow Animation +// +//------------------------------------------------------------------------------ +ed::FlowAnimation::FlowAnimation(FlowAnimationController* controller): + Animation(controller->Editor), + Controller(controller), + m_Link(nullptr), + m_Offset(0.0f), + m_PathLength(0.0f) +{ +} + +void ed::FlowAnimation::Flow(ed::Link* link, float markerDistance, float speed, float duration) +{ + Stop(); + + if (m_Link != link) + { + m_Offset = 0.0f; + ClearPath(); + } + + if (m_MarkerDistance != markerDistance) + ClearPath(); + + m_MarkerDistance = markerDistance; + m_Speed = speed; + m_Link = link; + + Play(duration); +} + +void ed::FlowAnimation::Draw(ImDrawList* drawList) +{ + if (!IsPlaying() || !IsLinkValid() || !m_Link->IsVisible()) + return; + + if (!IsPathValid()) + UpdatePath(); + + m_Offset = fmodf(m_Offset, m_MarkerDistance); + if (m_Offset < 0) + m_Offset += m_MarkerDistance; + + const auto progress = GetProgress(); + + const auto flowAlpha = 1.0f - progress * progress; + const auto flowColor = Editor->GetColor(StyleColor_Flow, flowAlpha); + //const auto flowPath = Link->GetCurve(); + + m_Link->Draw(drawList, flowColor, 2.0f); + + if (IsPathValid()) + { + //Offset = 0; + + const auto markerAlpha = powf(1.0f - progress, 0.35f); + const auto markerRadius = 4.0f * (1.0f - progress) + 2.0f; + const auto markerColor = Editor->GetColor(StyleColor_FlowMarker, markerAlpha); + + for (float d = m_Offset; d < m_PathLength; d += m_MarkerDistance) + drawList->AddCircleFilled(SamplePath(d), markerRadius, markerColor); + } +} + +bool ed::FlowAnimation::IsLinkValid() const +{ + return m_Link && m_Link->m_IsLive; +} + +bool ed::FlowAnimation::IsPathValid() const +{ + return m_Path.size() > 1 && m_PathLength > 0.0f && m_Link->m_Start == m_LastStart && m_Link->m_End == m_LastEnd; +} + +void ed::FlowAnimation::UpdatePath() +{ + if (!IsLinkValid()) + { + ClearPath(); + return; + } + + const auto curve = m_Link->GetCurve(); + + m_LastStart = m_Link->m_Start; + m_LastEnd = m_Link->m_End; + m_PathLength = ImCubicBezierLength(curve.P0, curve.P1, curve.P2, curve.P3); + + auto collectPointsCallback = [this](ImCubicBezierFixedStepSample& result) + { + m_Path.push_back(CurvePoint{ result.Length, result.Point }); + }; + + const auto step = ImMax(m_MarkerDistance * 0.5f, 15.0f); + + m_Path.resize(0); + ImCubicBezierFixedStep(collectPointsCallback, curve, step, false, 0.5f, 0.001f); +} + +void ed::FlowAnimation::ClearPath() +{ + vector().swap(m_Path); + m_PathLength = 0.0f; +} + +ImVec2 ed::FlowAnimation::SamplePath(float distance) const +{ + //distance = ImMax(0.0f, std::min(distance, PathLength)); + + auto endPointIt = std::find_if(m_Path.begin(), m_Path.end(), [distance](const CurvePoint& p) { return distance < p.Distance; }); + if (endPointIt == m_Path.end()) + endPointIt = m_Path.end() - 1; + else if (endPointIt == m_Path.begin()) + endPointIt = m_Path.begin() + 1; + + const auto& start = endPointIt[-1]; + const auto& end = *endPointIt; + const auto t = (distance - start.Distance) / (end.Distance - start.Distance); + + return start.Point + (end.Point - start.Point) * t; +} + +void ed::FlowAnimation::OnUpdate(float progress) +{ + IM_UNUSED(progress); + + m_Offset += m_Speed * ImGui::GetIO().DeltaTime; +} + +void ed::FlowAnimation::OnStop() +{ + Controller->Release(this); +} + + + + +//------------------------------------------------------------------------------ +// +// Flow Animation Controller +// +//------------------------------------------------------------------------------ +ed::FlowAnimationController::FlowAnimationController(EditorContext* editor): + AnimationController(editor) +{ +} + +ed::FlowAnimationController::~FlowAnimationController() +{ + for (auto animation : m_Animations) + delete animation; +} + +void ed::FlowAnimationController::Flow(Link* link, FlowDirection direction) +{ + if (!link || !link->m_IsLive) + return; + + auto& editorStyle = GetStyle(); + + auto animation = GetOrCreate(link); + + float speedDirection = 1.0f; + if (direction == FlowDirection::Backward) + speedDirection = -1.0f; + + animation->Flow(link, editorStyle.FlowMarkerDistance, editorStyle.FlowSpeed * speedDirection, editorStyle.FlowDuration); +} + +void ed::FlowAnimationController::Draw(ImDrawList* drawList) +{ + if (m_Animations.empty()) + return; + + drawList->ChannelsSetCurrent(c_LinkChannel_Flow); + + for (auto animation : m_Animations) + animation->Draw(drawList); +} + +ed::FlowAnimation* ed::FlowAnimationController::GetOrCreate(Link* link) +{ + // Return live animation which match target link + { + auto animationIt = std::find_if(m_Animations.begin(), m_Animations.end(), [link](FlowAnimation* animation) { return animation->m_Link == link; }); + if (animationIt != m_Animations.end()) + return *animationIt; + } + + // There are no live animations for target link, try to reuse inactive old one + if (!m_FreePool.empty()) + { + auto animation = m_FreePool.back(); + m_FreePool.pop_back(); + return animation; + } + + // Cache miss, allocate new one + auto animation = new FlowAnimation(this); + m_Animations.push_back(animation); + + return animation; +} + +void ed::FlowAnimationController::Release(FlowAnimation* animation) +{ + IM_UNUSED(animation); +} + + + +//------------------------------------------------------------------------------ +// +// Navigate Action +// +//------------------------------------------------------------------------------ +const float ed::NavigateAction::s_DefaultZoomLevels[] = +{ + 0.1f, 0.15f, 0.20f, 0.25f, 0.33f, 0.5f, 0.75f, 1.0f, 1.25f, 1.50f, 2.0f, 2.5f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f +}; + +const int ed::NavigateAction::s_DefaultZoomLevelCount = sizeof(s_DefaultZoomLevels) / sizeof(*s_DefaultZoomLevels); + +ed::NavigateAction::NavigateAction(EditorContext* editor, ImGuiEx::Canvas& canvas): + EditorAction(editor), + m_IsActive(false), + m_Zoom(1), + m_VisibleRect(), + m_Scroll(0, 0), + m_ScrollStart(0, 0), + m_ScrollDelta(0, 0), + m_Canvas(canvas), + m_WindowScreenPos(0, 0), + m_WindowScreenSize(0, 0), + m_Animation(editor, *this), + m_Reason(NavigationReason::Unknown), + m_LastSelectionId(0), + m_LastObject(nullptr), + m_MovingOverEdge(false), + m_MoveScreenOffset(0, 0), + m_ZoomLevels(editor->GetConfig().CustomZoomLevels.Size > 0 ? editor->GetConfig().CustomZoomLevels.Data : s_DefaultZoomLevels), + m_ZoomLevelCount(editor->GetConfig().CustomZoomLevels.Size > 0 ? editor->GetConfig().CustomZoomLevels.Size : s_DefaultZoomLevelCount) +{ +} + +ed::EditorAction::AcceptResult ed::NavigateAction::Accept(const Control& control) +{ + IM_ASSERT(!m_IsActive); + + if (m_IsActive) + return False; + + if (Editor->CanAcceptUserInput() /*&& !ImGui::IsAnyItemActive()*/ && ImGui::IsMouseDragging(Editor->GetConfig().NavigateButtonIndex, 0.0f)) + { + m_IsActive = true; + m_ScrollStart = m_Scroll; + m_ScrollDelta = ImGui::GetMouseDragDelta(Editor->GetConfig().NavigateButtonIndex); + m_Scroll = m_ScrollStart - m_ScrollDelta * m_Zoom; + } + + auto& io = ImGui::GetIO(); + + if (Editor->CanAcceptUserInput() && ImGui::IsKeyPressed(ImGuiKey_F) && Editor->AreShortcutsEnabled()) + { + const auto zoomMode = io.KeyShift ? NavigateAction::ZoomMode::WithMargin : NavigateAction::ZoomMode::None; + + auto findHotObjectToZoom = [this, &control, &io]() -> Object* + { + if (control.HotObject) + { + if (auto pin = control.HotObject->AsPin()) + return pin->m_Node; + else + return control.HotObject; + } + else if (control.BackgroundHot) + { + auto node = Editor->FindNodeAt(io.MousePos); + if (IsGroup(node)) + return node; + } + + return nullptr; + }; + + bool navigateToContent = false; + if (!Editor->GetSelectedObjects().empty()) + { + if (m_Reason != NavigationReason::Selection || m_LastSelectionId != Editor->GetSelectionId() || (zoomMode != NavigateAction::ZoomMode::None)) + { + m_LastSelectionId = Editor->GetSelectionId(); + NavigateTo(Editor->GetSelectionBounds(), zoomMode, -1.0f, NavigationReason::Selection); + } + else + navigateToContent = true; + } + else if(auto hotObject = findHotObjectToZoom()) + { + if (m_Reason != NavigationReason::Object || m_LastObject != hotObject || (zoomMode != NavigateAction::ZoomMode::None)) + { + m_LastObject = hotObject; + auto bounds = hotObject->GetBounds(); + NavigateTo(bounds, zoomMode, -1.0f, NavigationReason::Object); + } + else + navigateToContent = true; + } + else + navigateToContent = true; + + if (navigateToContent) + NavigateTo(Editor->GetContentBounds(), NavigateAction::ZoomMode::WithMargin, -1.0f, NavigationReason::Content); + } + + auto visibleRect = GetViewRect(); + if (m_VisibleRect.Min != visibleRect.Min || m_VisibleRect.Max != visibleRect.Max) + { + m_VisibleRect = visibleRect; + Editor->MakeDirty(SaveReasonFlags::Navigation); + } + + // // #debug + // if (m_DrawList) + // m_DrawList->AddCircleFilled(io.MousePos, 4.0f, IM_COL32(255, 0, 255, 255)); + + if (HandleZoom(control)) + return True; + + return m_IsActive ? True : False; +} + +bool ed::NavigateAction::Process(const Control& control) +{ + IM_UNUSED(control); + + if (!m_IsActive) + return false; + + if (ImGui::IsMouseDragging(Editor->GetConfig().NavigateButtonIndex, 0.0f)) + { + m_ScrollDelta = ImGui::GetMouseDragDelta(Editor->GetConfig().NavigateButtonIndex); + m_Scroll = m_ScrollStart - m_ScrollDelta * m_Zoom; + m_VisibleRect = GetViewRect(); +// if (IsActive && Animation.IsPlaying()) +// Animation.Target = Animation.Target - ScrollDelta * Animation.TargetZoom; + } + else + { + if (m_Scroll != m_ScrollStart) + Editor->MakeDirty(SaveReasonFlags::Navigation); + + m_IsActive = false; + } + + // #TODO: Handle zoom while scrolling + // HandleZoom(control); + + return m_IsActive; +} + +bool ed::NavigateAction::HandleZoom(const Control& control) +{ + IM_UNUSED(control); + + const auto currentAction = Editor->GetCurrentAction(); + const auto allowOffscreen = currentAction && currentAction->IsDragging(); + + auto& io = ImGui::GetIO(); + + if (!io.MouseWheel || (!allowOffscreen && !Editor->IsHoveredWithoutOverlapp()))// && !ImGui::IsAnyItemActive()) + return false; + + auto savedScroll = m_Scroll; + auto savedZoom = m_Zoom; + + m_Animation.Finish(); + + auto mousePos = io.MousePos; + auto steps = (int)io.MouseWheel; + auto newZoom = MatchZoom(steps, m_ZoomLevels[steps < 0 ? 0 : m_ZoomLevelCount - 1]); + + auto oldView = GetView(); + m_Zoom = newZoom; + auto newView = GetView(); + + auto screenPos = m_Canvas.FromLocal(mousePos, oldView); + auto canvasPos = m_Canvas.ToLocal(screenPos, newView); + + auto offset = (canvasPos - mousePos) * m_Zoom; + auto targetScroll = m_Scroll - offset; + + auto visibleRect = GetViewRect(); + + if (m_Scroll != savedScroll || m_Zoom != savedZoom || m_VisibleRect.Min != visibleRect.Min || m_VisibleRect.Max != visibleRect.Max) + { + m_Scroll = savedScroll; + m_Zoom = savedZoom; + m_VisibleRect = visibleRect; + + Editor->MakeDirty(SaveReasonFlags::Navigation); + } + + auto targetRect = m_Canvas.CalcViewRect(ImGuiEx::CanvasView(-targetScroll, newZoom)); + + NavigateTo(targetRect, c_MouseZoomDuration, NavigationReason::MouseZoom); + + return true; +} + +void ed::NavigateAction::ShowMetrics() +{ + EditorAction::ShowMetrics(); + + ImGui::Text("%s:", GetName()); + ImGui::Text(" Active: %s", m_IsActive ? "yes" : "no"); + ImGui::Text(" Scroll: { x=%g y=%g }", m_Scroll.x, m_Scroll.y); + ImGui::Text(" Zoom: %g", m_Zoom); + ImGui::Text(" Visible Rect: { l=%g t=%g, r=%g b=%g w=%g h=%g }", + m_VisibleRect.Min.x, m_VisibleRect.Min.y, + m_VisibleRect.Max.x, m_VisibleRect.Max.y, + m_VisibleRect.Max.x - m_VisibleRect.Min.x, + m_VisibleRect.Max.y - m_VisibleRect.Min.y); +} + +void ed::NavigateAction::NavigateTo(const ImRect& bounds, ZoomMode zoomMode, float duration, NavigationReason reason) +{ + if (ImRect_IsEmpty(bounds)) + return; + + if (duration < 0.0f) + duration = GetStyle().ScrollDuration; + + if (zoomMode == ZoomMode::None) + { + auto viewRect = m_Canvas.ViewRect(); + auto viewRectCenter = viewRect.GetCenter(); + auto targetCenter = bounds.GetCenter(); + + viewRect.Translate(targetCenter - viewRectCenter); + + NavigateTo(viewRect, duration, reason); + } + else + { + // Grow rect by 5% to leave some reasonable margin + // from the edges of the canvas. + auto rect = bounds; + + if (zoomMode == ZoomMode::WithMargin) + { + auto extend = ImMax(rect.GetWidth(), rect.GetHeight()); + rect.Expand(extend * c_NavigationZoomMargin * 0.5f); + } + + NavigateTo(rect, duration, reason); + } +} + +void ed::NavigateAction::NavigateTo(const ImRect& target, float duration, NavigationReason reason) +{ + m_Reason = reason; + + m_Animation.NavigateTo(target, duration); +} + +void ed::NavigateAction::StopNavigation() +{ + m_Animation.Stop(); +} + +void ed::NavigateAction::FinishNavigation() +{ + m_Animation.Finish(); +} + +bool ed::NavigateAction::MoveOverEdge(const ImVec2& canvasSize) +{ + // Don't interrupt non-edge animations + if (m_Animation.IsPlaying()) + return false; + + auto& io = ImGui::GetIO(); + + const auto screenMousePos = io.MousePos; + const auto screenRect = ImRect(ImGui::GetCursorScreenPos(), ImGui::GetCursorScreenPos() + canvasSize); + + // Mouse is over screen, do nothing + if (screenRect.Contains(screenMousePos)) + return false; + + // Several backend move mouse position to -FLT_MAX to indicate + // uninitialized/unknown state. To prevent all sorts + // of math problems, we just ignore such state. + if (screenMousePos.x <= -FLT_MAX || screenMousePos.y <= -FLT_MAX) + return false; + + const auto minDistance = ImVec2(-c_MaxMoveOverEdgeDistance, -c_MaxMoveOverEdgeDistance); + const auto maxDistance = ImVec2( c_MaxMoveOverEdgeDistance, c_MaxMoveOverEdgeDistance); + + const auto screenPointOnEdge = ImRect_ClosestPoint(screenRect, screenMousePos, true); + const auto offset = ImMin(ImMax(screenPointOnEdge - screenMousePos, minDistance), maxDistance); + const auto relativeOffset = -offset * io.DeltaTime * c_MaxMoveOverEdgeSpeed; + + m_Scroll = m_Scroll + relativeOffset; + + m_MoveScreenOffset = relativeOffset; + m_MovingOverEdge = true; + + return true; +} + +void ed::NavigateAction::StopMoveOverEdge() +{ + if (m_MovingOverEdge) + { + Editor->MakeDirty(SaveReasonFlags::Navigation); + + m_MoveScreenOffset = ImVec2(0, 0); + m_MovingOverEdge = false; + } +} + +void ed::NavigateAction::SetWindow(ImVec2 position, ImVec2 size) +{ + m_WindowScreenPos = position; + m_WindowScreenSize = size; +} + +ImGuiEx::CanvasView ed::NavigateAction::GetView() const +{ + return ImGuiEx::CanvasView(-m_Scroll, m_Zoom); +} + +ImVec2 ed::NavigateAction::GetViewOrigin() const +{ + return -m_Scroll; +} + +float ed::NavigateAction::GetViewScale() const +{ + return m_Zoom; +} + +void ed::NavigateAction::SetViewRect(const ImRect& rect) +{ + auto view = m_Canvas.CalcCenterView(rect); + m_Scroll = -view.Origin; + m_Zoom = view.Scale; +} + +ImRect ed::NavigateAction::GetViewRect() const +{ + return m_Canvas.CalcViewRect(GetView()); +} + +float ed::NavigateAction::MatchZoom(int steps, float fallbackZoom) +{ + auto currentZoomIndex = MatchZoomIndex(steps); + if (currentZoomIndex < 0) + return fallbackZoom; + + auto currentZoom = m_ZoomLevels[currentZoomIndex]; + if (fabsf(currentZoom - m_Zoom) > 0.001f) + return currentZoom; + + auto newIndex = currentZoomIndex + steps; + if (newIndex >= 0 && newIndex < m_ZoomLevelCount) + return m_ZoomLevels[newIndex]; + else + return fallbackZoom; +} + +int ed::NavigateAction::MatchZoomIndex(int direction) +{ + int bestIndex = -1; + float bestDistance = 0.0f; + + for (int i = 0; i < m_ZoomLevelCount; ++i) + { + auto distance = fabsf(m_ZoomLevels[i] - m_Zoom); + if (distance < bestDistance || bestIndex < 0) + { + bestDistance = distance; + bestIndex = i; + } + } + + if (bestDistance > 0.001f) + { + if (direction > 0) + { + ++bestIndex; + + if (bestIndex >= m_ZoomLevelCount) + bestIndex = m_ZoomLevelCount - 1; + } + else if (direction < 0) + { + --bestIndex; + + if (bestIndex < 0) + bestIndex = 0; + } + } + + return bestIndex; +} + + + + +//------------------------------------------------------------------------------ +// +// Size Action +// +//------------------------------------------------------------------------------ +ed::SizeAction::SizeAction(EditorContext* editor): + EditorAction(editor), + m_IsActive(false), + m_Clean(false), + m_SizedNode(nullptr), + m_Pivot(NodeRegion::None), + m_Cursor(ImGuiMouseCursor_Arrow) +{ +} + +ed::EditorAction::AcceptResult ed::SizeAction::Accept(const Control& control) +{ + IM_ASSERT(!m_IsActive); + + if (m_IsActive) + return False; + + if (control.ActiveNode && IsGroup(control.ActiveNode) && ImGui::IsMouseDragging(Editor->GetConfig().DragButtonIndex, 1)) + { + //const auto mousePos = to_point(ImGui::GetMousePos()); + //const auto closestPoint = control.ActiveNode->Bounds.get_closest_point_hollow(mousePos, static_cast(control.ActiveNode->Rounding)); + + auto pivot = GetRegion(control.ActiveNode); + if (pivot != NodeRegion::Header && pivot != NodeRegion::Center) + { + m_StartBounds = control.ActiveNode->m_Bounds; + m_StartGroupBounds = control.ActiveNode->m_GroupBounds; + m_LastSize = control.ActiveNode->m_Bounds.GetSize(); + m_MinimumSize = ImVec2(0, 0); + m_LastDragOffset = ImVec2(0, 0); + m_Pivot = pivot; + m_Cursor = ChooseCursor(m_Pivot); + m_SizedNode = control.ActiveNode; + m_IsActive = true; + } + } + else if (control.HotNode && IsGroup(control.HotNode)) + { + m_Cursor = ChooseCursor(GetRegion(control.HotNode)); + return Possible; + } + + return m_IsActive ? True : False; +} + +bool ed::SizeAction::Process(const Control& control) +{ + if (m_Clean) + { + m_Clean = false; + + if (m_SizedNode->m_Bounds.Min != m_StartBounds.Min || m_SizedNode->m_GroupBounds.Min != m_StartGroupBounds.Min) + Editor->MakeDirty(SaveReasonFlags::Position | SaveReasonFlags::User, m_SizedNode); + + if (m_SizedNode->m_Bounds.GetSize() != m_StartBounds.GetSize() || m_SizedNode->m_GroupBounds.GetSize() != m_StartGroupBounds.GetSize()) + Editor->MakeDirty(SaveReasonFlags::Size | SaveReasonFlags::User, m_SizedNode); + + m_SizedNode = nullptr; + } + + if (!m_IsActive) + return false; + + if (control.ActiveNode == m_SizedNode) + { + const auto dragOffset = (control.ActiveNode == m_SizedNode) ? ImGui::GetMouseDragDelta(0, 0.0f) : m_LastDragOffset; + m_LastDragOffset = dragOffset; + + if (m_MinimumSize.x == 0.0f && m_LastSize.x != m_SizedNode->m_Bounds.GetWidth()) + m_MinimumSize.x = m_SizedNode->m_Bounds.GetWidth(); + if (m_MinimumSize.y == 0.0f && m_LastSize.y != m_SizedNode->m_Bounds.GetHeight()) + m_MinimumSize.y = m_SizedNode->m_Bounds.GetHeight(); + + auto minimumSize = ImMax(m_MinimumSize, m_StartBounds.GetSize() - m_StartGroupBounds.GetSize()); + + + auto newBounds = m_StartBounds; + + if ((m_Pivot & NodeRegion::Top) == NodeRegion::Top) + newBounds.Min.y = ImMin(newBounds.Max.y - minimumSize.y, Editor->AlignPointToGrid(newBounds.Min.y + dragOffset.y)); + if ((m_Pivot & NodeRegion::Bottom) == NodeRegion::Bottom) + newBounds.Max.y = ImMax(newBounds.Min.y + minimumSize.y, Editor->AlignPointToGrid(newBounds.Max.y + dragOffset.y)); + if ((m_Pivot & NodeRegion::Left) == NodeRegion::Left) + newBounds.Min.x = ImMin(newBounds.Max.x - minimumSize.x, Editor->AlignPointToGrid(newBounds.Min.x + dragOffset.x)); + if ((m_Pivot & NodeRegion::Right) == NodeRegion::Right) + newBounds.Max.x = ImMax(newBounds.Min.x + minimumSize.x, Editor->AlignPointToGrid(newBounds.Max.x + dragOffset.x)); + + newBounds.Floor(); + + m_LastSize = newBounds.GetSize(); + + m_SizedNode->m_Bounds = newBounds; + m_SizedNode->m_GroupBounds = newBounds; + m_SizedNode->m_GroupBounds.Min.x -= m_StartBounds.Min.x - m_StartGroupBounds.Min.x; + m_SizedNode->m_GroupBounds.Min.y -= m_StartBounds.Min.y - m_StartGroupBounds.Min.y; + m_SizedNode->m_GroupBounds.Max.x -= m_StartBounds.Max.x - m_StartGroupBounds.Max.x; + m_SizedNode->m_GroupBounds.Max.y -= m_StartBounds.Max.y - m_StartGroupBounds.Max.y; + } + else if (!control.ActiveNode) + { + m_Clean = true; + m_IsActive = false; + return true; + } + + return m_IsActive; +} + +void ed::SizeAction::ShowMetrics() +{ + EditorAction::ShowMetrics(); + + auto getObjectName = [](Object* object) + { + if (!object) return ""; + else if (object->AsNode()) return "Node"; + else if (object->AsPin()) return "Pin"; + else if (object->AsLink()) return "Link"; + else return ""; + }; + + ImGui::Text("%s:", GetName()); + ImGui::Text(" Active: %s", m_IsActive ? "yes" : "no"); + ImGui::Text(" Node: %s (%p)", getObjectName(m_SizedNode), m_SizedNode ? m_SizedNode->m_ID.AsPointer() : nullptr); + if (m_SizedNode && m_IsActive) + { + ImGui::Text(" Bounds: { x=%g y=%g w=%g h=%g }", m_SizedNode->m_Bounds.Min.x, m_SizedNode->m_Bounds.Min.y, m_SizedNode->m_Bounds.GetWidth(), m_SizedNode->m_Bounds.GetHeight()); + ImGui::Text(" Group Bounds: { x=%g y=%g w=%g h=%g }", m_SizedNode->m_GroupBounds.Min.x, m_SizedNode->m_GroupBounds.Min.y, m_SizedNode->m_GroupBounds.GetWidth(), m_SizedNode->m_GroupBounds.GetHeight()); + ImGui::Text(" Start Bounds: { x=%g y=%g w=%g h=%g }", m_StartBounds.Min.x, m_StartBounds.Min.y, m_StartBounds.GetWidth(), m_StartBounds.GetHeight()); + ImGui::Text(" Start Group Bounds: { x=%g y=%g w=%g h=%g }", m_StartGroupBounds.Min.x, m_StartGroupBounds.Min.y, m_StartGroupBounds.GetWidth(), m_StartGroupBounds.GetHeight()); + ImGui::Text(" Minimum Size: { w=%g h=%g }", m_MinimumSize.x, m_MinimumSize.y); + ImGui::Text(" Last Size: { w=%g h=%g }", m_LastSize.x, m_LastSize.y); + } +} + +ed::NodeRegion ed::SizeAction::GetRegion(Node* node) +{ + return node->GetRegion(ImGui::GetMousePos()); +} + +ImGuiMouseCursor ed::SizeAction::ChooseCursor(NodeRegion region) +{ + switch (region) + { + default: + case NodeRegion::Center: + return ImGuiMouseCursor_Arrow; + + case NodeRegion::Top: + case NodeRegion::Bottom: + return ImGuiMouseCursor_ResizeNS; + + case NodeRegion::Left: + case NodeRegion::Right: + return ImGuiMouseCursor_ResizeEW; + + case NodeRegion::TopLeft: + case NodeRegion::BottomRight: + return ImGuiMouseCursor_ResizeNWSE; + + case NodeRegion::TopRight: + case NodeRegion::BottomLeft: + return ImGuiMouseCursor_ResizeNESW; + } +} + + + + +//------------------------------------------------------------------------------ +// +// Drag Action +// +//------------------------------------------------------------------------------ +ed::DragAction::DragAction(EditorContext* editor): + EditorAction(editor), + m_IsActive(false), + m_Clear(false), + m_DraggedObject(nullptr) +{ +} + +ed::EditorAction::AcceptResult ed::DragAction::Accept(const Control& control) +{ + IM_ASSERT(!m_IsActive); + + if (m_IsActive) + return False; + + if (Editor->CanAcceptUserInput() && control.ActiveObject && ImGui::IsMouseDragging(Editor->GetConfig().DragButtonIndex, 1)) + { + if (!control.ActiveObject->AcceptDrag()) + return False; + + m_DraggedObject = control.ActiveObject; + + m_Objects.resize(0); + m_Objects.push_back(m_DraggedObject); + + if (Editor->IsSelected(m_DraggedObject)) + { + for (auto selectedObject : Editor->GetSelectedObjects()) + if (auto selectedNode = selectedObject->AsNode()) + if (selectedNode != m_DraggedObject && selectedNode->AcceptDrag()) + m_Objects.push_back(selectedNode); + } + + auto& io = ImGui::GetIO(); + if (!io.KeyShift) + { + std::vector groupedNodes; + for (auto object : m_Objects) + if (auto node = object->AsNode()) + node->GetGroupedNodes(groupedNodes, true); + + auto isAlreadyPicked = [this](Node* node) + { + return std::find(m_Objects.begin(), m_Objects.end(), node) != m_Objects.end(); + }; + + for (auto candidate : groupedNodes) + if (!isAlreadyPicked(candidate) && candidate->AcceptDrag()) + m_Objects.push_back(candidate); + } + + m_IsActive = true; + } + else if (control.HotNode && IsGroup(control.HotNode) && control.HotNode->GetRegion(ImGui::GetMousePos()) == NodeRegion::Header) + { + return Possible; + } + + return m_IsActive ? True : False; +} + +bool ed::DragAction::Process(const Control& control) +{ + if (m_Clear) + { + m_Clear = false; + + for (auto object : m_Objects) + { + if (object->EndDrag()) + Editor->MakeDirty(SaveReasonFlags::Position | SaveReasonFlags::User, object->AsNode()); + } + + m_Objects.resize(0); + + m_DraggedObject = nullptr; + } + + if (!m_IsActive) + return false; + + if (control.ActiveObject == m_DraggedObject) + { + auto dragOffset = ImGui::GetMouseDragDelta(Editor->GetConfig().DragButtonIndex, 0.0f); + + auto draggedOrigin = m_DraggedObject->DragStartLocation(); + auto alignPivot = ImVec2(0, 0); + + // TODO: Move this experimental alignment to closes pivot out of internals to node API + if (auto draggedNode = m_DraggedObject->AsNode()) + { + float x = FLT_MAX; + float y = FLT_MAX; + + auto testPivot = [this, &x, &y, &draggedOrigin, &dragOffset, &alignPivot](const ImVec2& pivot) + { + auto initial = draggedOrigin + dragOffset + pivot; + auto candidate = Editor->AlignPointToGrid(initial) - draggedOrigin - pivot; + + if (ImFabs(candidate.x) < ImFabs(ImMin(x, FLT_MAX))) + { + x = candidate.x; + alignPivot.x = pivot.x; + } + + if (ImFabs(candidate.y) < ImFabs(ImMin(y, FLT_MAX))) + { + y = candidate.y; + alignPivot.y = pivot.y; + } + }; + + for (auto pin = draggedNode->m_LastPin; pin; pin = pin->m_PreviousPin) + { + auto pivot = pin->m_Pivot.GetCenter() - draggedNode->m_Bounds.Min; + testPivot(pivot); + } + + //testPivot(point(0, 0)); + } + + auto alignedOffset = Editor->AlignPointToGrid(draggedOrigin + dragOffset + alignPivot) - draggedOrigin - alignPivot; + + if (!ImGui::GetIO().KeyAlt) + dragOffset = alignedOffset; + + for (auto object : m_Objects) + object->UpdateDrag(dragOffset); + } + else if (!control.ActiveObject) + { + m_Clear = true; + + m_IsActive = false; + return true; + } + + return m_IsActive; +} + +void ed::DragAction::ShowMetrics() +{ + EditorAction::ShowMetrics(); + + auto getObjectName = [](Object* object) + { + if (!object) return ""; + else if (object->AsNode()) return "Node"; + else if (object->AsPin()) return "Pin"; + else if (object->AsLink()) return "Link"; + else return ""; + }; + + ImGui::Text("%s:", GetName()); + ImGui::Text(" Active: %s", m_IsActive ? "yes" : "no"); + ImGui::Text(" Node: %s (%p)", getObjectName(m_DraggedObject), m_DraggedObject ? m_DraggedObject->ID().AsPointer() : nullptr); +} + + + + +//------------------------------------------------------------------------------ +// +// Select Action +// +//------------------------------------------------------------------------------ +ed::SelectAction::SelectAction(EditorContext* editor): + EditorAction(editor), + m_IsActive(false), + m_SelectGroups(false), + m_SelectLinkMode(false), + m_CommitSelection(false), + m_StartPoint(), + m_Animation(editor) +{ +} + +ed::EditorAction::AcceptResult ed::SelectAction::Accept(const Control& control) +{ + IM_ASSERT(!m_IsActive); + + if (m_IsActive) + return False; + + auto& io = ImGui::GetIO(); + m_SelectGroups = io.KeyShift; + m_SelectLinkMode = io.KeyAlt; + + m_SelectedObjectsAtStart.clear(); + + if (Editor->CanAcceptUserInput() && control.BackgroundHot && ImGui::IsMouseDragging(Editor->GetConfig().SelectButtonIndex, 1)) + { + m_IsActive = true; + m_StartPoint = ImGui_GetMouseClickPos(Editor->GetConfig().SelectButtonIndex); + m_EndPoint = m_StartPoint; + + // Links and nodes cannot be selected together + if ((m_SelectLinkMode && Editor->IsAnyNodeSelected()) || + (!m_SelectLinkMode && Editor->IsAnyLinkSelected())) + { + Editor->ClearSelection(); + } + + if (io.KeyCtrl) + m_SelectedObjectsAtStart = Editor->GetSelectedObjects(); + } + else if (control.BackgroundClickButtonIndex == Editor->GetConfig().SelectButtonIndex) + { + Editor->ClearSelection(); + } + else + { + Object* clickedObject = control.ClickedNode ? static_cast(control.ClickedNode) : static_cast(control.ClickedLink); + + if (clickedObject) + { + // Links and nodes cannot be selected together + if ((clickedObject->AsLink() && Editor->IsAnyNodeSelected()) || + (clickedObject->AsNode() && Editor->IsAnyLinkSelected())) + { + Editor->ClearSelection(); + } + + if (io.KeyCtrl) + Editor->ToggleObjectSelection(clickedObject); + else + Editor->SetSelectedObject(clickedObject); + } + } + + if (m_IsActive) + m_Animation.Stop(); + + return m_IsActive ? True : False; +} + +bool ed::SelectAction::Process(const Control& control) +{ + IM_UNUSED(control); + + if (m_CommitSelection) + { + Editor->ClearSelection(); + for (auto object : m_CandidateObjects) + Editor->SelectObject(object); + + m_CandidateObjects.clear(); + + m_CommitSelection = false; + } + + if (!m_IsActive) + return false; + + if (ImGui::IsMouseDragging(Editor->GetConfig().SelectButtonIndex, 0)) + { + m_EndPoint = ImGui::GetMousePos(); + + auto topLeft = ImVec2(std::min(m_StartPoint.x, m_EndPoint.x), std::min(m_StartPoint.y, m_EndPoint.y)); + auto bottomRight = ImVec2(ImMax(m_StartPoint.x, m_EndPoint.x), ImMax(m_StartPoint.y, m_EndPoint.y)); + auto rect = ImRect(topLeft, bottomRight); + if (rect.GetWidth() <= 0) + rect.Max.x = rect.Min.x + 1; + if (rect.GetHeight() <= 0) + rect.Max.y = rect.Min.y + 1; + + vector nodes; + vector links; + + if (m_SelectLinkMode) + { + Editor->FindLinksInRect(rect, links); + m_CandidateObjects.assign(links.begin(), links.end()); + } + else + { + Editor->FindNodesInRect(rect, nodes); + m_CandidateObjects.assign(nodes.begin(), nodes.end()); + + if (m_SelectGroups) + { + auto endIt = std::remove_if(m_CandidateObjects.begin(), m_CandidateObjects.end(), [](Object* object) { return !IsGroup(object->AsNode()); }); + m_CandidateObjects.erase(endIt, m_CandidateObjects.end()); + } + else + { + auto endIt = std::remove_if(m_CandidateObjects.begin(), m_CandidateObjects.end(), [](Object* object) { return IsGroup(object->AsNode()); }); + m_CandidateObjects.erase(endIt, m_CandidateObjects.end()); + } + } + + m_CandidateObjects.insert(m_CandidateObjects.end(), m_SelectedObjectsAtStart.begin(), m_SelectedObjectsAtStart.end()); + std::sort(m_CandidateObjects.begin(), m_CandidateObjects.end()); + m_CandidateObjects.erase(std::unique(m_CandidateObjects.begin(), m_CandidateObjects.end()), m_CandidateObjects.end()); + } + else + { + m_IsActive = false; + + m_Animation.Play(c_SelectionFadeOutDuration); + + m_CommitSelection = true; + + return true; + } + + return m_IsActive; +} + +void ed::SelectAction::ShowMetrics() +{ + EditorAction::ShowMetrics(); + + ImGui::Text("%s:", GetName()); + ImGui::Text(" Active: %s", m_IsActive ? "yes" : "no"); +} + +void ed::SelectAction::Draw(ImDrawList* drawList) +{ + if (!m_IsActive && !m_Animation.IsPlaying()) + return; + + const auto alpha = m_Animation.IsPlaying() ? ImEasing::EaseOutQuad(1.0f, -1.0f, m_Animation.GetProgress()) : 1.0f; + + const auto fillColor = Editor->GetColor(m_SelectLinkMode ? StyleColor_LinkSelRect : StyleColor_NodeSelRect, alpha); + const auto outlineColor = Editor->GetColor(m_SelectLinkMode ? StyleColor_LinkSelRectBorder : StyleColor_NodeSelRectBorder, alpha); + + drawList->ChannelsSetCurrent(c_BackgroundChannel_SelectionRect); + + auto min = ImVec2(std::min(m_StartPoint.x, m_EndPoint.x), std::min(m_StartPoint.y, m_EndPoint.y)); + auto max = ImVec2(ImMax(m_StartPoint.x, m_EndPoint.x), ImMax(m_StartPoint.y, m_EndPoint.y)); + + drawList->AddRectFilled(min, max, fillColor); + drawList->AddRect(min, max, outlineColor); +} + + + + +//------------------------------------------------------------------------------ +// +// Context Menu Action +// +//------------------------------------------------------------------------------ +ed::ContextMenuAction::ContextMenuAction(EditorContext* editor): + EditorAction(editor), + m_CandidateMenu(Menu::None), + m_CurrentMenu(Menu::None), + m_ContextId() +{ +} + +ed::EditorAction::AcceptResult ed::ContextMenuAction::Accept(const Control& control) +{ + const auto isPressed = ImGui::IsMouseClicked(Editor->GetConfig().ContextMenuButtonIndex); + const auto isReleased = ImGui::IsMouseReleased(Editor->GetConfig().ContextMenuButtonIndex); + const auto isDragging = ImGui::IsMouseDragging(Editor->GetConfig().ContextMenuButtonIndex, 1); + + if (isPressed || isReleased || isDragging) + { + Menu candidateMenu = ContextMenuAction::None; + ObjectId contextId; + + if (auto hotObejct = control.HotObject) + { + if (hotObejct->AsNode()) + candidateMenu = Node; + else if (hotObejct->AsPin()) + candidateMenu = Pin; + else if (hotObejct->AsLink()) + candidateMenu = Link; + + if (candidateMenu != None) + contextId = hotObejct->ID(); + } + else if (control.BackgroundHot) + candidateMenu = Background; + + if (isPressed) + { + m_CandidateMenu = candidateMenu; + m_ContextId = contextId; + return Possible; + } + else if (isReleased && m_CandidateMenu == candidateMenu && m_ContextId == contextId) + { + m_CurrentMenu = m_CandidateMenu; + m_CandidateMenu = ContextMenuAction::None; + return True; + } + else + { + m_CandidateMenu = None; + m_CurrentMenu = None; + m_ContextId = ObjectId(); + return False; + } + } + + return False; +} + +bool ed::ContextMenuAction::Process(const Control& control) +{ + IM_UNUSED(control); + + m_CandidateMenu = None; + m_CurrentMenu = None; + m_ContextId = ObjectId(); + return false; +} + +void ed::ContextMenuAction::Reject() +{ + m_CandidateMenu = None; + m_CurrentMenu = None; + m_ContextId = ObjectId(); +} + +void ed::ContextMenuAction::ShowMetrics() +{ + EditorAction::ShowMetrics(); + + auto getMenuName = [](Menu menu) + { + switch (menu) + { + default: + case None: return "None"; + case Node: return "Node"; + case Pin: return "Pin"; + case Link: return "Link"; + case Background: return "Background"; + } + }; + + + ImGui::Text("%s:", GetName()); + ImGui::Text(" Menu: %s", getMenuName(m_CurrentMenu)); +} + +bool ed::ContextMenuAction::ShowNodeContextMenu(NodeId* nodeId) +{ + if (m_CurrentMenu != Node) + return false; + + *nodeId = m_ContextId.AsNodeId(); + Editor->SetUserContext(); + return true; +} + +bool ed::ContextMenuAction::ShowPinContextMenu(PinId* pinId) +{ + if (m_CurrentMenu != Pin) + return false; + + *pinId = m_ContextId.AsPinId(); + Editor->SetUserContext(); + return true; +} + +bool ed::ContextMenuAction::ShowLinkContextMenu(LinkId* linkId) +{ + if (m_CurrentMenu != Link) + return false; + + *linkId = m_ContextId.AsLinkId(); + Editor->SetUserContext(); + return true; +} + +bool ed::ContextMenuAction::ShowBackgroundContextMenu() +{ + if (m_CurrentMenu != Background) + return false; + + Editor->SetUserContext(); + return true; +} + + + + +//------------------------------------------------------------------------------ +// +// Cut/Copy/Paste Action +// +//------------------------------------------------------------------------------ +ed::ShortcutAction::ShortcutAction(EditorContext* editor): + EditorAction(editor), + m_IsActive(false), + m_InAction(false), + m_CurrentAction(Action::None), + m_Context() +{ +} + +ed::EditorAction::AcceptResult ed::ShortcutAction::Accept(const Control& control) +{ + if (!Editor->IsFocused() || !Editor->AreShortcutsEnabled()) + return False; + + Action candidateAction = None; + + auto& io = ImGui::GetIO(); + if (io.KeyCtrl && !io.KeyShift && !io.KeyAlt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_X))) + candidateAction = Cut; + if (io.KeyCtrl && !io.KeyShift && !io.KeyAlt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_C))) + candidateAction = Copy; + if (io.KeyCtrl && !io.KeyShift && !io.KeyAlt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_V))) + candidateAction = Paste; + if (io.KeyCtrl && !io.KeyShift && !io.KeyAlt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_D))) + candidateAction = Duplicate; + if (!io.KeyCtrl && !io.KeyShift && !io.KeyAlt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Space))) + candidateAction = CreateNode; + + if (candidateAction != None) + { + if (candidateAction != Paste && candidateAction != CreateNode) + { + auto& selection = Editor->GetSelectedObjects(); + if (!selection.empty()) + { + // #TODO: Find a way to simplify logic. + + m_Context.assign(selection.begin(), selection.end()); + + // Expand groups + vector extra; + for (auto object : m_Context) + { + auto node = object->AsNode(); + if (IsGroup(node)) + node->GetGroupedNodes(extra, true); + } + + // Apply groups and remove duplicates + if (!extra.empty()) + { + m_Context.insert(m_Context.end(), extra.begin(), extra.end()); + std::sort(m_Context.begin(), m_Context.end()); + m_Context.erase(std::unique(m_Context.begin(), m_Context.end()), m_Context.end()); + } + } + else if (control.HotObject && control.HotObject->IsSelectable() && !IsGroup(control.HotObject->AsNode())) + { + m_Context.push_back(control.HotObject); + } + + if (m_Context.empty()) + return False; + + // Does copying only links make sense? + //const auto hasOnlyLinks = std::all_of(Context.begin(), Context.end(), [](Object* object) { return object->AsLink() != nullptr; }); + //if (hasOnlyLinks) + // return False; + + // If no links are selected, pick all links between nodes within context + const auto hasAnyLinks = std::any_of(m_Context.begin(), m_Context.end(), [](Object* object) { return object->AsLink() != nullptr; }); + if (!hasAnyLinks && m_Context.size() > 1) // one node cannot make connection to anything + { + // Collect nodes in sorted vector viable for binary search + std::vector> nodes; + + nodes.reserve(m_Context.size()); + std::for_each(m_Context.begin(), m_Context.end(), [&nodes](Object* object) { if (auto node = object->AsNode()) nodes.push_back({node->m_ID, node}); }); + + std::sort(nodes.begin(), nodes.end()); + + auto isNodeInContext = [&nodes](NodeId nodeId) + { + return std::binary_search(nodes.begin(), nodes.end(), ObjectWrapper{nodeId, nullptr}); + }; + + // Collect links connected to nodes and drop those reaching out of context + std::vector links; + + for (auto node : nodes) + Editor->FindLinksForNode(node.m_ID, links, true); + + // Remove duplicates + std::sort(links.begin(), links.end()); + links.erase(std::unique(links.begin(), links.end()), links.end()); + + // Drop out of context links + links.erase(std::remove_if(links.begin(), links.end(), [&isNodeInContext](Link* link) + { + return !isNodeInContext(link->m_StartPin->m_Node->m_ID) || !isNodeInContext(link->m_EndPin->m_Node->m_ID); + }), links.end()); + + // Append links and remove duplicates + m_Context.insert(m_Context.end(), links.begin(), links.end()); + } + } + else + m_Context.resize(0); + + m_IsActive = true; + m_CurrentAction = candidateAction; + + return True; + } + + return False; +} + +bool ed::ShortcutAction::Process(const Control& control) +{ + IM_UNUSED(control); + + m_IsActive = false; + m_CurrentAction = None; + m_Context.resize(0); + return false; +} + +void ed::ShortcutAction::Reject() +{ + m_IsActive = false; + m_CurrentAction = None; + m_Context.resize(0); +} + +void ed::ShortcutAction::ShowMetrics() +{ + EditorAction::ShowMetrics(); + + auto getActionName = [](Action action) + { + switch (action) + { + default: + case None: return "None"; + case Cut: return "Cut"; + case Copy: return "Copy"; + case Paste: return "Paste"; + case Duplicate: return "Duplicate"; + case CreateNode: return "CreateNode"; + } + }; + + ImGui::Text("%s:", GetName()); + ImGui::Text(" Action: %s", getActionName(m_CurrentAction)); +} + +bool ed::ShortcutAction::Begin() +{ + if (m_IsActive) + m_InAction = true; + return m_IsActive; +} + +void ed::ShortcutAction::End() +{ + if (m_IsActive) + m_InAction = false; +} + +bool ed::ShortcutAction::AcceptCut() +{ + IM_ASSERT(m_InAction); + return m_CurrentAction == Cut; +} + +bool ed::ShortcutAction::AcceptCopy() +{ + IM_ASSERT(m_InAction); + return m_CurrentAction == Copy; +} + +bool ed::ShortcutAction::AcceptPaste() +{ + IM_ASSERT(m_InAction); + return m_CurrentAction == Paste; +} + +bool ed::ShortcutAction::AcceptDuplicate() +{ + IM_ASSERT(m_InAction); + return m_CurrentAction == Duplicate; +} + +bool ed::ShortcutAction::AcceptCreateNode() +{ + IM_ASSERT(m_InAction); + return m_CurrentAction == CreateNode; +} + + + + +//------------------------------------------------------------------------------ +// +// Create Item Action +// +//------------------------------------------------------------------------------ +ed::CreateItemAction::CreateItemAction(EditorContext* editor): + EditorAction(editor), + m_InActive(false), + m_NextStage(None), + m_CurrentStage(None), + m_ItemType(NoItem), + m_UserAction(Unknown), + m_LinkColor(IM_COL32_WHITE), + m_LinkThickness(1.0f), + m_LinkStart(nullptr), + m_LinkEnd(nullptr), + + m_IsActive(false), + m_DraggedPin(nullptr), + + m_IsInGlobalSpace(false) +{ +} + +ed::EditorAction::AcceptResult ed::CreateItemAction::Accept(const Control& control) +{ + IM_ASSERT(!m_IsActive); + + if (m_IsActive) + return EditorAction::False; + + if (control.ActivePin && ImGui::IsMouseDragging(Editor->GetConfig().DragButtonIndex, 1)) + { + m_DraggedPin = control.ActivePin; + DragStart(m_DraggedPin); + + Editor->ClearSelection(); + } + else if (control.HotPin) + { + return EditorAction::Possible; + } + else + return EditorAction::False; + + m_IsActive = true; + + return EditorAction::True; +} + +bool ed::CreateItemAction::Process(const Control& control) +{ + IM_ASSERT(m_IsActive); + + if (!m_IsActive) + return false; + + if (m_DraggedPin && control.ActivePin == m_DraggedPin && (m_CurrentStage == Possible)) + { + const auto draggingFromSource = (m_DraggedPin->m_Kind == PinKind::Output); + + ed::Pin cursorPin(Editor, 0, draggingFromSource ? PinKind::Input : PinKind::Output); + cursorPin.m_Pivot = ImRect(ImGui::GetMousePos(), ImGui::GetMousePos()); + cursorPin.m_Dir = -m_DraggedPin->m_Dir; + cursorPin.m_Strength = m_DraggedPin->m_Strength; + + ed::Link candidate(Editor, 0); + candidate.m_Color = m_LinkColor; + candidate.m_StartPin = draggingFromSource ? m_DraggedPin : &cursorPin; + candidate.m_EndPin = draggingFromSource ? &cursorPin : m_DraggedPin; + + ed::Pin*& freePin = draggingFromSource ? candidate.m_EndPin : candidate.m_StartPin; + + if (control.HotPin) + { + DropPin(control.HotPin); + + if (m_UserAction == UserAccept) + freePin = control.HotPin; + } + else if (control.BackgroundHot) + DropNode(); + else + DropNothing(); + + auto drawList = Editor->GetDrawList(); + drawList->ChannelsSetCurrent(c_LinkChannel_NewLink); + + candidate.UpdateEndpoints(); + candidate.Draw(drawList, m_LinkColor, m_LinkThickness); + } + else if (m_CurrentStage == Possible || !control.ActivePin) + { + if (!Editor->CanAcceptUserInput()) + { + m_DraggedPin = nullptr; + DropNothing(); + } + + DragEnd(); + m_IsActive = false; + } + + return m_IsActive; +} + +void ed::CreateItemAction::ShowMetrics() +{ + EditorAction::ShowMetrics(); + + auto getStageName = [](Stage stage) + { + switch (stage) + { + case None: return "None"; + case Possible: return "Possible"; + case Create: return "Create"; + default: return ""; + } + }; + + auto getActionName = [](Action action) + { + switch (action) + { + default: + case Unknown: return "Unknown"; + case UserReject: return "Reject"; + case UserAccept: return "Accept"; + } + }; + + auto getItemName = [](Type item) + { + switch (item) + { + default: + case NoItem: return "None"; + case Node: return "Node"; + case Link: return "Link"; + } + }; + + ImGui::Text("%s:", GetName()); + ImGui::Text(" Stage: %s", getStageName(m_CurrentStage)); + ImGui::Text(" User Action: %s", getActionName(m_UserAction)); + ImGui::Text(" Item Type: %s", getItemName(m_ItemType)); +} + +void ed::CreateItemAction::SetStyle(ImU32 color, float thickness) +{ + m_LinkColor = color; + m_LinkThickness = thickness; +} + +bool ed::CreateItemAction::Begin() +{ + IM_ASSERT(false == m_InActive); + + m_InActive = true; + m_CurrentStage = m_NextStage; + m_UserAction = Unknown; + m_LinkColor = IM_COL32_WHITE; + m_LinkThickness = 1.0f; + + if (m_CurrentStage == None) + return false; + + m_LastChannel = Editor->GetDrawList()->_Splitter._Current; + + return true; +} + +void ed::CreateItemAction::End() +{ + IM_ASSERT(m_InActive); + + if (m_IsInGlobalSpace) + { + ImGui::PopClipRect(); + Editor->Resume(SuspendFlags::KeepSplitter); + + auto currentChannel = Editor->GetDrawList()->_Splitter._Current; + if (currentChannel != m_LastChannel) + Editor->GetDrawList()->ChannelsSetCurrent(m_LastChannel); + + m_IsInGlobalSpace = false; + } + + m_InActive = false; +} + +void ed::CreateItemAction::DragStart(Pin* startPin) +{ + IM_ASSERT(!m_InActive); + + m_NextStage = Possible; + m_LinkStart = startPin; + m_LinkEnd = nullptr; +} + +void ed::CreateItemAction::DragEnd() +{ + IM_ASSERT(!m_InActive); + + if (m_CurrentStage == Possible && m_UserAction == UserAccept) + { + m_NextStage = Create; + } + else + { + m_NextStage = None; + m_ItemType = NoItem; + m_LinkStart = nullptr; + m_LinkEnd = nullptr; + } +} + +void ed::CreateItemAction::DropPin(Pin* endPin) +{ + IM_ASSERT(!m_InActive); + + m_ItemType = Link; + m_LinkEnd = endPin; +} + +void ed::CreateItemAction::DropNode() +{ + IM_ASSERT(!m_InActive); + + m_ItemType = Node; + m_LinkEnd = nullptr; +} + +void ed::CreateItemAction::DropNothing() +{ + IM_ASSERT(!m_InActive); + + m_ItemType = NoItem; + m_LinkEnd = nullptr; +} + +ed::CreateItemAction::Result ed::CreateItemAction::RejectItem() +{ + IM_ASSERT(m_InActive); + + if (!m_InActive || m_CurrentStage == None || m_ItemType == NoItem) + return Indeterminate; + + m_UserAction = UserReject; + + return True; +} + +ed::CreateItemAction::Result ed::CreateItemAction::AcceptItem() +{ + IM_ASSERT(m_InActive); + + if (!m_InActive || m_CurrentStage == None || m_ItemType == NoItem) + return Indeterminate; + + m_UserAction = UserAccept; + + if (m_CurrentStage == Create) + { + m_NextStage = None; + m_ItemType = NoItem; + m_LinkStart = nullptr; + m_LinkEnd = nullptr; + return True; + } + else + return False; +} + +ed::CreateItemAction::Result ed::CreateItemAction::QueryLink(PinId* startId, PinId* endId) +{ + IM_ASSERT(m_InActive); + + if (!m_InActive || m_CurrentStage == None || m_ItemType != Link) + return Indeterminate; + + auto linkStartId = m_LinkStart->m_ID; + auto linkEndId = m_LinkEnd->m_ID; + + *startId = linkStartId; + *endId = linkEndId; + + Editor->SetUserContext(true); + + if (!m_IsInGlobalSpace) + { + Editor->Suspend(SuspendFlags::KeepSplitter); + + auto rect = Editor->GetRect(); + ImGui::PushClipRect(rect.Min + ImVec2(1, 1), rect.Max - ImVec2(1, 1), false); + m_IsInGlobalSpace = true; + } + + return True; +} + +ed::CreateItemAction::Result ed::CreateItemAction::QueryNode(PinId* pinId) +{ + IM_ASSERT(m_InActive); + + if (!m_InActive || m_CurrentStage == None || m_ItemType != Node) + return Indeterminate; + + *pinId = m_LinkStart ? m_LinkStart->m_ID : 0; + + Editor->SetUserContext(true); + + if (!m_IsInGlobalSpace) + { + Editor->Suspend(SuspendFlags::KeepSplitter); + + auto rect = Editor->GetRect(); + ImGui::PushClipRect(rect.Min + ImVec2(1, 1), rect.Max - ImVec2(1, 1), false); + m_IsInGlobalSpace = true; + } + + return True; +} + + + + +//------------------------------------------------------------------------------ +// +// Delete Items Action +// +//------------------------------------------------------------------------------ +ed::DeleteItemsAction::DeleteItemsAction(EditorContext* editor): + EditorAction(editor), + m_IsActive(false), + m_InInteraction(false), + m_CurrentItemType(Unknown), + m_UserAction(Undetermined) +{ +} + +void ed::DeleteItemsAction::DeleteDeadLinks(NodeId nodeId) +{ + vector links; + Editor->FindLinksForNode(nodeId, links, true); + for (auto link : links) + { + link->m_DeleteOnNewFrame = true; + + auto it = std::find(m_CandidateObjects.begin(), m_CandidateObjects.end(), link); + if (it != m_CandidateObjects.end()) + continue; + + m_CandidateObjects.push_back(link); + } +} + +void ed::DeleteItemsAction::DeleteDeadPins(NodeId nodeId) +{ + auto node = Editor->FindNode(nodeId); + if (!node) + return; + + for (auto pin = node->m_LastPin; pin; pin = pin->m_PreviousPin) + pin->m_DeleteOnNewFrame = true; +} + +ed::EditorAction::AcceptResult ed::DeleteItemsAction::Accept(const Control& control) +{ + IM_ASSERT(!m_IsActive); + + if (m_IsActive) + return False; + + auto& io = ImGui::GetIO(); + if (Editor->CanAcceptUserInput() && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Delete)) && Editor->AreShortcutsEnabled()) + { + auto& selection = Editor->GetSelectedObjects(); + if (!selection.empty()) + { + m_CandidateObjects = selection; + m_IsActive = true; + return True; + } + } + else if (control.ClickedLink && io.KeyAlt) + { + m_CandidateObjects.clear(); + m_CandidateObjects.push_back(control.ClickedLink); + m_IsActive = true; + return True; + } + + else if (!m_ManuallyDeletedObjects.empty()) + { + m_CandidateObjects = m_ManuallyDeletedObjects; + m_ManuallyDeletedObjects.clear(); + m_IsActive = true; + return True; + } + + return m_IsActive ? True : False; +} + +bool ed::DeleteItemsAction::Process(const Control& control) +{ + IM_UNUSED(control); + + if (!m_IsActive) + return false; + + m_IsActive = false; + return true; +} + +void ed::DeleteItemsAction::ShowMetrics() +{ + EditorAction::ShowMetrics(); + + //auto getObjectName = [](Object* object) + //{ + // if (!object) return ""; + // else if (object->AsNode()) return "Node"; + // else if (object->AsPin()) return "Pin"; + // else if (object->AsLink()) return "Link"; + // else return ""; + //}; + + ImGui::Text("%s:", GetName()); + ImGui::Text(" Active: %s", m_IsActive ? "yes" : "no"); + //ImGui::Text(" Node: %s (%d)", getObjectName(DeleteItemsgedNode), DeleteItemsgedNode ? DeleteItemsgedNode->ID : 0); +} + +bool ed::DeleteItemsAction::Add(Object* object) +{ + if (Editor->GetCurrentAction() != nullptr) + return false; + + m_ManuallyDeletedObjects.push_back(object); + + return true; +} + +bool ed::DeleteItemsAction::Begin() +{ + if (!m_IsActive) + return false; + + IM_ASSERT(!m_InInteraction); + m_InInteraction = true; + + m_CurrentItemType = Unknown; + m_UserAction = Undetermined; + + return m_IsActive; +} + +void ed::DeleteItemsAction::End() +{ + if (!m_IsActive) + return; + + IM_ASSERT(m_InInteraction); + m_InInteraction = false; +} + +bool ed::DeleteItemsAction::QueryLink(LinkId* linkId, PinId* startId, PinId* endId) +{ + ObjectId objectId; + if (!QueryItem(&objectId, Link)) + return false; + + if (auto id = objectId.AsLinkId()) + *linkId = id; + else + return false; + + if (startId || endId) + { + auto link = Editor->FindLink(*linkId); + if (startId) + *startId = link->m_StartPin->m_ID; + if (endId) + *endId = link->m_EndPin->m_ID; + } + + return true; +} + +bool ed::DeleteItemsAction::QueryNode(NodeId* nodeId) +{ + ObjectId objectId; + if (!QueryItem(&objectId, Node)) + return false; + + if (auto id = objectId.AsNodeId()) + *nodeId = id; + else + return false; + + return true; +} + +bool ed::DeleteItemsAction::QueryItem(ObjectId* itemId, IteratorType itemType) +{ + if (!m_InInteraction) + return false; + + if (m_CurrentItemType != itemType) + { + m_CurrentItemType = itemType; + m_CandidateItemIndex = 0; + } + else if (m_UserAction == Undetermined) + { + RejectItem(); + } + + m_UserAction = Undetermined; + + auto itemCount = (int)m_CandidateObjects.size(); + while (m_CandidateItemIndex < itemCount) + { + auto item = m_CandidateObjects[m_CandidateItemIndex]; + if (itemType == Node) + { + if (auto node = item->AsNode()) + { + *itemId = node->m_ID; + return true; + } + } + else if (itemType == Link) + { + if (auto link = item->AsLink()) + { + *itemId = link->m_ID; + return true; + } + } + + ++m_CandidateItemIndex; + } + + if (m_CandidateItemIndex == itemCount) + m_CurrentItemType = Unknown; + + return false; +} + +bool ed::DeleteItemsAction::AcceptItem(bool deleteDependencies) +{ + if (!m_InInteraction) + return false; + + m_UserAction = Accepted; + + RemoveItem(deleteDependencies); + + return true; +} + +void ed::DeleteItemsAction::RejectItem() +{ + if (!m_InInteraction) + return; + + m_UserAction = Rejected; + + DropCurrentItem(); +} + +void ed::DeleteItemsAction::RemoveItem(bool deleteDependencies) +{ + auto item = DropCurrentItem(); + + Editor->DeselectObject(item); + + Editor->RemoveSettings(item); + + item->m_DeleteOnNewFrame = true; + + if (deleteDependencies && m_CurrentItemType == Node) + { + auto node = item->ID().AsNodeId(); + DeleteDeadLinks(node); + DeleteDeadPins(node); + } + + if (m_CurrentItemType == Link) + Editor->NotifyLinkDeleted(item->AsLink()); +} + +ed::Object* ed::DeleteItemsAction::DropCurrentItem() +{ + auto item = m_CandidateObjects[m_CandidateItemIndex]; + m_CandidateObjects.erase(m_CandidateObjects.begin() + m_CandidateItemIndex); + + return item; +} + + + + +//------------------------------------------------------------------------------ +// +// Node Builder +// +//------------------------------------------------------------------------------ +ed::NodeBuilder::NodeBuilder(EditorContext* editor): + Editor(editor), + m_CurrentNode(nullptr), + m_CurrentPin(nullptr) +{ +} + +ed::NodeBuilder::~NodeBuilder() +{ + m_Splitter.ClearFreeMemory(); + m_PinSplitter.ClearFreeMemory(); +} + +void ed::NodeBuilder::Begin(NodeId nodeId) +{ + IM_ASSERT(nullptr == m_CurrentNode); + + m_CurrentNode = Editor->GetNode(nodeId); + + Editor->UpdateNodeState(m_CurrentNode); + + if (m_CurrentNode->m_CenterOnScreen) + { + auto bounds = Editor->GetViewRect(); + auto offset = bounds.GetCenter() - m_CurrentNode->m_Bounds.GetCenter(); + + if (ImLengthSqr(offset) > 0) + { + if (::IsGroup(m_CurrentNode)) + { + std::vector groupedNodes; + m_CurrentNode->GetGroupedNodes(groupedNodes); + groupedNodes.push_back(m_CurrentNode); + + for (auto node : groupedNodes) + { + node->m_Bounds.Translate(ImFloor(offset)); + node->m_GroupBounds.Translate(ImFloor(offset)); + Editor->MakeDirty(SaveReasonFlags::Position | SaveReasonFlags::User, node); + } + } + else + { + m_CurrentNode->m_Bounds.Translate(ImFloor(offset)); + m_CurrentNode->m_GroupBounds.Translate(ImFloor(offset)); + Editor->MakeDirty(SaveReasonFlags::Position | SaveReasonFlags::User, m_CurrentNode); + } + } + + m_CurrentNode->m_CenterOnScreen = false; + } + + // Position node on screen + ImGui::SetCursorScreenPos(m_CurrentNode->m_Bounds.Min); + + auto& editorStyle = Editor->GetStyle(); + + const auto alpha = ImGui::GetStyle().Alpha; + + m_CurrentNode->m_IsLive = true; + m_CurrentNode->m_LastPin = nullptr; + m_CurrentNode->m_Color = Editor->GetColor(StyleColor_NodeBg, alpha); + m_CurrentNode->m_BorderColor = Editor->GetColor(StyleColor_NodeBorder, alpha); + m_CurrentNode->m_BorderWidth = editorStyle.NodeBorderWidth; + m_CurrentNode->m_Rounding = editorStyle.NodeRounding; + m_CurrentNode->m_GroupColor = Editor->GetColor(StyleColor_GroupBg, alpha); + m_CurrentNode->m_GroupBorderColor = Editor->GetColor(StyleColor_GroupBorder, alpha); + m_CurrentNode->m_GroupBorderWidth = editorStyle.GroupBorderWidth; + m_CurrentNode->m_GroupRounding = editorStyle.GroupRounding; + m_CurrentNode->m_HighlightConnectedLinks = editorStyle.HighlightConnectedLinks != 0.0f; + + m_IsGroup = false; + + // Grow channel list and select user channel + if (auto drawList = Editor->GetDrawList()) + { + m_CurrentNode->m_Channel = drawList->_Splitter._Count; + ImDrawList_ChannelsGrow(drawList, drawList->_Splitter._Count + c_ChannelsPerNode); + drawList->ChannelsSetCurrent(m_CurrentNode->m_Channel + c_NodeContentChannel); + + m_Splitter.Clear(); + ImDrawList_SwapSplitter(drawList, m_Splitter); + } + + // Begin outer group + ImGui::BeginGroup(); + + // Apply frame padding. Begin inner group if necessary. + if (editorStyle.NodePadding.x != 0 || editorStyle.NodePadding.y != 0 || editorStyle.NodePadding.z != 0 || editorStyle.NodePadding.w != 0) + { + ImGui::SetCursorPos(ImGui::GetCursorPos() + ImVec2(editorStyle.NodePadding.x, editorStyle.NodePadding.y)); + ImGui::BeginGroup(); + } +} + +void ed::NodeBuilder::End() +{ + IM_ASSERT(nullptr != m_CurrentNode); + + if (auto drawList = Editor->GetDrawList()) + { + IM_ASSERT(drawList->_Splitter._Count == 1); // Did you forgot to call drawList->ChannelsMerge()? + ImDrawList_SwapSplitter(drawList, m_Splitter); + } + + // Apply frame padding. This must be done in this convoluted way if outer group + // size must contain inner group padding. + auto& editorStyle = Editor->GetStyle(); + if (editorStyle.NodePadding.x != 0 || editorStyle.NodePadding.y != 0 || editorStyle.NodePadding.z != 0 || editorStyle.NodePadding.w != 0) + { + ImGui::EndGroup(); + ImGui::SameLine(0, editorStyle.NodePadding.z); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f)); + ImGui::Dummy(ImVec2(0, 0)); // bump cursor at the end of the line and move to next one + ImGui::Dummy(ImVec2(0, editorStyle.NodePadding.w)); // apply padding + ImGui::PopStyleVar(); + } + + // End outer group. + ImGui::EndGroup(); + + m_NodeRect = ImGui_GetItemRect(); + m_NodeRect.Floor(); + + if (m_CurrentNode->m_Bounds.GetSize() != m_NodeRect.GetSize()) + { + m_CurrentNode->m_Bounds.Max = m_CurrentNode->m_Bounds.Min + m_NodeRect.GetSize(); + Editor->MakeDirty(SaveReasonFlags::Size, m_CurrentNode); + } + + if (m_IsGroup) + { + // Groups cannot have pins. Discard them. + for (auto pin = m_CurrentNode->m_LastPin; pin; pin = pin->m_PreviousPin) + pin->Reset(); + + m_CurrentNode->m_Type = NodeType::Group; + m_CurrentNode->m_GroupBounds = m_GroupBounds; + m_CurrentNode->m_LastPin = nullptr; + } + else + m_CurrentNode->m_Type = NodeType::Node; + + m_CurrentNode = nullptr; +} + +void ed::NodeBuilder::BeginPin(PinId pinId, PinKind kind) +{ + IM_ASSERT(nullptr != m_CurrentNode); + IM_ASSERT(nullptr == m_CurrentPin); + IM_ASSERT(false == m_IsGroup); + + auto& editorStyle = Editor->GetStyle(); + + m_CurrentPin = Editor->GetPin(pinId, kind); + m_CurrentPin->m_Node = m_CurrentNode; + + m_CurrentPin->m_IsLive = true; + m_CurrentPin->m_Color = Editor->GetColor(StyleColor_PinRect); + m_CurrentPin->m_BorderColor = Editor->GetColor(StyleColor_PinRectBorder); + m_CurrentPin->m_BorderWidth = editorStyle.PinBorderWidth; + m_CurrentPin->m_Rounding = editorStyle.PinRounding; + m_CurrentPin->m_Corners = static_cast(editorStyle.PinCorners); + m_CurrentPin->m_Radius = editorStyle.PinRadius; + m_CurrentPin->m_ArrowSize = editorStyle.PinArrowSize; + m_CurrentPin->m_ArrowWidth = editorStyle.PinArrowWidth; + m_CurrentPin->m_Dir = kind == PinKind::Output ? editorStyle.SourceDirection : editorStyle.TargetDirection; + m_CurrentPin->m_Strength = editorStyle.LinkStrength; + m_CurrentPin->m_SnapLinkToDir = editorStyle.SnapLinkToPinDir != 0.0f; + + m_CurrentPin->m_PreviousPin = m_CurrentNode->m_LastPin; + m_CurrentNode->m_LastPin = m_CurrentPin; + + m_PivotAlignment = editorStyle.PivotAlignment; + m_PivotSize = editorStyle.PivotSize; + m_PivotScale = editorStyle.PivotScale; + m_ResolvePinRect = true; + m_ResolvePivot = true; + + if (auto drawList = Editor->GetDrawList()) + { + m_PinSplitter.Clear(); + ImDrawList_SwapSplitter(drawList, m_PinSplitter); + } + + ImGui::BeginGroup(); +} + +void ed::NodeBuilder::EndPin() +{ + IM_ASSERT(nullptr != m_CurrentPin); + + if (auto drawList = Editor->GetDrawList()) + { + IM_ASSERT(drawList->_Splitter._Count == 1); // Did you forgot to call drawList->ChannelsMerge()? + ImDrawList_SwapSplitter(drawList, m_PinSplitter); + } + + ImGui::EndGroup(); + + if (m_ResolvePinRect) + m_CurrentPin->m_Bounds = ImGui_GetItemRect(); + + if (m_ResolvePivot) + { + auto& pinRect = m_CurrentPin->m_Bounds; + + if (m_PivotSize.x < 0) + m_PivotSize.x = pinRect.GetWidth(); + if (m_PivotSize.y < 0) + m_PivotSize.y = pinRect.GetHeight(); + + m_CurrentPin->m_Pivot.Min = pinRect.Min + ImMul(pinRect.GetSize(), m_PivotAlignment); + m_CurrentPin->m_Pivot.Max = m_CurrentPin->m_Pivot.Min + ImMul(m_PivotSize, m_PivotScale); + } + + // #debug: Draw pin bounds + //Editor->GetDrawList()->AddRect(m_CurrentPin->m_Bounds.Min, m_CurrentPin->m_Bounds.Max, IM_COL32(255, 255, 0, 255)); + + // #debug: Draw pin pivot rectangle + //Editor->GetDrawList()->AddRect(m_CurrentPin->m_Pivot.Min, m_CurrentPin->m_Pivot.Max, IM_COL32(255, 0, 255, 255)); + + m_CurrentPin = nullptr; +} + +void ed::NodeBuilder::PinRect(const ImVec2& a, const ImVec2& b) +{ + IM_ASSERT(nullptr != m_CurrentPin); + + m_CurrentPin->m_Bounds = ImRect(a, b); + m_CurrentPin->m_Bounds.Floor(); + m_ResolvePinRect = false; +} + +void ed::NodeBuilder::PinPivotRect(const ImVec2& a, const ImVec2& b) +{ + IM_ASSERT(nullptr != m_CurrentPin); + + m_CurrentPin->m_Pivot = ImRect(a, b); + m_ResolvePivot = false; +} + +void ed::NodeBuilder::PinPivotSize(const ImVec2& size) +{ + IM_ASSERT(nullptr != m_CurrentPin); + + m_PivotSize = size; + m_ResolvePivot = true; +} + +void ed::NodeBuilder::PinPivotScale(const ImVec2& scale) +{ + IM_ASSERT(nullptr != m_CurrentPin); + + m_PivotScale = scale; + m_ResolvePivot = true; +} + +void ed::NodeBuilder::PinPivotAlignment(const ImVec2& alignment) +{ + IM_ASSERT(nullptr != m_CurrentPin); + + m_PivotAlignment = alignment; + m_ResolvePivot = true; +} + +void ed::NodeBuilder::Group(const ImVec2& size) +{ + IM_ASSERT(nullptr != m_CurrentNode); + IM_ASSERT(nullptr == m_CurrentPin); + IM_ASSERT(false == m_IsGroup); + + m_IsGroup = true; + + if (IsGroup(m_CurrentNode)) + ImGui::Dummy(m_CurrentNode->m_GroupBounds.GetSize()); + else + ImGui::Dummy(size); + + m_GroupBounds = ImGui_GetItemRect(); + m_GroupBounds.Floor(); +} + +ImDrawList* ed::NodeBuilder::GetUserBackgroundDrawList() const +{ + return GetUserBackgroundDrawList(m_CurrentNode); +} + +ImDrawList* ed::NodeBuilder::GetUserBackgroundDrawList(Node* node) const +{ + if (node && node->m_IsLive) + { + auto drawList = Editor->GetDrawList(); + drawList->ChannelsSetCurrent(node->m_Channel + c_NodeUserBackgroundChannel); + return drawList; + } + else + return nullptr; +} + + + + +//------------------------------------------------------------------------------ +// +// Node Builder +// +//------------------------------------------------------------------------------ +ed::HintBuilder::HintBuilder(EditorContext* editor): + Editor(editor), + m_IsActive(false), + m_CurrentNode(nullptr) +{ +} + +bool ed::HintBuilder::Begin(NodeId nodeId) +{ + IM_ASSERT(nullptr == m_CurrentNode); + + auto& view = Editor->GetView(); + auto& rect = Editor->GetRect(); + + const float c_min_zoom = 0.75f; + const float c_max_zoom = 0.50f; + + if (view.Scale > 0.75f) + return false; + + auto node = Editor->FindNode(nodeId); + if (!IsGroup(node)) + return false; + + m_CurrentNode = node; + + m_LastChannel = Editor->GetDrawList()->_Splitter._Current; + + Editor->Suspend(SuspendFlags::KeepSplitter); + + const auto alpha = ImMax(0.0f, std::min(1.0f, (view.Scale - c_min_zoom) / (c_max_zoom - c_min_zoom))); + + Editor->GetDrawList()->ChannelsSetCurrent(c_UserChannel_HintsBackground); + ImGui::PushClipRect(rect.Min + ImVec2(1, 1), rect.Max - ImVec2(1, 1), false); + + Editor->GetDrawList()->ChannelsSetCurrent(c_UserChannel_Hints); + ImGui::PushClipRect(rect.Min + ImVec2(1, 1), rect.Max - ImVec2(1, 1), false); + + ImGui::PushStyleVar(ImGuiStyleVar_Alpha, alpha); + + m_IsActive = true; + + return true; +} + +void ed::HintBuilder::End() +{ + if (!m_IsActive) + return; + + ImGui::PopStyleVar(); + + Editor->GetDrawList()->ChannelsSetCurrent(c_UserChannel_Hints); + ImGui::PopClipRect(); + + Editor->GetDrawList()->ChannelsSetCurrent(c_UserChannel_HintsBackground); + ImGui::PopClipRect(); + + Editor->GetDrawList()->ChannelsSetCurrent(m_LastChannel); + + Editor->Resume(SuspendFlags::KeepSplitter); + + m_IsActive = false; + m_CurrentNode = nullptr; +} + +ImVec2 ed::HintBuilder::GetGroupMin() +{ + IM_ASSERT(nullptr != m_CurrentNode); + + return Editor->ToScreen(m_CurrentNode->m_Bounds.Min); +} + +ImVec2 ed::HintBuilder::GetGroupMax() +{ + IM_ASSERT(nullptr != m_CurrentNode); + + return Editor->ToScreen(m_CurrentNode->m_Bounds.Max); +} + +ImDrawList* ed::HintBuilder::GetForegroundDrawList() +{ + IM_ASSERT(nullptr != m_CurrentNode); + + auto drawList = Editor->GetDrawList(); + + drawList->ChannelsSetCurrent(c_UserChannel_Hints); + + return drawList; +} + +ImDrawList* ed::HintBuilder::GetBackgroundDrawList() +{ + IM_ASSERT(nullptr != m_CurrentNode); + + auto drawList = Editor->GetDrawList(); + + drawList->ChannelsSetCurrent(c_UserChannel_HintsBackground); + + return drawList; +} + + + + +//------------------------------------------------------------------------------ +// +// Style +// +//------------------------------------------------------------------------------ +void ed::Style::PushColor(StyleColor colorIndex, const ImVec4& color) +{ + ColorModifier modifier; + modifier.Index = colorIndex; + modifier.Value = Colors[colorIndex]; + m_ColorStack.push_back(modifier); + Colors[colorIndex] = color; +} + +void ed::Style::PopColor(int count) +{ + while (count > 0) + { + auto& modifier = m_ColorStack.back(); + Colors[modifier.Index] = modifier.Value; + m_ColorStack.pop_back(); + --count; + } +} + +void ed::Style::PushVar(StyleVar varIndex, float value) +{ + auto* var = GetVarFloatAddr(varIndex); + IM_ASSERT(var != nullptr); + VarModifier modifier; + modifier.Index = varIndex; + modifier.Value = ImVec4(*var, 0, 0, 0); + *var = value; + m_VarStack.push_back(modifier); +} + +void ed::Style::PushVar(StyleVar varIndex, const ImVec2& value) +{ + auto* var = GetVarVec2Addr(varIndex); + IM_ASSERT(var != nullptr); + VarModifier modifier; + modifier.Index = varIndex; + modifier.Value = ImVec4(var->x, var->y, 0, 0); + *var = value; + m_VarStack.push_back(modifier); +} + +void ed::Style::PushVar(StyleVar varIndex, const ImVec4& value) +{ + auto* var = GetVarVec4Addr(varIndex); + IM_ASSERT(var != nullptr); + VarModifier modifier; + modifier.Index = varIndex; + modifier.Value = *var; + *var = value; + m_VarStack.push_back(modifier); +} + +void ed::Style::PopVar(int count) +{ + while (count > 0) + { + auto& modifier = m_VarStack.back(); + if (auto floatValue = GetVarFloatAddr(modifier.Index)) + *floatValue = modifier.Value.x; + else if (auto vec2Value = GetVarVec2Addr(modifier.Index)) + *vec2Value = ImVec2(modifier.Value.x, modifier.Value.y); + else if (auto vec4Value = GetVarVec4Addr(modifier.Index)) + *vec4Value = modifier.Value; + m_VarStack.pop_back(); + --count; + } +} + +const char* ed::Style::GetColorName(StyleColor colorIndex) const +{ + switch (colorIndex) + { + case StyleColor_Bg: return "Bg"; + case StyleColor_Grid: return "Grid"; + case StyleColor_NodeBg: return "NodeBg"; + case StyleColor_NodeBorder: return "NodeBorder"; + case StyleColor_HovNodeBorder: return "HoveredNodeBorder"; + case StyleColor_SelNodeBorder: return "SelNodeBorder"; + case StyleColor_NodeSelRect: return "NodeSelRect"; + case StyleColor_NodeSelRectBorder: return "NodeSelRectBorder"; + case StyleColor_HovLinkBorder: return "HoveredLinkBorder"; + case StyleColor_SelLinkBorder: return "SelLinkBorder"; + case StyleColor_HighlightLinkBorder: return "HighlightLinkBorder"; + case StyleColor_LinkSelRect: return "LinkSelRect"; + case StyleColor_LinkSelRectBorder: return "LinkSelRectBorder"; + case StyleColor_PinRect: return "PinRect"; + case StyleColor_PinRectBorder: return "PinRectBorder"; + case StyleColor_Flow: return "Flow"; + case StyleColor_FlowMarker: return "FlowMarker"; + case StyleColor_GroupBg: return "GroupBg"; + case StyleColor_GroupBorder: return "GroupBorder"; + case StyleColor_Count: break; + } + + IM_ASSERT(0); + return "Unknown"; +} + +float* ed::Style::GetVarFloatAddr(StyleVar idx) +{ + switch (idx) + { + case StyleVar_NodeRounding: return &NodeRounding; + case StyleVar_NodeBorderWidth: return &NodeBorderWidth; + case StyleVar_HoveredNodeBorderWidth: return &HoveredNodeBorderWidth; + case StyleVar_SelectedNodeBorderWidth: return &SelectedNodeBorderWidth; + case StyleVar_PinRounding: return &PinRounding; + case StyleVar_PinBorderWidth: return &PinBorderWidth; + case StyleVar_LinkStrength: return &LinkStrength; + case StyleVar_ScrollDuration: return &ScrollDuration; + case StyleVar_FlowMarkerDistance: return &FlowMarkerDistance; + case StyleVar_FlowSpeed: return &FlowSpeed; + case StyleVar_FlowDuration: return &FlowDuration; + case StyleVar_PinCorners: return &PinCorners; + case StyleVar_PinRadius: return &PinRadius; + case StyleVar_PinArrowSize: return &PinArrowSize; + case StyleVar_PinArrowWidth: return &PinArrowWidth; + case StyleVar_GroupRounding: return &GroupRounding; + case StyleVar_GroupBorderWidth: return &GroupBorderWidth; + case StyleVar_HighlightConnectedLinks: return &HighlightConnectedLinks; + case StyleVar_SnapLinkToPinDir: return &SnapLinkToPinDir; + default: return nullptr; + } +} + +ImVec2* ed::Style::GetVarVec2Addr(StyleVar idx) +{ + switch (idx) + { + case StyleVar_SourceDirection: return &SourceDirection; + case StyleVar_TargetDirection: return &TargetDirection; + case StyleVar_PivotAlignment: return &PivotAlignment; + case StyleVar_PivotSize: return &PivotSize; + case StyleVar_PivotScale: return &PivotScale; + default: return nullptr; + } +} + +ImVec4* ed::Style::GetVarVec4Addr(StyleVar idx) +{ + switch (idx) + { + case StyleVar_NodePadding: return &NodePadding; + default: return nullptr; + } +} + + + + +//------------------------------------------------------------------------------ +// +// Config +// +//------------------------------------------------------------------------------ +ed::Config::Config(const ax::NodeEditor::Config* config) +{ + if (config) + *static_cast(this) = *config; +} + +std::string ed::Config::Load() +{ + std::string data; + + if (LoadSettings) + { + const auto size = LoadSettings(nullptr, UserPointer); + if (size > 0) + { + data.resize(size); + LoadSettings(const_cast(data.data()), UserPointer); + } + } + else if (SettingsFile) + { + std::ifstream file(SettingsFile); + if (file) + { + file.seekg(0, std::ios_base::end); + auto size = static_cast(file.tellg()); + file.seekg(0, std::ios_base::beg); + + data.reserve(size); + data.assign(std::istreambuf_iterator(file), std::istreambuf_iterator()); + } + } + + return data; +} + +std::string ed::Config::LoadNode(NodeId nodeId) +{ + std::string data; + + if (LoadNodeSettings) + { + const auto size = LoadNodeSettings(nodeId, nullptr, UserPointer); + if (size > 0) + { + data.resize(size); + LoadNodeSettings(nodeId, const_cast(data.data()), UserPointer); + } + } + + return data; +} + +void ed::Config::BeginSave() +{ + if (BeginSaveSession) + BeginSaveSession(UserPointer); +} + +bool ed::Config::Save(const std::string& data, SaveReasonFlags flags) +{ + if (SaveSettings) + { + return SaveSettings(data.c_str(), data.size(), flags, UserPointer); + } + else if (SettingsFile) + { + std::ofstream settingsFile(SettingsFile); + if (settingsFile) + settingsFile << data; + + return !!settingsFile; + } + + return false; +} + +bool ed::Config::SaveNode(NodeId nodeId, const std::string& data, SaveReasonFlags flags) +{ + if (SaveNodeSettings) + return SaveNodeSettings(nodeId, data.c_str(), data.size(), flags, UserPointer); + + return false; +} + +void ed::Config::EndSave() +{ + if (EndSaveSession) + EndSaveSession(UserPointer); +} + +#ifndef _MSC_VER +#pragma GCC diagnostic pop +#endif diff --git a/3rdparty/imgui-node-editor/imgui_node_editor.h b/3rdparty/imgui-node-editor/imgui_node_editor.h new file mode 100644 index 0000000..400c0d7 --- /dev/null +++ b/3rdparty/imgui-node-editor/imgui_node_editor.h @@ -0,0 +1,511 @@ +//------------------------------------------------------------------------------ +// VERSION 0.9.1 +// +// LICENSE +// This software is dual-licensed to the public domain and under the following +// license: you are granted a perpetual, irrevocable license to copy, modify, +// publish, and distribute this file as you see fit. +// +// CREDITS +// Written by Michal Cichon +//------------------------------------------------------------------------------ +# ifndef __IMGUI_NODE_EDITOR_H__ +# define __IMGUI_NODE_EDITOR_H__ +# pragma once + + +//------------------------------------------------------------------------------ +#define IMGUI_DEFINE_MATH_OPERATORS +# include +# include // std::uintXX_t +# include // std::move + + +//------------------------------------------------------------------------------ +# define IMGUI_NODE_EDITOR_VERSION "0.9.2" +# define IMGUI_NODE_EDITOR_VERSION_NUM 000902 + + +//------------------------------------------------------------------------------ +namespace ax { +namespace NodeEditor { + + +//------------------------------------------------------------------------------ +struct NodeId; +struct LinkId; +struct PinId; + + +//------------------------------------------------------------------------------ +enum class PinKind +{ + Input, + Output +}; + +enum class FlowDirection +{ + Forward, + Backward +}; + +enum class CanvasSizeMode +{ + FitVerticalView, // Previous view will be scaled to fit new view on Y axis + FitHorizontalView, // Previous view will be scaled to fit new view on X axis + CenterOnly, // Previous view will be centered on new view +}; + + +//------------------------------------------------------------------------------ +enum class SaveReasonFlags: uint32_t +{ + None = 0x00000000, + Navigation = 0x00000001, + Position = 0x00000002, + Size = 0x00000004, + Selection = 0x00000008, + AddNode = 0x00000010, + RemoveNode = 0x00000020, + User = 0x00000040 +}; + +inline SaveReasonFlags operator |(SaveReasonFlags lhs, SaveReasonFlags rhs) { return static_cast(static_cast(lhs) | static_cast(rhs)); } +inline SaveReasonFlags operator &(SaveReasonFlags lhs, SaveReasonFlags rhs) { return static_cast(static_cast(lhs) & static_cast(rhs)); } + +using ConfigSaveSettings = bool (*)(const char* data, size_t size, SaveReasonFlags reason, void* userPointer); +using ConfigLoadSettings = size_t (*)(char* data, void* userPointer); + +using ConfigSaveNodeSettings = bool (*)(NodeId nodeId, const char* data, size_t size, SaveReasonFlags reason, void* userPointer); +using ConfigLoadNodeSettings = size_t (*)(NodeId nodeId, char* data, void* userPointer); + +using ConfigSession = void (*)(void* userPointer); + +struct Config +{ + using CanvasSizeModeAlias = ax::NodeEditor::CanvasSizeMode; + + const char* SettingsFile; + ConfigSession BeginSaveSession; + ConfigSession EndSaveSession; + ConfigSaveSettings SaveSettings; + ConfigLoadSettings LoadSettings; + ConfigSaveNodeSettings SaveNodeSettings; + ConfigLoadNodeSettings LoadNodeSettings; + void* UserPointer; + ImVector CustomZoomLevels; + CanvasSizeModeAlias CanvasSizeMode; + int DragButtonIndex; // Mouse button index drag action will react to (0-left, 1-right, 2-middle) + int SelectButtonIndex; // Mouse button index select action will react to (0-left, 1-right, 2-middle) + int NavigateButtonIndex; // Mouse button index navigate action will react to (0-left, 1-right, 2-middle) + int ContextMenuButtonIndex; // Mouse button index context menu action will react to (0-left, 1-right, 2-middle) + + Config() + : SettingsFile("NodeEditor.json") + , BeginSaveSession(nullptr) + , EndSaveSession(nullptr) + , SaveSettings(nullptr) + , LoadSettings(nullptr) + , SaveNodeSettings(nullptr) + , LoadNodeSettings(nullptr) + , UserPointer(nullptr) + , CustomZoomLevels() + , CanvasSizeMode(CanvasSizeModeAlias::FitVerticalView) + , DragButtonIndex(0) + , SelectButtonIndex(0) + , NavigateButtonIndex(1) + , ContextMenuButtonIndex(1) + { + } +}; + + +//------------------------------------------------------------------------------ +enum StyleColor +{ + StyleColor_Bg, + StyleColor_Grid, + StyleColor_NodeBg, + StyleColor_NodeBorder, + StyleColor_HovNodeBorder, + StyleColor_SelNodeBorder, + StyleColor_NodeSelRect, + StyleColor_NodeSelRectBorder, + StyleColor_HovLinkBorder, + StyleColor_SelLinkBorder, + StyleColor_HighlightLinkBorder, + StyleColor_LinkSelRect, + StyleColor_LinkSelRectBorder, + StyleColor_PinRect, + StyleColor_PinRectBorder, + StyleColor_Flow, + StyleColor_FlowMarker, + StyleColor_GroupBg, + StyleColor_GroupBorder, + + StyleColor_Count +}; + +enum StyleVar +{ + StyleVar_NodePadding, + StyleVar_NodeRounding, + StyleVar_NodeBorderWidth, + StyleVar_HoveredNodeBorderWidth, + StyleVar_SelectedNodeBorderWidth, + StyleVar_PinRounding, + StyleVar_PinBorderWidth, + StyleVar_LinkStrength, + StyleVar_SourceDirection, + StyleVar_TargetDirection, + StyleVar_ScrollDuration, + StyleVar_FlowMarkerDistance, + StyleVar_FlowSpeed, + StyleVar_FlowDuration, + StyleVar_PivotAlignment, + StyleVar_PivotSize, + StyleVar_PivotScale, + StyleVar_PinCorners, + StyleVar_PinRadius, + StyleVar_PinArrowSize, + StyleVar_PinArrowWidth, + StyleVar_GroupRounding, + StyleVar_GroupBorderWidth, + StyleVar_HighlightConnectedLinks, + StyleVar_SnapLinkToPinDir, + + StyleVar_Count +}; + +struct Style +{ + ImVec4 NodePadding; + float NodeRounding; + float NodeBorderWidth; + float HoveredNodeBorderWidth; + float SelectedNodeBorderWidth; + float PinRounding; + float PinBorderWidth; + float LinkStrength; + ImVec2 SourceDirection; + ImVec2 TargetDirection; + float ScrollDuration; + float FlowMarkerDistance; + float FlowSpeed; + float FlowDuration; + ImVec2 PivotAlignment; + ImVec2 PivotSize; + ImVec2 PivotScale; + float PinCorners; + float PinRadius; + float PinArrowSize; + float PinArrowWidth; + float GroupRounding; + float GroupBorderWidth; + float HighlightConnectedLinks; + float SnapLinkToPinDir; // when true link will start on the line defined by pin direction + ImVec4 Colors[StyleColor_Count]; + + Style() + { + NodePadding = ImVec4(8, 8, 8, 8); + NodeRounding = 12.0f; + NodeBorderWidth = 1.5f; + HoveredNodeBorderWidth = 3.5f; + SelectedNodeBorderWidth = 3.5f; + PinRounding = 4.0f; + PinBorderWidth = 0.0f; + LinkStrength = 100.0f; + SourceDirection = ImVec2(1.0f, 0.0f); + TargetDirection = ImVec2(-1.0f, 0.0f); + ScrollDuration = 0.35f; + FlowMarkerDistance = 30.0f; + FlowSpeed = 150.0f; + FlowDuration = 2.0f; + PivotAlignment = ImVec2(0.5f, 0.5f); + PivotSize = ImVec2(0.0f, 0.0f); + PivotScale = ImVec2(1, 1); +#if IMGUI_VERSION_NUM > 18101 + PinCorners = ImDrawFlags_RoundCornersAll; +#else + PinCorners = ImDrawCornerFlags_All; +#endif + PinRadius = 0.0f; + PinArrowSize = 0.0f; + PinArrowWidth = 0.0f; + GroupRounding = 6.0f; + GroupBorderWidth = 1.0f; + HighlightConnectedLinks = 0.0f; + SnapLinkToPinDir = 0.0f; + + Colors[StyleColor_Bg] = ImColor( 60, 60, 70, 200); + Colors[StyleColor_Grid] = ImColor(120, 120, 120, 40); + Colors[StyleColor_NodeBg] = ImColor( 32, 32, 32, 200); + Colors[StyleColor_NodeBorder] = ImColor(255, 255, 255, 96); + Colors[StyleColor_HovNodeBorder] = ImColor( 50, 176, 255, 255); + Colors[StyleColor_SelNodeBorder] = ImColor(255, 176, 50, 255); + Colors[StyleColor_NodeSelRect] = ImColor( 5, 130, 255, 64); + Colors[StyleColor_NodeSelRectBorder] = ImColor( 5, 130, 255, 128); + Colors[StyleColor_HovLinkBorder] = ImColor( 50, 176, 255, 255); + Colors[StyleColor_SelLinkBorder] = ImColor(255, 176, 50, 255); + Colors[StyleColor_HighlightLinkBorder]= ImColor(204, 105, 0, 255); + Colors[StyleColor_LinkSelRect] = ImColor( 5, 130, 255, 64); + Colors[StyleColor_LinkSelRectBorder] = ImColor( 5, 130, 255, 128); + Colors[StyleColor_PinRect] = ImColor( 60, 180, 255, 100); + Colors[StyleColor_PinRectBorder] = ImColor( 60, 180, 255, 128); + Colors[StyleColor_Flow] = ImColor(255, 128, 64, 255); + Colors[StyleColor_FlowMarker] = ImColor(255, 128, 64, 255); + Colors[StyleColor_GroupBg] = ImColor( 0, 0, 0, 160); + Colors[StyleColor_GroupBorder] = ImColor(255, 255, 255, 32); + } +}; + + +//------------------------------------------------------------------------------ +struct EditorContext; + + +//------------------------------------------------------------------------------ +void SetCurrentEditor(EditorContext* ctx); +EditorContext* GetCurrentEditor(); +EditorContext* CreateEditor(const Config* config = nullptr); +void DestroyEditor(EditorContext* ctx); +const Config& GetConfig(EditorContext* ctx = nullptr); + +Style& GetStyle(); +const char* GetStyleColorName(StyleColor colorIndex); + +void PushStyleColor(StyleColor colorIndex, const ImVec4& color); +void PopStyleColor(int count = 1); + +void PushStyleVar(StyleVar varIndex, float value); +void PushStyleVar(StyleVar varIndex, const ImVec2& value); +void PushStyleVar(StyleVar varIndex, const ImVec4& value); +void PopStyleVar(int count = 1); + +void Begin(const char* id, const ImVec2& size = ImVec2(0, 0)); +void End(); + +void BeginNode(NodeId id); +void BeginPin(PinId id, PinKind kind); +void PinRect(const ImVec2& a, const ImVec2& b); +void PinPivotRect(const ImVec2& a, const ImVec2& b); +void PinPivotSize(const ImVec2& size); +void PinPivotScale(const ImVec2& scale); +void PinPivotAlignment(const ImVec2& alignment); +void EndPin(); +void Group(const ImVec2& size); +void EndNode(); + +bool BeginGroupHint(NodeId nodeId); +ImVec2 GetGroupMin(); +ImVec2 GetGroupMax(); +ImDrawList* GetHintForegroundDrawList(); +ImDrawList* GetHintBackgroundDrawList(); +void EndGroupHint(); + +// TODO: Add a way to manage node background channels +ImDrawList* GetNodeBackgroundDrawList(NodeId nodeId); + +bool Link(LinkId id, PinId startPinId, PinId endPinId, const ImVec4& color = ImVec4(1, 1, 1, 1), float thickness = 1.0f); + +void Flow(LinkId linkId, FlowDirection direction = FlowDirection::Forward); + +bool BeginCreate(const ImVec4& color = ImVec4(1, 1, 1, 1), float thickness = 1.0f); +bool QueryNewLink(PinId* startId, PinId* endId); +bool QueryNewLink(PinId* startId, PinId* endId, const ImVec4& color, float thickness = 1.0f); +bool QueryNewNode(PinId* pinId); +bool QueryNewNode(PinId* pinId, const ImVec4& color, float thickness = 1.0f); +bool AcceptNewItem(); +bool AcceptNewItem(const ImVec4& color, float thickness = 1.0f); +void RejectNewItem(); +void RejectNewItem(const ImVec4& color, float thickness = 1.0f); +void EndCreate(); + +bool BeginDelete(); +bool QueryDeletedLink(LinkId* linkId, PinId* startId = nullptr, PinId* endId = nullptr); +bool QueryDeletedNode(NodeId* nodeId); +bool AcceptDeletedItem(bool deleteDependencies = true); +void RejectDeletedItem(); +void EndDelete(); + +void SetNodePosition(NodeId nodeId, const ImVec2& editorPosition); +void SetGroupSize(NodeId nodeId, const ImVec2& size); +ImVec2 GetNodePosition(NodeId nodeId); +ImVec2 GetNodeSize(NodeId nodeId); +void CenterNodeOnScreen(NodeId nodeId); +void SetNodeZPosition(NodeId nodeId, float z); // Sets node z position, nodes with higher value are drawn over nodes with lower value +float GetNodeZPosition(NodeId nodeId); // Returns node z position, defaults is 0.0f + +void RestoreNodeState(NodeId nodeId); + +void Suspend(); +void Resume(); +bool IsSuspended(); + +bool IsActive(); + +bool HasSelectionChanged(); +int GetSelectedObjectCount(); +int GetSelectedNodes(NodeId* nodes, int size); +int GetSelectedLinks(LinkId* links, int size); +bool IsNodeSelected(NodeId nodeId); +bool IsLinkSelected(LinkId linkId); +void ClearSelection(); +void SelectNode(NodeId nodeId, bool append = false); +void SelectLink(LinkId linkId, bool append = false); +void DeselectNode(NodeId nodeId); +void DeselectLink(LinkId linkId); + +bool DeleteNode(NodeId nodeId); +bool DeleteLink(LinkId linkId); + +bool HasAnyLinks(NodeId nodeId); // Returns true if node has any link connected +bool HasAnyLinks(PinId pinId); // Return true if pin has any link connected +int BreakLinks(NodeId nodeId); // Break all links connected to this node +int BreakLinks(PinId pinId); // Break all links connected to this pin + +void NavigateToContent(float duration = -1); +void NavigateToSelection(bool zoomIn = false, float duration = -1); + +bool ShowNodeContextMenu(NodeId* nodeId); +bool ShowPinContextMenu(PinId* pinId); +bool ShowLinkContextMenu(LinkId* linkId); +bool ShowBackgroundContextMenu(); + +void EnableShortcuts(bool enable); +bool AreShortcutsEnabled(); + +bool BeginShortcut(); +bool AcceptCut(); +bool AcceptCopy(); +bool AcceptPaste(); +bool AcceptDuplicate(); +bool AcceptCreateNode(); +int GetActionContextSize(); +int GetActionContextNodes(NodeId* nodes, int size); +int GetActionContextLinks(LinkId* links, int size); +void EndShortcut(); + +float GetCurrentZoom(); + +NodeId GetHoveredNode(); +PinId GetHoveredPin(); +LinkId GetHoveredLink(); +NodeId GetDoubleClickedNode(); +PinId GetDoubleClickedPin(); +LinkId GetDoubleClickedLink(); +bool IsBackgroundClicked(); +bool IsBackgroundDoubleClicked(); +ImGuiMouseButton GetBackgroundClickButtonIndex(); // -1 if none +ImGuiMouseButton GetBackgroundDoubleClickButtonIndex(); // -1 if none + +bool GetLinkPins(LinkId linkId, PinId* startPinId, PinId* endPinId); // pass nullptr if particular pin do not interest you + +bool PinHadAnyLinks(PinId pinId); + +ImVec2 GetScreenSize(); +ImVec2 ScreenToCanvas(const ImVec2& pos); +ImVec2 CanvasToScreen(const ImVec2& pos); + +int GetNodeCount(); // Returns number of submitted nodes since Begin() call +int GetOrderedNodeIds(NodeId* nodes, int size); // Fills an array with node id's in order they're drawn; up to 'size` elements are set. Returns actual size of filled id's. + + + + + + + +//------------------------------------------------------------------------------ +namespace Details { + +template +struct SafeType +{ + SafeType(T t) + : m_Value(std::move(t)) + { + } + + SafeType(const SafeType&) = default; + + template + SafeType( + const SafeType + < + typename std::enable_if::value, T2>::type, + typename std::enable_if::value, Tag2>::type + >&) = delete; + + SafeType& operator=(const SafeType&) = default; + + explicit operator T() const { return Get(); } + + T Get() const { return m_Value; } + +private: + T m_Value; +}; + + +template +struct SafePointerType + : SafeType +{ + static const Tag Invalid; + + using SafeType::SafeType; + + SafePointerType() + : SafePointerType(Invalid) + { + } + + template explicit SafePointerType(T* ptr): SafePointerType(reinterpret_cast(ptr)) {} + template T* AsPointer() const { return reinterpret_cast(this->Get()); } + + explicit operator bool() const { return *this != Invalid; } +}; + +template +const Tag SafePointerType::Invalid = { 0 }; + +template +inline bool operator==(const SafePointerType& lhs, const SafePointerType& rhs) +{ + return lhs.Get() == rhs.Get(); +} + +template +inline bool operator!=(const SafePointerType& lhs, const SafePointerType& rhs) +{ + return lhs.Get() != rhs.Get(); +} + +} // namespace Details + +struct NodeId final: Details::SafePointerType +{ + using SafePointerType::SafePointerType; +}; + +struct LinkId final: Details::SafePointerType +{ + using SafePointerType::SafePointerType; +}; + +struct PinId final: Details::SafePointerType +{ + using SafePointerType::SafePointerType; +}; + + +//------------------------------------------------------------------------------ +} // namespace Editor +} // namespace ax + + +//------------------------------------------------------------------------------ +# endif // __IMGUI_NODE_EDITOR_H__ diff --git a/3rdparty/imgui-node-editor/imgui_node_editor_api.cpp b/3rdparty/imgui-node-editor/imgui_node_editor_api.cpp new file mode 100644 index 0000000..7433085 --- /dev/null +++ b/3rdparty/imgui-node-editor/imgui_node_editor_api.cpp @@ -0,0 +1,774 @@ +//Disable a bunch of warnings for now +#ifndef _MSC_VER +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wshadow" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//------------------------------------------------------------------------------ +// VERSION 0.9.1 +// +// LICENSE +// This software is dual-licensed to the public domain and under the following +// license: you are granted a perpetual, irrevocable license to copy, modify, +// publish, and distribute this file as you see fit. +// +// CREDITS +// Written by Michal Cichon +//------------------------------------------------------------------------------ +# include "imgui_node_editor_internal.h" +# include + + +//------------------------------------------------------------------------------ +static ax::NodeEditor::Detail::EditorContext* s_Editor = nullptr; + + +//------------------------------------------------------------------------------ +template +static int BuildIdList(C& container, I* list, int listSize, F&& accept) +{ + if (list != nullptr) + { + int count = 0; + for (auto object : container) + { + if (listSize <= 0) + break; + + if (accept(object)) + { + list[count] = I(object->ID().AsPointer()); + ++count; + --listSize;} + } + + return count; + } + else + return static_cast(std::count_if(container.begin(), container.end(), accept)); +} + + +//------------------------------------------------------------------------------ +ax::NodeEditor::EditorContext* ax::NodeEditor::CreateEditor(const Config* config) +{ + return reinterpret_cast(new ax::NodeEditor::Detail::EditorContext(config)); +} + +void ax::NodeEditor::DestroyEditor(EditorContext* ctx) +{ + auto lastContext = GetCurrentEditor(); + + // Set context we're about to destroy as current, to give callback valid context + if (lastContext != ctx) + SetCurrentEditor(ctx); + + auto editor = reinterpret_cast(ctx); + + delete editor; + + if (lastContext != ctx) + SetCurrentEditor(lastContext); +} + +const ax::NodeEditor::Config& ax::NodeEditor::GetConfig(EditorContext* ctx) +{ + if (ctx == nullptr) + ctx = GetCurrentEditor(); + + if (ctx) + { + auto editor = reinterpret_cast(ctx); + + return editor->GetConfig(); + } + else + { + static Config s_EmptyConfig; + return s_EmptyConfig; + } +} + +void ax::NodeEditor::SetCurrentEditor(EditorContext* ctx) +{ + s_Editor = reinterpret_cast(ctx); +} + +ax::NodeEditor::EditorContext* ax::NodeEditor::GetCurrentEditor() +{ + return reinterpret_cast(s_Editor); +} + +ax::NodeEditor::Style& ax::NodeEditor::GetStyle() +{ + return s_Editor->GetStyle(); +} + +const char* ax::NodeEditor::GetStyleColorName(StyleColor colorIndex) +{ + return s_Editor->GetStyle().GetColorName(colorIndex); +} + +void ax::NodeEditor::PushStyleColor(StyleColor colorIndex, const ImVec4& color) +{ + s_Editor->GetStyle().PushColor(colorIndex, color); +} + +void ax::NodeEditor::PopStyleColor(int count) +{ + s_Editor->GetStyle().PopColor(count); +} + +void ax::NodeEditor::PushStyleVar(StyleVar varIndex, float value) +{ + s_Editor->GetStyle().PushVar(varIndex, value); +} + +void ax::NodeEditor::PushStyleVar(StyleVar varIndex, const ImVec2& value) +{ + s_Editor->GetStyle().PushVar(varIndex, value); +} + +void ax::NodeEditor::PushStyleVar(StyleVar varIndex, const ImVec4& value) +{ + s_Editor->GetStyle().PushVar(varIndex, value); +} + +void ax::NodeEditor::PopStyleVar(int count) +{ + s_Editor->GetStyle().PopVar(count); +} + +void ax::NodeEditor::Begin(const char* id, const ImVec2& size) +{ + s_Editor->Begin(id, size); +} + +void ax::NodeEditor::End() +{ + s_Editor->End(); +} + +void ax::NodeEditor::BeginNode(NodeId id) +{ + s_Editor->GetNodeBuilder().Begin(id); +} + +void ax::NodeEditor::BeginPin(PinId id, PinKind kind) +{ + s_Editor->GetNodeBuilder().BeginPin(id, kind); +} + +void ax::NodeEditor::PinRect(const ImVec2& a, const ImVec2& b) +{ + s_Editor->GetNodeBuilder().PinRect(a, b); +} + +void ax::NodeEditor::PinPivotRect(const ImVec2& a, const ImVec2& b) +{ + s_Editor->GetNodeBuilder().PinPivotRect(a, b); +} + +void ax::NodeEditor::PinPivotSize(const ImVec2& size) +{ + s_Editor->GetNodeBuilder().PinPivotSize(size); +} + +void ax::NodeEditor::PinPivotScale(const ImVec2& scale) +{ + s_Editor->GetNodeBuilder().PinPivotScale(scale); +} + +void ax::NodeEditor::PinPivotAlignment(const ImVec2& alignment) +{ + s_Editor->GetNodeBuilder().PinPivotAlignment(alignment); +} + +void ax::NodeEditor::EndPin() +{ + s_Editor->GetNodeBuilder().EndPin(); +} + +void ax::NodeEditor::Group(const ImVec2& size) +{ + s_Editor->GetNodeBuilder().Group(size); +} + +void ax::NodeEditor::EndNode() +{ + s_Editor->GetNodeBuilder().End(); +} + +bool ax::NodeEditor::BeginGroupHint(NodeId nodeId) +{ + return s_Editor->GetHintBuilder().Begin(nodeId); +} + +ImVec2 ax::NodeEditor::GetGroupMin() +{ + return s_Editor->GetHintBuilder().GetGroupMin(); +} + +ImVec2 ax::NodeEditor::GetGroupMax() +{ + return s_Editor->GetHintBuilder().GetGroupMax(); +} + +ImDrawList* ax::NodeEditor::GetHintForegroundDrawList() +{ + return s_Editor->GetHintBuilder().GetForegroundDrawList(); +} + +ImDrawList* ax::NodeEditor::GetHintBackgroundDrawList() +{ + return s_Editor->GetHintBuilder().GetBackgroundDrawList(); +} + +void ax::NodeEditor::EndGroupHint() +{ + s_Editor->GetHintBuilder().End(); +} + +ImDrawList* ax::NodeEditor::GetNodeBackgroundDrawList(NodeId nodeId) +{ + if (auto node = s_Editor->FindNode(nodeId)) + return s_Editor->GetNodeBuilder().GetUserBackgroundDrawList(node); + else + return nullptr; +} + +bool ax::NodeEditor::Link(LinkId id, PinId startPinId, PinId endPinId, const ImVec4& color/* = ImVec4(1, 1, 1, 1)*/, float thickness/* = 1.0f*/) +{ + return s_Editor->DoLink(id, startPinId, endPinId, ImColor(color), thickness); +} + +void ax::NodeEditor::Flow(LinkId linkId, FlowDirection direction) +{ + if (auto link = s_Editor->FindLink(linkId)) + s_Editor->Flow(link, direction); +} + +bool ax::NodeEditor::BeginCreate(const ImVec4& color, float thickness) +{ + auto& context = s_Editor->GetItemCreator(); + + if (context.Begin()) + { + context.SetStyle(ImColor(color), thickness); + return true; + } + else + return false; +} + +bool ax::NodeEditor::QueryNewLink(PinId* startId, PinId* endId) +{ + using Result = ax::NodeEditor::Detail::CreateItemAction::Result; + + auto& context = s_Editor->GetItemCreator(); + + return context.QueryLink(startId, endId) == Result::True; +} + +bool ax::NodeEditor::QueryNewLink(PinId* startId, PinId* endId, const ImVec4& color, float thickness) +{ + using Result = ax::NodeEditor::Detail::CreateItemAction::Result; + + auto& context = s_Editor->GetItemCreator(); + + auto result = context.QueryLink(startId, endId); + if (result != Result::Indeterminate) + context.SetStyle(ImColor(color), thickness); + + return result == Result::True; +} + +bool ax::NodeEditor::QueryNewNode(PinId* pinId) +{ + using Result = ax::NodeEditor::Detail::CreateItemAction::Result; + + auto& context = s_Editor->GetItemCreator(); + + return context.QueryNode(pinId) == Result::True; +} + +bool ax::NodeEditor::QueryNewNode(PinId* pinId, const ImVec4& color, float thickness) +{ + using Result = ax::NodeEditor::Detail::CreateItemAction::Result; + + auto& context = s_Editor->GetItemCreator(); + + auto result = context.QueryNode(pinId); + if (result != Result::Indeterminate) + context.SetStyle(ImColor(color), thickness); + + return result == Result::True; +} + +bool ax::NodeEditor::AcceptNewItem() +{ + using Result = ax::NodeEditor::Detail::CreateItemAction::Result; + + auto& context = s_Editor->GetItemCreator(); + + return context.AcceptItem() == Result::True; +} + +bool ax::NodeEditor::AcceptNewItem(const ImVec4& color, float thickness) +{ + using Result = ax::NodeEditor::Detail::CreateItemAction::Result; + + auto& context = s_Editor->GetItemCreator(); + + auto result = context.AcceptItem(); + if (result != Result::Indeterminate) + context.SetStyle(ImColor(color), thickness); + + return result == Result::True; +} + +void ax::NodeEditor::RejectNewItem() +{ + auto& context = s_Editor->GetItemCreator(); + + context.RejectItem(); +} + +void ax::NodeEditor::RejectNewItem(const ImVec4& color, float thickness) +{ + using Result = ax::NodeEditor::Detail::CreateItemAction::Result; + + auto& context = s_Editor->GetItemCreator(); + + if (context.RejectItem() != Result::Indeterminate) + context.SetStyle(ImColor(color), thickness); +} + +void ax::NodeEditor::EndCreate() +{ + auto& context = s_Editor->GetItemCreator(); + + context.End(); +} + +bool ax::NodeEditor::BeginDelete() +{ + auto& context = s_Editor->GetItemDeleter(); + + return context.Begin(); +} + +bool ax::NodeEditor::QueryDeletedLink(LinkId* linkId, PinId* startId, PinId* endId) +{ + auto& context = s_Editor->GetItemDeleter(); + + return context.QueryLink(linkId, startId, endId); +} + +bool ax::NodeEditor::QueryDeletedNode(NodeId* nodeId) +{ + auto& context = s_Editor->GetItemDeleter(); + + return context.QueryNode(nodeId); +} + +bool ax::NodeEditor::AcceptDeletedItem(bool deleteDependencies) +{ + auto& context = s_Editor->GetItemDeleter(); + + return context.AcceptItem(deleteDependencies); +} + +void ax::NodeEditor::RejectDeletedItem() +{ + auto& context = s_Editor->GetItemDeleter(); + + context.RejectItem(); +} + +void ax::NodeEditor::EndDelete() +{ + auto& context = s_Editor->GetItemDeleter(); + + context.End(); +} + +void ax::NodeEditor::SetNodePosition(NodeId nodeId, const ImVec2& position) +{ + s_Editor->SetNodePosition(nodeId, position); +} + +void ax::NodeEditor::SetGroupSize(NodeId nodeId, const ImVec2& size) +{ + s_Editor->SetGroupSize(nodeId, size); +} + +ImVec2 ax::NodeEditor::GetNodePosition(NodeId nodeId) +{ + return s_Editor->GetNodePosition(nodeId); +} + +ImVec2 ax::NodeEditor::GetNodeSize(NodeId nodeId) +{ + return s_Editor->GetNodeSize(nodeId); +} + +void ax::NodeEditor::CenterNodeOnScreen(NodeId nodeId) +{ + if (auto node = s_Editor->FindNode(nodeId)) + node->CenterOnScreenInNextFrame(); +} + +void ax::NodeEditor::SetNodeZPosition(NodeId nodeId, float z) +{ + s_Editor->SetNodeZPosition(nodeId, z); +} + +float ax::NodeEditor::GetNodeZPosition(NodeId nodeId) +{ + return s_Editor->GetNodeZPosition(nodeId); +} + +void ax::NodeEditor::RestoreNodeState(NodeId nodeId) +{ + if (auto node = s_Editor->FindNode(nodeId)) + s_Editor->MarkNodeToRestoreState(node); +} + +void ax::NodeEditor::Suspend() +{ + s_Editor->Suspend(); +} + +void ax::NodeEditor::Resume() +{ + s_Editor->Resume(); +} + +bool ax::NodeEditor::IsSuspended() +{ + return s_Editor->IsSuspended(); +} + +bool ax::NodeEditor::IsActive() +{ + return s_Editor->IsFocused(); +} + +bool ax::NodeEditor::HasSelectionChanged() +{ + return s_Editor->HasSelectionChanged(); +} + +int ax::NodeEditor::GetSelectedObjectCount() +{ + return (int)s_Editor->GetSelectedObjects().size(); +} + +int ax::NodeEditor::GetSelectedNodes(NodeId* nodes, int size) +{ + return BuildIdList(s_Editor->GetSelectedObjects(), nodes, size, [](auto object) + { + return object->AsNode() != nullptr; + }); +} + +int ax::NodeEditor::GetSelectedLinks(LinkId* links, int size) +{ + return BuildIdList(s_Editor->GetSelectedObjects(), links, size, [](auto object) + { + return object->AsLink() != nullptr; + }); +} + +bool ax::NodeEditor::IsNodeSelected(NodeId nodeId) +{ + if (auto node = s_Editor->FindNode(nodeId)) + return s_Editor->IsSelected(node); + else + return false; +} + +bool ax::NodeEditor::IsLinkSelected(LinkId linkId) +{ + if (auto link = s_Editor->FindLink(linkId)) + return s_Editor->IsSelected(link); + else + return false; +} + +void ax::NodeEditor::ClearSelection() +{ + s_Editor->ClearSelection(); +} + +void ax::NodeEditor::SelectNode(NodeId nodeId, bool append) +{ + if (auto node = s_Editor->FindNode(nodeId)) + { + if (append) + s_Editor->SelectObject(node); + else + s_Editor->SetSelectedObject(node); + } +} + +void ax::NodeEditor::SelectLink(LinkId linkId, bool append) +{ + if (auto link = s_Editor->FindLink(linkId)) + { + if (append) + s_Editor->SelectObject(link); + else + s_Editor->SetSelectedObject(link); + } +} + +void ax::NodeEditor::DeselectNode(NodeId nodeId) +{ + if (auto node = s_Editor->FindNode(nodeId)) + s_Editor->DeselectObject(node); +} + +void ax::NodeEditor::DeselectLink(LinkId linkId) +{ + if (auto link = s_Editor->FindLink(linkId)) + s_Editor->DeselectObject(link); +} + +bool ax::NodeEditor::DeleteNode(NodeId nodeId) +{ + if (auto node = s_Editor->FindNode(nodeId)) + return s_Editor->GetItemDeleter().Add(node); + else + return false; +} + +bool ax::NodeEditor::DeleteLink(LinkId linkId) +{ + if (auto link = s_Editor->FindLink(linkId)) + return s_Editor->GetItemDeleter().Add(link); + else + return false; +} + +bool ax::NodeEditor::HasAnyLinks(NodeId nodeId) +{ + return s_Editor->HasAnyLinks(nodeId); +} + +bool ax::NodeEditor::HasAnyLinks(PinId pinId) +{ + return s_Editor->HasAnyLinks(pinId); +} + +int ax::NodeEditor::BreakLinks(NodeId nodeId) +{ + return s_Editor->BreakLinks(nodeId); +} + +int ax::NodeEditor::BreakLinks(PinId pinId) +{ + return s_Editor->BreakLinks(pinId); +} + +void ax::NodeEditor::NavigateToContent(float duration) +{ + s_Editor->NavigateTo(s_Editor->GetContentBounds(), true, duration); +} + +void ax::NodeEditor::NavigateToSelection(bool zoomIn, float duration) +{ + s_Editor->NavigateTo(s_Editor->GetSelectionBounds(), zoomIn, duration); +} + +bool ax::NodeEditor::ShowNodeContextMenu(NodeId* nodeId) +{ + return s_Editor->GetContextMenu().ShowNodeContextMenu(nodeId); +} + +bool ax::NodeEditor::ShowPinContextMenu(PinId* pinId) +{ + return s_Editor->GetContextMenu().ShowPinContextMenu(pinId); +} + +bool ax::NodeEditor::ShowLinkContextMenu(LinkId* linkId) +{ + return s_Editor->GetContextMenu().ShowLinkContextMenu(linkId); +} + +bool ax::NodeEditor::ShowBackgroundContextMenu() +{ + return s_Editor->GetContextMenu().ShowBackgroundContextMenu(); +} + +void ax::NodeEditor::EnableShortcuts(bool enable) +{ + s_Editor->EnableShortcuts(enable); +} + +bool ax::NodeEditor::AreShortcutsEnabled() +{ + return s_Editor->AreShortcutsEnabled(); +} + +bool ax::NodeEditor::BeginShortcut() +{ + return s_Editor->GetShortcut().Begin(); +} + +bool ax::NodeEditor::AcceptCut() +{ + return s_Editor->GetShortcut().AcceptCut(); +} + +bool ax::NodeEditor::AcceptCopy() +{ + return s_Editor->GetShortcut().AcceptCopy(); +} + +bool ax::NodeEditor::AcceptPaste() +{ + return s_Editor->GetShortcut().AcceptPaste(); +} + +bool ax::NodeEditor::AcceptDuplicate() +{ + return s_Editor->GetShortcut().AcceptDuplicate(); +} + +bool ax::NodeEditor::AcceptCreateNode() +{ + return s_Editor->GetShortcut().AcceptCreateNode(); +} + +int ax::NodeEditor::GetActionContextSize() +{ + return static_cast(s_Editor->GetShortcut().m_Context.size()); +} + +int ax::NodeEditor::GetActionContextNodes(NodeId* nodes, int size) +{ + return BuildIdList(s_Editor->GetSelectedObjects(), nodes, size, [](auto object) + { + return object->AsNode() != nullptr; + }); +} + +int ax::NodeEditor::GetActionContextLinks(LinkId* links, int size) +{ + return BuildIdList(s_Editor->GetSelectedObjects(), links, size, [](auto object) + { + return object->AsLink() != nullptr; + }); +} + +void ax::NodeEditor::EndShortcut() +{ + return s_Editor->GetShortcut().End(); +} + +float ax::NodeEditor::GetCurrentZoom() +{ + return s_Editor->GetView().InvScale; +} + +ax::NodeEditor::NodeId ax::NodeEditor::GetHoveredNode() +{ + return s_Editor->GetHoveredNode(); +} + +ax::NodeEditor::PinId ax::NodeEditor::GetHoveredPin() +{ + return s_Editor->GetHoveredPin(); +} + +ax::NodeEditor::LinkId ax::NodeEditor::GetHoveredLink() +{ + return s_Editor->GetHoveredLink(); +} + +ax::NodeEditor::NodeId ax::NodeEditor::GetDoubleClickedNode() +{ + return s_Editor->GetDoubleClickedNode(); +} + +ax::NodeEditor::PinId ax::NodeEditor::GetDoubleClickedPin() +{ + return s_Editor->GetDoubleClickedPin(); +} + +ax::NodeEditor::LinkId ax::NodeEditor::GetDoubleClickedLink() +{ + return s_Editor->GetDoubleClickedLink(); +} + +bool ax::NodeEditor::IsBackgroundClicked() +{ + return s_Editor->IsBackgroundClicked(); +} + +bool ax::NodeEditor::IsBackgroundDoubleClicked() +{ + return s_Editor->IsBackgroundDoubleClicked(); +} + +ImGuiMouseButton ax::NodeEditor::GetBackgroundClickButtonIndex() +{ + return s_Editor->GetBackgroundClickButtonIndex(); +} + +ImGuiMouseButton ax::NodeEditor::GetBackgroundDoubleClickButtonIndex() +{ + return s_Editor->GetBackgroundDoubleClickButtonIndex(); +} + +bool ax::NodeEditor::GetLinkPins(LinkId linkId, PinId* startPinId, PinId* endPinId) +{ + auto link = s_Editor->FindLink(linkId); + if (!link) + return false; + + if (startPinId) + *startPinId = link->m_StartPin->m_ID; + if (endPinId) + *endPinId = link->m_EndPin->m_ID; + + return true; +} + +bool ax::NodeEditor::PinHadAnyLinks(PinId pinId) +{ + return s_Editor->PinHadAnyLinks(pinId); +} + +ImVec2 ax::NodeEditor::GetScreenSize() +{ + return s_Editor->GetRect().GetSize(); +} + +ImVec2 ax::NodeEditor::ScreenToCanvas(const ImVec2& pos) +{ + return s_Editor->ToCanvas(pos); +} + +ImVec2 ax::NodeEditor::CanvasToScreen(const ImVec2& pos) +{ + return s_Editor->ToScreen(pos); +} + +int ax::NodeEditor::GetNodeCount() +{ + return s_Editor->CountLiveNodes(); +} + +int ax::NodeEditor::GetOrderedNodeIds(NodeId* nodes, int size) +{ + return s_Editor->GetNodeIds(nodes, size); +} + +//Disable a bunch of warnings for now +#ifndef _MSC_VER +#pragma GCC diagnostic pop +#endif diff --git a/3rdparty/imgui-node-editor/imgui_node_editor_internal.h b/3rdparty/imgui-node-editor/imgui_node_editor_internal.h new file mode 100644 index 0000000..fd2bfac --- /dev/null +++ b/3rdparty/imgui-node-editor/imgui_node_editor_internal.h @@ -0,0 +1,1568 @@ +//Disable a bunch of warnings for now +#ifndef _MSC_VER +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wshadow" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//------------------------------------------------------------------------------ +// VERSION 0.9.1 +// +// LICENSE +// This software is dual-licensed to the public domain and under the following +// license: you are granted a perpetual, irrevocable license to copy, modify, +// publish, and distribute this file as you see fit. +// +// CREDITS +// Written by Michal Cichon +//------------------------------------------------------------------------------ +# ifndef __IMGUI_NODE_EDITOR_INTERNAL_H__ +# define __IMGUI_NODE_EDITOR_INTERNAL_H__ +# pragma once + + +//------------------------------------------------------------------------------ +# include "imgui_node_editor.h" + + +//------------------------------------------------------------------------------ +# include +# define IMGUI_DEFINE_MATH_OPERATORS +# include +# include "imgui_extra_math.h" +# include "imgui_bezier_math.h" +# include "imgui_canvas.h" + +# include "crude_json.h" + +# include +# include + + +//------------------------------------------------------------------------------ +namespace ax { +namespace NodeEditor { +namespace Detail { + + +//------------------------------------------------------------------------------ +namespace ed = ax::NodeEditor::Detail; +namespace json = crude_json; + + +//------------------------------------------------------------------------------ +using std::vector; +using std::string; + + +//------------------------------------------------------------------------------ +void Log(const char* fmt, ...); + + +//------------------------------------------------------------------------------ +//inline ImRect ToRect(const ax::rectf& rect); +//inline ImRect ToRect(const ax::rect& rect); +inline ImRect ImGui_GetItemRect(); +inline ImVec2 ImGui_GetMouseClickPos(ImGuiMouseButton buttonIndex); + + +//------------------------------------------------------------------------------ +// https://stackoverflow.com/a/36079786 +# define DECLARE_HAS_MEMBER(__trait_name__, __member_name__) \ + \ + template \ + class __trait_name__ \ + { \ + using check_type = ::std::remove_const_t<__boost_has_member_T__>; \ + struct no_type {char x[2];}; \ + using yes_type = char; \ + \ + struct base { void __member_name__() {}}; \ + struct mixin : public base, public check_type {}; \ + \ + template struct aux {}; \ + \ + template static no_type test(aux<&U::__member_name__>*); \ + template static yes_type test(...); \ + \ + public: \ + \ + static constexpr bool value = (sizeof(yes_type) == sizeof(test(0))); \ + } + +DECLARE_HAS_MEMBER(HasFringeScale, _FringeScale); + +# undef DECLARE_HAS_MEMBER + +struct FringeScaleRef +{ + // Overload is present when ImDrawList does have _FringeScale member variable. + template + static float& Get(typename std::enable_if::value, T>::type* drawList) + { + return drawList->_FringeScale; + } + + // Overload is present when ImDrawList does not have _FringeScale member variable. + template + static float& Get(typename std::enable_if::value, T>::type*) + { + static float placeholder = 1.0f; + return placeholder; + } +}; + +static inline float& ImFringeScaleRef(ImDrawList* drawList) +{ + return FringeScaleRef::Get(drawList); +} + +struct FringeScaleScope +{ + + FringeScaleScope(float scale) + : m_LastFringeScale(ImFringeScaleRef(ImGui::GetWindowDrawList())) + { + ImFringeScaleRef(ImGui::GetWindowDrawList()) = scale; + } + + ~FringeScaleScope() + { + ImFringeScaleRef(ImGui::GetWindowDrawList()) = m_LastFringeScale; + } + +private: + float m_LastFringeScale; +}; + + +//------------------------------------------------------------------------------ +enum class ObjectType +{ + None, + Node, + Link, + Pin +}; + +using ax::NodeEditor::PinKind; +using ax::NodeEditor::StyleColor; +using ax::NodeEditor::StyleVar; +using ax::NodeEditor::SaveReasonFlags; + +using ax::NodeEditor::NodeId; +using ax::NodeEditor::PinId; +using ax::NodeEditor::LinkId; + +struct ObjectId final: Details::SafePointerType +{ + using Super = Details::SafePointerType; + using Super::Super; + + ObjectId(): Super(Invalid), m_Type(ObjectType::None) {} + ObjectId(PinId pinId): Super(pinId.AsPointer()), m_Type(ObjectType::Pin) {} + ObjectId(NodeId nodeId): Super(nodeId.AsPointer()), m_Type(ObjectType::Node) {} + ObjectId(LinkId linkId): Super(linkId.AsPointer()), m_Type(ObjectType::Link) {} + + explicit operator PinId() const { return AsPinId(); } + explicit operator NodeId() const { return AsNodeId(); } + explicit operator LinkId() const { return AsLinkId(); } + + PinId AsPinId() const { IM_ASSERT(IsPinId()); return PinId(AsPointer()); } + NodeId AsNodeId() const { IM_ASSERT(IsNodeId()); return NodeId(AsPointer()); } + LinkId AsLinkId() const { IM_ASSERT(IsLinkId()); return LinkId(AsPointer()); } + + bool IsPinId() const { return m_Type == ObjectType::Pin; } + bool IsNodeId() const { return m_Type == ObjectType::Node; } + bool IsLinkId() const { return m_Type == ObjectType::Link; } + + ObjectType Type() const { return m_Type; } + +private: + ObjectType m_Type; +}; + +struct EditorContext; + +struct Node; +struct Pin; +struct Link; + +template +struct ObjectWrapper +{ + Id m_ID; + T* m_Object; + + T* operator->() { return m_Object; } + const T* operator->() const { return m_Object; } + + operator T*() { return m_Object; } + operator const T*() const { return m_Object; } + + bool operator<(const ObjectWrapper& rhs) const + { + return m_ID.AsPointer() < rhs.m_ID.AsPointer(); + } +}; + +struct Object +{ + enum DrawFlags + { + None = 0, + Hovered = 1, + Selected = 2, + Highlighted = 4, + }; + + inline friend DrawFlags operator|(DrawFlags lhs, DrawFlags rhs) { return static_cast(static_cast(lhs) | static_cast(rhs)); } + inline friend DrawFlags operator&(DrawFlags lhs, DrawFlags rhs) { return static_cast(static_cast(lhs) & static_cast(rhs)); } + inline friend DrawFlags& operator|=(DrawFlags& lhs, DrawFlags rhs) { lhs = lhs | rhs; return lhs; } + inline friend DrawFlags& operator&=(DrawFlags& lhs, DrawFlags rhs) { lhs = lhs & rhs; return lhs; } + + EditorContext* const Editor; + + bool m_IsLive; + bool m_IsSelected; + bool m_DeleteOnNewFrame; + + Object(EditorContext* editor) + : Editor(editor) + , m_IsLive(true) + , m_IsSelected(false) + , m_DeleteOnNewFrame(false) + { + } + + virtual ~Object() = default; + + virtual ObjectId ID() = 0; + + bool IsVisible() const + { + if (!m_IsLive) + return false; + + const auto bounds = GetBounds(); + + return ImGui::IsRectVisible(bounds.Min, bounds.Max); + } + + virtual void Reset() { m_IsLive = false; } + + virtual void Draw(ImDrawList* drawList, DrawFlags flags = None) = 0; + + virtual bool AcceptDrag() { return false; } + virtual void UpdateDrag(const ImVec2& offset) { IM_UNUSED(offset); } + virtual bool EndDrag() { return false; } + virtual ImVec2 DragStartLocation() { return GetBounds().Min; } + + virtual bool IsDraggable() { bool result = AcceptDrag(); EndDrag(); return result; } + virtual bool IsSelectable() { return false; } + + virtual bool TestHit(const ImVec2& point, float extraThickness = 0.0f) const + { + if (!m_IsLive) + return false; + + auto bounds = GetBounds(); + if (extraThickness > 0) + bounds.Expand(extraThickness); + + return bounds.Contains(point); + } + + virtual bool TestHit(const ImRect& rect, bool allowIntersect = true) const + { + if (!m_IsLive) + return false; + + const auto bounds = GetBounds(); + + return !ImRect_IsEmpty(bounds) && (allowIntersect ? bounds.Overlaps(rect) : rect.Contains(bounds)); + } + + virtual ImRect GetBounds() const = 0; + + virtual Node* AsNode() { return nullptr; } + virtual Pin* AsPin() { return nullptr; } + virtual Link* AsLink() { return nullptr; } +}; + +struct Pin final: Object +{ + using IdType = PinId; + + PinId m_ID; + PinKind m_Kind; + Node* m_Node; + ImRect m_Bounds; + ImRect m_Pivot; + Pin* m_PreviousPin; + ImU32 m_Color; + ImU32 m_BorderColor; + float m_BorderWidth; + float m_Rounding; + int m_Corners; + ImVec2 m_Dir; + float m_Strength; + float m_Radius; + float m_ArrowSize; + float m_ArrowWidth; + bool m_SnapLinkToDir; + bool m_HasConnection; + bool m_HadConnection; + + Pin(EditorContext* editor, PinId id, PinKind kind) + : Object(editor) + , m_ID(id) + , m_Kind(kind) + , m_Node(nullptr) + , m_Bounds() + , m_PreviousPin(nullptr) + , m_Color(IM_COL32_WHITE) + , m_BorderColor(IM_COL32_BLACK) + , m_BorderWidth(0) + , m_Rounding(0) + , m_Corners(0) + , m_Dir(0, 0) + , m_Strength(0) + , m_Radius(0) + , m_ArrowSize(0) + , m_ArrowWidth(0) + , m_SnapLinkToDir(true) + , m_HasConnection(false) + , m_HadConnection(false) + { + } + + virtual ObjectId ID() override { return m_ID; } + + virtual void Reset() override final + { + m_HadConnection = m_HasConnection && m_IsLive; + m_HasConnection = false; + + Object::Reset(); + } + + virtual void Draw(ImDrawList* drawList, DrawFlags flags = None) override final; + + ImVec2 GetClosestPoint(const ImVec2& p) const; + ImLine GetClosestLine(const Pin* pin) const; + + virtual ImRect GetBounds() const override final { return m_Bounds; } + + virtual Pin* AsPin() override final { return this; } +}; + +enum class NodeType +{ + Node, + Group +}; + +enum class NodeRegion : uint8_t +{ + None = 0x00, + Top = 0x01, + Bottom = 0x02, + Left = 0x04, + Right = 0x08, + Center = 0x10, + Header = 0x20, + TopLeft = Top | Left, + TopRight = Top | Right, + BottomLeft = Bottom | Left, + BottomRight = Bottom | Right, +}; + +inline NodeRegion operator |(NodeRegion lhs, NodeRegion rhs) { return static_cast(static_cast(lhs) | static_cast(rhs)); } +inline NodeRegion operator &(NodeRegion lhs, NodeRegion rhs) { return static_cast(static_cast(lhs) & static_cast(rhs)); } + + +struct Node final: Object +{ + using IdType = NodeId; + + NodeId m_ID; + NodeType m_Type; + ImRect m_Bounds; + float m_ZPosition; + int m_Channel; + Pin* m_LastPin; + ImVec2 m_DragStart; + + ImU32 m_Color; + ImU32 m_BorderColor; + float m_BorderWidth; + float m_Rounding; + + ImU32 m_GroupColor; + ImU32 m_GroupBorderColor; + float m_GroupBorderWidth; + float m_GroupRounding; + ImRect m_GroupBounds; + + bool m_HighlightConnectedLinks; + + bool m_RestoreState; + bool m_CenterOnScreen; + + Node(EditorContext* editor, NodeId id) + : Object(editor) + , m_ID(id) + , m_Type(NodeType::Node) + , m_Bounds() + , m_ZPosition(0.0f) + , m_Channel(0) + , m_LastPin(nullptr) + , m_DragStart() + , m_Color(IM_COL32_WHITE) + , m_BorderColor(IM_COL32_BLACK) + , m_BorderWidth(0) + , m_Rounding(0) + , m_GroupBounds() + , m_HighlightConnectedLinks(false) + , m_RestoreState(false) + , m_CenterOnScreen(false) + { + } + + virtual ObjectId ID() override { return m_ID; } + + bool AcceptDrag() override; + void UpdateDrag(const ImVec2& offset) override; + bool EndDrag() override; // return true, when changed + ImVec2 DragStartLocation() override { return m_DragStart; } + + virtual bool IsSelectable() override { return true; } + + virtual void Draw(ImDrawList* drawList, DrawFlags flags = None) override final; + void DrawBorder(ImDrawList* drawList, ImU32 color, float thickness = 1.0f); + + void GetGroupedNodes(std::vector& result, bool append = false); + + void CenterOnScreenInNextFrame() { m_CenterOnScreen = true; } + + ImRect GetRegionBounds(NodeRegion region) const; + NodeRegion GetRegion(const ImVec2& point) const; + + virtual ImRect GetBounds() const override final { return m_Bounds; } + + virtual Node* AsNode() override final { return this; } +}; + +struct Link final: Object +{ + using IdType = LinkId; + + LinkId m_ID; + Pin* m_StartPin; + Pin* m_EndPin; + ImU32 m_Color; + ImU32 m_HighlightColor; + float m_Thickness; + ImVec2 m_Start; + ImVec2 m_End; + + Link(EditorContext* editor, LinkId id) + : Object(editor) + , m_ID(id) + , m_StartPin(nullptr) + , m_EndPin(nullptr) + , m_Color(IM_COL32_WHITE) + , m_Thickness(1.0f) + { + } + + virtual ObjectId ID() override { return m_ID; } + + virtual bool IsSelectable() override { return true; } + + virtual void Draw(ImDrawList* drawList, DrawFlags flags = None) override final; + void Draw(ImDrawList* drawList, ImU32 color, float extraThickness = 0.0f) const; + + void UpdateEndpoints(); + + ImCubicBezierPoints GetCurve() const; + + virtual bool TestHit(const ImVec2& point, float extraThickness = 0.0f) const override final; + virtual bool TestHit(const ImRect& rect, bool allowIntersect = true) const override final; + + virtual ImRect GetBounds() const override final; + + virtual Link* AsLink() override final { return this; } +}; + +struct NodeSettings +{ + NodeId m_ID; + ImVec2 m_Location; + ImVec2 m_Size; + ImVec2 m_GroupSize; + bool m_WasUsed; + + bool m_Saved; + bool m_IsDirty; + SaveReasonFlags m_DirtyReason; + + NodeSettings(NodeId id) + : m_ID(id) + , m_Location(0, 0) + , m_Size(0, 0) + , m_GroupSize(0, 0) + , m_WasUsed(false) + , m_Saved(false) + , m_IsDirty(false) + , m_DirtyReason(SaveReasonFlags::None) + { + } + + void ClearDirty(); + void MakeDirty(SaveReasonFlags reason); + + json::value Serialize(); + + static bool Parse(const std::string& string, NodeSettings& settings); + static bool Parse(const json::value& data, NodeSettings& result); +}; + +struct Settings +{ + bool m_IsDirty; + SaveReasonFlags m_DirtyReason; + + vector m_Nodes; + vector m_Selection; + ImVec2 m_ViewScroll; + float m_ViewZoom; + ImRect m_VisibleRect; + + Settings() + : m_IsDirty(false) + , m_DirtyReason(SaveReasonFlags::None) + , m_ViewScroll(0, 0) + , m_ViewZoom(1.0f) + , m_VisibleRect() + { + } + + NodeSettings* AddNode(NodeId id); + NodeSettings* FindNode(NodeId id); + void RemoveNode(NodeId id); + + void ClearDirty(Node* node = nullptr); + void MakeDirty(SaveReasonFlags reason, Node* node = nullptr); + + std::string Serialize(); + + static bool Parse(const std::string& string, Settings& settings); +}; + +struct Control +{ + Object* HotObject; + Object* ActiveObject; + Object* ClickedObject; + Object* DoubleClickedObject; + Node* HotNode; + Node* ActiveNode; + Node* ClickedNode; + Node* DoubleClickedNode; + Pin* HotPin; + Pin* ActivePin; + Pin* ClickedPin; + Pin* DoubleClickedPin; + Link* HotLink; + Link* ActiveLink; + Link* ClickedLink; + Link* DoubleClickedLink; + bool BackgroundHot; + bool BackgroundActive; + int BackgroundClickButtonIndex; + int BackgroundDoubleClickButtonIndex; + + Control() + : Control(nullptr, nullptr, nullptr, nullptr, false, false, -1, -1) + { + } + + Control(Object* hotObject, Object* activeObject, Object* clickedObject, Object* doubleClickedObject, + bool backgroundHot, bool backgroundActive, int backgroundClickButtonIndex, int backgroundDoubleClickButtonIndex) + : HotObject(hotObject) + , ActiveObject(activeObject) + , ClickedObject(clickedObject) + , DoubleClickedObject(doubleClickedObject) + , HotNode(nullptr) + , ActiveNode(nullptr) + , ClickedNode(nullptr) + , DoubleClickedNode(nullptr) + , HotPin(nullptr) + , ActivePin(nullptr) + , ClickedPin(nullptr) + , DoubleClickedPin(nullptr) + , HotLink(nullptr) + , ActiveLink(nullptr) + , ClickedLink(nullptr) + , DoubleClickedLink(nullptr) + , BackgroundHot(backgroundHot) + , BackgroundActive(backgroundActive) + , BackgroundClickButtonIndex(backgroundClickButtonIndex) + , BackgroundDoubleClickButtonIndex(backgroundDoubleClickButtonIndex) + { + if (hotObject) + { + HotNode = hotObject->AsNode(); + HotPin = hotObject->AsPin(); + HotLink = hotObject->AsLink(); + + if (HotPin) + HotNode = HotPin->m_Node; + } + + if (activeObject) + { + ActiveNode = activeObject->AsNode(); + ActivePin = activeObject->AsPin(); + ActiveLink = activeObject->AsLink(); + } + + if (clickedObject) + { + ClickedNode = clickedObject->AsNode(); + ClickedPin = clickedObject->AsPin(); + ClickedLink = clickedObject->AsLink(); + } + + if (doubleClickedObject) + { + DoubleClickedNode = doubleClickedObject->AsNode(); + DoubleClickedPin = doubleClickedObject->AsPin(); + DoubleClickedLink = doubleClickedObject->AsLink(); + } + } +}; + +struct NavigateAction; +struct SizeAction; +struct DragAction; +struct SelectAction; +struct CreateItemAction; +struct DeleteItemsAction; +struct ContextMenuAction; +struct ShortcutAction; + +struct AnimationController; +struct FlowAnimationController; + +struct Animation +{ + enum State + { + Playing, + Stopped + }; + + EditorContext* Editor; + State m_State; + float m_Time; + float m_Duration; + + Animation(EditorContext* editor); + virtual ~Animation(); + + void Play(float duration); + void Stop(); + void Finish(); + void Update(); + + bool IsPlaying() const { return m_State == Playing; } + + float GetProgress() const { return m_Time / m_Duration; } + +protected: + virtual void OnPlay() {} + virtual void OnFinish() {} + virtual void OnStop() {} + + virtual void OnUpdate(float progress) { IM_UNUSED(progress); } +}; + +struct NavigateAnimation final: Animation +{ + NavigateAction& Action; + ImRect m_Start; + ImRect m_Target; + + NavigateAnimation(EditorContext* editor, NavigateAction& scrollAction); + + void NavigateTo(const ImRect& target, float duration); + +private: + void OnUpdate(float progress) override final; + void OnStop() override final; + void OnFinish() override final; +}; + +struct FlowAnimation final: Animation +{ + FlowAnimationController* Controller; + Link* m_Link; + float m_Speed; + float m_MarkerDistance; + float m_Offset; + + FlowAnimation(FlowAnimationController* controller); + + void Flow(Link* link, float markerDistance, float speed, float duration); + + void Draw(ImDrawList* drawList); + +private: + struct CurvePoint + { + float Distance; + ImVec2 Point; + }; + + ImVec2 m_LastStart; + ImVec2 m_LastEnd; + float m_PathLength; + vector m_Path; + + bool IsLinkValid() const; + bool IsPathValid() const; + void UpdatePath(); + void ClearPath(); + + ImVec2 SamplePath(float distance) const; + + void OnUpdate(float progress) override final; + void OnStop() override final; +}; + +struct AnimationController +{ + EditorContext* Editor; + + AnimationController(EditorContext* editor) + : Editor(editor) + { + } + + virtual ~AnimationController() + { + } + + virtual void Draw(ImDrawList* drawList) + { + IM_UNUSED(drawList); + } +}; + +struct FlowAnimationController final : AnimationController +{ + FlowAnimationController(EditorContext* editor); + virtual ~FlowAnimationController(); + + void Flow(Link* link, FlowDirection direction = FlowDirection::Forward); + + virtual void Draw(ImDrawList* drawList) override final; + + void Release(FlowAnimation* animation); + +private: + FlowAnimation* GetOrCreate(Link* link); + + vector m_Animations; + vector m_FreePool; +}; + +struct EditorAction +{ + enum AcceptResult { False, True, Possible }; + + EditorAction(EditorContext* editor) + : Editor(editor) + { + } + + virtual ~EditorAction() {} + + virtual const char* GetName() const = 0; + + virtual AcceptResult Accept(const Control& control) = 0; + virtual bool Process(const Control& control) = 0; + virtual void Reject() {} // celled when Accept return 'Possible' and was rejected + + virtual ImGuiMouseCursor GetCursor() { return ImGuiMouseCursor_Arrow; } + + virtual bool IsDragging() { return false; } + + virtual void ShowMetrics() {} + + virtual NavigateAction* AsNavigate() { return nullptr; } + virtual SizeAction* AsSize() { return nullptr; } + virtual DragAction* AsDrag() { return nullptr; } + virtual SelectAction* AsSelect() { return nullptr; } + virtual CreateItemAction* AsCreateItem() { return nullptr; } + virtual DeleteItemsAction* AsDeleteItems() { return nullptr; } + virtual ContextMenuAction* AsContextMenu() { return nullptr; } + virtual ShortcutAction* AsCutCopyPaste() { return nullptr; } + + EditorContext* Editor; +}; + +struct NavigateAction final: EditorAction +{ + enum class ZoomMode + { + None, + Exact, + WithMargin + }; + + enum class NavigationReason + { + Unknown, + MouseZoom, + Selection, + Object, + Content, + Edge + }; + + bool m_IsActive; + float m_Zoom; + ImRect m_VisibleRect; + ImVec2 m_Scroll; + ImVec2 m_ScrollStart; + ImVec2 m_ScrollDelta; + + NavigateAction(EditorContext* editor, ImGuiEx::Canvas& canvas); + + virtual const char* GetName() const override final { return "Navigate"; } + + virtual AcceptResult Accept(const Control& control) override final; + virtual bool Process(const Control& control) override final; + + virtual void ShowMetrics() override final; + + virtual NavigateAction* AsNavigate() override final { return this; } + + void NavigateTo(const ImRect& bounds, ZoomMode zoomMode, float duration = -1.0f, NavigationReason reason = NavigationReason::Unknown); + void StopNavigation(); + void FinishNavigation(); + + bool MoveOverEdge(const ImVec2& canvasSize); + void StopMoveOverEdge(); + bool IsMovingOverEdge() const { return m_MovingOverEdge; } + ImVec2 GetMoveScreenOffset() const { return m_MoveScreenOffset; } + + void SetWindow(ImVec2 position, ImVec2 size); + ImVec2 GetWindowScreenPos() const { return m_WindowScreenPos; }; + ImVec2 GetWindowScreenSize() const { return m_WindowScreenSize; }; + + ImGuiEx::CanvasView GetView() const; + ImVec2 GetViewOrigin() const; + float GetViewScale() const; + + void SetViewRect(const ImRect& rect); + ImRect GetViewRect() const; + +private: + ImGuiEx::Canvas& m_Canvas; + ImVec2 m_WindowScreenPos; + ImVec2 m_WindowScreenSize; + + NavigateAnimation m_Animation; + NavigationReason m_Reason; + uint64_t m_LastSelectionId; + Object* m_LastObject; + bool m_MovingOverEdge; + ImVec2 m_MoveScreenOffset; + + const float* m_ZoomLevels; + int m_ZoomLevelCount; + + bool HandleZoom(const Control& control); + + void NavigateTo(const ImRect& target, float duration = -1.0f, NavigationReason reason = NavigationReason::Unknown); + + float MatchZoom(int steps, float fallbackZoom); + int MatchZoomIndex(int direction); + + static const float s_DefaultZoomLevels[]; + static const int s_DefaultZoomLevelCount; +}; + +struct SizeAction final: EditorAction +{ + bool m_IsActive; + bool m_Clean; + Node* m_SizedNode; + + SizeAction(EditorContext* editor); + + virtual const char* GetName() const override final { return "Size"; } + + virtual AcceptResult Accept(const Control& control) override final; + virtual bool Process(const Control& control) override final; + + virtual ImGuiMouseCursor GetCursor() override final { return m_Cursor; } + + virtual void ShowMetrics() override final; + + virtual SizeAction* AsSize() override final { return this; } + + virtual bool IsDragging() override final { return m_IsActive; } + + const ImRect& GetStartGroupBounds() const { return m_StartGroupBounds; } + +private: + NodeRegion GetRegion(Node* node); + ImGuiMouseCursor ChooseCursor(NodeRegion region); + + ImRect m_StartBounds; + ImRect m_StartGroupBounds; + ImVec2 m_LastSize; + ImVec2 m_MinimumSize; + ImVec2 m_LastDragOffset; + ed::NodeRegion m_Pivot; + ImGuiMouseCursor m_Cursor; +}; + +struct DragAction final: EditorAction +{ + bool m_IsActive; + bool m_Clear; + Object* m_DraggedObject; + vector m_Objects; + + DragAction(EditorContext* editor); + + virtual const char* GetName() const override final { return "Drag"; } + + virtual AcceptResult Accept(const Control& control) override final; + virtual bool Process(const Control& control) override final; + + virtual ImGuiMouseCursor GetCursor() override final { return ImGuiMouseCursor_ResizeAll; } + + virtual bool IsDragging() override final { return m_IsActive; } + + virtual void ShowMetrics() override final; + + virtual DragAction* AsDrag() override final { return this; } +}; + +struct SelectAction final: EditorAction +{ + bool m_IsActive; + + bool m_SelectGroups; + bool m_SelectLinkMode; + bool m_CommitSelection; + ImVec2 m_StartPoint; + ImVec2 m_EndPoint; + vector m_CandidateObjects; + vector m_SelectedObjectsAtStart; + + Animation m_Animation; + + SelectAction(EditorContext* editor); + + virtual const char* GetName() const override final { return "Select"; } + + virtual AcceptResult Accept(const Control& control) override final; + virtual bool Process(const Control& control) override final; + + virtual void ShowMetrics() override final; + + virtual bool IsDragging() override final { return m_IsActive; } + + virtual SelectAction* AsSelect() override final { return this; } + + void Draw(ImDrawList* drawList); +}; + +struct ContextMenuAction final: EditorAction +{ + enum Menu { None, Node, Pin, Link, Background }; + + Menu m_CandidateMenu; + Menu m_CurrentMenu; + ObjectId m_ContextId; + + ContextMenuAction(EditorContext* editor); + + virtual const char* GetName() const override final { return "Context Menu"; } + + virtual AcceptResult Accept(const Control& control) override final; + virtual bool Process(const Control& control) override final; + virtual void Reject() override final; + + virtual void ShowMetrics() override final; + + virtual ContextMenuAction* AsContextMenu() override final { return this; } + + bool ShowNodeContextMenu(NodeId* nodeId); + bool ShowPinContextMenu(PinId* pinId); + bool ShowLinkContextMenu(LinkId* linkId); + bool ShowBackgroundContextMenu(); +}; + +struct ShortcutAction final: EditorAction +{ + enum Action { None, Cut, Copy, Paste, Duplicate, CreateNode }; + + bool m_IsActive; + bool m_InAction; + Action m_CurrentAction; + vector m_Context; + + ShortcutAction(EditorContext* editor); + + virtual const char* GetName() const override final { return "Shortcut"; } + + virtual AcceptResult Accept(const Control& control) override final; + virtual bool Process(const Control& control) override final; + virtual void Reject() override final; + + virtual void ShowMetrics() override final; + + virtual ShortcutAction* AsCutCopyPaste() override final { return this; } + + bool Begin(); + void End(); + + bool AcceptCut(); + bool AcceptCopy(); + bool AcceptPaste(); + bool AcceptDuplicate(); + bool AcceptCreateNode(); +}; + +struct CreateItemAction final : EditorAction +{ + enum Stage + { + None, + Possible, + Create + }; + + enum Action + { + Unknown, + UserReject, + UserAccept + }; + + enum Type + { + NoItem, + Node, + Link + }; + + enum Result + { + True, + False, + Indeterminate + }; + + bool m_InActive; + Stage m_NextStage; + + Stage m_CurrentStage; + Type m_ItemType; + Action m_UserAction; + ImU32 m_LinkColor; + float m_LinkThickness; + Pin* m_LinkStart; + Pin* m_LinkEnd; + + bool m_IsActive; + Pin* m_DraggedPin; + + int m_LastChannel = -1; + + + CreateItemAction(EditorContext* editor); + + virtual const char* GetName() const override final { return "Create Item"; } + + virtual AcceptResult Accept(const Control& control) override final; + virtual bool Process(const Control& control) override final; + + virtual ImGuiMouseCursor GetCursor() override final { return ImGuiMouseCursor_Arrow; } + + virtual void ShowMetrics() override final; + + virtual bool IsDragging() override final { return m_IsActive; } + + virtual CreateItemAction* AsCreateItem() override final { return this; } + + void SetStyle(ImU32 color, float thickness); + + bool Begin(); + void End(); + + Result RejectItem(); + Result AcceptItem(); + + Result QueryLink(PinId* startId, PinId* endId); + Result QueryNode(PinId* pinId); + +private: + bool m_IsInGlobalSpace; + + void DragStart(Pin* startPin); + void DragEnd(); + void DropPin(Pin* endPin); + void DropNode(); + void DropNothing(); +}; + +struct DeleteItemsAction final: EditorAction +{ + bool m_IsActive; + bool m_InInteraction; + + DeleteItemsAction(EditorContext* editor); + + virtual const char* GetName() const override final { return "Delete Items"; } + + virtual AcceptResult Accept(const Control& control) override final; + virtual bool Process(const Control& control) override final; + + virtual void ShowMetrics() override final; + + virtual DeleteItemsAction* AsDeleteItems() override final { return this; } + + bool Add(Object* object); + + bool Begin(); + void End(); + + bool QueryLink(LinkId* linkId, PinId* startId = nullptr, PinId* endId = nullptr); + bool QueryNode(NodeId* nodeId); + + bool AcceptItem(bool deleteDependencies); + void RejectItem(); + +private: + enum IteratorType { Unknown, Link, Node }; + enum UserAction { Undetermined, Accepted, Rejected }; + + void DeleteDeadLinks(NodeId nodeId); + void DeleteDeadPins(NodeId nodeId); + + bool QueryItem(ObjectId* itemId, IteratorType itemType); + void RemoveItem(bool deleteDependencies); + Object* DropCurrentItem(); + + vector m_ManuallyDeletedObjects; + + IteratorType m_CurrentItemType; + UserAction m_UserAction; + vector m_CandidateObjects; + int m_CandidateItemIndex; +}; + +struct NodeBuilder +{ + EditorContext* const Editor; + + Node* m_CurrentNode; + Pin* m_CurrentPin; + + ImRect m_NodeRect; + + ImRect m_PivotRect; + ImVec2 m_PivotAlignment; + ImVec2 m_PivotSize; + ImVec2 m_PivotScale; + bool m_ResolvePinRect; + bool m_ResolvePivot; + + ImRect m_GroupBounds; + bool m_IsGroup; + + ImDrawListSplitter m_Splitter; + ImDrawListSplitter m_PinSplitter; + + NodeBuilder(EditorContext* editor); + ~NodeBuilder(); + + void Begin(NodeId nodeId); + void End(); + + void BeginPin(PinId pinId, PinKind kind); + void EndPin(); + + void PinRect(const ImVec2& a, const ImVec2& b); + void PinPivotRect(const ImVec2& a, const ImVec2& b); + void PinPivotSize(const ImVec2& size); + void PinPivotScale(const ImVec2& scale); + void PinPivotAlignment(const ImVec2& alignment); + + void Group(const ImVec2& size); + + ImDrawList* GetUserBackgroundDrawList() const; + ImDrawList* GetUserBackgroundDrawList(Node* node) const; +}; + +struct HintBuilder +{ + EditorContext* const Editor; + bool m_IsActive; + Node* m_CurrentNode; + float m_LastFringe = 1.0f; + int m_LastChannel = 0; + + HintBuilder(EditorContext* editor); + + bool Begin(NodeId nodeId); + void End(); + + ImVec2 GetGroupMin(); + ImVec2 GetGroupMax(); + + ImDrawList* GetForegroundDrawList(); + ImDrawList* GetBackgroundDrawList(); +}; + +struct Style: ax::NodeEditor::Style +{ + void PushColor(StyleColor colorIndex, const ImVec4& color); + void PopColor(int count = 1); + + void PushVar(StyleVar varIndex, float value); + void PushVar(StyleVar varIndex, const ImVec2& value); + void PushVar(StyleVar varIndex, const ImVec4& value); + void PopVar(int count = 1); + + const char* GetColorName(StyleColor colorIndex) const; + +private: + struct ColorModifier + { + StyleColor Index; + ImVec4 Value; + }; + + struct VarModifier + { + StyleVar Index; + ImVec4 Value; + }; + + float* GetVarFloatAddr(StyleVar idx); + ImVec2* GetVarVec2Addr(StyleVar idx); + ImVec4* GetVarVec4Addr(StyleVar idx); + + vector m_ColorStack; + vector m_VarStack; +}; + +struct Config: ax::NodeEditor::Config +{ + Config(const ax::NodeEditor::Config* config); + + std::string Load(); + std::string LoadNode(NodeId nodeId); + + void BeginSave(); + bool Save(const std::string& data, SaveReasonFlags flags); + bool SaveNode(NodeId nodeId, const std::string& data, SaveReasonFlags flags); + void EndSave(); +}; + +enum class SuspendFlags : uint8_t +{ + None = 0, + KeepSplitter = 1 +}; + +inline SuspendFlags operator |(SuspendFlags lhs, SuspendFlags rhs) { return static_cast(static_cast(lhs) | static_cast(rhs)); } +inline SuspendFlags operator &(SuspendFlags lhs, SuspendFlags rhs) { return static_cast(static_cast(lhs) & static_cast(rhs)); } + + +struct EditorContext +{ + EditorContext(const ax::NodeEditor::Config* config = nullptr); + ~EditorContext(); + + const Config& GetConfig() const { return m_Config; } + + Style& GetStyle() { return m_Style; } + + void Begin(const char* id, const ImVec2& size = ImVec2(0, 0)); + void End(); + + bool DoLink(LinkId id, PinId startPinId, PinId endPinId, ImU32 color, float thickness); + + + NodeBuilder& GetNodeBuilder() { return m_NodeBuilder; } + HintBuilder& GetHintBuilder() { return m_HintBuilder; } + + EditorAction* GetCurrentAction() { return m_CurrentAction; } + + CreateItemAction& GetItemCreator() { return m_CreateItemAction; } + DeleteItemsAction& GetItemDeleter() { return m_DeleteItemsAction; } + ContextMenuAction& GetContextMenu() { return m_ContextMenuAction; } + ShortcutAction& GetShortcut() { return m_ShortcutAction; } + + const ImGuiEx::CanvasView& GetView() const { return m_Canvas.View(); } + const ImRect& GetViewRect() const { return m_Canvas.ViewRect(); } + const ImRect& GetRect() const { return m_Canvas.Rect(); } + + void SetNodePosition(NodeId nodeId, const ImVec2& screenPosition); + void SetGroupSize(NodeId nodeId, const ImVec2& size); + ImVec2 GetNodePosition(NodeId nodeId); + ImVec2 GetNodeSize(NodeId nodeId); + + void SetNodeZPosition(NodeId nodeId, float z); + float GetNodeZPosition(NodeId nodeId); + + void MarkNodeToRestoreState(Node* node); + void UpdateNodeState(Node* node); + + void RemoveSettings(Object* object); + + void ClearSelection(); + void SelectObject(Object* object); + void DeselectObject(Object* object); + void SetSelectedObject(Object* object); + void ToggleObjectSelection(Object* object); + bool IsSelected(Object* object); + const vector& GetSelectedObjects(); + bool IsAnyNodeSelected(); + bool IsAnyLinkSelected(); + bool HasSelectionChanged(); + uint64_t GetSelectionId() const { return m_SelectionId; } + + Node* FindNodeAt(const ImVec2& p); + void FindNodesInRect(const ImRect& r, vector& result, bool append = false, bool includeIntersecting = true); + void FindLinksInRect(const ImRect& r, vector& result, bool append = false); + + bool HasAnyLinks(NodeId nodeId) const; + bool HasAnyLinks(PinId pinId) const; + + int BreakLinks(NodeId nodeId); + int BreakLinks(PinId pinId); + + void FindLinksForNode(NodeId nodeId, vector& result, bool add = false); + + bool PinHadAnyLinks(PinId pinId); + + ImVec2 ToCanvas(const ImVec2& point) const { return m_Canvas.ToLocal(point); } + ImVec2 ToScreen(const ImVec2& point) const { return m_Canvas.FromLocal(point); } + + void NotifyLinkDeleted(Link* link); + + void Suspend(SuspendFlags flags = SuspendFlags::None); + void Resume(SuspendFlags flags = SuspendFlags::None); + bool IsSuspended(); + + bool IsFocused(); + bool IsHovered() const; + bool IsHoveredWithoutOverlapp() const; + bool CanAcceptUserInput() const; + + void MakeDirty(SaveReasonFlags reason); + void MakeDirty(SaveReasonFlags reason, Node* node); + + int CountLiveNodes() const; + int CountLivePins() const; + int CountLiveLinks() const; + + Pin* CreatePin(PinId id, PinKind kind); + Node* CreateNode(NodeId id); + Link* CreateLink(LinkId id); + + Node* FindNode(NodeId id); + Pin* FindPin(PinId id); + Link* FindLink(LinkId id); + Object* FindObject(ObjectId id); + + Node* GetNode(NodeId id); + Pin* GetPin(PinId id, PinKind kind); + Link* GetLink(LinkId id); + + Link* FindLinkAt(const ImVec2& p); + + template + ImRect GetBounds(const std::vector& objects) + { + ImRect bounds(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX); + + for (auto object : objects) + if (object->m_IsLive) + bounds.Add(object->GetBounds()); + + if (ImRect_IsEmpty(bounds)) + bounds = ImRect(); + + return bounds; + } + + template + ImRect GetBounds(const std::vector>& objects) + { + ImRect bounds(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX); + + for (auto object : objects) + if (object.m_Object->m_IsLive) + bounds.Add(object.m_Object->GetBounds()); + + if (ImRect_IsEmpty(bounds)) + bounds = ImRect(); + + return bounds; + } + + ImRect GetSelectionBounds() { return GetBounds(m_SelectedObjects); } + ImRect GetContentBounds() { return GetBounds(m_Nodes); } + + ImU32 GetColor(StyleColor colorIndex) const; + ImU32 GetColor(StyleColor colorIndex, float alpha) const; + + int GetNodeIds(NodeId* nodes, int size) const; + + void NavigateTo(const ImRect& bounds, bool zoomIn = false, float duration = -1) + { + auto zoomMode = zoomIn ? NavigateAction::ZoomMode::WithMargin : NavigateAction::ZoomMode::None; + m_NavigateAction.NavigateTo(bounds, zoomMode, duration); + } + + void RegisterAnimation(Animation* animation); + void UnregisterAnimation(Animation* animation); + + void Flow(Link* link, FlowDirection direction); + + void SetUserContext(bool globalSpace = false); + + void EnableShortcuts(bool enable); + bool AreShortcutsEnabled(); + + NodeId GetHoveredNode() const { return m_HoveredNode; } + PinId GetHoveredPin() const { return m_HoveredPin; } + LinkId GetHoveredLink() const { return m_HoveredLink; } + NodeId GetDoubleClickedNode() const { return m_DoubleClickedNode; } + PinId GetDoubleClickedPin() const { return m_DoubleClickedPin; } + LinkId GetDoubleClickedLink() const { return m_DoubleClickedLink; } + bool IsBackgroundClicked() const { return m_BackgroundClickButtonIndex >= 0; } + bool IsBackgroundDoubleClicked() const { return m_BackgroundDoubleClickButtonIndex >= 0; } + ImGuiMouseButton GetBackgroundClickButtonIndex() const { return m_BackgroundClickButtonIndex; } + ImGuiMouseButton GetBackgroundDoubleClickButtonIndex() const { return m_BackgroundDoubleClickButtonIndex; } + + float AlignPointToGrid(float p) const + { + if (!ImGui::GetIO().KeyAlt) + return p - ImFmod(p, 16.0f); + else + return p; + } + + ImVec2 AlignPointToGrid(const ImVec2& p) const + { + return ImVec2(AlignPointToGrid(p.x), AlignPointToGrid(p.y)); + } + + ImDrawList* GetDrawList() { return m_DrawList; } + +private: + void LoadSettings(); + void SaveSettings(); + + Control BuildControl(bool allowOffscreen); + + void ShowMetrics(const Control& control); + + void UpdateAnimations(); + + Config m_Config; + + ImGuiID m_EditorActiveId; + bool m_IsFirstFrame; + bool m_IsFocused; + bool m_IsHovered; + bool m_IsHoveredWithoutOverlapp; + + bool m_ShortcutsEnabled; + + Style m_Style; + + vector> m_Nodes; + vector> m_Pins; + vector> m_Links; + + vector m_SelectedObjects; + + vector m_LastSelectedObjects; + uint64_t m_SelectionId; + + Link* m_LastActiveLink; + + vector m_LiveAnimations; + vector m_LastLiveAnimations; + + ImGuiEx::Canvas m_Canvas; + bool m_IsCanvasVisible; + + NodeBuilder m_NodeBuilder; + HintBuilder m_HintBuilder; + + EditorAction* m_CurrentAction; + NavigateAction m_NavigateAction; + SizeAction m_SizeAction; + DragAction m_DragAction; + SelectAction m_SelectAction; + ContextMenuAction m_ContextMenuAction; + ShortcutAction m_ShortcutAction; + CreateItemAction m_CreateItemAction; + DeleteItemsAction m_DeleteItemsAction; + + vector m_AnimationControllers; + FlowAnimationController m_FlowAnimationController; + + NodeId m_HoveredNode; + PinId m_HoveredPin; + LinkId m_HoveredLink; + NodeId m_DoubleClickedNode; + PinId m_DoubleClickedPin; + LinkId m_DoubleClickedLink; + int m_BackgroundClickButtonIndex; + int m_BackgroundDoubleClickButtonIndex; + + bool m_IsInitialized; + Settings m_Settings; + + ImDrawList* m_DrawList; + int m_ExternalChannel; + ImDrawListSplitter m_Splitter; +}; + + +//------------------------------------------------------------------------------ +} // namespace Detail +} // namespace Editor +} // namespace ax + + +//------------------------------------------------------------------------------ +# include "imgui_node_editor_internal.inl" + + +//------------------------------------------------------------------------------ +# endif // __IMGUI_NODE_EDITOR_INTERNAL_H__ + +//Disable a bunch of warnings for now +#ifndef _MSC_VER +#pragma GCC diagnostic pop +#endif diff --git a/3rdparty/imgui-node-editor/imgui_node_editor_internal.inl b/3rdparty/imgui-node-editor/imgui_node_editor_internal.inl new file mode 100644 index 0000000..df0dd25 --- /dev/null +++ b/3rdparty/imgui-node-editor/imgui_node_editor_internal.inl @@ -0,0 +1,65 @@ +//------------------------------------------------------------------------------ +// VERSION 0.9.1 +// +// LICENSE +// This software is dual-licensed to the public domain and under the following +// license: you are granted a perpetual, irrevocable license to copy, modify, +// publish, and distribute this file as you see fit. +// +// CREDITS +// Written by Michal Cichon +//------------------------------------------------------------------------------ +# ifndef __IMGUI_NODE_EDITOR_INTERNAL_INL__ +# define __IMGUI_NODE_EDITOR_INTERNAL_INL__ +# pragma once + + +//------------------------------------------------------------------------------ +# include "imgui_node_editor_internal.h" + + +//------------------------------------------------------------------------------ +namespace ax { +namespace NodeEditor { +namespace Detail { + + +//------------------------------------------------------------------------------ +//inline ImRect ToRect(const ax::rectf& rect) +//{ +// return ImRect( +// to_imvec(rect.top_left()), +// to_imvec(rect.bottom_right()) +// ); +//} +// +//inline ImRect ToRect(const ax::rect& rect) +//{ +// return ImRect( +// to_imvec(rect.top_left()), +// to_imvec(rect.bottom_right()) +// ); +//} + +inline ImRect ImGui_GetItemRect() +{ + return ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax()); +} + +inline ImVec2 ImGui_GetMouseClickPos(ImGuiMouseButton buttonIndex) +{ + if (ImGui::IsMouseDown(buttonIndex)) + return ImGui::GetIO().MouseClickedPos[buttonIndex]; + else + return ImGui::GetMousePos(); +} + + +//------------------------------------------------------------------------------ +} // namespace Detail +} // namespace Editor +} // namespace ax + + +//------------------------------------------------------------------------------ +# endif // __IMGUI_NODE_EDITOR_INTERNAL_INL__ diff --git a/3rdparty/imgui-node-editor/misc/cmake-modules/FindScopeGuard.cmake b/3rdparty/imgui-node-editor/misc/cmake-modules/FindScopeGuard.cmake new file mode 100644 index 0000000..48e4d7f --- /dev/null +++ b/3rdparty/imgui-node-editor/misc/cmake-modules/FindScopeGuard.cmake @@ -0,0 +1,17 @@ +if (TARGET ScopeGuard) + return() +endif() + +set(_ScopeGuard_SourceDir ${IMGUI_NODE_EDITOR_ROOT_DIR}/external/ScopeGuard) +set(_ScopeGuard_BinaryDir ${CMAKE_BINARY_DIR}/external/ScopeGuard) + +add_subdirectory(${_ScopeGuard_SourceDir} ${_ScopeGuard_BinaryDir}) + +include(${CMAKE_ROOT}/Modules/FindPackageHandleStandardArgs.cmake) + +find_package_handle_standard_args( + ScopeGuard + REQUIRED_VARS + _ScopeGuard_SourceDir +) + diff --git a/3rdparty/imgui-node-editor/misc/cmake-modules/Findgl3w.cmake b/3rdparty/imgui-node-editor/misc/cmake-modules/Findgl3w.cmake new file mode 100644 index 0000000..452cb75 --- /dev/null +++ b/3rdparty/imgui-node-editor/misc/cmake-modules/Findgl3w.cmake @@ -0,0 +1,17 @@ +if (TARGET gl3w) + return() +endif() + +set(_gl3w_SourceDir ${IMGUI_NODE_EDITOR_ROOT_DIR}/external/gl3w) +set(_gl3w_BinaryDir ${CMAKE_BINARY_DIR}/external/gl3w) + +add_subdirectory(${_gl3w_SourceDir} ${_gl3w_BinaryDir}) + +include(${CMAKE_ROOT}/Modules/FindPackageHandleStandardArgs.cmake) + +find_package_handle_standard_args( + gl3w + REQUIRED_VARS + _gl3w_SourceDir +) + diff --git a/3rdparty/imgui-node-editor/misc/cmake-modules/Findimgui.cmake b/3rdparty/imgui-node-editor/misc/cmake-modules/Findimgui.cmake new file mode 100644 index 0000000..67a0ad9 --- /dev/null +++ b/3rdparty/imgui-node-editor/misc/cmake-modules/Findimgui.cmake @@ -0,0 +1,17 @@ +if (TARGET imgui) + return() +endif() + +set(_imgui_SourceDir ${IMGUI_NODE_EDITOR_ROOT_DIR}/external/imgui) +set(_imgui_BinaryDir ${CMAKE_BINARY_DIR}/external/imgui) + +add_subdirectory(${_imgui_SourceDir} ${_imgui_BinaryDir}) + +include(${CMAKE_ROOT}/Modules/FindPackageHandleStandardArgs.cmake) + +find_package_handle_standard_args( + imgui + REQUIRED_VARS + _imgui_SourceDir +) + diff --git a/3rdparty/imgui-node-editor/misc/cmake-modules/Findimgui_node_editor.cmake b/3rdparty/imgui-node-editor/misc/cmake-modules/Findimgui_node_editor.cmake new file mode 100644 index 0000000..a8c295f --- /dev/null +++ b/3rdparty/imgui-node-editor/misc/cmake-modules/Findimgui_node_editor.cmake @@ -0,0 +1,49 @@ +if (TARGET imgui_node_editor) + return() +endif() + +#set(_imgui_node_editor_SourceDir ${IMGUI_NODE_EDITOR_ROOT_DIR}) +#set(_imgui_node_editor_BinaryDir ${CMAKE_BINARY_DIR}/NodeEditor) + +#add_subdirectory(${_imgui_node_editor_SourceDir} ${_imgui_node_editor_BinaryDir}) + +find_package(imgui REQUIRED) + +set(_imgui_node_editor_Sources + ${IMGUI_NODE_EDITOR_ROOT_DIR}/crude_json.cpp + ${IMGUI_NODE_EDITOR_ROOT_DIR}/crude_json.h + ${IMGUI_NODE_EDITOR_ROOT_DIR}/imgui_bezier_math.h + ${IMGUI_NODE_EDITOR_ROOT_DIR}/imgui_bezier_math.inl + ${IMGUI_NODE_EDITOR_ROOT_DIR}/imgui_canvas.cpp + ${IMGUI_NODE_EDITOR_ROOT_DIR}/imgui_canvas.cpp + ${IMGUI_NODE_EDITOR_ROOT_DIR}/imgui_canvas.h + ${IMGUI_NODE_EDITOR_ROOT_DIR}/imgui_canvas.h + ${IMGUI_NODE_EDITOR_ROOT_DIR}/imgui_extra_math.h + ${IMGUI_NODE_EDITOR_ROOT_DIR}/imgui_extra_math.inl + ${IMGUI_NODE_EDITOR_ROOT_DIR}/imgui_node_editor_api.cpp + ${IMGUI_NODE_EDITOR_ROOT_DIR}/imgui_node_editor_internal.h + ${IMGUI_NODE_EDITOR_ROOT_DIR}/imgui_node_editor_internal.inl + ${IMGUI_NODE_EDITOR_ROOT_DIR}/imgui_node_editor.cpp + ${IMGUI_NODE_EDITOR_ROOT_DIR}/imgui_node_editor.h + ${IMGUI_NODE_EDITOR_ROOT_DIR}/misc/imgui_node_editor.natvis +) + +add_library(imgui_node_editor STATIC + ${_imgui_node_editor_Sources} +) + +target_include_directories(imgui_node_editor PUBLIC + ${IMGUI_NODE_EDITOR_ROOT_DIR} +) + +target_link_libraries(imgui_node_editor PUBLIC imgui) + +source_group(TREE ${IMGUI_NODE_EDITOR_ROOT_DIR} FILES ${_imgui_node_editor_Sources}) + +include(${CMAKE_ROOT}/Modules/FindPackageHandleStandardArgs.cmake) + +find_package_handle_standard_args( + imgui_node_editor + REQUIRED_VARS + IMGUI_NODE_EDITOR_ROOT_DIR +) \ No newline at end of file diff --git a/3rdparty/imgui-node-editor/misc/cmake-modules/Findstb_image.cmake b/3rdparty/imgui-node-editor/misc/cmake-modules/Findstb_image.cmake new file mode 100644 index 0000000..34bffac --- /dev/null +++ b/3rdparty/imgui-node-editor/misc/cmake-modules/Findstb_image.cmake @@ -0,0 +1,17 @@ +if (TARGET stb_image) + return() +endif() + +set(_stb_image_SourceDir ${IMGUI_NODE_EDITOR_ROOT_DIR}/external/stb_image) +set(_stb_image_BinaryDir ${CMAKE_BINARY_DIR}/external/stb_image) + +add_subdirectory(${_stb_image_SourceDir} ${_stb_image_BinaryDir}) + +include(${CMAKE_ROOT}/Modules/FindPackageHandleStandardArgs.cmake) + +find_package_handle_standard_args( + stb_image + REQUIRED_VARS + _stb_image_SourceDir +) + diff --git a/3rdparty/imgui-node-editor/misc/crude_json.natvis b/3rdparty/imgui-node-editor/misc/crude_json.natvis new file mode 100644 index 0000000..158f208 --- /dev/null +++ b/3rdparty/imgui-node-editor/misc/crude_json.natvis @@ -0,0 +1,18 @@ + + + + + {m_Type,en} {*(crude_json::object*)&m_Storage,view(simple)} + {m_Type,en} {*(crude_json::array*)&m_Storage,view(simple)} + {*(crude_json::string*)&m_Storage,view(simple)} + {*(crude_json::boolean*)&m_Storage} + {*(crude_json::number*)&m_Storage,g} + {m_Type,en} + *(crude_json::string*)&m_Storage + + *(crude_json::object*)&m_Storage,view(simple) + *(crude_json::array*)&m_Storage,view(simple) + + + + diff --git a/3rdparty/imgui-node-editor/misc/imgui_node_editor.natvis b/3rdparty/imgui-node-editor/misc/imgui_node_editor.natvis new file mode 100644 index 0000000..e95ac0d --- /dev/null +++ b/3rdparty/imgui-node-editor/misc/imgui_node_editor.natvis @@ -0,0 +1,64 @@ + + + + + {m_Value} + + m_Value + ($T1*)m_Value + + + + + Node {m_Value} + + m_Value + + + + + Link {m_Value} + + m_Value + + + + + Pin {m_Value} + + m_Value + + + + + {second} + + second + + + + + + + + + + + null + {*object_ptr()} : object + {*array_ptr()} : array + {*string_ptr()} : string + {*boolean_ptr()} : boolean + {*number_ptr(),g} : number + discarded + + + *object_ptr(),view(simple) + *array_ptr(),view(simple) + *string_ptr(),view(simple) + *boolean_ptr() + *number_ptr() + + + + diff --git a/CMakeLists.txt b/CMakeLists.txt index 96abbb3..2cc1e06 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -92,6 +92,18 @@ target_sources(AnimTestbed PRIVATE 3rdparty/imgui/backends/imgui_impl_opengl3.cpp 3rdparty/imgui/misc/cpp/imgui_stdlib.cpp 3rdparty/imnodes/imnodes.cpp + 3rdparty/imgui-node-editor/imgui_node_editor.cpp + 3rdparty/imgui-node-editor/imgui_node_editor_api.cpp + 3rdparty/imgui-node-editor/imgui_node_editor.h + 3rdparty/imgui-node-editor/imgui_node_editor_internal.h + 3rdparty/imgui-node-editor/imgui_bezier_math.h + 3rdparty/imgui-node-editor/imgui_bezier_math.inl + 3rdparty/imgui-node-editor/imgui_canvas.cpp + 3rdparty/imgui-node-editor/imgui_canvas.h + 3rdparty/imgui-node-editor/imgui_extra_math.h + 3rdparty/imgui-node-editor/imgui_extra_math.inl + 3rdparty/imgui-node-editor/crude_json.cpp + 3rdparty/imgui-node-editor/crude_json.h ) target_link_libraries(AnimTestbed AnimTestbedCode glfw ozz_base ozz_geometry ozz_animation ${OPENGL_LIBRARIES}) diff --git a/src/main.cc b/src/main.cc index 1834cb0..0363687 100644 --- a/src/main.cc +++ b/src/main.cc @@ -22,6 +22,7 @@ #include "SkinnedMesh.h" #include "SkinnedMeshResource.h" #include "src/AnimGraph/AnimGraphEditor.h" +#include "3rdparty/imgui-node-editor/imgui_node_editor.h" const int Width = 1024; const int Height = 768; @@ -172,13 +173,22 @@ struct ApplicationConfig { int window_position[2] = {100, 30}; int window_size[2] = {1000, 600}; - struct GraphEditor { + struct LegacyGraphEditor { bool visible = false; int position[2] = {20, 20}; int size[2] = {800, 500}; }; - GraphEditor graph_editor; + LegacyGraphEditor legacy_graph_editor; + struct GraphEditor { + bool visible = false; + int position[2] = {20, 20}; + int size[2] = {800, 500}; + ax::NodeEditor::Config config = {}; + ax::NodeEditor::EditorContext* context = nullptr; + }; + GraphEditor graph_editor; + struct SkinnedMeshWidget { bool visible = false; int position[2] = {20, 20}; @@ -215,12 +225,18 @@ void to_json(nlohmann::json& j, const ApplicationConfig& config) { j["main_window"]["size"][0] = config.window_size[0]; j["main_window"]["size"][1] = config.window_size[1]; + j["legacy_graph_editor"]["visible"] = config.legacy_graph_editor.visible; + j["legacy_graph_editor"]["position"][0] = config.legacy_graph_editor.position[0]; + j["legacy_graph_editor"]["position"][1] = config.legacy_graph_editor.position[1]; + j["legacy_graph_editor"]["size"][0] = config.legacy_graph_editor.size[0]; + j["legacy_graph_editor"]["size"][1] = config.legacy_graph_editor.size[1]; + j["graph_editor"]["visible"] = config.graph_editor.visible; j["graph_editor"]["position"][0] = config.graph_editor.position[0]; j["graph_editor"]["position"][1] = config.graph_editor.position[1]; j["graph_editor"]["size"][0] = config.graph_editor.size[0]; j["graph_editor"]["size"][1] = config.graph_editor.size[1]; - + j["skinned_mesh_widget"]["visible"] = config.skinned_mesh_widget.visible; j["skinned_mesh_widget"]["position"][0] = config.skinned_mesh_widget.position[0]; @@ -266,11 +282,29 @@ void from_json(const nlohmann::json& j, ApplicationConfig& config) { } } + if (j.contains("legacy_graph_editor")) { + if (j["legacy_graph_editor"].contains("visible")) { + config.legacy_graph_editor.visible = j["legacy_graph_editor"]["visible"]; + } + + if (j["legacy_graph_editor"].contains("position") + and j["legacy_graph_editor"]["position"].size() == 2) { + config.legacy_graph_editor.position[0] = j["legacy_graph_editor"]["position"].at(0); + config.legacy_graph_editor.position[1] = j["legacy_graph_editor"]["position"].at(1); + } + + if (j["legacy_graph_editor"].contains("size") + and j["legacy_graph_editor"]["size"].size() == 2) { + config.legacy_graph_editor.size[0] = j["legacy_graph_editor"]["size"].at(0); + config.legacy_graph_editor.size[1] = j["legacy_graph_editor"]["size"].at(1); + } + } + if (j.contains("graph_editor")) { if (j["graph_editor"].contains("visible")) { config.graph_editor.visible = j["graph_editor"]["visible"]; } - + if (j["graph_editor"].contains("position") and j["graph_editor"]["position"].size() == 2) { config.graph_editor.position[0] = j["graph_editor"]["position"].at(0); @@ -283,7 +317,7 @@ void from_json(const nlohmann::json& j, ApplicationConfig& config) { config.graph_editor.size[1] = j["graph_editor"]["size"].at(1); } } - + if (j.contains("skinned_mesh_widget")) { if (j["skinned_mesh_widget"].contains("visible")) { config.skinned_mesh_widget.visible = j["skinned_mesh_widget"]["visible"]; @@ -636,6 +670,10 @@ int main() { Viewport offscreen_viewport; + // Graph Editor + gApplicationConfig.graph_editor.config.SettingsFile = "graph_editor.json"; + gApplicationConfig.graph_editor.context = ax::NodeEditor::CreateEditor(&gApplicationConfig.graph_editor.config); + // draw loop while (!glfwWindowShouldClose(w)) { // Update time @@ -762,6 +800,10 @@ int main() { &gApplicationConfig.animation_player_widget.visible); ImGui::Separator(); + ImGui::Checkbox( + "Legacy Graph Editor", + &gApplicationConfig.legacy_graph_editor.visible); + ImGui::Checkbox( "ImGui Demo", &gApplicationConfig.show_imgui_demo_window); @@ -1031,6 +1073,86 @@ int main() { gApplicationConfig.graph_editor.size[0] = graph_editor_size.x; gApplicationConfig.graph_editor.size[1] = graph_editor_size.y; + ax::NodeEditor::SetCurrentEditor(gApplicationConfig.graph_editor.context); + ax::NodeEditor::Begin("Graph Editor"); + + int unique_id = 1; + ax::NodeEditor::BeginNode(unique_id++); + + // Node A + ImGui::Text("Node A"); + ax::NodeEditor::BeginPin(unique_id++, ax::NodeEditor::PinKind::Input); + ImGui::Text("In"); + ax::NodeEditor::EndPin(); + ImGui::SameLine(); + ax::NodeEditor::BeginPin(unique_id++, ax::NodeEditor::PinKind::Output); + ImGui::Text("Out"); + ax::NodeEditor::EndPin(); + + ax::NodeEditor::EndNode(); + + // Node B + ax::NodeEditor::BeginNode(unique_id++); + + ImGui::Text("Node B"); + ax::NodeEditor::BeginPin(unique_id++, ax::NodeEditor::PinKind::Input); + ImGui::Text("In"); + ax::NodeEditor::EndPin(); + ImGui::SameLine(); + ax::NodeEditor::BeginPin(unique_id++, ax::NodeEditor::PinKind::Output); + ImGui::Text("Out"); + ax::NodeEditor::EndPin(); + + ax::NodeEditor::EndNode(); + + // Create Connections + if (ax::NodeEditor::BeginCreate()) { + ax::NodeEditor::PinId input_pin_id, output_pin_id; + if (ax::NodeEditor::QueryNewLink(&input_pin_id, &output_pin_id)) { + if (input_pin_id && output_pin_id) { + if (ax::NodeEditor::AcceptNewItem()) { + + } + } + } + } + ax::NodeEditor::EndCreate(); + + ax::NodeEditor::End(); + + ax::NodeEditor::SetCurrentEditor(nullptr); + + + + ImGui::End(); + } + + // Legacy Animation Graph Editor + if (gApplicationConfig.legacy_graph_editor.visible) { + ImGui::SetNextWindowPos( + ImVec2( + gApplicationConfig.legacy_graph_editor.position[0], + gApplicationConfig.legacy_graph_editor.position[1]), + ImGuiCond_FirstUseEver); + ImGui::SetNextWindowSize( + ImVec2( + gApplicationConfig.legacy_graph_editor.size[0], + gApplicationConfig.legacy_graph_editor.size[1]), + ImGuiCond_FirstUseEver); + + ImGui::Begin( + "Legacy Graph Editor", + &gApplicationConfig.legacy_graph_editor.visible, + ImGuiWindowFlags_MenuBar); + + ImVec2 graph_editor_position = ImGui::GetWindowPos(); + gApplicationConfig.legacy_graph_editor.position[0] = graph_editor_position.x; + gApplicationConfig.legacy_graph_editor.position[1] = graph_editor_position.y; + + ImVec2 graph_editor_size = ImGui::GetWindowSize(); + gApplicationConfig.legacy_graph_editor.size[0] = graph_editor_size.x; + gApplicationConfig.legacy_graph_editor.size[1] = graph_editor_size.y; + AnimGraphEditorUpdate(); ImGui::End(); @@ -1065,6 +1187,7 @@ int main() { save_application_config("animtestbed_config.json"); /* cleanup */ + ax::NodeEditor::DestroyEditor(gApplicationConfig.graph_editor.context); ImNodes::DestroyContext(); ImGui::DestroyContext(); sgl_shutdown();