From 1eeb49147a6f46c61e9e1b7e58ec8c2211f4263e Mon Sep 17 00:00:00 2001 From: falkTX Date: Fri, 15 Jul 2022 14:54:04 +0100 Subject: [PATCH] Update dpf and plugins Signed-off-by: falkTX --- dpf/Makefile.base.mk | 274 +- dpf/Makefile.plugins.mk | 112 +- dpf/cmake/DPF-plugin.cmake | 41 +- dpf/dgl/Application.hpp | 22 +- dpf/dgl/Base.hpp | 71 +- dpf/dgl/Cairo.hpp | 6 +- .../Line.cpp => dgl/FileBrowserDialog.hpp} | 18 +- dpf/dgl/Makefile | 36 +- dpf/dgl/NanoVG.hpp | 2 +- dpf/dgl/OpenGL-include.hpp | 112 + dpf/dgl/OpenGL.hpp | 103 +- dpf/dgl/StandaloneWindow.hpp | 1 + dpf/dgl/SubWidget.hpp | 2 +- dpf/dgl/TopLevelWidget.hpp | 4 +- dpf/dgl/Widget.hpp | 69 +- dpf/dgl/Window.hpp | 111 +- dpf/dgl/src/Application.cpp | 17 +- dpf/dgl/src/ApplicationPrivateData.cpp | 12 +- dpf/dgl/src/ApplicationPrivateData.hpp | 3 + dpf/dgl/src/NanoVG.cpp | 37 +- dpf/dgl/src/OpenGL.cpp | 62 +- dpf/dgl/src/TopLevelWidget.cpp | 8 +- dpf/dgl/src/Window.cpp | 112 +- dpf/dgl/src/WindowPrivateData.cpp | 241 +- dpf/dgl/src/WindowPrivateData.hpp | 22 +- dpf/dgl/src/nanovg/fontstash.h | 3 + dpf/dgl/src/nanovg/nanovg_gl.h | 61 +- dpf/dgl/src/pugl-upstream/.clang-format | 1 + dpf/dgl/src/pugl-upstream/.includes.imp | 12 +- dpf/dgl/src/pugl-upstream/.reuse/dep5 | 16 + .../src/pugl-upstream/LICENSES/CC0-1.0.txt | 121 + dpf/dgl/src/pugl-upstream/LICENSES/ISC.txt | 11 + dpf/dgl/src/pugl-upstream/LICENSES/MIT.txt | 17 + dpf/dgl/src/pugl-upstream/README.md | 66 +- .../bindings/cpp/include/.clang-tidy | 15 - .../bindings/cpp/include/meson.build | 12 - .../bindings/cpp/include/pugl/cairo.hpp | 45 - .../bindings/cpp/include/pugl/gl.hpp | 70 - .../bindings/cpp/include/pugl/pugl.hpp | 734 -- .../bindings/cpp/include/pugl/stub.hpp | 45 - .../bindings/cpp/include/pugl/vulkan.hpp | 168 - .../pugl-upstream/bindings/cpp/meson.build | 7 - .../src/pugl-upstream/doc/_static/meson.build | 2 - dpf/dgl/src/pugl-upstream/doc/c/Doxyfile.in | 32 - .../src/pugl-upstream/doc/c/api/meson.build | 5 - .../src/pugl-upstream/doc/c/event-loop.rst | 101 - dpf/dgl/src/pugl-upstream/doc/c/events.rst | 84 - dpf/dgl/src/pugl-upstream/doc/c/index.rst | 11 - dpf/dgl/src/pugl-upstream/doc/c/meson.build | 48 - dpf/dgl/src/pugl-upstream/doc/c/overview.rst | 26 - .../src/pugl-upstream/doc/c/shutting-down.rst | 20 - dpf/dgl/src/pugl-upstream/doc/c/view.rst | 321 - dpf/dgl/src/pugl-upstream/doc/c/world.rst | 65 - .../src/pugl-upstream/doc/c/xml/meson.build | 19 - dpf/dgl/src/pugl-upstream/doc/conf.py.in | 85 - dpf/dgl/src/pugl-upstream/doc/cpp/Doxyfile.in | 37 - .../src/pugl-upstream/doc/cpp/api/meson.build | 5 - .../src/pugl-upstream/doc/cpp/event-loop.rst | 37 - dpf/dgl/src/pugl-upstream/doc/cpp/events.rst | 43 - dpf/dgl/src/pugl-upstream/doc/cpp/index.rst | 12 - dpf/dgl/src/pugl-upstream/doc/cpp/meson.build | 47 - .../src/pugl-upstream/doc/cpp/overview.rst | 35 - dpf/dgl/src/pugl-upstream/doc/cpp/view.rst | 299 - dpf/dgl/src/pugl-upstream/doc/cpp/world.rst | 41 - .../src/pugl-upstream/doc/cpp/xml/meson.build | 21 - dpf/dgl/src/pugl-upstream/doc/deployment.rst | 23 - dpf/dgl/src/pugl-upstream/doc/meson.build | 13 - dpf/dgl/src/pugl-upstream/doc/summary.rst | 22 - .../src/pugl-upstream/examples/.clang-tidy | 43 - .../src/pugl-upstream/examples/cube_view.h | 193 - .../src/pugl-upstream/examples/demo_utils.h | 124 - .../src/pugl-upstream/examples/file_utils.c | 68 - .../src/pugl-upstream/examples/file_utils.h | 41 - .../src/pugl-upstream/examples/glad/glad.c | 1138 --- .../src/pugl-upstream/examples/glad/glad.h | 2127 ----- .../pugl-upstream/examples/glad/khrplatform.h | 290 - .../src/pugl-upstream/examples/meson.build | 124 - .../pugl-upstream/examples/pugl_cairo_demo.c | 261 - .../pugl-upstream/examples/pugl_cpp_demo.cpp | 153 - .../pugl-upstream/examples/pugl_cursor_demo.c | 169 - .../pugl-upstream/examples/pugl_embed_demo.c | 363 - .../examples/pugl_print_events.c | 79 - .../pugl-upstream/examples/pugl_shader_demo.c | 480 -- .../examples/pugl_vulkan_cpp_demo.cpp | 1826 ----- .../pugl-upstream/examples/pugl_vulkan_demo.c | 1127 --- .../pugl-upstream/examples/pugl_window_demo.c | 254 - dpf/dgl/src/pugl-upstream/examples/rects.h | 79 - .../src/pugl-upstream/examples/shader_utils.h | 106 - .../examples/shaders/header_330.glsl | 4 - .../examples/shaders/header_420.glsl | 4 - .../examples/shaders/meson.build | 35 - .../pugl-upstream/examples/shaders/rect.frag | 33 - .../pugl-upstream/examples/shaders/rect.vert | 36 - dpf/dgl/src/pugl-upstream/examples/sybok.hpp | 2325 ------ dpf/dgl/src/pugl-upstream/include/.clang-tidy | 2 +- dpf/dgl/src/pugl-upstream/include/meson.build | 3 + .../src/pugl-upstream/include/pugl/cairo.h | 17 +- dpf/dgl/src/pugl-upstream/include/pugl/gl.h | 17 +- dpf/dgl/src/pugl-upstream/include/pugl/pugl.h | 514 +- dpf/dgl/src/pugl-upstream/include/pugl/stub.h | 17 +- .../src/pugl-upstream/include/pugl/vulkan.h | 17 +- dpf/dgl/src/pugl-upstream/meson.build | 377 - dpf/dgl/src/pugl-upstream/meson/meson.build | 196 - dpf/dgl/src/pugl-upstream/meson_options.txt | 20 - .../src/pugl-upstream/resources/Info.plist.in | 20 - dpf/dgl/src/pugl-upstream/resources/pugl.ipe | 293 - dpf/dgl/src/pugl-upstream/resources/pugl.png | Bin 2641 -> 0 bytes dpf/dgl/src/pugl-upstream/resources/pugl.svg | 9 - dpf/dgl/src/pugl-upstream/scripts/cat.py | 7 - .../pugl-upstream/scripts/dox_to_sphinx.py | 652 -- dpf/dgl/src/pugl-upstream/src/.clang-tidy | 8 +- dpf/dgl/src/pugl-upstream/src/attributes.h | 23 + dpf/dgl/src/pugl-upstream/src/common.c | 273 + .../src/pugl-upstream/src/implementation.c | 468 -- .../src/pugl-upstream/src/implementation.h | 86 - dpf/dgl/src/pugl-upstream/src/internal.c | 190 + dpf/dgl/src/pugl-upstream/src/internal.h | 51 + dpf/dgl/src/pugl-upstream/src/mac.h | 27 +- dpf/dgl/src/pugl-upstream/src/mac.m | 519 +- dpf/dgl/src/pugl-upstream/src/mac_cairo.m | 36 +- dpf/dgl/src/pugl-upstream/src/mac_gl.m | 27 +- dpf/dgl/src/pugl-upstream/src/mac_stub.m | 24 +- dpf/dgl/src/pugl-upstream/src/mac_vulkan.m | 22 +- dpf/dgl/src/pugl-upstream/src/platform.h | 33 + dpf/dgl/src/pugl-upstream/src/stub.h | 26 +- dpf/dgl/src/pugl-upstream/src/types.h | 56 +- dpf/dgl/src/pugl-upstream/src/wasm.c | 734 ++ dpf/dgl/src/pugl-upstream/src/wasm.h | 33 + dpf/dgl/src/pugl-upstream/src/wasm_gl.c | 255 + dpf/dgl/src/pugl-upstream/src/wasm_stub.c | 26 + dpf/dgl/src/pugl-upstream/src/win.c | 371 +- dpf/dgl/src/pugl-upstream/src/win.h | 36 +- dpf/dgl/src/pugl-upstream/src/win_cairo.c | 21 +- dpf/dgl/src/pugl-upstream/src/win_gl.c | 32 +- dpf/dgl/src/pugl-upstream/src/win_stub.c | 17 +- dpf/dgl/src/pugl-upstream/src/win_vulkan.c | 17 +- dpf/dgl/src/pugl-upstream/src/x11.c | 925 ++- dpf/dgl/src/pugl-upstream/src/x11.h | 60 +- dpf/dgl/src/pugl-upstream/src/x11_cairo.c | 23 +- dpf/dgl/src/pugl-upstream/src/x11_gl.c | 118 +- dpf/dgl/src/pugl-upstream/src/x11_stub.c | 17 +- dpf/dgl/src/pugl-upstream/src/x11_vulkan.c | 18 +- dpf/dgl/src/pugl-upstream/test/.clang-tidy | 18 - dpf/dgl/src/pugl-upstream/test/meson.build | 167 - dpf/dgl/src/pugl-upstream/test/test_build.c | 32 - dpf/dgl/src/pugl-upstream/test/test_build.cpp | 33 - dpf/dgl/src/pugl-upstream/test/test_cairo.c | 94 - .../src/pugl-upstream/test/test_clipboard.c | 106 - dpf/dgl/src/pugl-upstream/test/test_gl.c | 120 - .../src/pugl-upstream/test/test_gl_hints.c | 102 - .../pugl-upstream/test/test_inline_cpp.cpp | 70 - .../pugl-upstream/test/test_inline_objcpp.mm | 50 - .../test/test_local_copy_paste.c | 124 - dpf/dgl/src/pugl-upstream/test/test_realize.c | 101 - .../src/pugl-upstream/test/test_redisplay.c | 155 - .../test/test_remote_copy_paste.c | 170 - .../src/pugl-upstream/test/test_show_hide.c | 149 - dpf/dgl/src/pugl-upstream/test/test_size.c | 138 - .../src/pugl-upstream/test/test_strerror.c | 41 - dpf/dgl/src/pugl-upstream/test/test_stub.c | 79 - .../src/pugl-upstream/test/test_stub_hints.c | 103 - dpf/dgl/src/pugl-upstream/test/test_timer.c | 171 - dpf/dgl/src/pugl-upstream/test/test_update.c | 126 - dpf/dgl/src/pugl-upstream/test/test_utils.h | 356 - dpf/dgl/src/pugl-upstream/test/test_view.c | 103 - dpf/dgl/src/pugl-upstream/test/test_vulkan.c | 212 - dpf/dgl/src/pugl-upstream/test/test_world.c | 50 - dpf/dgl/src/pugl.cpp | 480 +- dpf/dgl/src/pugl.hpp | 113 +- dpf/distrho/DistrhoPlugin.hpp | 121 +- dpf/distrho/DistrhoPluginMain.cpp | 4 + dpf/distrho/DistrhoStandaloneUtils.hpp | 86 + dpf/distrho/DistrhoUI.hpp | 41 +- dpf/distrho/DistrhoUIMain.cpp | 6 +- dpf/distrho/DistrhoUI_macOS.mm | 44 +- dpf/distrho/extra/FileBrowserDialog.hpp | 110 +- ...erDialog.cpp => FileBrowserDialogImpl.cpp} | 374 +- dpf/distrho/extra/FileBrowserDialogImpl.hpp | 121 + dpf/distrho/extra/RingBuffer.hpp | 25 +- dpf/distrho/extra/Runner.hpp | 251 + dpf/distrho/extra/String.hpp | 8 +- dpf/distrho/extra/Thread.hpp | 4 + dpf/distrho/extra/sofd/libsofd.c | 12 +- dpf/distrho/src/DistrhoDefines.h | 83 +- dpf/distrho/src/DistrhoPlugin.cpp | 45 +- dpf/distrho/src/DistrhoPluginCarla.cpp | 42 +- dpf/distrho/src/DistrhoPluginChecks.h | 39 +- dpf/distrho/src/DistrhoPluginInternal.hpp | 75 +- dpf/distrho/src/DistrhoPluginJACK.cpp | 114 +- dpf/distrho/src/DistrhoPluginLADSPA+DSSI.cpp | 4 +- dpf/distrho/src/DistrhoPluginLV2.cpp | 254 +- dpf/distrho/src/DistrhoPluginLV2export.cpp | 207 +- ...rhoPluginVST3.hpp => DistrhoPluginVST.hpp} | 145 +- dpf/distrho/src/DistrhoPluginVST2.cpp | 280 +- dpf/distrho/src/DistrhoPluginVST3.cpp | 823 +- dpf/distrho/src/DistrhoUI.cpp | 119 +- dpf/distrho/src/DistrhoUIInternal.hpp | 91 +- dpf/distrho/src/DistrhoUILV2.cpp | 55 +- dpf/distrho/src/DistrhoUIPrivateData.hpp | 85 +- dpf/distrho/src/DistrhoUIVST3.cpp | 446 +- dpf/distrho/src/DistrhoUtils.cpp | 22 +- dpf/distrho/src/jackbridge/JackBridge.cpp | 474 +- dpf/distrho/src/jackbridge/JackBridge.hpp | 19 +- dpf/distrho/src/jackbridge/NativeBridge.hpp | 294 + dpf/distrho/src/jackbridge/RtAudioBridge.hpp | 176 +- dpf/distrho/src/jackbridge/SDL2Bridge.hpp | 242 + dpf/distrho/src/jackbridge/WebBridge.hpp | 468 ++ dpf/distrho/src/lv2/atom-forge.h | 107 +- dpf/distrho/src/lv2/atom-util.h | 130 +- dpf/distrho/src/lv2/atom.h | 88 +- dpf/distrho/src/lv2/buf-size.h | 33 +- dpf/distrho/src/lv2/data-access.h | 19 +- dpf/distrho/src/lv2/dynmanifest.h | 17 +- dpf/distrho/src/lv2/event-helpers.h | 33 +- dpf/distrho/src/lv2/event.h | 54 +- dpf/distrho/src/lv2/instance-access.h | 29 +- dpf/distrho/src/lv2/log.h | 36 +- dpf/distrho/src/lv2/logger.h | 54 +- dpf/distrho/src/lv2/lv2.h | 214 +- dpf/distrho/src/lv2/midi.h | 106 +- dpf/distrho/src/lv2/morph.h | 34 +- dpf/distrho/src/lv2/options.h | 29 +- dpf/distrho/src/lv2/parameters.h | 71 +- dpf/distrho/src/lv2/patch.h | 74 +- dpf/distrho/src/lv2/port-groups.h | 87 +- dpf/distrho/src/lv2/port-props.h | 44 +- dpf/distrho/src/lv2/presets.h | 25 +- dpf/distrho/src/lv2/resize-port.h | 36 +- dpf/distrho/src/lv2/state.h | 148 +- dpf/distrho/src/lv2/time.h | 56 +- dpf/distrho/src/lv2/units.h | 85 +- dpf/distrho/src/lv2/uri-map.h | 16 +- dpf/distrho/src/lv2/urid.h | 31 +- dpf/distrho/src/lv2/worker.h | 55 +- dpf/distrho/src/travesty/audio_processor.h | 14 +- dpf/distrho/src/travesty/base.h | 70 +- dpf/distrho/src/travesty/bstream.h | 5 +- dpf/distrho/src/travesty/component.h | 5 +- dpf/distrho/src/travesty/edit_controller.h | 24 +- dpf/distrho/src/travesty/events.h | 17 +- dpf/distrho/src/travesty/factory.h | 33 +- dpf/distrho/src/travesty/host.h | 7 +- dpf/distrho/src/travesty/message.h | 11 +- dpf/distrho/src/travesty/unit.h | 69 + dpf/distrho/src/travesty/view.h | 23 +- dpf/tests/Application.cpp | 91 - dpf/tests/Circle.cpp | 30 - dpf/tests/Color.cpp | 219 - dpf/tests/Demo.cpp | 581 -- dpf/tests/FileBrowserDialog.cpp | 194 - dpf/tests/Makefile | 159 - dpf/tests/NanoImage.cpp | 229 - dpf/tests/NanoSubWidgets.cpp | 167 - dpf/tests/Point.cpp | 90 - dpf/tests/README.txt | 42 - dpf/tests/Rectangle.cpp | 30 - dpf/tests/Triangle.cpp | 30 - dpf/tests/Window.cpp | 64 - dpf/tests/demo_res/DemoArtwork.cpp | 569 -- dpf/tests/demo_res/DemoArtwork.hpp | 35 - dpf/tests/demo_res/ico1.png | Bin 259 -> 0 bytes dpf/tests/demo_res/ico2.png | Bin 3462 -> 0 bytes dpf/tests/demo_res/ico3.png | Bin 415 -> 0 bytes dpf/tests/demo_res/ico4.png | Bin 1355 -> 0 bytes dpf/tests/demo_res/ico5.png | Bin 539 -> 0 bytes dpf/tests/images_res/CREDITS.txt | 3 - dpf/tests/images_res/CatPics.cpp | 7083 ----------------- dpf/tests/images_res/CatPics.hpp | 25 - dpf/tests/images_res/cat1.png | Bin 121583 -> 0 bytes dpf/tests/images_res/cat2.png | Bin 70352 -> 0 bytes dpf/tests/images_res/cat3.png | Bin 64331 -> 0 bytes dpf/tests/tests.hpp | 59 - dpf/tests/widgets/ExampleColorWidget.hpp | 179 - dpf/tests/widgets/ExampleImagesWidget.hpp | 215 - dpf/tests/widgets/ExampleRectanglesWidget.hpp | 193 - dpf/tests/widgets/ExampleShapesWidget.hpp | 131 - dpf/tests/widgets/ExampleTextWidget.hpp | 128 - dpf/tests/widgets/NanoPerfWidget.hpp | 240 - dpf/utils/plugin.pkg/package.xml.in | 2 +- get-plugins.sh | 20 +- 280 files changed, 10570 insertions(+), 34070 deletions(-) rename dpf/{tests/Line.cpp => dgl/FileBrowserDialog.hpp} (66%) create mode 100644 dpf/dgl/OpenGL-include.hpp create mode 100644 dpf/dgl/src/pugl-upstream/.reuse/dep5 create mode 100644 dpf/dgl/src/pugl-upstream/LICENSES/CC0-1.0.txt create mode 100644 dpf/dgl/src/pugl-upstream/LICENSES/ISC.txt create mode 100644 dpf/dgl/src/pugl-upstream/LICENSES/MIT.txt delete mode 100644 dpf/dgl/src/pugl-upstream/bindings/cpp/include/.clang-tidy delete mode 100644 dpf/dgl/src/pugl-upstream/bindings/cpp/include/meson.build delete mode 100644 dpf/dgl/src/pugl-upstream/bindings/cpp/include/pugl/cairo.hpp delete mode 100644 dpf/dgl/src/pugl-upstream/bindings/cpp/include/pugl/gl.hpp delete mode 100644 dpf/dgl/src/pugl-upstream/bindings/cpp/include/pugl/pugl.hpp delete mode 100644 dpf/dgl/src/pugl-upstream/bindings/cpp/include/pugl/stub.hpp delete mode 100644 dpf/dgl/src/pugl-upstream/bindings/cpp/include/pugl/vulkan.hpp delete mode 100644 dpf/dgl/src/pugl-upstream/bindings/cpp/meson.build delete mode 100644 dpf/dgl/src/pugl-upstream/doc/_static/meson.build delete mode 100644 dpf/dgl/src/pugl-upstream/doc/c/Doxyfile.in delete mode 100644 dpf/dgl/src/pugl-upstream/doc/c/api/meson.build delete mode 100644 dpf/dgl/src/pugl-upstream/doc/c/event-loop.rst delete mode 100644 dpf/dgl/src/pugl-upstream/doc/c/events.rst delete mode 100644 dpf/dgl/src/pugl-upstream/doc/c/index.rst delete mode 100644 dpf/dgl/src/pugl-upstream/doc/c/meson.build delete mode 100644 dpf/dgl/src/pugl-upstream/doc/c/overview.rst delete mode 100644 dpf/dgl/src/pugl-upstream/doc/c/shutting-down.rst delete mode 100644 dpf/dgl/src/pugl-upstream/doc/c/view.rst delete mode 100644 dpf/dgl/src/pugl-upstream/doc/c/world.rst delete mode 100644 dpf/dgl/src/pugl-upstream/doc/c/xml/meson.build delete mode 100644 dpf/dgl/src/pugl-upstream/doc/conf.py.in delete mode 100644 dpf/dgl/src/pugl-upstream/doc/cpp/Doxyfile.in delete mode 100644 dpf/dgl/src/pugl-upstream/doc/cpp/api/meson.build delete mode 100644 dpf/dgl/src/pugl-upstream/doc/cpp/event-loop.rst delete mode 100644 dpf/dgl/src/pugl-upstream/doc/cpp/events.rst delete mode 100644 dpf/dgl/src/pugl-upstream/doc/cpp/index.rst delete mode 100644 dpf/dgl/src/pugl-upstream/doc/cpp/meson.build delete mode 100644 dpf/dgl/src/pugl-upstream/doc/cpp/overview.rst delete mode 100644 dpf/dgl/src/pugl-upstream/doc/cpp/view.rst delete mode 100644 dpf/dgl/src/pugl-upstream/doc/cpp/world.rst delete mode 100644 dpf/dgl/src/pugl-upstream/doc/cpp/xml/meson.build delete mode 100644 dpf/dgl/src/pugl-upstream/doc/deployment.rst delete mode 100644 dpf/dgl/src/pugl-upstream/doc/meson.build delete mode 100644 dpf/dgl/src/pugl-upstream/doc/summary.rst delete mode 100644 dpf/dgl/src/pugl-upstream/examples/.clang-tidy delete mode 100644 dpf/dgl/src/pugl-upstream/examples/cube_view.h delete mode 100644 dpf/dgl/src/pugl-upstream/examples/demo_utils.h delete mode 100644 dpf/dgl/src/pugl-upstream/examples/file_utils.c delete mode 100644 dpf/dgl/src/pugl-upstream/examples/file_utils.h delete mode 100644 dpf/dgl/src/pugl-upstream/examples/glad/glad.c delete mode 100644 dpf/dgl/src/pugl-upstream/examples/glad/glad.h delete mode 100644 dpf/dgl/src/pugl-upstream/examples/glad/khrplatform.h delete mode 100644 dpf/dgl/src/pugl-upstream/examples/meson.build delete mode 100644 dpf/dgl/src/pugl-upstream/examples/pugl_cairo_demo.c delete mode 100644 dpf/dgl/src/pugl-upstream/examples/pugl_cpp_demo.cpp delete mode 100644 dpf/dgl/src/pugl-upstream/examples/pugl_cursor_demo.c delete mode 100644 dpf/dgl/src/pugl-upstream/examples/pugl_embed_demo.c delete mode 100644 dpf/dgl/src/pugl-upstream/examples/pugl_print_events.c delete mode 100644 dpf/dgl/src/pugl-upstream/examples/pugl_shader_demo.c delete mode 100644 dpf/dgl/src/pugl-upstream/examples/pugl_vulkan_cpp_demo.cpp delete mode 100644 dpf/dgl/src/pugl-upstream/examples/pugl_vulkan_demo.c delete mode 100644 dpf/dgl/src/pugl-upstream/examples/pugl_window_demo.c delete mode 100644 dpf/dgl/src/pugl-upstream/examples/rects.h delete mode 100644 dpf/dgl/src/pugl-upstream/examples/shader_utils.h delete mode 100644 dpf/dgl/src/pugl-upstream/examples/shaders/header_330.glsl delete mode 100644 dpf/dgl/src/pugl-upstream/examples/shaders/header_420.glsl delete mode 100644 dpf/dgl/src/pugl-upstream/examples/shaders/meson.build delete mode 100644 dpf/dgl/src/pugl-upstream/examples/shaders/rect.frag delete mode 100644 dpf/dgl/src/pugl-upstream/examples/shaders/rect.vert delete mode 100644 dpf/dgl/src/pugl-upstream/examples/sybok.hpp delete mode 100644 dpf/dgl/src/pugl-upstream/meson.build delete mode 100644 dpf/dgl/src/pugl-upstream/meson/meson.build delete mode 100644 dpf/dgl/src/pugl-upstream/meson_options.txt delete mode 100644 dpf/dgl/src/pugl-upstream/resources/Info.plist.in delete mode 100644 dpf/dgl/src/pugl-upstream/resources/pugl.ipe delete mode 100644 dpf/dgl/src/pugl-upstream/resources/pugl.png delete mode 100644 dpf/dgl/src/pugl-upstream/resources/pugl.svg delete mode 100755 dpf/dgl/src/pugl-upstream/scripts/cat.py delete mode 100755 dpf/dgl/src/pugl-upstream/scripts/dox_to_sphinx.py create mode 100644 dpf/dgl/src/pugl-upstream/src/attributes.h create mode 100644 dpf/dgl/src/pugl-upstream/src/common.c delete mode 100644 dpf/dgl/src/pugl-upstream/src/implementation.c delete mode 100644 dpf/dgl/src/pugl-upstream/src/implementation.h create mode 100644 dpf/dgl/src/pugl-upstream/src/internal.c create mode 100644 dpf/dgl/src/pugl-upstream/src/internal.h create mode 100644 dpf/dgl/src/pugl-upstream/src/platform.h create mode 100644 dpf/dgl/src/pugl-upstream/src/wasm.c create mode 100644 dpf/dgl/src/pugl-upstream/src/wasm.h create mode 100644 dpf/dgl/src/pugl-upstream/src/wasm_gl.c create mode 100644 dpf/dgl/src/pugl-upstream/src/wasm_stub.c delete mode 100644 dpf/dgl/src/pugl-upstream/test/.clang-tidy delete mode 100644 dpf/dgl/src/pugl-upstream/test/meson.build delete mode 100644 dpf/dgl/src/pugl-upstream/test/test_build.c delete mode 100644 dpf/dgl/src/pugl-upstream/test/test_build.cpp delete mode 100644 dpf/dgl/src/pugl-upstream/test/test_cairo.c delete mode 100644 dpf/dgl/src/pugl-upstream/test/test_clipboard.c delete mode 100644 dpf/dgl/src/pugl-upstream/test/test_gl.c delete mode 100644 dpf/dgl/src/pugl-upstream/test/test_gl_hints.c delete mode 100644 dpf/dgl/src/pugl-upstream/test/test_inline_cpp.cpp delete mode 100644 dpf/dgl/src/pugl-upstream/test/test_inline_objcpp.mm delete mode 100644 dpf/dgl/src/pugl-upstream/test/test_local_copy_paste.c delete mode 100644 dpf/dgl/src/pugl-upstream/test/test_realize.c delete mode 100644 dpf/dgl/src/pugl-upstream/test/test_redisplay.c delete mode 100644 dpf/dgl/src/pugl-upstream/test/test_remote_copy_paste.c delete mode 100644 dpf/dgl/src/pugl-upstream/test/test_show_hide.c delete mode 100644 dpf/dgl/src/pugl-upstream/test/test_size.c delete mode 100644 dpf/dgl/src/pugl-upstream/test/test_strerror.c delete mode 100644 dpf/dgl/src/pugl-upstream/test/test_stub.c delete mode 100644 dpf/dgl/src/pugl-upstream/test/test_stub_hints.c delete mode 100644 dpf/dgl/src/pugl-upstream/test/test_timer.c delete mode 100644 dpf/dgl/src/pugl-upstream/test/test_update.c delete mode 100644 dpf/dgl/src/pugl-upstream/test/test_utils.h delete mode 100644 dpf/dgl/src/pugl-upstream/test/test_view.c delete mode 100644 dpf/dgl/src/pugl-upstream/test/test_vulkan.c delete mode 100644 dpf/dgl/src/pugl-upstream/test/test_world.c create mode 100644 dpf/distrho/DistrhoStandaloneUtils.hpp rename dpf/distrho/extra/{FileBrowserDialog.cpp => FileBrowserDialogImpl.cpp} (59%) create mode 100644 dpf/distrho/extra/FileBrowserDialogImpl.hpp create mode 100644 dpf/distrho/extra/Runner.hpp rename dpf/distrho/src/{DistrhoPluginVST3.hpp => DistrhoPluginVST.hpp} (68%) create mode 100644 dpf/distrho/src/jackbridge/NativeBridge.hpp create mode 100644 dpf/distrho/src/jackbridge/SDL2Bridge.hpp create mode 100644 dpf/distrho/src/jackbridge/WebBridge.hpp create mode 100644 dpf/distrho/src/travesty/unit.h delete mode 100644 dpf/tests/Application.cpp delete mode 100644 dpf/tests/Circle.cpp delete mode 100644 dpf/tests/Color.cpp delete mode 100644 dpf/tests/Demo.cpp delete mode 100644 dpf/tests/FileBrowserDialog.cpp delete mode 100644 dpf/tests/Makefile delete mode 100644 dpf/tests/NanoImage.cpp delete mode 100644 dpf/tests/NanoSubWidgets.cpp delete mode 100644 dpf/tests/Point.cpp delete mode 100644 dpf/tests/README.txt delete mode 100644 dpf/tests/Rectangle.cpp delete mode 100644 dpf/tests/Triangle.cpp delete mode 100644 dpf/tests/Window.cpp delete mode 100644 dpf/tests/demo_res/DemoArtwork.cpp delete mode 100644 dpf/tests/demo_res/DemoArtwork.hpp delete mode 100644 dpf/tests/demo_res/ico1.png delete mode 100644 dpf/tests/demo_res/ico2.png delete mode 100644 dpf/tests/demo_res/ico3.png delete mode 100644 dpf/tests/demo_res/ico4.png delete mode 100644 dpf/tests/demo_res/ico5.png delete mode 100644 dpf/tests/images_res/CREDITS.txt delete mode 100644 dpf/tests/images_res/CatPics.cpp delete mode 100644 dpf/tests/images_res/CatPics.hpp delete mode 100644 dpf/tests/images_res/cat1.png delete mode 100644 dpf/tests/images_res/cat2.png delete mode 100644 dpf/tests/images_res/cat3.png delete mode 100644 dpf/tests/tests.hpp delete mode 100644 dpf/tests/widgets/ExampleColorWidget.hpp delete mode 100644 dpf/tests/widgets/ExampleImagesWidget.hpp delete mode 100644 dpf/tests/widgets/ExampleRectanglesWidget.hpp delete mode 100644 dpf/tests/widgets/ExampleShapesWidget.hpp delete mode 100644 dpf/tests/widgets/ExampleTextWidget.hpp delete mode 100644 dpf/tests/widgets/NanoPerfWidget.hpp diff --git a/dpf/Makefile.base.mk b/dpf/Makefile.base.mk index efccd0e..696cdb6 100644 --- a/dpf/Makefile.base.mk +++ b/dpf/Makefile.base.mk @@ -25,30 +25,36 @@ ifneq ($(HAIKU),true) ifneq ($(HURD),true) ifneq ($(LINUX),true) ifneq ($(MACOS),true) +ifneq ($(WASM),true) ifneq ($(WINDOWS),true) ifneq (,$(findstring bsd,$(TARGET_MACHINE))) -BSD=true +BSD = true else ifneq (,$(findstring haiku,$(TARGET_MACHINE))) -HAIKU=true +HAIKU = true else ifneq (,$(findstring linux,$(TARGET_MACHINE))) -LINUX=true +LINUX = true else ifneq (,$(findstring gnu,$(TARGET_MACHINE))) -HURD=true +HURD = true else ifneq (,$(findstring apple,$(TARGET_MACHINE))) -MACOS=true +MACOS = true else ifneq (,$(findstring mingw,$(TARGET_MACHINE))) -WINDOWS=true +WINDOWS = true +else ifneq (,$(findstring msys,$(TARGET_MACHINE))) +WINDOWS = true +else ifneq (,$(findstring wasm,$(TARGET_MACHINE))) +WASM = true else ifneq (,$(findstring windows,$(TARGET_MACHINE))) -WINDOWS=true +WINDOWS = true endif -endif -endif -endif -endif -endif -endif +endif # WINDOWS +endif # WASM +endif # MACOS +endif # LINUX +endif # HURD +endif # HAIKU +endif # BSD # --------------------------------------------------------------------------------------------------------------------- # Auto-detect the processor @@ -56,81 +62,105 @@ endif TARGET_PROCESSOR := $(firstword $(subst -, ,$(TARGET_MACHINE))) ifneq (,$(filter i%86,$(TARGET_PROCESSOR))) -CPU_I386=true -CPU_I386_OR_X86_64=true +CPU_I386 = true +CPU_I386_OR_X86_64 = true +endif +ifneq (,$(filter wasm32,$(TARGET_PROCESSOR))) +CPU_I386 = true +CPU_I386_OR_X86_64 = true endif ifneq (,$(filter x86_64,$(TARGET_PROCESSOR))) -CPU_X86_64=true -CPU_I386_OR_X86_64=true +CPU_X86_64 = true +CPU_I386_OR_X86_64 = true endif ifneq (,$(filter arm%,$(TARGET_PROCESSOR))) -CPU_ARM=true -CPU_ARM_OR_AARCH64=true +CPU_ARM = true +CPU_ARM_OR_AARCH64 = true endif ifneq (,$(filter arm64%,$(TARGET_PROCESSOR))) -CPU_ARM64=true -CPU_ARM_OR_AARCH64=true +CPU_ARM64 = true +CPU_ARM_OR_AARCH64 = true endif ifneq (,$(filter aarch64%,$(TARGET_PROCESSOR))) -CPU_AARCH64=true -CPU_ARM_OR_AARCH64=true +CPU_AARCH64 = true +CPU_ARM_OR_AARCH64 = true endif # --------------------------------------------------------------------------------------------------------------------- # Set PKG_CONFIG (can be overridden by environment variable) -ifeq ($(WINDOWS),true) +ifeq ($(WASM),true) +# Skip on wasm by default +PKG_CONFIG ?= false +else ifeq ($(WINDOWS),true) # Build statically on Windows by default PKG_CONFIG ?= pkg-config --static else PKG_CONFIG ?= pkg-config endif +# --------------------------------------------------------------------------------------------------------------------- +# Set cross compiling flag + +ifeq ($(WASM),true) +CROSS_COMPILING = true +endif + # --------------------------------------------------------------------------------------------------------------------- # Set LINUX_OR_MACOS ifeq ($(LINUX),true) -LINUX_OR_MACOS=true +LINUX_OR_MACOS = true endif ifeq ($(MACOS),true) -LINUX_OR_MACOS=true +LINUX_OR_MACOS = true endif # --------------------------------------------------------------------------------------------------------------------- -# Set MACOS_OR_WINDOWS and HAIKU_OR_MACOS_OR_WINDOWS +# Set MACOS_OR_WINDOWS, MACOS_OR_WASM_OR_WINDOWS, HAIKU_OR_MACOS_OR_WINDOWS and HAIKU_OR_MACOS_OR_WASM_OR_WINDOWS ifeq ($(HAIKU),true) -HAIKU_OR_MACOS_OR_WINDOWS=true +HAIKU_OR_MACOS_OR_WASM_OR_WINDOWS = true +HAIKU_OR_MACOS_OR_WINDOWS = true endif ifeq ($(MACOS),true) -MACOS_OR_WINDOWS=true -HAIKU_OR_MACOS_OR_WINDOWS=true +HAIKU_OR_MACOS_OR_WASM_OR_WINDOWS = true +HAIKU_OR_MACOS_OR_WINDOWS = true +MACOS_OR_WASM_OR_WINDOWS = true +MACOS_OR_WINDOWS = true +endif + +ifeq ($(WASM),true) +HAIKU_OR_MACOS_OR_WASM_OR_WINDOWS = true +MACOS_OR_WASM_OR_WINDOWS = true endif ifeq ($(WINDOWS),true) -MACOS_OR_WINDOWS=true -HAIKU_OR_MACOS_OR_WINDOWS=true +HAIKU_OR_MACOS_OR_WASM_OR_WINDOWS = true +HAIKU_OR_MACOS_OR_WINDOWS = true +MACOS_OR_WASM_OR_WINDOWS = true +MACOS_OR_WINDOWS = true endif # --------------------------------------------------------------------------------------------------------------------- # Set UNIX ifeq ($(BSD),true) -UNIX=true +UNIX = true endif ifeq ($(HURD),true) -UNIX=true +UNIX = true endif ifeq ($(LINUX),true) -UNIX=true +UNIX = true endif ifeq ($(MACOS),true) -UNIX=true +UNIX = true endif # --------------------------------------------------------------------------------------------------------------------- @@ -140,7 +170,12 @@ BASE_FLAGS = -Wall -Wextra -pipe -MD -MP BASE_OPTS = -O3 -ffast-math -fdata-sections -ffunction-sections ifeq ($(CPU_I386_OR_X86_64),true) -BASE_OPTS += -mtune=generic -msse -msse2 -mfpmath=sse +BASE_OPTS += -mtune=generic +ifeq ($(WASM),true) +BASE_OPTS += -msse -msse2 -msse3 -msimd128 +else +BASE_OPTS += -msse -msse2 -mfpmath=sse +endif endif ifeq ($(CPU_ARM),true) @@ -150,19 +185,26 @@ endif endif ifeq ($(MACOS),true) + # MacOS linker flags -LINK_OPTS = -fdata-sections -ffunction-sections -Wl,-dead_strip -Wl,-dead_strip_dylibs +LINK_OPTS = -fdata-sections -ffunction-sections -Wl,-dead_strip,-dead_strip_dylibs ifneq ($(SKIP_STRIPPING),true) LINK_OPTS += -Wl,-x endif + else + # Common linker flags -LINK_OPTS = -fdata-sections -ffunction-sections -Wl,--gc-sections -Wl,-O1 -Wl,--as-needed +LINK_OPTS = -fdata-sections -ffunction-sections -Wl,-O1,--gc-sections +ifneq ($(WASM),true) +LINK_OPTS += -Wl,--as-needed ifneq ($(SKIP_STRIPPING),true) LINK_OPTS += -Wl,--strip-all endif endif +endif + ifeq ($(SKIP_STRIPPING),true) BASE_FLAGS += -g endif @@ -172,9 +214,15 @@ ifeq ($(NOOPT),true) BASE_OPTS = -O2 -ffast-math -fdata-sections -ffunction-sections endif +ifneq ($(MACOS_OR_WASM_OR_WINDOWS),true) +ifneq ($(BSD),true) +BASE_FLAGS += -fno-gnu-unique +endif +endif + ifeq ($(WINDOWS),true) # Assume we want posix -BASE_FLAGS += -posix -D__STDC_FORMAT_MACROS +BASE_FLAGS += -posix -D__STDC_FORMAT_MACROS=1 -D__USE_MINGW_ANSI_STDIO=1 # Needed for windows, see https://github.com/falkTX/Carla/issues/855 BASE_FLAGS += -mstackrealign else @@ -185,29 +233,45 @@ endif ifeq ($(DEBUG),true) BASE_FLAGS += -DDEBUG -O0 -g LINK_OPTS = +ifeq ($(WASM),true) +LINK_OPTS += -sASSERTIONS=1 +endif else BASE_FLAGS += -DNDEBUG $(BASE_OPTS) -fvisibility=hidden CXXFLAGS += -fvisibility-inlines-hidden endif +ifeq ($(STATIC_BUILD),true) +BASE_FLAGS += -DSTATIC_BUILD +# LINK_OPTS += -static +endif + ifeq ($(WITH_LTO),true) BASE_FLAGS += -fno-strict-aliasing -flto -LINK_FLAGS += -fno-strict-aliasing -flto -Werror=odr -Werror=lto-type-mismatch +LINK_OPTS += -fno-strict-aliasing -flto -Werror=odr -Werror=lto-type-mismatch endif BUILD_C_FLAGS = $(BASE_FLAGS) -std=gnu99 $(CFLAGS) BUILD_CXX_FLAGS = $(BASE_FLAGS) -std=gnu++11 $(CXXFLAGS) LINK_FLAGS = $(LINK_OPTS) $(LDFLAGS) -ifneq ($(MACOS),true) +ifeq ($(WASM),true) +# Special flag for emscripten +LINK_FLAGS += -sLLD_REPORT_UNDEFINED +else ifneq ($(MACOS),true) # Not available on MacOS -LINK_FLAGS += -Wl,--no-undefined +LINK_FLAGS += -Wl,--no-undefined endif ifeq ($(MACOS_OLD),true) BUILD_CXX_FLAGS = $(BASE_FLAGS) $(CXXFLAGS) -DHAVE_CPP11_SUPPORT=0 endif +ifeq ($(WASM_EXCEPTIONS),true) +BUILD_CXX_FLAGS += -fexceptions +LINK_FLAGS += -fexceptions +endif + ifeq ($(WINDOWS),true) # Always build statically on windows LINK_FLAGS += -static -static-libgcc -static-libstdc++ @@ -241,46 +305,47 @@ endif HAVE_CAIRO = $(shell $(PKG_CONFIG) --exists cairo && echo true) -# Vulkan is not supported yet -# HAVE_VULKAN = $(shell $(PKG_CONFIG) --exists vulkan && echo true) - -ifeq ($(MACOS_OR_WINDOWS),true) +ifeq ($(MACOS_OR_WASM_OR_WINDOWS),true) HAVE_OPENGL = true else -HAVE_OPENGL = $(shell $(PKG_CONFIG) --exists gl && echo true) -ifneq ($(HAIKU),true) +HAVE_OPENGL = $(shell $(PKG_CONFIG) --exists gl && echo true) HAVE_DBUS = $(shell $(PKG_CONFIG) --exists dbus-1 && echo true) HAVE_X11 = $(shell $(PKG_CONFIG) --exists x11 && echo true) HAVE_XCURSOR = $(shell $(PKG_CONFIG) --exists xcursor && echo true) HAVE_XEXT = $(shell $(PKG_CONFIG) --exists xext && echo true) HAVE_XRANDR = $(shell $(PKG_CONFIG) --exists xrandr && echo true) endif -endif + +# Vulkan is not supported yet +# HAVE_VULKAN = $(shell $(PKG_CONFIG) --exists vulkan && echo true) # --------------------------------------------------------------------------------------------------------------------- # Check for optional libraries HAVE_LIBLO = $(shell $(PKG_CONFIG) --exists liblo && echo true) -ifeq ($(SKIP_RTAUDIO_FALLBACK),true) -CXXFLAGS += -DDPF_JACK_STANDALONE_SKIP_RTAUDIO_FALLBACK -else +ifneq ($(SKIP_NATIVE_AUDIO_FALLBACK),true) +ifneq ($(SKIP_RTAUDIO_FALLBACK),true) + ifeq ($(MACOS),true) HAVE_RTAUDIO = true else ifeq ($(WINDOWS),true) HAVE_RTAUDIO = true -else ifneq ($(HAIKU),true) +else HAVE_ALSA = $(shell $(PKG_CONFIG) --exists alsa && echo true) HAVE_PULSEAUDIO = $(shell $(PKG_CONFIG) --exists libpulse-simple && echo true) +HAVE_SDL2 = $(shell $(PKG_CONFIG) --exists sdl2 && echo true) ifeq ($(HAVE_ALSA),true) HAVE_RTAUDIO = true else ifeq ($(HAVE_PULSEAUDIO),true) HAVE_RTAUDIO = true endif +endif + endif endif -# backwards compat +# backwards compat, always available/enabled HAVE_JACK = true # --------------------------------------------------------------------------------------------------------------------- @@ -288,18 +353,13 @@ HAVE_JACK = true ifeq ($(HAIKU),true) DGL_SYSTEM_LIBS += -lbe -endif - -ifeq ($(MACOS),true) +else ifeq ($(MACOS),true) DGL_SYSTEM_LIBS += -framework Cocoa -framework CoreVideo -endif - -ifeq ($(WINDOWS),true) +else ifeq ($(WASM),true) +else ifeq ($(WINDOWS),true) DGL_SYSTEM_LIBS += -lgdi32 -lcomdlg32 # -lole32 -endif - -ifneq ($(HAIKU_OR_MACOS_OR_WINDOWS),true) +else ifeq ($(HAVE_DBUS),true) DGL_FLAGS += $(shell $(PKG_CONFIG) --cflags dbus-1) -DHAVE_DBUS DGL_SYSTEM_LIBS += $(shell $(PKG_CONFIG) --libs dbus-1) @@ -346,18 +406,18 @@ DGL_FLAGS += -DHAVE_OPENGL ifeq ($(HAIKU),true) OPENGL_FLAGS = $(shell $(PKG_CONFIG) --cflags gl) OPENGL_LIBS = $(shell $(PKG_CONFIG) --libs gl) -endif - -ifeq ($(MACOS),true) +else ifeq ($(MACOS),true) OPENGL_FLAGS = -DGL_SILENCE_DEPRECATION=1 -Wno-deprecated-declarations OPENGL_LIBS = -framework OpenGL +else ifeq ($(WASM),true) +ifneq ($(USE_GLES2),true) +ifneq ($(USE_GLES3),true) +OPENGL_LIBS = -sLEGACY_GL_EMULATION -sGL_UNSAFE_OPTS=0 endif - -ifeq ($(WINDOWS),true) -OPENGL_LIBS = -lopengl32 endif - -ifneq ($(HAIKU_OR_MACOS_OR_WINDOWS),true) +else ifeq ($(WINDOWS),true) +OPENGL_LIBS = -lopengl32 +else OPENGL_FLAGS = $(shell $(PKG_CONFIG) --cflags gl x11) OPENGL_LIBS = $(shell $(PKG_CONFIG) --libs gl x11) endif @@ -369,7 +429,7 @@ endif # --------------------------------------------------------------------------------------------------------------------- # Set Stub specific stuff -ifeq ($(HAIKU_OR_MACOS_OR_WINDOWS),true) +ifeq ($(MACOS_OR_WASM_OR_WINDOWS),true) HAVE_STUB = true else HAVE_STUB = $(HAVE_X11) @@ -409,21 +469,40 @@ PULSEAUDIO_FLAGS = $(shell $(PKG_CONFIG) --cflags libpulse-simple) PULSEAUDIO_LIBS = $(shell $(PKG_CONFIG) --libs libpulse-simple) endif -ifneq ($(HAIKU_OR_MACOS_OR_WINDOWS),true) +ifeq ($(HAVE_SDL2),true) +SDL2_FLAGS = $(shell $(PKG_CONFIG) --cflags sdl2) +SDL2_LIBS = $(shell $(PKG_CONFIG) --libs sdl2) +endif + +ifeq ($(HAVE_JACK),true) +ifeq ($(STATIC_BUILD),true) +JACK_FLAGS = $(shell $(PKG_CONFIG) --cflags jack) +JACK_LIBS = $(shell $(PKG_CONFIG) --libs jack) +endif +endif + +ifneq ($(HAIKU_OR_MACOS_OR_WASM_OR_WINDOWS),true) SHARED_MEMORY_LIBS = -lrt endif # --------------------------------------------------------------------------------------------------------------------- # Backwards-compatible HAVE_DGL -ifeq ($(MACOS_OR_WINDOWS),true) +ifeq ($(MACOS_OR_WASM_OR_WINDOWS),true) HAVE_DGL = true else ifeq ($(HAVE_OPENGL),true) -ifeq ($(HAIKU),true) -HAVE_DGL = true -else HAVE_DGL = $(HAVE_X11) endif + +# --------------------------------------------------------------------------------------------------------------------- +# Namespace flags + +ifneq ($(DISTRHO_NAMESPACE),) +BUILD_CXX_FLAGS += -DDISTRHO_NAMESPACE=$(DISTRHO_NAMESPACE) +endif + +ifneq ($(DGL_NAMESPACE),) +BUILD_CXX_FLAGS += -DDGL_NAMESPACE=$(DGL_NAMESPACE) endif # --------------------------------------------------------------------------------------------------------------------- @@ -441,6 +520,18 @@ ifeq ($(FILE_BROWSER_DISABLED),true) BUILD_CXX_FLAGS += -DDGL_FILE_BROWSER_DISABLED endif +ifneq ($(WINDOWS_ICON_ID),) +BUILD_CXX_FLAGS += -DDGL_WINDOWS_ICON_ID=$(WINDOWS_ICON_ID) +endif + +ifeq ($(USE_GLES2),true) +BUILD_CXX_FLAGS += -DDGL_USE_GLES -DDGL_USE_GLES2 +endif + +ifeq ($(USE_GLES3),true) +BUILD_CXX_FLAGS += -DDGL_USE_GLES -DDGL_USE_GLES3 +endif + ifeq ($(USE_OPENGL3),true) BUILD_CXX_FLAGS += -DDGL_USE_OPENGL3 endif @@ -457,25 +548,26 @@ ifeq ($(USE_RGBA),true) BUILD_CXX_FLAGS += -DDGL_USE_RGBA endif - # --------------------------------------------------------------------------------------------------------------------- # Set app extension -ifeq ($(WINDOWS),true) +ifeq ($(WASM),true) +APP_EXT = .html +else ifeq ($(WINDOWS),true) APP_EXT = .exe endif # --------------------------------------------------------------------------------------------------------------------- # Set shared lib extension -LIB_EXT = .so - ifeq ($(MACOS),true) LIB_EXT = .dylib -endif - -ifeq ($(WINDOWS),true) +else ifeq ($(WASM),true) +LIB_EXT = .wasm +else ifeq ($(WINDOWS),true) LIB_EXT = .dll +else +LIB_EXT = .so endif # --------------------------------------------------------------------------------------------------------------------- @@ -483,6 +575,8 @@ endif ifeq ($(MACOS),true) SHARED = -dynamiclib +else ifeq ($(WASM),true) +SHARED = -sSIDE_MODULE=2 else SHARED = -shared endif @@ -490,8 +584,12 @@ endif # --------------------------------------------------------------------------------------------------------------------- # Handle the verbosity switch -ifeq ($(VERBOSE),true) SILENT = + +ifeq ($(VERBOSE),1) +else ifeq ($(VERBOSE),y) +else ifeq ($(VERBOSE),yes) +else ifeq ($(VERBOSE),true) else SILENT = @ endif @@ -520,9 +618,12 @@ features: $(call print_available,HURD) $(call print_available,LINUX) $(call print_available,MACOS) + $(call print_available,WASM) $(call print_available,WINDOWS) + $(call print_available,HAIKU_OR_MACOS_OR_WASM_OR_WINDOWS) $(call print_available,HAIKU_OR_MACOS_OR_WINDOWS) $(call print_available,LINUX_OR_MACOS) + $(call print_available,MACOS_OR_WASM_OR_WINDOWS) $(call print_available,MACOS_OR_WINDOWS) $(call print_available,UNIX) @echo === Detected features @@ -534,6 +635,7 @@ features: $(call print_available,HAVE_OPENGL) $(call print_available,HAVE_PULSEAUDIO) $(call print_available,HAVE_RTAUDIO) + $(call print_available,HAVE_SDL2) $(call print_available,HAVE_STUB) $(call print_available,HAVE_VULKAN) $(call print_available,HAVE_X11) diff --git a/dpf/Makefile.plugins.mk b/dpf/Makefile.plugins.mk index 3bc341b..d419de7 100644 --- a/dpf/Makefile.plugins.mk +++ b/dpf/Makefile.plugins.mk @@ -38,6 +38,10 @@ ifeq ($(HAVE_ALSA),true) BASE_FLAGS += -DHAVE_ALSA endif +ifeq ($(HAVE_JACK),true) +BASE_FLAGS += -DHAVE_JACK +endif + ifeq ($(HAVE_LIBLO),true) BASE_FLAGS += -DHAVE_LIBLO endif @@ -46,6 +50,36 @@ ifeq ($(HAVE_PULSEAUDIO),true) BASE_FLAGS += -DHAVE_PULSEAUDIO endif +ifeq ($(HAVE_RTAUDIO),true) +BASE_FLAGS += -DHAVE_RTAUDIO +endif + +ifeq ($(HAVE_SDL2),true) +BASE_FLAGS += -DHAVE_SDL2 +endif + +# always needed +ifneq ($(HAIKU_OR_MACOS_OR_WASM_OR_WINDOWS),true) +ifneq ($(STATIC_BUILD),true) +LINK_FLAGS += -ldl +endif +endif + +# --------------------------------------------------------------------------------------------------------------------- +# JACK/Standalone setup + +ifeq ($(WASM),true) + +JACK_FLAGS += -sUSE_SDL=2 +JACK_LIBS += -sUSE_SDL=2 +JACK_LIBS += -sMAIN_MODULE -ldl + +ifneq ($(FILE_BROWSER_DISABLED),true) +JACK_LIBS += -sEXPORTED_RUNTIME_METHODS=FS,cwrap +endif + +else ifneq ($(SKIP_RTAUDIO_FALLBACK),true) + ifeq ($(MACOS),true) JACK_LIBS += -framework CoreAudio -framework CoreFoundation else ifeq ($(WINDOWS),true) @@ -54,26 +88,25 @@ JACK_LIBS += -lole32 -lwinmm JACK_LIBS += -ldsound # WASAPI # JACK_LIBS += -lksuser -lmfplat -lmfuuid -lwmcodecdspuuid -else ifneq ($(HAIKU),true) -ifeq ($(HAVE_ALSA),true) -JACK_FLAGS += $(ALSA_FLAGS) -JACK_LIBS += $(ALSA_LIBS) -endif -ifeq ($(HAVE_PULSEAUDIO),true) +else ifeq ($(HAVE_PULSEAUDIO),true) JACK_FLAGS += $(PULSEAUDIO_FLAGS) JACK_LIBS += $(PULSEAUDIO_LIBS) +else ifeq ($(HAVE_ALSA),true) +JACK_FLAGS += $(ALSA_FLAGS) +JACK_LIBS += $(ALSA_LIBS) endif + ifeq ($(HAVE_RTAUDIO),true) +ifneq ($(HAIKU),true) JACK_LIBS += -lpthread -endif # !HAIKU +endif endif -# backwards compat -BASE_FLAGS += -DHAVE_JACK +ifeq ($(HAVE_SDL2),true) +JACK_FLAGS += $(SDL2_FLAGS) +JACK_LIBS += $(SDL2_LIBS) +endif -# always needed -ifneq ($(HAIKU_OR_MACOS_OR_WINDOWS),true) -LINK_FLAGS += -ldl endif # --------------------------------------------------------------------------------------------------------------------- @@ -103,13 +136,17 @@ endif ifeq ($(LINUX),true) VST3_FILENAME = $(NAME).vst3/Contents/$(TARGET_PROCESSOR)-linux/$(NAME).so -endif -ifeq ($(MACOS),true) +else ifeq ($(MACOS),true) VST3_CONTENTS = $(NAME).vst3/Contents VST3_FILENAME = $(VST3_CONTENTS)/MacOS/$(NAME) +else ifeq ($(WASM),true) +VST3_FILENAME = $(NAME).vst3/Contents/wasm/$(NAME).vst3 +else ifeq ($(WINDOWS),true) +ifeq ($(CPU_I386),true) +VST3_FILENAME = $(NAME).vst3/Contents/x86-win/$(NAME).vst3 +else ifeq ($(CPU_X86_64),true) +VST3_FILENAME = $(NAME).vst3/Contents/x86_64-win/$(NAME).vst3 endif -ifeq ($(WINDOWS),true) -VST3_FILENAME = $(NAME).vst3/Contents/$(TARGET_PROCESSOR)-win/$(NAME).vst3 endif # --------------------------------------------------------------------------------------------------------------------- @@ -127,6 +164,7 @@ ifneq ($(VST3_FILENAME),) vst3 = $(TARGET_DIR)/$(VST3_FILENAME) endif shared = $(TARGET_DIR)/$(NAME)$(LIB_EXT) +static = $(TARGET_DIR)/$(NAME).a ifeq ($(MACOS),true) vst2files += $(TARGET_DIR)/$(VST2_CONTENTS)/Info.plist @@ -149,6 +187,15 @@ SYMBOLS_LV2 = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/lv2.exp SYMBOLS_VST2 = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/vst2.exp SYMBOLS_VST3 = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/vst3.exp SYMBOLS_SHARED = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/shared.exp +else ifeq ($(WASM),true) +SYMBOLS_LADSPA = -sEXPORTED_FUNCTIONS="['ladspa_descriptor']" +SYMBOLS_DSSI = -sEXPORTED_FUNCTIONS="['ladspa_descriptor','dssi_descriptor']" +SYMBOLS_LV2DSP = -sEXPORTED_FUNCTIONS="['lv2_descriptor','lv2_generate_ttl']" +SYMBOLS_LV2UI = -sEXPORTED_FUNCTIONS="['lv2ui_descriptor']" +SYMBOLS_LV2 = -sEXPORTED_FUNCTIONS="['lv2_descriptor','lv2_generate_ttl','lv2ui_descriptor']" +SYMBOLS_VST2 = -sEXPORTED_FUNCTIONS="['VSTPluginMain']" +SYMBOLS_VST3 = -sEXPORTED_FUNCTIONS="['GetPluginFactory','ModuleEntry','ModuleExit']" +SYMBOLS_SHARED = -sEXPORTED_FUNCTIONS="['createSharedPlugin']" else ifeq ($(WINDOWS),true) SYMBOLS_LADSPA = $(DPF_PATH)/utils/symbols/ladspa.def SYMBOLS_DSSI = $(DPF_PATH)/utils/symbols/dssi.def @@ -314,7 +361,11 @@ $(BUILD_DIR)/%.mm.o: %.mm clean: rm -rf $(BUILD_DIR) - rm -rf $(TARGET_DIR)/$(NAME) $(TARGET_DIR)/$(NAME)-* $(TARGET_DIR)/$(NAME).lv2 + rm -rf $(TARGET_DIR)/$(NAME) + rm -rf $(TARGET_DIR)/$(NAME)-* + rm -rf $(TARGET_DIR)/$(NAME).lv2 + rm -rf $(TARGET_DIR)/$(NAME).vst + rm -rf $(TARGET_DIR)/$(NAME).vst3 # --------------------------------------------------------------------------------------------------------------------- # DGL @@ -336,8 +387,6 @@ $(DPF_PATH)/build/libdgl-vulkan.a: # --------------------------------------------------------------------------------------------------------------------- -AS_PUGL_NAMESPACE = $(subst -,_,$(1)) - $(BUILD_DIR)/DistrhoPluginMain_%.cpp.o: $(DPF_PATH)/distrho/DistrhoPluginMain.cpp $(EXTRA_DEPENDENCIES) -@mkdir -p $(BUILD_DIR) @echo "Compiling DistrhoPluginMain.cpp ($*)" @@ -351,7 +400,7 @@ $(BUILD_DIR)/DistrhoUIMain_%.cpp.o: $(DPF_PATH)/distrho/DistrhoUIMain.cpp $(EXTR $(BUILD_DIR)/DistrhoUI_macOS_%.mm.o: $(DPF_PATH)/distrho/DistrhoUI_macOS.mm $(EXTRA_DEPENDENCIES) -@mkdir -p $(BUILD_DIR) @echo "Compiling DistrhoUI_macOS.mm ($*)" - $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -DPUGL_NAMESPACE=$(call AS_PUGL_NAMESPACE,$*) -DGL_SILENCE_DEPRECATION -Wno-deprecated-declarations -I$(DPF_PATH)/dgl/src -I$(DPF_PATH)/dgl/src/pugl-upstream/include -ObjC++ -c -o $@ + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -ObjC++ -c -o $@ $(BUILD_DIR)/DistrhoPluginMain_JACK.cpp.o: $(DPF_PATH)/distrho/DistrhoPluginMain.cpp $(EXTRA_DEPENDENCIES) -@mkdir -p $(BUILD_DIR) @@ -361,7 +410,7 @@ $(BUILD_DIR)/DistrhoPluginMain_JACK.cpp.o: $(DPF_PATH)/distrho/DistrhoPluginMain $(BUILD_DIR)/DistrhoUIMain_DSSI.cpp.o: $(DPF_PATH)/distrho/DistrhoUIMain.cpp $(EXTRA_DEPENDENCIES) -@mkdir -p $(BUILD_DIR) @echo "Compiling DistrhoUIMain.cpp (DSSI)" - $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(LIBLO_FLAGS) -DDISTRHO_PLUGIN_TARGET_DSSI -c -o $@ + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -DDISTRHO_PLUGIN_TARGET_DSSI $(LIBLO_FLAGS) -c -o $@ # --------------------------------------------------------------------------------------------------------------------- # JACK @@ -423,12 +472,12 @@ endif $(lv2_dsp): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.o -@mkdir -p $(shell dirname $@) @echo "Creating LV2 plugin library for $(NAME)" - $(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(SHARED) $(SYMBOLS_LV2DSP) -o $@ + $(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(EXTRA_LIBS) $(SHARED) $(SYMBOLS_LV2DSP) -o $@ $(lv2_ui): $(OBJS_UI) $(BUILD_DIR)/DistrhoUIMain_LV2.cpp.o $(DGL_LIB) -@mkdir -p $(shell dirname $@) @echo "Creating LV2 plugin UI for $(NAME)" - $(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(SHARED) $(SYMBOLS_LV2UI) -o $@ + $(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(EXTRA_LIBS) $(DGL_LIBS) $(SHARED) $(SYMBOLS_LV2UI) -o $@ # --------------------------------------------------------------------------------------------------------------------- # VST2 @@ -472,6 +521,21 @@ endif @echo "Creating shared library for $(NAME)" $(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(EXTRA_LIBS) $(DGL_LIBS) $(SHARED) $(SYMBOLS_SHARED) -o $@ +# --------------------------------------------------------------------------------------------------------------------- +# Static + +static: $(static) + +ifeq ($(HAVE_DGL),true) +$(static): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_STATIC.cpp.o $(BUILD_DIR)/DistrhoUIMain_STATIC.cpp.o +else +$(static): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_STATIC.cpp.o +endif + -@mkdir -p $(shell dirname $@) + @echo "Creating static library for $(NAME)" + $(SILENT)rm -f $@ + $(SILENT)$(AR) crs $@ $^ + # --------------------------------------------------------------------------------------------------------------------- # macOS files @@ -501,6 +565,7 @@ endif -include $(BUILD_DIR)/DistrhoPluginMain_VST2.cpp.d -include $(BUILD_DIR)/DistrhoPluginMain_VST3.cpp.d -include $(BUILD_DIR)/DistrhoPluginMain_SHARED.cpp.d +-include $(BUILD_DIR)/DistrhoPluginMain_STATIC.cpp.d -include $(BUILD_DIR)/DistrhoUIMain_JACK.cpp.d -include $(BUILD_DIR)/DistrhoUIMain_DSSI.cpp.d @@ -508,5 +573,6 @@ endif -include $(BUILD_DIR)/DistrhoUIMain_VST2.cpp.d -include $(BUILD_DIR)/DistrhoUIMain_VST3.cpp.d -include $(BUILD_DIR)/DistrhoUIMain_SHARED.cpp.d +-include $(BUILD_DIR)/DistrhoUIMain_STATIC.cpp.d # --------------------------------------------------------------------------------------------------------------------- diff --git a/dpf/cmake/DPF-plugin.cmake b/dpf/cmake/DPF-plugin.cmake index 66b6927..858c49c 100644 --- a/dpf/cmake/DPF-plugin.cmake +++ b/dpf/cmake/DPF-plugin.cmake @@ -142,7 +142,7 @@ function(dpf_add_plugin NAME) if((NOT WIN32) AND (NOT APPLE) AND (NOT HAIKU)) target_link_libraries("${NAME}-ui" PRIVATE "dl") endif() - # add the files containing Objective-C classes, recompiled under namespace + # add the files containing Objective-C classes dpf__add_plugin_specific_ui_sources("${NAME}-ui") else() add_library("${NAME}-ui" INTERFACE) @@ -468,9 +468,9 @@ function(dpf__add_dgl_cairo) if(NOT APPLE) target_sources(dgl-cairo PRIVATE "${DPF_ROOT_DIR}/dgl/src/pugl.cpp") - else() # Note: macOS pugl will be built as part of DistrhoUI_macOS.mm - #target_sources(dgl-opengl PRIVATE - # "${DPF_ROOT_DIR}/dgl/src/pugl.mm") + else() + target_sources(dgl-opengl PRIVATE + "${DPF_ROOT_DIR}/dgl/src/pugl.mm") endif() target_include_directories(dgl-cairo PUBLIC "${DPF_ROOT_DIR}/dgl") @@ -530,9 +530,9 @@ function(dpf__add_dgl_opengl) if(NOT APPLE) target_sources(dgl-opengl PRIVATE "${DPF_ROOT_DIR}/dgl/src/pugl.cpp") - else() # Note: macOS pugl will be built as part of DistrhoUI_macOS.mm - #target_sources(dgl-opengl PRIVATE - # "${DPF_ROOT_DIR}/dgl/src/pugl.mm") + else() + target_sources(dgl-opengl PRIVATE + "${DPF_ROOT_DIR}/dgl/src/pugl.mm") endif() target_include_directories(dgl-opengl PUBLIC "${DPF_ROOT_DIR}/dgl") @@ -556,19 +556,12 @@ endfunction() # dpf__add_plugin_specific_ui_sources # ------------------------------------------------------------------------------ # -# Compile plugin-specific UI sources into the target designated by the given -# name. There are some special considerations here: -# - On most platforms, sources can be compiled only once, as part of DGL; -# - On macOS, for any sources which define Objective-C interfaces, these must -# be recompiled for each plugin under a unique namespace. In this case, the -# name must be a plugin-specific identifier, and it will be used for computing -# the unique ID along with the project version. +# Compile system specific files, for now it is just Objective-C code +# function(dpf__add_plugin_specific_ui_sources NAME) if(APPLE) target_sources("${NAME}" PRIVATE "${DPF_ROOT_DIR}/distrho/DistrhoUI_macOS.mm") - string(SHA256 _hash "${NAME}:${PROJECT_VERSION}") - target_compile_definitions("${NAME}" PUBLIC "PUGL_NAMESPACE=${_hash}") endif() endfunction() @@ -596,22 +589,22 @@ function(dpf__add_dgl_system_libs) target_include_directories(dgl-system-libs INTERFACE "${X11_INCLUDE_DIR}") target_link_libraries(dgl-system-libs INTERFACE "${X11_X11_LIB}") target_compile_definitions(dgl-system-libs-definitions INTERFACE "HAVE_X11") + if(X11_Xcursor_FOUND) + target_link_libraries(dgl-system-libs INTERFACE "${X11_Xcursor_LIB}") + target_compile_definitions(dgl-system-libs-definitions INTERFACE "HAVE_XCURSOR") + endif() if(X11_Xext_FOUND) target_link_libraries(dgl-system-libs INTERFACE "${X11_Xext_LIB}") target_compile_definitions(dgl-system-libs-definitions INTERFACE "HAVE_XEXT") endif() - if(X11_XSync_FOUND) - target_link_libraries(dgl-system-libs INTERFACE "${X11_XSync_LIB}") - target_compile_definitions(dgl-system-libs-definitions INTERFACE "HAVE_XSYNC") - endif() if(X11_Xrandr_FOUND) target_link_libraries(dgl-system-libs INTERFACE "${X11_Xrandr_LIB}") target_compile_definitions(dgl-system-libs-definitions INTERFACE "HAVE_XRANDR") endif() - #if(X11_Xcursor_FOUND) - # target_link_libraries(dgl-system-libs INTERFACE "${X11_Xcursor_LIB}") - # target_compile_definitions(dgl-system-libs-definitions INTERFACE "HAVE_XCURSOR") - #endif() + if(X11_XSync_FOUND) + target_link_libraries(dgl-system-libs INTERFACE "${X11_XSync_LIB}") + target_compile_definitions(dgl-system-libs-definitions INTERFACE "HAVE_XSYNC") + endif() endif() if(MSVC) diff --git a/dpf/dgl/Application.hpp b/dpf/dgl/Application.hpp index 1024e22..ed25a64 100644 --- a/dpf/dgl/Application.hpp +++ b/dpf/dgl/Application.hpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho + * Copyright (C) 2012-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -19,6 +19,12 @@ #include "Base.hpp" +#ifdef DISTRHO_NAMESPACE +START_NAMESPACE_DISTRHO +class PluginApplication; +END_NAMESPACE_DISTRHO +#endif + START_NAMESPACE_DGL // -------------------------------------------------------------------------------------------------------------------- @@ -33,7 +39,7 @@ START_NAMESPACE_DGL Unless stated otherwise, functions within this class are not thread-safe. */ -class Application +class DISTRHO_API Application { public: /** @@ -103,7 +109,7 @@ public: void removeIdleCallback(IdleCallback* callback); /** - Set the class name of the application. + Get the class name of the application. This is a stable identifier for the application, used as the window class/instance name on X11 and Windows. It is not displayed to the user, but can be used in scripts and by window managers, @@ -111,13 +117,21 @@ public: Plugins created with DPF have their class name automatically set based on DGL_NAMESPACE and plugin name. */ + const char* getClassName() const noexcept; + + /** + Set the class name of the application. + @see getClassName + */ void setClassName(const char* name); private: struct PrivateData; PrivateData* const pData; - friend class PluginApplication; friend class Window; + #ifdef DISTRHO_NAMESPACE + friend class DISTRHO_NAMESPACE::PluginApplication; + #endif DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Application) }; diff --git a/dpf/dgl/Base.hpp b/dpf/dgl/Base.hpp index bb0538c..1ecdb64 100644 --- a/dpf/dgl/Base.hpp +++ b/dpf/dgl/Base.hpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho + * Copyright (C) 2012-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -130,21 +130,44 @@ enum CrossingMode { kCrossingUngrab ///< Crossing due to a grab release }; +/** + A mouse button. + + Mouse button numbers start from 1, and are ordered: primary, secondary, middle. + So, on a typical right-handed mouse, the button numbers are: + + Left: 1 + Right: 2 + Middle (often a wheel): 3 + + Higher button numbers are reported in the same order they are represented on the system. + There is no universal standard here, but buttons 4 and 5 are typically a pair of buttons or a rocker, + which are usually bound to "back" and "forward" operations. + + Note that these numbers may differ from those used on the underlying + platform, since they are manipulated to provide a consistent portable API. +*/ +enum MouseButton { + kMouseButtonLeft = 1, + kMouseButtonRight, + kMouseButtonMiddle, +}; + /** A mouse cursor type. This is a portable subset of mouse cursors that exist on X11, MacOS, and Windows. */ enum MouseCursor { - kMouseCursorArrow, ///< Default pointing arrow - kMouseCursorCaret, ///< Caret (I-Beam) for text entry - kMouseCursorCrosshair, ///< Cross-hair - kMouseCursorHand, ///< Hand with a pointing finger - kMouseCursorNotAllowed, ///< Operation not allowed - kMouseCursorLeftRight, ///< Left/right arrow for horizontal resize - kMouseCursorUpDown, ///< Up/down arrow for vertical resize - kMouseCursorDiagonal, ///< Top-left to bottom-right arrow for diagonal resize - kMouseCursorAntiDiagonal ///< Bottom-left to top-right arrow for diagonal resize + kMouseCursorArrow, ///< Default pointing arrow + kMouseCursorCaret, ///< Caret (I-Beam) for text entry + kMouseCursorCrosshair, ///< Cross-hair + kMouseCursorHand, ///< Hand with a pointing finger + kMouseCursorNotAllowed, ///< Operation not allowed + kMouseCursorLeftRight, ///< Left/right arrow for horizontal resize + kMouseCursorUpDown, ///< Up/down arrow for vertical resize + kMouseCursorDiagonal, ///< Top-left to bottom-right arrow for diagonal resize + kMouseCursorAntiDiagonal ///< Bottom-left to top-right arrow for diagonal resize }; /** @@ -155,11 +178,29 @@ enum MouseCursor { while a smooth scroll is for those with arbitrary scroll direction freedom, like some touchpads. */ enum ScrollDirection { - kScrollUp, ///< Scroll up - kScrollDown, ///< Scroll down - kScrollLeft, ///< Scroll left - kScrollRight, ///< Scroll right - kScrollSmooth ///< Smooth scroll in any direction + kScrollUp, ///< Scroll up + kScrollDown, ///< Scroll down + kScrollLeft, ///< Scroll left + kScrollRight, ///< Scroll right + kScrollSmooth ///< Smooth scroll in any direction +}; + +/** + A clipboard data offer. + @see Window::onClipboardDataOffer +*/ +struct ClipboardDataOffer { + /** + The id of this data offer. + @note The value 0 is reserved for null/invalid. + */ + uint32_t id; + + /** + The type of this data offer. + Usually a MIME type, but may also be another platform-specific type identifier. + */ + const char* type; }; // -------------------------------------------------------------------------------------------------------------------- diff --git a/dpf/dgl/Cairo.hpp b/dpf/dgl/Cairo.hpp index 567aa63..87970c9 100644 --- a/dpf/dgl/Cairo.hpp +++ b/dpf/dgl/Cairo.hpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho + * Copyright (C) 2012-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -20,7 +20,7 @@ #include "ImageBase.hpp" #include "ImageBaseWidgets.hpp" -#include +#include START_NAMESPACE_DGL @@ -151,7 +151,7 @@ public: /** Destructor. */ - virtual ~CairoBaseWidget() {} + ~CairoBaseWidget() override {} protected: /** diff --git a/dpf/tests/Line.cpp b/dpf/dgl/FileBrowserDialog.hpp similarity index 66% rename from dpf/tests/Line.cpp rename to dpf/dgl/FileBrowserDialog.hpp index e00d80b..05c53e0 100644 --- a/dpf/tests/Line.cpp +++ b/dpf/dgl/FileBrowserDialog.hpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho + * Copyright (C) 2012-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -14,17 +14,15 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "tests.hpp" +#ifndef DGL_FILE_BROWSER_DIALOG_HPP_INCLUDED +#define DGL_FILE_BROWSER_DIALOG_HPP_INCLUDED -// -------------------------------------------------------------------------------------------------------------------- +#include "Base.hpp" -int main() -{ - USE_NAMESPACE_DGL; +START_NAMESPACE_DGL - // TODO +#include "../distrho/extra/FileBrowserDialogImpl.hpp" - return 0; -} +END_NAMESPACE_DGL -// -------------------------------------------------------------------------------------------------------------------- +#endif // DGL_FILE_BROWSER_DIALOG_HPP_INCLUDED diff --git a/dpf/dgl/Makefile b/dpf/dgl/Makefile index 867d36d..be92632 100644 --- a/dpf/dgl/Makefile +++ b/dpf/dgl/Makefile @@ -13,10 +13,10 @@ BUILD_CXX_FLAGS += $(DGL_FLAGS) -I. -Isrc -DDONT_SET_USING_DGL_NAMESPACE -Wno-un BUILD_CXX_FLAGS += -Isrc/pugl-upstream/include LINK_FLAGS += $(DGL_LIBS) -# TODO fix these after pugl-upstream is done -BUILD_CXX_FLAGS += -Wno-attributes -Wno-extra -Wno-missing-field-initializers -ifneq ($(MACOS),true) -BUILD_CXX_FLAGS += -Wno-narrowing +ifeq ($(MACOS),true) +BUILD_CXX_FLAGS += -Wno-deprecated-declarations +else +PUGL_EXTRA_FLAGS = -Wno-extra -Wmissing-field-initializers endif # ifneq ($(MACOS_OLD),true) @@ -186,51 +186,63 @@ vulkan: ../build/libdgl-vulkan.a # --------------------------------------------------------------------------------------------------------------------- +../build/dgl/pugl.cpp.o: src/pugl.cpp + -@mkdir -p ../build/dgl + @echo "Compiling $<" + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(PUGL_EXTRA_FLAGS) -c -o $@ + +../build/dgl/pugl.mm.o: src/pugl.mm + -@mkdir -p ../build/dgl + @echo "Compiling $<" + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(PUGL_EXTRA_FLAGS) -c -ObjC++ -o $@ + +# --------------------------------------------------------------------------------------------------------------------- + ../build/dgl/%.cpp.cairo.o: src/%.cpp -@mkdir -p ../build/dgl @echo "Compiling $< (Cairo variant)" - $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(CAIRO_FLAGS) -DDGL_CAIRO -c -o $@ + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(PUGL_EXTRA_FLAGS) $(CAIRO_FLAGS) -DDGL_CAIRO -c -o $@ ../build/dgl/%.mm.cairo.o: src/%.mm -@mkdir -p ../build/dgl @echo "Compiling $< (Cairo variant)" - $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(CAIRO_FLAGS) -DDGL_CAIRO -c -ObjC++ -o $@ + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(PUGL_EXTRA_FLAGS) $(CAIRO_FLAGS) -DDGL_CAIRO -c -ObjC++ -o $@ # --------------------------------------------------------------------------------------------------------------------- ../build/dgl/%.cpp.opengl.o: src/%.cpp -@mkdir -p ../build/dgl @echo "Compiling $< (OpenGL variant)" - $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(OPENGL_FLAGS) -DDGL_OPENGL -c -o $@ + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(PUGL_EXTRA_FLAGS) $(OPENGL_FLAGS) -DDGL_OPENGL -c -o $@ ../build/dgl/%.mm.opengl.o: src/%.mm -@mkdir -p ../build/dgl @echo "Compiling $< (OpenGL variant)" - $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(OPENGL_FLAGS) -DDGL_OPENGL -c -ObjC++ -o $@ + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(PUGL_EXTRA_FLAGS) $(OPENGL_FLAGS) -DDGL_OPENGL -c -ObjC++ -o $@ # --------------------------------------------------------------------------------------------------------------------- ../build/dgl/%.cpp.opengl3.o: src/%.cpp -@mkdir -p ../build/dgl @echo "Compiling $< (OpenGL3 variant)" - $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(OPENGL_FLAGS) -DDGL_OPENGL -DDGL_USE_OPENGL3 -c -o $@ + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(PUGL_EXTRA_FLAGS) $(OPENGL_FLAGS) -DDGL_OPENGL -DDGL_USE_OPENGL3 -c -o $@ ../build/dgl/%.mm.opengl3.o: src/%.mm -@mkdir -p ../build/dgl @echo "Compiling $< (OpenGL3 variant)" - $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(OPENGL_FLAGS) -DDGL_OPENGL -DDGL_USE_OPENGL3 -c -ObjC++ -o $@ + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(PUGL_EXTRA_FLAGS) $(OPENGL_FLAGS) -DDGL_OPENGL -DDGL_USE_OPENGL3 -c -ObjC++ -o $@ # --------------------------------------------------------------------------------------------------------------------- ../build/dgl/%.cpp.vulkan.o: src/%.cpp -@mkdir -p ../build/dgl @echo "Compiling $< (Vulkan variant)" - $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(VULKAN_FLAGS) -DDGL_VULKAN -c -o $@ + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(PUGL_EXTRA_FLAGS) $(VULKAN_FLAGS) -DDGL_VULKAN -c -o $@ ../build/dgl/%.mm.vulkan.o: src/%.mm -@mkdir -p ../build/dgl @echo "Compiling $< (Vulkan variant)" - $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(VULKAN_FLAGS) -DDGL_VULKAN -c -ObjC++ -o $@ + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(PUGL_EXTRA_FLAGS) $(VULKAN_FLAGS) -DDGL_VULKAN -c -ObjC++ -o $@ # --------------------------------------------------------------------------------------------------------------------- diff --git a/dpf/dgl/NanoVG.hpp b/dpf/dgl/NanoVG.hpp index e18074f..bae8f27 100644 --- a/dpf/dgl/NanoVG.hpp +++ b/dpf/dgl/NanoVG.hpp @@ -940,7 +940,7 @@ public: /** Destructor. */ - virtual ~NanoBaseWidget() {} + ~NanoBaseWidget() override {} protected: /** diff --git a/dpf/dgl/OpenGL-include.hpp b/dpf/dgl/OpenGL-include.hpp new file mode 100644 index 0000000..4f4bb0c --- /dev/null +++ b/dpf/dgl/OpenGL-include.hpp @@ -0,0 +1,112 @@ +/* + * DISTRHO Plugin Framework (DPF) + * Copyright (C) 2012-2021 Filipe Coelho + * + * Permission to use, copy, modify, and/or distribute this software for any purpose with + * or without fee is hereby granted, provided that the above copyright notice and this + * permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD + * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef DGL_OPENGL_INCLUDE_HPP_INCLUDED +#define DGL_OPENGL_INCLUDE_HPP_INCLUDED + +#include "../distrho/src/DistrhoDefines.h" + +// -------------------------------------------------------------------------------------------------------------------- +// Fix OpenGL includes for Windows, based on glfw code (part 1) + +#undef DGL_CALLBACK_DEFINED +#undef DGL_WINGDIAPI_DEFINED + +#ifdef DISTRHO_OS_WINDOWS + +#ifndef APIENTRY +# define APIENTRY __stdcall +#endif // APIENTRY + +/* We need WINGDIAPI defined */ +#ifndef WINGDIAPI +# if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__POCC__) +# define WINGDIAPI __declspec(dllimport) +# elif defined(__LCC__) +# define WINGDIAPI __stdcall +# else +# define WINGDIAPI extern +# endif +# define DGL_WINGDIAPI_DEFINED +#endif // WINGDIAPI + +/* Some files also need CALLBACK defined */ +#ifndef CALLBACK +# if defined(_MSC_VER) +# if (defined(_M_MRX000) || defined(_M_IX86) || defined(_M_ALPHA) || defined(_M_PPC)) && !defined(MIDL_PASS) +# define CALLBACK __stdcall +# else +# define CALLBACK +# endif +# else +# define CALLBACK __stdcall +# endif +# define DGL_CALLBACK_DEFINED +#endif // CALLBACK + +#endif // DISTRHO_OS_WINDOWS + +// -------------------------------------------------------------------------------------------------------------------- +// OpenGL includes + +#ifdef DISTRHO_OS_MAC +# ifdef DGL_USE_OPENGL3 +# include +# include +# else +# include +# endif +#else +# ifndef DISTRHO_OS_WINDOWS +# define GL_GLEXT_PROTOTYPES +# endif +# ifndef __GLEW_H__ +# include +# include +# endif +#endif + +// -------------------------------------------------------------------------------------------------------------------- +// Missing OpenGL defines + +#if defined(GL_BGR_EXT) && !defined(GL_BGR) +# define GL_BGR GL_BGR_EXT +#endif + +#if defined(GL_BGRA_EXT) && !defined(GL_BGRA) +# define GL_BGRA GL_BGRA_EXT +#endif + +#ifndef GL_CLAMP_TO_BORDER +# define GL_CLAMP_TO_BORDER 0x812D +#endif + +// -------------------------------------------------------------------------------------------------------------------- +// Fix OpenGL includes for Windows, based on glfw code (part 2) + +#ifdef DGL_CALLBACK_DEFINED +# undef CALLBACK +# undef DGL_CALLBACK_DEFINED +#endif + +#ifdef DGL_WINGDIAPI_DEFINED +# undef WINGDIAPI +# undef DGL_WINGDIAPI_DEFINED +#endif + +// -------------------------------------------------------------------------------------------------------------------- + +#endif diff --git a/dpf/dgl/OpenGL.hpp b/dpf/dgl/OpenGL.hpp index 629d831..91da7e3 100644 --- a/dpf/dgl/OpenGL.hpp +++ b/dpf/dgl/OpenGL.hpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho + * Copyright (C) 2012-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -20,96 +20,7 @@ #include "ImageBase.hpp" #include "ImageBaseWidgets.hpp" -// ----------------------------------------------------------------------- -// Fix OpenGL includes for Windows, based on glfw code (part 1) - -#undef DGL_CALLBACK_DEFINED -#undef DGL_WINGDIAPI_DEFINED - -#ifdef DISTRHO_OS_WINDOWS - -#ifndef APIENTRY -# define APIENTRY __stdcall -#endif // APIENTRY - -/* We need WINGDIAPI defined */ -#ifndef WINGDIAPI -# if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__POCC__) -# define WINGDIAPI __declspec(dllimport) -# elif defined(__LCC__) -# define WINGDIAPI __stdcall -# else -# define WINGDIAPI extern -# endif -# define DGL_WINGDIAPI_DEFINED -#endif // WINGDIAPI - -/* Some files also need CALLBACK defined */ -#ifndef CALLBACK -# if defined(_MSC_VER) -# if (defined(_M_MRX000) || defined(_M_IX86) || defined(_M_ALPHA) || defined(_M_PPC)) && !defined(MIDL_PASS) -# define CALLBACK __stdcall -# else -# define CALLBACK -# endif -# else -# define CALLBACK __stdcall -# endif -# define DGL_CALLBACK_DEFINED -#endif // CALLBACK - -/* Most GL/glu.h variants on Windows need wchar_t */ -#include - -#endif // DISTRHO_OS_WINDOWS - -// ----------------------------------------------------------------------- -// OpenGL includes - -#ifdef DISTRHO_OS_MAC -# ifdef DGL_USE_OPENGL3 -# include -# include -# else -# include -# endif -#else -# ifndef DISTRHO_OS_WINDOWS -# define GL_GLEXT_PROTOTYPES -# endif -# ifndef __GLEW_H__ -# include -# include -# endif -#endif - -// ----------------------------------------------------------------------- -// Missing OpenGL defines - -#if defined(GL_BGR_EXT) && !defined(GL_BGR) -# define GL_BGR GL_BGR_EXT -#endif - -#if defined(GL_BGRA_EXT) && !defined(GL_BGRA) -# define GL_BGRA GL_BGRA_EXT -#endif - -#ifndef GL_CLAMP_TO_BORDER -# define GL_CLAMP_TO_BORDER 0x812D -#endif - -// ----------------------------------------------------------------------- -// Fix OpenGL includes for Windows, based on glfw code (part 2) - -#ifdef DGL_CALLBACK_DEFINED -# undef CALLBACK -# undef DGL_CALLBACK_DEFINED -#endif - -#ifdef DGL_WINGDIAPI_DEFINED -# undef WINGDIAPI -# undef DGL_WINGDIAPI_DEFINED -#endif +#include "OpenGL-include.hpp" START_NAMESPACE_DGL @@ -120,6 +31,8 @@ START_NAMESPACE_DGL */ struct OpenGLGraphicsContext : GraphicsContext { +#ifdef DGL_USE_OPENGL3 +#endif }; // ----------------------------------------------------------------------- @@ -238,11 +151,11 @@ public: // FIXME this should not be needed inline void loadFromMemory(const char* rdata, uint w, uint h, ImageFormat fmt = kImageFormatBGRA) - { loadFromMemory(rdata, Size(w, h), fmt); }; + { loadFromMemory(rdata, Size(w, h), fmt); } inline void draw(const GraphicsContext& context) - { drawAt(context, Point(0, 0)); }; + { drawAt(context, Point(0, 0)); } inline void drawAt(const GraphicsContext& context, int x, int y) - { drawAt(context, Point(x, y)); }; + { drawAt(context, Point(x, y)); } /** Constructor using raw image data, specifying an OpenGL image format. @@ -305,4 +218,4 @@ typedef ImageBaseSwitch OpenGLImageSwitch; END_NAMESPACE_DGL -#endif +#endif // DGL_OPENGL_HPP_INCLUDED diff --git a/dpf/dgl/StandaloneWindow.hpp b/dpf/dgl/StandaloneWindow.hpp index f86e4c3..673a85e 100644 --- a/dpf/dgl/StandaloneWindow.hpp +++ b/dpf/dgl/StandaloneWindow.hpp @@ -71,6 +71,7 @@ public: bool addIdleCallback(IdleCallback* callback, uint timerFrequencyInMs = 0) { return Window::addIdleCallback(callback, timerFrequencyInMs); } bool removeIdleCallback(IdleCallback* callback) { return Window::removeIdleCallback(callback); } + Application& getApp() const noexcept { return Window::getApp(); } const GraphicsContext& getGraphicsContext() const noexcept { return Window::getGraphicsContext(); } double getScaleFactor() const noexcept { return Window::getScaleFactor(); } void setGeometryConstraints(uint minimumWidth, uint minimumHeight, diff --git a/dpf/dgl/SubWidget.hpp b/dpf/dgl/SubWidget.hpp index eab84b7..eefb4c5 100644 --- a/dpf/dgl/SubWidget.hpp +++ b/dpf/dgl/SubWidget.hpp @@ -47,7 +47,7 @@ public: /** Destructor. */ - virtual ~SubWidget(); + ~SubWidget() override; /** Check if this widget contains the point defined by @a x and @a y. diff --git a/dpf/dgl/TopLevelWidget.hpp b/dpf/dgl/TopLevelWidget.hpp index 5e53784..47015a6 100644 --- a/dpf/dgl/TopLevelWidget.hpp +++ b/dpf/dgl/TopLevelWidget.hpp @@ -54,7 +54,7 @@ public: /** Destructor. */ - virtual ~TopLevelWidget(); + ~TopLevelWidget() override; /** Get the application associated with this top-level widget's window. @@ -101,8 +101,8 @@ public: void repaint(const Rectangle& rect) noexcept; // TODO group stuff after here, convenience functions present in Window class + const void* getClipboard(size_t& dataSize); bool setClipboard(const char* mimeType, const void* data, size_t dataSize); - const void* getClipboard(const char*& mimeType, size_t& dataSize); bool setCursor(MouseCursor cursor); bool addIdleCallback(IdleCallback* callback, uint timerFrequencyInMs = 0); bool removeIdleCallback(IdleCallback* callback); diff --git a/dpf/dgl/Widget.hpp b/dpf/dgl/Widget.hpp index 463f7c9..38a49b1 100644 --- a/dpf/dgl/Widget.hpp +++ b/dpf/dgl/Widget.hpp @@ -56,17 +56,16 @@ public: /** Base event data. These are the fields present on all Widget events. - - @a mod Currently active keyboard modifiers, @see Modifier. - @a mod Event flags, @see EventFlag. - @a time Event timestamp (if any). */ struct BaseEvent { + /** Currently active keyboard modifiers. @see Modifier */ uint mod; + /** Event flags. @see EventFlag */ uint flags; + /** Event timestamp (if any). */ uint time; - /** Constructor */ + /** Constructor for default/null values */ BaseEvent() noexcept : mod(0x0), flags(0x0), time(0) {} /** Destuctor */ virtual ~BaseEvent() noexcept {} @@ -86,17 +85,17 @@ public: Alternatively, the raw @a keycode can be used to work directly with physical keys, but note that this value is not portable and differs between platforms and hardware. - @a press True if the key was pressed, false if released. - @a key Unicode point of the key pressed. - @a keycode Raw keycode. @see onKeyboard */ struct KeyboardEvent : BaseEvent { + /** True if the key was pressed, false if released. */ bool press; + /** Unicode point of the key pressed. */ uint key; + /** Raw keycode. */ uint keycode; - /** Constructor */ + /** Constructor for default/null values */ KeyboardEvent() noexcept : BaseEvent(), press(false), @@ -112,9 +111,9 @@ public: */ struct DISTRHO_DEPRECATED_BY("KeyboardEvent") SpecialEvent : BaseEvent { bool press; - Key key; + Key key; - /** Constructor */ + /** Constructor for default/null values */ SpecialEvent() noexcept : BaseEvent(), press(false), @@ -131,17 +130,17 @@ public: so there is not necessarily a direct correspondence between text events and physical key presses. For example, with some input methods a sequence of several key presses will generate a single character. - @a keycode Raw key code. - @a character Unicode character code. - @a string UTF-8 string. @see onCharacterInput */ struct CharacterInputEvent : BaseEvent { + /** Raw key code. */ uint keycode; + /** Unicode character code. */ uint character; + /** UTF-8 string. */ char string[8]; - /** Constructor */ + /** Constructor for default/null values */ CharacterInputEvent() noexcept : BaseEvent(), keycode(0), @@ -155,20 +154,19 @@ public: /** Mouse press or release event. - - @a button The button number starting from 1 (1 = left, 2 = middle, 3 = right). - @a press True if the button was pressed, false if released. - @a pos The widget-relative coordinates of the pointer. - @a absolutePos The absolute coordinates of the pointer. @see onMouse */ struct MouseEvent : BaseEvent { + /** The button number starting from 1. @see MouseButton */ uint button; + /** True if the button was pressed, false if released. */ bool press; + /** The widget-relative coordinates of the pointer. */ Point pos; + /** The absolute coordinates of the pointer. */ Point absolutePos; - /** Constructor */ + /** Constructor for default/null values */ MouseEvent() noexcept : BaseEvent(), button(0), @@ -179,16 +177,15 @@ public: /** Mouse motion event. - - @a pos The widget-relative coordinates of the pointer. - @a absolutePos The absolute coordinates of the pointer. @see onMotion */ struct MotionEvent : BaseEvent { + /** The widget-relative coordinates of the pointer. */ Point pos; + /** The absolute coordinates of the pointer. */ Point absolutePos; - /** Constructor */ + /** Constructor for default/null values */ MotionEvent() noexcept : BaseEvent(), pos(0.0, 0.0), @@ -204,19 +201,19 @@ public: Some systems and devices support finer resolution and/or higher values for fast scrolls, so programs should handle any value gracefully. - @a pos The widget-relative coordinates of the pointer. - @a absolutePos The absolute coordinates of the pointer. - @a delta The scroll distance. - @a direction The direction of the scroll or "smooth". @see onScroll */ struct ScrollEvent : BaseEvent { + /** The widget-relative coordinates of the pointer. */ Point pos; + /** The absolute coordinates of the pointer. */ Point absolutePos; + /** The scroll distance. */ Point delta; + /** The direction of the scroll or "smooth". */ ScrollDirection direction; - /** Constructor */ + /** Constructor for default/null values */ ScrollEvent() noexcept : BaseEvent(), pos(0.0, 0.0), @@ -227,15 +224,15 @@ public: /** Resize event. - @a size The new widget size. - @a oldSize The previous size, may be null. @see onResize */ struct ResizeEvent { + /** The new widget size. */ Size size; + /** The previous size, can be null. */ Size oldSize; - /** Constructor */ + /** Constructor for default/null values */ ResizeEvent() noexcept : size(0, 0), oldSize(0, 0) {} @@ -243,15 +240,15 @@ public: /** Widget position changed event. - @a pos The new absolute position of the widget. - @a oldPos The previous absolute position of the widget. @see onPositionChanged */ struct PositionChangedEvent { + /** The new absolute position of the widget. */ Point pos; + /** The previous absolute position of the widget. */ Point oldPos; - /** Constructor */ + /** Constructor for default/null values */ PositionChangedEvent() noexcept : pos(0, 0), oldPos(0, 0) {} diff --git a/dpf/dgl/Window.hpp b/dpf/dgl/Window.hpp index 3de57e8..c32ba0f 100644 --- a/dpf/dgl/Window.hpp +++ b/dpf/dgl/Window.hpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho + * Copyright (C) 2012-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -20,13 +20,20 @@ #include "Geometry.hpp" #ifndef DGL_FILE_BROWSER_DISABLED -# include "../distrho/extra/FileBrowserDialog.hpp" +# include "FileBrowserDialog.hpp" +#endif + +#include + +#ifdef DISTRHO_NAMESPACE +START_NAMESPACE_DISTRHO +class PluginWindow; +END_NAMESPACE_DISTRHO #endif START_NAMESPACE_DGL class Application; -class PluginWindow; class TopLevelWidget; // ----------------------------------------------------------------------- @@ -52,16 +59,11 @@ class TopLevelWidget; ... */ -class Window +class DISTRHO_API Window { struct PrivateData; public: -#ifndef DGL_FILE_BROWSER_DISABLED - typedef DISTRHO_NAMESPACE::FileBrowserHandle FileBrowserHandle; - typedef DISTRHO_NAMESPACE::FileBrowserOptions FileBrowserOptions; -#endif - /** Window graphics context as a scoped struct. This class gives graphics context drawing time to a window's widgets. @@ -206,6 +208,41 @@ public: */ void setResizable(bool resizable); + /** + Get X offset, typically 0. + */ + int getOffsetX() const noexcept; + + /** + Get Y offset, typically 0. + */ + int getOffsetY() const noexcept; + + /** + Get offset. + */ + Point getOffset() const noexcept; + + /** + Set X offset. + */ + void setOffsetX(int x); + + /** + Set Y offset. + */ + void setOffsetY(int y); + + /** + Set offset using @a x and @a y values. + */ + void setOffset(int x, int y); + + /** + Set offset. + */ + void setOffset(const Point& offset); + /** Get width. */ @@ -263,6 +300,19 @@ public: */ void setIgnoringKeyRepeat(bool ignore) noexcept; + /** + Get the clipboard contents. + + This gets the system clipboard contents, + which may have been set with setClipboard() or copied from another application. + + Returns the clipboard contents, or null. + + @note By default only "text/plain" mimetype is supported and returned. + Override onClipboardDataOffer for supporting other types. + */ + const void* getClipboard(size_t& dataSize); + /** Set the clipboard contents. @@ -274,16 +324,6 @@ public: */ bool setClipboard(const char* mimeType, const void* data, size_t dataSize); - /** - Get the clipboard contents. - - This gets the system clipboard contents, - which may have been set with setClipboard() or copied from another application. - - returns the clipboard contents, or null. - */ - const void* getClipboard(const char*& mimeType, size_t& dataSize); - /** Set the mouse cursor. @@ -360,7 +400,7 @@ public: This function does not block the event loop. */ - bool openFileBrowser(const FileBrowserOptions& options = FileBrowserOptions()); + bool openFileBrowser(const DGL_NAMESPACE::FileBrowserOptions& options = FileBrowserOptions()); #endif /** @@ -402,6 +442,14 @@ public: bool automaticallyScale = false, bool resizeNowIfAutoScaling = true); + /** + Set the transient parent of the window. + + Set this for transient children like dialogs, to have them properly associated with their parent window. + This should be not be called for embed windows, or after making the window visible. + */ + void setTransientParent(uintptr_t transientParentWindowHandle); + /** DEPRECATED Use isIgnoringKeyRepeat(). */ DISTRHO_DEPRECATED_BY("isIgnoringKeyRepeat()") inline bool getIgnoringKeyRepeat() const noexcept { return isIgnoringKeyRepeat(); } @@ -415,6 +463,23 @@ public: inline void exec(bool blockWait = false) { runAsModal(blockWait); } protected: + /** + Get the types available for the data in a clipboard. + Must only be called within the context of onClipboardDataOffer. + */ + std::vector getClipboardDataOfferTypes(); + + /** + A function called when clipboard has data present, possibly with several datatypes. + While handling this event, the data types can be investigated with getClipboardDataOfferTypes() to decide whether to accept the offer. + + Reimplement and return a non-zero id to accept the clipboard data offer for a particular type. + Applications must ignore any type they do not recognize. + + The default implementation accepts the "text/plain" mimetype. + */ + virtual uint32_t onClipboardDataOffer(); + /** A function called when the window is attempted to be closed. Returning true closes the window, which is the default behaviour. @@ -464,8 +529,10 @@ protected: private: PrivateData* const pData; friend class Application; - friend class PluginWindow; friend class TopLevelWidget; + #ifdef DISTRHO_NAMESPACE + friend class DISTRHO_NAMESPACE::PluginWindow; + #endif /** @internal */ explicit Window(Application& app, @@ -477,7 +544,7 @@ private: bool isVST3, bool doPostInit); - DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Window); + DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Window) }; // ----------------------------------------------------------------------- diff --git a/dpf/dgl/src/Application.cpp b/dpf/dgl/src/Application.cpp index 5d6529a..0ec4de8 100644 --- a/dpf/dgl/src/Application.cpp +++ b/dpf/dgl/src/Application.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho + * Copyright (C) 2012-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -16,10 +16,21 @@ #include "ApplicationPrivateData.hpp" +#ifdef __EMSCRIPTEN__ +# include +#endif + START_NAMESPACE_DGL // -------------------------------------------------------------------------------------------------------------------- +#ifdef __EMSCRIPTEN__ +static void app_idle(void* const app) +{ + static_cast(app)->idle(); +} +#endif + Application::Application(const bool isStandalone) : pData(new PrivateData(isStandalone)) {} @@ -37,8 +48,12 @@ void Application::exec(const uint idleTimeInMs) { DISTRHO_SAFE_ASSERT_RETURN(pData->isStandalone,); +#ifdef __EMSCRIPTEN__ + emscripten_set_main_loop_arg(app_idle, this, 0, true); +#else while (! pData->isQuitting) pData->idle(idleTimeInMs); +#endif } void Application::quit() diff --git a/dpf/dgl/src/ApplicationPrivateData.cpp b/dpf/dgl/src/ApplicationPrivateData.cpp index f54535f..ca06a1b 100644 --- a/dpf/dgl/src/ApplicationPrivateData.cpp +++ b/dpf/dgl/src/ApplicationPrivateData.cpp @@ -45,6 +45,13 @@ static bool isThisTheMainThread(const d_ThreadHandle mainThreadHandle) noexcept // -------------------------------------------------------------------------------------------------------------------- +const char* Application::getClassName() const noexcept +{ + return puglGetClassName(pData->world); +} + +// -------------------------------------------------------------------------------------------------------------------- + Application::PrivateData::PrivateData(const bool standalone) : world(puglNewWorld(standalone ? PUGL_PROGRAM : PUGL_MODULE, standalone ? PUGL_WORLD_THREADS : 0x0)), @@ -60,11 +67,8 @@ Application::PrivateData::PrivateData(const bool standalone) DISTRHO_SAFE_ASSERT_RETURN(world != nullptr,); puglSetWorldHandle(world, this); +#ifndef __EMSCRIPTEN__ puglSetClassName(world, DISTRHO_MACRO_AS_STRING(DGL_NAMESPACE)); - -#ifdef DISTRHO_OS_MAC - if (standalone) - puglMacOSActivateApp(); #endif } diff --git a/dpf/dgl/src/ApplicationPrivateData.hpp b/dpf/dgl/src/ApplicationPrivateData.hpp index 40fbc1a..0e33c98 100644 --- a/dpf/dgl/src/ApplicationPrivateData.hpp +++ b/dpf/dgl/src/ApplicationPrivateData.hpp @@ -22,6 +22,9 @@ #include #ifdef DISTRHO_OS_WINDOWS +# ifndef NOMINMAX +# define NOMINMAX +# endif # include # include typedef HANDLE d_ThreadHandle; diff --git a/dpf/dgl/src/NanoVG.cpp b/dpf/dgl/src/NanoVG.cpp index cb78fad..42c0fcd 100644 --- a/dpf/dgl/src/NanoVG.cpp +++ b/dpf/dgl/src/NanoVG.cpp @@ -55,9 +55,9 @@ DGL_EXT(PFNGLUSEPROGRAMPROC, glUseProgram) DGL_EXT(PFNGLVERTEXATTRIBPOINTERPROC, glVertexAttribPointer) DGL_EXT(PFNGLBLENDFUNCSEPARATEPROC, glBlendFuncSeparate) # ifdef DGL_USE_NANOVG_FBO +DGL_EXT(PFNGLCHECKFRAMEBUFFERSTATUSPROC, glCheckFramebufferStatus) DGL_EXT(PFNGLBINDFRAMEBUFFERPROC, glBindFramebuffer) DGL_EXT(PFNGLBINDRENDERBUFFERPROC, glBindRenderbuffer) -DGL_EXT(PFNGLCHECKFRAMEBUFFERSTATUSPROC, glCheckFramebufferStatus) DGL_EXT(PFNGLDELETEFRAMEBUFFERSPROC, glDeleteFramebuffers) DGL_EXT(PFNGLDELETERENDERBUFFERSPROC, glDeleteRenderbuffers) DGL_EXT(PFNGLFRAMEBUFFERTEXTURE2DPROC, glFramebufferTexture2D) @@ -82,7 +82,9 @@ DGL_EXT(PFNGLUNIFORMBLOCKBINDINGPROC, glUniformBlockBinding) // Include NanoVG OpenGL implementation //#define STB_IMAGE_STATIC -#ifdef DGL_USE_OPENGL3 +#if defined(DGL_USE_GLES2) +# define NANOVG_GLES2_IMPLEMENTATION +#elif defined(DGL_USE_OPENGL3) # define NANOVG_GL3_IMPLEMENTATION #else # define NANOVG_GL2_IMPLEMENTATION @@ -138,6 +140,11 @@ NVGcontext* nvgCreateGL(int flags) # define DGL_EXT(PROC, func) \ if (needsInit) func = (PROC) wglGetProcAddress ( #func ); \ DISTRHO_SAFE_ASSERT_RETURN(func != nullptr, nullptr); +# define DGL_EXT2(PROC, func, fallback) \ + if (needsInit) { \ + func = (PROC) wglGetProcAddress ( #func ); \ + if (func == nullptr) func = (PROC) wglGetProcAddress ( #fallback ); \ + } DISTRHO_SAFE_ASSERT_RETURN(func != nullptr, nullptr); DGL_EXT(PFNGLACTIVETEXTUREPROC, glActiveTexture) DGL_EXT(PFNGLATTACHSHADERPROC, glAttachShader) DGL_EXT(PFNGLBINDATTRIBLOCATIONPROC, glBindAttribLocation) @@ -167,16 +174,16 @@ DGL_EXT(PFNGLUSEPROGRAMPROC, glUseProgram) DGL_EXT(PFNGLVERTEXATTRIBPOINTERPROC, glVertexAttribPointer) DGL_EXT(PFNGLBLENDFUNCSEPARATEPROC, glBlendFuncSeparate) # ifdef DGL_USE_NANOVG_FBO -DGL_EXT(PFNGLBINDFRAMEBUFFERPROC, glBindFramebuffer) -DGL_EXT(PFNGLBINDRENDERBUFFERPROC, glBindRenderbuffer) DGL_EXT(PFNGLCHECKFRAMEBUFFERSTATUSPROC, glCheckFramebufferStatus) -DGL_EXT(PFNGLDELETEFRAMEBUFFERSPROC, glDeleteFramebuffers) -DGL_EXT(PFNGLDELETERENDERBUFFERSPROC, glDeleteRenderbuffers) -DGL_EXT(PFNGLFRAMEBUFFERTEXTURE2DPROC, glFramebufferTexture2D) -DGL_EXT(PFNGLFRAMEBUFFERRENDERBUFFERPROC, glFramebufferRenderbuffer) -DGL_EXT(PFNGLGENFRAMEBUFFERSPROC, glGenFramebuffers) -DGL_EXT(PFNGLGENRENDERBUFFERSPROC, glGenRenderbuffers) -DGL_EXT(PFNGLRENDERBUFFERSTORAGEPROC, glRenderbufferStorage) +DGL_EXT2(PFNGLBINDFRAMEBUFFERPROC, glBindFramebuffer, glBindFramebufferEXT) +DGL_EXT2(PFNGLBINDRENDERBUFFERPROC, glBindRenderbuffer, glBindRenderbufferEXT) +DGL_EXT2(PFNGLDELETEFRAMEBUFFERSPROC, glDeleteFramebuffers, glDeleteFramebuffersEXT) +DGL_EXT2(PFNGLDELETERENDERBUFFERSPROC, glDeleteRenderbuffers, glDeleteRenderbuffersEXT) +DGL_EXT2(PFNGLFRAMEBUFFERTEXTURE2DPROC, glFramebufferTexture2D, glFramebufferTexture2DEXT) +DGL_EXT2(PFNGLFRAMEBUFFERRENDERBUFFERPROC, glFramebufferRenderbuffer, glFramebufferRenderbufferEXT) +DGL_EXT2(PFNGLGENFRAMEBUFFERSPROC, glGenFramebuffers, glGenFramebuffersEXT) +DGL_EXT2(PFNGLGENRENDERBUFFERSPROC, glGenRenderbuffers, glGenRenderbuffersEXT) +DGL_EXT2(PFNGLRENDERBUFFERSTORAGEPROC, glRenderbufferStorage, glRenderbufferStorageEXT) # endif # ifdef DGL_USE_OPENGL3 DGL_EXT(PFNGLBINDBUFFERRANGEPROC, glBindBufferRange) @@ -188,6 +195,7 @@ DGL_EXT(PFNGLGENVERTEXARRAYSPROC, glGenVertexArrays) DGL_EXT(PFNGLUNIFORMBLOCKBINDINGPROC, glUniformBlockBinding) # endif # undef DGL_EXT +# undef DGL_EXT2 needsInit = false; # if defined(__GNUC__) && (__GNUC__ >= 9) # pragma GCC diagnostic pop @@ -314,11 +322,14 @@ NanoVG::Paint::operator NVGpaint() const noexcept NanoVG::NanoVG(int flags) : fContext(nvgCreateGL(flags)), fInFrame(false), - fIsSubWidget(false) {} + fIsSubWidget(false) +{ + DISTRHO_CUSTOM_SAFE_ASSERT("Failed to create NanoVG context, expect a black screen", fContext != nullptr); +} NanoVG::~NanoVG() { - DISTRHO_SAFE_ASSERT(! fInFrame); + DISTRHO_CUSTOM_SAFE_ASSERT("Destroying NanoVG context with still active frame", ! fInFrame); if (fContext != nullptr && ! fIsSubWidget) nvgDeleteGL(fContext); diff --git a/dpf/dgl/src/OpenGL.cpp b/dpf/dgl/src/OpenGL.cpp index 0992cc3..b742637 100644 --- a/dpf/dgl/src/OpenGL.cpp +++ b/dpf/dgl/src/OpenGL.cpp @@ -35,11 +35,23 @@ START_NAMESPACE_DGL // ----------------------------------------------------------------------- -#ifdef DGL_USE_OPENGL3 +#if defined(DGL_USE_GLES2) +static void notImplemented(const char* const name) +{ +// d_stderr2("GLES2 function not implemented: %s", name); +} +#elif defined(DGL_USE_GLES3) +static void notImplemented(const char* const name) +{ + d_stderr2("GLES3 function not implemented: %s", name); +} +#elif defined(DGL_USE_OPENGL3) static void notImplemented(const char* const name) { d_stderr2("OpenGL3 function not implemented: %s", name); } +#else +# define DGL_USE_COMPAT_OPENGL #endif // ----------------------------------------------------------------------- @@ -47,7 +59,7 @@ static void notImplemented(const char* const name) void Color::setFor(const GraphicsContext&, const bool includeAlpha) { -#ifndef DGL_USE_OPENGL3 +#ifdef DGL_USE_COMPAT_OPENGL if (includeAlpha) glColor4f(red, green, blue, alpha); else @@ -62,7 +74,7 @@ void Color::setFor(const GraphicsContext&, const bool includeAlpha) // ----------------------------------------------------------------------- // Line -#ifndef DGL_USE_OPENGL3 +#ifdef DGL_USE_COMPAT_OPENGL template static void drawLine(const Point& posStart, const Point& posEnd) { @@ -82,7 +94,7 @@ static void drawLine(const Point& posStart, const Point& posEnd) template void Line::draw(const GraphicsContext&, const T width) { -#ifndef DGL_USE_OPENGL3 +#ifdef DGL_USE_COMPAT_OPENGL DISTRHO_SAFE_ASSERT_RETURN(width != 0,); glLineWidth(static_cast(width)); @@ -96,7 +108,7 @@ void Line::draw(const GraphicsContext&, const T width) template void Line::draw() { -#ifndef DGL_USE_OPENGL3 +#ifdef DGL_USE_COMPAT_OPENGL drawLine(posStart, posEnd); #else notImplemented("Line::draw"); @@ -113,7 +125,7 @@ template class Line; // ----------------------------------------------------------------------- // Circle -#ifndef DGL_USE_OPENGL3 +#ifdef DGL_USE_COMPAT_OPENGL template static void drawCircle(const Point& pos, const uint numSegments, @@ -146,7 +158,7 @@ static void drawCircle(const Point& pos, template void Circle::draw(const GraphicsContext&) { -#ifndef DGL_USE_OPENGL3 +#ifdef DGL_USE_COMPAT_OPENGL drawCircle(fPos, fNumSegments, fSize, fSin, fCos, false); #else notImplemented("Circle::draw"); @@ -159,7 +171,7 @@ void Circle::drawOutline(const GraphicsContext&, const T lineWidth) DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,); glLineWidth(static_cast(lineWidth)); -#ifndef DGL_USE_OPENGL3 +#ifdef DGL_USE_COMPAT_OPENGL drawCircle(fPos, fNumSegments, fSize, fSin, fCos, true); #else notImplemented("Circle::drawOutline"); @@ -170,7 +182,7 @@ void Circle::drawOutline(const GraphicsContext&, const T lineWidth) template void Circle::draw() { -#ifndef DGL_USE_OPENGL3 +#ifdef DGL_USE_COMPAT_OPENGL drawCircle(fPos, fNumSegments, fSize, fSin, fCos, false); #else notImplemented("Circle::draw"); @@ -180,7 +192,7 @@ void Circle::draw() template void Circle::drawOutline() { -#ifndef DGL_USE_OPENGL3 +#ifdef DGL_USE_COMPAT_OPENGL drawCircle(fPos, fNumSegments, fSize, fSin, fCos, true); #else notImplemented("Circle::drawOutline"); @@ -197,7 +209,7 @@ template class Circle; // ----------------------------------------------------------------------- // Triangle -#ifndef DGL_USE_OPENGL3 +#ifdef DGL_USE_COMPAT_OPENGL template static void drawTriangle(const Point& pos1, const Point& pos2, @@ -221,7 +233,7 @@ static void drawTriangle(const Point& pos1, template void Triangle::draw(const GraphicsContext&) { -#ifndef DGL_USE_OPENGL3 +#ifdef DGL_USE_COMPAT_OPENGL drawTriangle(pos1, pos2, pos3, false); #else notImplemented("Triangle::draw"); @@ -234,7 +246,7 @@ void Triangle::drawOutline(const GraphicsContext&, const T lineWidth) DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,); glLineWidth(static_cast(lineWidth)); -#ifndef DGL_USE_OPENGL3 +#ifdef DGL_USE_COMPAT_OPENGL drawTriangle(pos1, pos2, pos3, true); #else notImplemented("Triangle::drawOutline"); @@ -245,7 +257,7 @@ void Triangle::drawOutline(const GraphicsContext&, const T lineWidth) template void Triangle::draw() { -#ifndef DGL_USE_OPENGL3 +#ifdef DGL_USE_COMPAT_OPENGL drawTriangle(pos1, pos2, pos3, false); #else notImplemented("Triangle::draw"); @@ -255,7 +267,7 @@ void Triangle::draw() template void Triangle::drawOutline() { -#ifndef DGL_USE_OPENGL3 +#ifdef DGL_USE_COMPAT_OPENGL drawTriangle(pos1, pos2, pos3, true); #else notImplemented("Triangle::drawOutline"); @@ -272,7 +284,7 @@ template class Triangle; // ----------------------------------------------------------------------- // Rectangle -#ifndef DGL_USE_OPENGL3 +#ifdef DGL_USE_COMPAT_OPENGL template static void drawRectangle(const Rectangle& rect, const bool outline) { @@ -306,7 +318,7 @@ static void drawRectangle(const Rectangle& rect, const bool outline) template void Rectangle::draw(const GraphicsContext&) { -#ifndef DGL_USE_OPENGL3 +#ifdef DGL_USE_COMPAT_OPENGL drawRectangle(*this, false); #else notImplemented("Rectangle::draw"); @@ -319,7 +331,7 @@ void Rectangle::drawOutline(const GraphicsContext&, const T lineWidth) DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,); glLineWidth(static_cast(lineWidth)); -#ifndef DGL_USE_OPENGL3 +#ifdef DGL_USE_COMPAT_OPENGL drawRectangle(*this, true); #else notImplemented("Rectangle::drawOutline"); @@ -330,7 +342,7 @@ void Rectangle::drawOutline(const GraphicsContext&, const T lineWidth) template void Rectangle::draw() { -#ifndef DGL_USE_OPENGL3 +#ifdef DGL_USE_COMPAT_OPENGL drawRectangle(*this, false); #else notImplemented("Rectangle::draw"); @@ -340,7 +352,7 @@ void Rectangle::draw() template void Rectangle::drawOutline() { -#ifndef DGL_USE_OPENGL3 +#ifdef DGL_USE_COMPAT_OPENGL drawRectangle(*this, true); #else notImplemented("Rectangle::drawOutline"); @@ -395,14 +407,14 @@ static void drawOpenGLImage(const OpenGLImage& image, const Point& pos, con setupCalled = true; } -#ifndef DGL_USE_OPENGL3 +#ifdef DGL_USE_COMPAT_OPENGL glColor4f(1.0f, 1.0f, 1.0f, 1.0f); #endif glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, textureId); -#ifndef DGL_USE_OPENGL3 +#ifdef DGL_USE_COMPAT_OPENGL glBegin(GL_QUADS); { @@ -616,21 +628,21 @@ void ImageBaseKnob::onDisplay() if (pData->rotationAngle != 0) { -#ifndef DGL_USE_OPENGL3 +#ifdef DGL_USE_COMPAT_OPENGL glPushMatrix(); #endif const int w2 = w/2; const int h2 = h/2; -#ifndef DGL_USE_OPENGL3 +#ifdef DGL_USE_COMPAT_OPENGL glTranslatef(static_cast(w2), static_cast(h2), 0.0f); glRotatef(normValue*static_cast(pData->rotationAngle), 0.0f, 0.0f, 1.0f); #endif Rectangle(-w2, -h2, w, h).draw(context); -#ifndef DGL_USE_OPENGL3 +#ifdef DGL_USE_COMPAT_OPENGL glPopMatrix(); #endif } diff --git a/dpf/dgl/src/TopLevelWidget.cpp b/dpf/dgl/src/TopLevelWidget.cpp index f577a1c..ab1fa4b 100644 --- a/dpf/dgl/src/TopLevelWidget.cpp +++ b/dpf/dgl/src/TopLevelWidget.cpp @@ -60,14 +60,14 @@ void TopLevelWidget::setSize(const Size& size) pData->window.setSize(size); } -bool TopLevelWidget::setClipboard(const char* const mimeType, const void* const data, const size_t dataSize) +const void* TopLevelWidget::getClipboard(size_t& dataSize) { - return pData->window.setClipboard(mimeType, data, dataSize); + return pData->window.getClipboard(dataSize); } -const void* TopLevelWidget::getClipboard(const char*& mimeType, size_t& dataSize) +bool TopLevelWidget::setClipboard(const char* const mimeType, const void* const data, const size_t dataSize) { - return pData->window.getClipboard(mimeType, dataSize); + return pData->window.setClipboard(mimeType, data, dataSize); } bool TopLevelWidget::setCursor(const MouseCursor cursor) diff --git a/dpf/dgl/src/Window.cpp b/dpf/dgl/src/Window.cpp index d67ab2b..37c61d1 100644 --- a/dpf/dgl/src/Window.cpp +++ b/dpf/dgl/src/Window.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho + * Copyright (C) 2012-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -155,6 +155,48 @@ void Window::setResizable(const bool resizable) pData->setResizable(resizable); } +int Window::getOffsetX() const noexcept +{ + DISTRHO_SAFE_ASSERT_RETURN(pData->view != nullptr, 0); + + return puglGetFrame(pData->view).x; +} + +int Window::getOffsetY() const noexcept +{ + DISTRHO_SAFE_ASSERT_RETURN(pData->view != nullptr, 0); + + return puglGetFrame(pData->view).y; +} + +Point Window::getOffset() const noexcept +{ + DISTRHO_SAFE_ASSERT_RETURN(pData->view != nullptr, Point()); + + const PuglRect rect = puglGetFrame(pData->view); + return Point(rect.x, rect.y); +} + +void Window::setOffsetX(const int x) +{ + setOffset(x, getOffsetY()); +} + +void Window::setOffsetY(const int y) +{ + setOffset(getOffsetX(), y); +} + +void Window::setOffset(const int x, const int y) +{ + puglSetPosition(pData->view, x, y); +} + +void Window::setOffset(const Point& offset) +{ + setOffset(offset.getX(), offset.getY()); +} + uint Window::getWidth() const noexcept { DISTRHO_SAFE_ASSERT_RETURN(pData->view != nullptr, 0); @@ -247,7 +289,7 @@ void Window::setSize(uint width, uint height) } else { - puglSetWindowSize(pData->view, width, height); + puglSetSizeAndDefault(pData->view, width, height); } } @@ -277,18 +319,14 @@ void Window::setIgnoringKeyRepeat(const bool ignore) noexcept puglSetViewHint(pData->view, PUGL_IGNORE_KEY_REPEAT, ignore); } -bool Window::setClipboard(const char* const mimeType, const void* const data, const size_t dataSize) +const void* Window::getClipboard(size_t& dataSize) { - return puglSetClipboard(pData->view, mimeType, data, dataSize) == PUGL_SUCCESS; + return pData->getClipboard(dataSize); } -const void* Window::getClipboard(const char*& mimeType, size_t& dataSize) +bool Window::setClipboard(const char* const mimeType, const void* const data, const size_t dataSize) { - DISTRHO_SAFE_ASSERT_RETURN(!pData->ignoreEvents, nullptr); - pData->ignoreEvents = true; - const void* const clipboard = puglGetClipboard(pData->view, &mimeType, &dataSize); - pData->ignoreEvents = false; - return clipboard; + return puglSetClipboard(pData->view, mimeType != nullptr ? mimeType : "text/plain", data, dataSize) == PUGL_SUCCESS; } bool Window::setCursor(const MouseCursor cursor) @@ -324,7 +362,7 @@ const GraphicsContext& Window::getGraphicsContext() const noexcept uintptr_t Window::getNativeWindowHandle() const noexcept { - return puglGetNativeWindow(pData->view); + return puglGetNativeView(pData->view); } double Window::getScaleFactor() const noexcept @@ -358,10 +396,10 @@ void Window::repaint(const Rectangle& rect) noexcept return; PuglRect prect = { - static_cast(rect.getX()), - static_cast(rect.getY()), - static_cast(rect.getWidth()), - static_cast(rect.getHeight()), + static_cast(rect.getX()), + static_cast(rect.getY()), + static_cast(rect.getWidth()), + static_cast(rect.getHeight()), }; if (pData->autoScaling) { @@ -427,6 +465,43 @@ void Window::setGeometryConstraints(uint minimumWidth, } } +void Window::setTransientParent(const uintptr_t transientParentWindowHandle) +{ + puglSetTransientParent(pData->view, transientParentWindowHandle); +} + +std::vector Window::getClipboardDataOfferTypes() +{ + std::vector offerTypes; + + if (const uint32_t numTypes = puglGetNumClipboardTypes(pData->view)) + { + offerTypes.reserve(numTypes); + + for (uint32_t i=0; iview, i) }; + offerTypes.push_back(offer); + } + } + + return offerTypes; +} + +uint32_t Window::onClipboardDataOffer() +{ + std::vector offers(getClipboardDataOfferTypes()); + + for (std::vector::iterator it=offers.begin(), end=offers.end(); it != end;++it) + { + const ClipboardDataOffer offer = *it; + if (std::strcmp(offer.type, "text/plain") == 0) + return offer.id; + } + + return 0; +} + bool Window::onClose() { return true; @@ -451,13 +526,6 @@ void Window::onFileSelected(const char*) } #endif -#if 0 -void Window::setTransientWinId(const uintptr_t winId) -{ - puglSetTransientFor(pData->view, winId); -} -#endif - // ----------------------------------------------------------------------- END_NAMESPACE_DGL diff --git a/dpf/dgl/src/WindowPrivateData.cpp b/dpf/dgl/src/WindowPrivateData.cpp index 6a9467d..60b8195 100644 --- a/dpf/dgl/src/WindowPrivateData.cpp +++ b/dpf/dgl/src/WindowPrivateData.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho + * Copyright (C) 2012-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -52,39 +52,66 @@ START_NAMESPACE_DGL // ----------------------------------------------------------------------- -static double getDesktopScaleFactor(const PuglView* const view) +static double getScaleFactorFromParent(const PuglView* const view) { // allow custom scale for testing if (const char* const scale = getenv("DPF_SCALE_FACTOR")) return std::max(1.0, std::atof(scale)); if (view != nullptr) - return puglGetDesktopScaleFactor(view); + return puglGetScaleFactorFromParent(view); return 1.0; } +static PuglView* puglNewViewWithTransientParent(PuglWorld* const world, PuglView* const transientParentView) +{ + DISTRHO_SAFE_ASSERT_RETURN(world != nullptr, nullptr); + + if (PuglView* const view = puglNewView(world)) + { + puglSetTransientParent(view, puglGetNativeView(transientParentView)); + return view; + } + + return nullptr; +} + +static PuglView* puglNewViewWithParentWindow(PuglWorld* const world, const uintptr_t parentWindowHandle) +{ + DISTRHO_SAFE_ASSERT_RETURN(world != nullptr, nullptr); + + if (PuglView* const view = puglNewView(world)) + { + puglSetParentWindow(view, parentWindowHandle); + return view; + } + + return nullptr; +} + // ----------------------------------------------------------------------- Window::PrivateData::PrivateData(Application& a, Window* const s) : app(a), appData(a.pData), self(s), - view(puglNewView(appData->world)), - transientParentView(nullptr), + view(appData->world != nullptr ? puglNewView(appData->world) : nullptr), topLevelWidgets(), isClosed(true), isVisible(false), isEmbed(false), usesSizeRequest(false), - scaleFactor(getDesktopScaleFactor(view)), + scaleFactor(getScaleFactorFromParent(view)), autoScaling(false), autoScaleFactor(1.0), minWidth(0), minHeight(0), keepAspectRatio(false), ignoreIdleCallbacks(false), - ignoreEvents(false), + waitingForClipboardData(false), + waitingForClipboardEvents(false), + clipboardTypeId(0), filenameToRenderInto(nullptr), #ifndef DGL_FILE_BROWSER_DISABLED fileBrowserHandle(nullptr), @@ -98,8 +125,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, PrivateData* c : app(a), appData(a.pData), self(s), - view(puglNewView(appData->world)), - transientParentView(ppData->view), + view(puglNewViewWithTransientParent(appData->world, ppData->view)), topLevelWidgets(), isClosed(true), isVisible(false), @@ -112,15 +138,15 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, PrivateData* c minHeight(0), keepAspectRatio(false), ignoreIdleCallbacks(false), - ignoreEvents(false), + waitingForClipboardData(false), + waitingForClipboardEvents(false), + clipboardTypeId(0), filenameToRenderInto(nullptr), #ifndef DGL_FILE_BROWSER_DISABLED fileBrowserHandle(nullptr), #endif modal(ppData) { - puglSetTransientFor(view, puglGetNativeWindow(transientParentView)); - initPre(DEFAULT_WIDTH, DEFAULT_HEIGHT, false); } @@ -130,30 +156,28 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, : app(a), appData(a.pData), self(s), - view(puglNewView(appData->world)), - transientParentView(nullptr), + view(puglNewViewWithParentWindow(appData->world, parentWindowHandle)), topLevelWidgets(), isClosed(parentWindowHandle == 0), isVisible(parentWindowHandle != 0), isEmbed(parentWindowHandle != 0), usesSizeRequest(false), - scaleFactor(scale != 0.0 ? scale : getDesktopScaleFactor(view)), + scaleFactor(scale != 0.0 ? scale : getScaleFactorFromParent(view)), autoScaling(false), autoScaleFactor(1.0), minWidth(0), minHeight(0), keepAspectRatio(false), ignoreIdleCallbacks(false), - ignoreEvents(false), + waitingForClipboardData(false), + waitingForClipboardEvents(false), + clipboardTypeId(0), filenameToRenderInto(nullptr), #ifndef DGL_FILE_BROWSER_DISABLED fileBrowserHandle(nullptr), #endif modal() { - if (isEmbed) - puglSetParentWindow(view, parentWindowHandle); - initPre(DEFAULT_WIDTH, DEFAULT_HEIGHT, resizable); } @@ -164,21 +188,22 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, : app(a), appData(a.pData), self(s), - view(appData->world != nullptr ? puglNewView(appData->world) : nullptr), - transientParentView(nullptr), + view(puglNewViewWithParentWindow(appData->world, parentWindowHandle)), topLevelWidgets(), isClosed(parentWindowHandle == 0), isVisible(parentWindowHandle != 0 && view != nullptr), isEmbed(parentWindowHandle != 0), usesSizeRequest(isVST3), - scaleFactor(scale != 0.0 ? scale : getDesktopScaleFactor(view)), + scaleFactor(scale != 0.0 ? scale : getScaleFactorFromParent(view)), autoScaling(false), autoScaleFactor(1.0), minWidth(0), minHeight(0), keepAspectRatio(false), ignoreIdleCallbacks(false), - ignoreEvents(false), + waitingForClipboardData(false), + waitingForClipboardEvents(false), + clipboardTypeId(0), filenameToRenderInto(nullptr), #ifndef DGL_FILE_BROWSER_DISABLED fileBrowserHandle(nullptr), @@ -230,11 +255,8 @@ void Window::PrivateData::initPre(const uint width, const uint height, const boo } puglSetMatchingBackendForCurrentBuild(view); - - puglClearMinSize(view); - puglSetWindowSize(view, width, height); - puglSetHandle(view, this); + puglSetViewHint(view, PUGL_RESIZABLE, resizable ? PUGL_TRUE : PUGL_FALSE); puglSetViewHint(view, PUGL_IGNORE_KEY_REPEAT, PUGL_FALSE); #if DGL_USE_RGBA @@ -243,12 +265,23 @@ void Window::PrivateData::initPre(const uint width, const uint height, const boo puglSetViewHint(view, PUGL_DEPTH_BITS, 16); #endif puglSetViewHint(view, PUGL_STENCIL_BITS, 8); -#ifdef DGL_USE_OPENGL3 + +#if defined(DGL_USE_OPENGL3) || defined(DGL_USE_GLES3) puglSetViewHint(view, PUGL_USE_COMPAT_PROFILE, PUGL_FALSE); puglSetViewHint(view, PUGL_CONTEXT_VERSION_MAJOR, 3); +#elif defined(DGL_USE_GLES2) + puglSetViewHint(view, PUGL_USE_COMPAT_PROFILE, PUGL_FALSE); + puglSetViewHint(view, PUGL_CONTEXT_VERSION_MAJOR, 2); +#else + puglSetViewHint(view, PUGL_USE_COMPAT_PROFILE, PUGL_TRUE); + puglSetViewHint(view, PUGL_CONTEXT_VERSION_MAJOR, 2); #endif + // PUGL_SAMPLES ?? puglSetEventFunc(view, puglEventCallback); + + // setting default size triggers system-level calls, do it last + puglSetSizeHint(view, PUGL_DEFAULT_SIZE, width, height); } bool Window::PrivateData::initPost() @@ -314,8 +347,8 @@ void Window::PrivateData::show() appData->oneWindowShown(); // FIXME - PuglRect rect = puglGetFrame(view); - puglSetWindowSize(view, static_cast(rect.width), static_cast(rect.height)); +// PuglRect rect = puglGetFrame(view); +// puglSetWindowSize(view, static_cast(rect.width), static_cast(rect.height)); #if defined(DISTRHO_OS_WINDOWS) puglWin32ShowCentered(view); @@ -378,11 +411,7 @@ void Window::PrivateData::focus() if (! isEmbed) puglRaiseWindow(view); -#ifdef HAVE_X11 - puglX11GrabFocus(view); -#else puglGrabFocus(view); -#endif } // ----------------------------------------------------------------------- @@ -393,10 +422,7 @@ void Window::PrivateData::setResizable(const bool resizable) DGL_DBG("Window setResizable called\n"); - puglSetViewHint(view, PUGL_RESIZABLE, resizable ? PUGL_TRUE : PUGL_FALSE); -#ifdef DISTRHO_OS_WINDOWS - puglWin32SetWindowResizable(view, resizable); -#endif + puglSetResizable(view, resizable); } // ----------------------------------------------------------------------- @@ -460,7 +486,7 @@ bool Window::PrivateData::openFileBrowser(const FileBrowserOptions& options) options2.title = puglGetWindowTitle(view); fileBrowserHandle = fileBrowserCreate(isEmbed, - puglGetNativeWindow(view), + puglGetNativeView(view), autoScaling ? autoScaleFactor : scaleFactor, options2); @@ -588,7 +614,7 @@ void Window::PrivateData::onPuglConfigure(const double width, const double heigh void Window::PrivateData::onPuglExpose() { - DGL_DBGp("PUGL: onPuglExpose\n"); + DGL_DBG("PUGL: onPuglExpose\n"); puglOnDisplayPrepare(view); @@ -744,6 +770,78 @@ void Window::PrivateData::onPuglScroll(const Widget::ScrollEvent& ev) #endif } +const void* Window::PrivateData::getClipboard(size_t& dataSize) +{ + clipboardTypeId = 0; + waitingForClipboardData = true, + waitingForClipboardEvents = true; + + // begin clipboard dance here + if (puglPaste(view) != PUGL_SUCCESS) + { + dataSize = 0; + waitingForClipboardEvents = false; + return nullptr; + } + + #ifdef DGL_USING_X11 + // wait for type request, clipboardTypeId must be != 0 to be valid + int retry = static_cast(2 / 0.03); + while (clipboardTypeId == 0 && waitingForClipboardData && --retry >= 0) + { + if (puglX11UpdateWithoutExposures(appData->world) != PUGL_SUCCESS) + break; + } + #endif + + if (clipboardTypeId == 0) + { + dataSize = 0; + waitingForClipboardEvents = false; + return nullptr; + } + + #ifdef DGL_USING_X11 + // wait for actual data (assumes offer was accepted) + retry = static_cast(2 / 0.03); + while (waitingForClipboardData && --retry >= 0) + { + if (puglX11UpdateWithoutExposures(appData->world) != PUGL_SUCCESS) + break; + } + #endif + + if (clipboardTypeId == 0) + { + dataSize = 0; + waitingForClipboardEvents = false; + return nullptr; + } + + waitingForClipboardEvents = false; + return puglGetClipboard(view, clipboardTypeId - 1, &dataSize); +} + +uint32_t Window::PrivateData::onClipboardDataOffer() +{ + DGL_DBG("onClipboardDataOffer\n"); + + if ((clipboardTypeId = self->onClipboardDataOffer()) != 0) + return clipboardTypeId; + + // stop waiting for data, it was rejected + waitingForClipboardData = false; + return 0; +} + +void Window::PrivateData::onClipboardData(const uint32_t typeId) +{ + if (clipboardTypeId != typeId) + clipboardTypeId = 0; + + waitingForClipboardData = false; +} + #if defined(DEBUG) && defined(DGL_DEBUG_EVENTS) static int printEvent(const PuglEvent* event, const char* prefix, const bool verbose); #endif @@ -757,6 +855,36 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu } #endif + if (pData->waitingForClipboardEvents) + { + switch (event->type) + { + case PUGL_UPDATE: + case PUGL_EXPOSE: + case PUGL_FOCUS_IN: + case PUGL_FOCUS_OUT: + case PUGL_KEY_PRESS: + case PUGL_KEY_RELEASE: + case PUGL_TEXT: + case PUGL_POINTER_IN: + case PUGL_POINTER_OUT: + case PUGL_BUTTON_PRESS: + case PUGL_BUTTON_RELEASE: + case PUGL_MOTION: + case PUGL_SCROLL: + case PUGL_TIMER: + case PUGL_LOOP_ENTER: + case PUGL_LOOP_LEAVE: + return PUGL_SUCCESS; + case PUGL_DATA_OFFER: + case PUGL_DATA: + break; + default: + d_stdout("Got event %d while waitingForClipboardEvents", event->type); + break; + } + } + switch (event->type) { ///< No event @@ -765,10 +893,10 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu ///< View created, a #PuglEventCreate case PUGL_CREATE: -#ifdef HAVE_X11 + #ifdef DGL_USING_X11 if (! pData->isEmbed) puglX11SetWindowTypeAndPID(view, pData->appData->isStandalone); -#endif + #endif break; ///< View destroyed, a #PuglEventDestroy @@ -795,8 +923,6 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu ///< View must be drawn, a #PuglEventExpose case PUGL_EXPOSE: - if (pData->ignoreEvents) - break; // unused x, y, width, height (double) pData->onPuglExpose(); break; @@ -810,8 +936,6 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu case PUGL_FOCUS_IN: ///< Keyboard focus left view, a #PuglEventFocus case PUGL_FOCUS_OUT: - if (pData->ignoreEvents) - break; pData->onPuglFocus(event->type == PUGL_FOCUS_IN, static_cast(event->focus.mode)); break; @@ -821,8 +945,6 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu ///< Key released, a #PuglEventKey case PUGL_KEY_RELEASE: { - if (pData->ignoreEvents) - break; // unused x, y, xRoot, yRoot (double) Widget::KeyboardEvent ev; ev.mod = event->key.state; @@ -846,8 +968,6 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu ///< Character entered, a #PuglEventText case PUGL_TEXT: { - if (pData->ignoreEvents) - break; // unused x, y, xRoot, yRoot (double) Widget::CharacterInputEvent ev; ev.mod = event->text.state; @@ -872,13 +992,11 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu ///< Mouse button released, a #PuglEventButton case PUGL_BUTTON_RELEASE: { - if (pData->ignoreEvents) - break; Widget::MouseEvent ev; ev.mod = event->button.state; ev.flags = event->button.flags; ev.time = static_cast(event->button.time * 1000.0 + 0.5); - ev.button = event->button.button; + ev.button = event->button.button + 1; ev.press = event->type == PUGL_BUTTON_PRESS; ev.pos = Point(event->button.x, event->button.y); ev.absolutePos = ev.pos; @@ -889,8 +1007,6 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu ///< Pointer moved, a #PuglEventMotion case PUGL_MOTION: { - if (pData->ignoreEvents) - break; Widget::MotionEvent ev; ev.mod = event->motion.state; ev.flags = event->motion.flags; @@ -904,8 +1020,6 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu ///< Scrolled, a #PuglEventScroll case PUGL_SCROLL: { - if (pData->ignoreEvents) - break; Widget::ScrollEvent ev; ev.mod = event->scroll.state; ev.flags = event->scroll.flags; @@ -924,8 +1038,6 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu ///< Timer triggered, a #PuglEventTimer case PUGL_TIMER: - if (pData->ignoreEvents) - break; if (IdleCallback* const idleCallback = reinterpret_cast(event->timer.id)) idleCallback->idleCallback(); break; @@ -937,6 +1049,17 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu ///< Recursive loop left, a #PuglEventLoopLeave case PUGL_LOOP_LEAVE: break; + + ///< Data offered from clipboard, a #PuglDataOfferEvent + case PUGL_DATA_OFFER: + if (const uint32_t offerTypeId = pData->onClipboardDataOffer()) + puglAcceptOffer(view, &event->offer, offerTypeId - 1); + break; + + ///< Data available from clipboard, a #PuglDataEvent + case PUGL_DATA: + pData->onClipboardData(event->data.typeIndex + 1); + break; } return PUGL_SUCCESS; diff --git a/dpf/dgl/src/WindowPrivateData.hpp b/dpf/dgl/src/WindowPrivateData.hpp index 36d2ce4..d5c3cbd 100644 --- a/dpf/dgl/src/WindowPrivateData.hpp +++ b/dpf/dgl/src/WindowPrivateData.hpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho + * Copyright (C) 2012-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -44,9 +44,6 @@ struct Window::PrivateData : IdleCallback { /** Pugl view instance. */ PuglView* view; - /** Pugl view instance of the transient parent window. */ - PuglView* const transientParentView; - /** Reserved space for graphics context. */ mutable uint8_t graphicsContext[sizeof(void*)]; @@ -80,15 +77,19 @@ struct Window::PrivateData : IdleCallback { /** Whether to ignore idle callback requests, useful for temporary windows. */ bool ignoreIdleCallbacks; - /** Whether to ignore pugl events (except create and destroy), used for puglGetClipboard. */ - bool ignoreEvents; + /** Whether we are waiting to receive clipboard data, ignoring some events in the process. */ + bool waitingForClipboardData; + bool waitingForClipboardEvents; + + /** The type id returned by the last onClipboardDataOffer call. */ + uint32_t clipboardTypeId; /** Render to a picture file when non-null, automatically free+unset after saving. */ char* filenameToRenderInto; #ifndef DGL_FILE_BROWSER_DISABLED /** Handle for file browser dialog operations. */ - FileBrowserHandle fileBrowserHandle; + DGL_NAMESPACE::FileBrowserHandle fileBrowserHandle; #endif /** Modal window setup. */ @@ -165,7 +166,7 @@ struct Window::PrivateData : IdleCallback { #ifndef DGL_FILE_BROWSER_DISABLED // file handling - bool openFileBrowser(const FileBrowserOptions& options); + bool openFileBrowser(const DGL_NAMESPACE::FileBrowserOptions& options); #endif static void renderToPicture(const char* filename, const GraphicsContext& context, uint width, uint height); @@ -186,6 +187,11 @@ struct Window::PrivateData : IdleCallback { void onPuglMotion(const Widget::MotionEvent& ev); void onPuglScroll(const Widget::ScrollEvent& ev); + // clipboard related handling + const void* getClipboard(size_t& dataSize); + uint32_t onClipboardDataOffer(); + void onClipboardData(uint32_t typeId); + // Pugl event handling entry point static PuglStatus puglEventCallback(PuglView* view, const PuglEvent* event); diff --git a/dpf/dgl/src/nanovg/fontstash.h b/dpf/dgl/src/nanovg/fontstash.h index 4a28c6b..37ecafc 100644 --- a/dpf/dgl/src/nanovg/fontstash.h +++ b/dpf/dgl/src/nanovg/fontstash.h @@ -967,7 +967,10 @@ int fonsAddFontMem(FONScontext* stash, const char* name, unsigned char* data, in int idx = fons__allocFont(stash); if (idx == FONS_INVALID) + { + if (freeData && data) free(data); return FONS_INVALID; + } font = stash->fonts[idx]; diff --git a/dpf/dgl/src/nanovg/nanovg_gl.h b/dpf/dgl/src/nanovg/nanovg_gl.h index dc541ff..27e1283 100644 --- a/dpf/dgl/src/nanovg/nanovg_gl.h +++ b/dpf/dgl/src/nanovg/nanovg_gl.h @@ -18,6 +18,28 @@ #ifndef NANOVG_GL_H #define NANOVG_GL_H +#if defined NANOVG_GL2_FORCED +# undef NANOVG_GL3 +# undef NANOVG_GLES2 +# undef NANOVG_GLES3 +# define NANOVG_GL2 1 +#elif defined NANOVG_GL3_FORCED +# undef NANOVG_GL2 +# undef NANOVG_GLES2 +# undef NANOVG_GLES3 +# define NANOVG_GL3 1 +#elif defined NANOVG_GLES2_FORCED +# undef NANOVG_GL2 +# undef NANOVG_GL3 +# undef NANOVG_GLES3 +# define NANOVG_GLES2 1 +#elif defined NANOVG_GLES3_FORCED +# undef NANOVG_GL2 +# undef NANOVG_GL3 +# undef NANOVG_GLES2 +# define NANOVG_GLES3 1 +#endif + #ifdef __cplusplus extern "C" { #endif @@ -151,6 +173,9 @@ struct GLNVGtexture { int width, height; int type; int flags; +#if defined NANOVG_GLES2 + unsigned char* data; +#endif }; typedef struct GLNVGtexture GLNVGtexture; @@ -399,7 +424,12 @@ static int glnvg__deleteTexture(GLNVGcontext* gl, int id) for (i = 0; i < gl->textureContext->ntextures; i++) { if (gl->textureContext->textures[i].id == id) { if (gl->textureContext->textures[i].tex != 0 && (gl->textureContext->textures[i].flags & NVG_IMAGE_NODELETE) == 0) + { glDeleteTextures(1, &gl->textureContext->textures[i].tex); +#if defined NANOVG_GLES2 + free(gl->textureContext->textures[i].data); +#endif + } memset(&gl->textureContext->textures[i], 0, sizeof(gl->textureContext->textures[i])); return 1; } @@ -753,7 +783,7 @@ static int glnvg__renderCreateTexture(void* uptr, int type, int w, int h, int im } // No mips. if (imageFlags & NVG_IMAGE_GENERATE_MIPMAPS) { - printf("Mip-maps is not support for non power-of-two textures (%d x %d)\n", w, h); + printf("Mip-maps is not supported for non power-of-two textures (%d x %d)\n", w, h); imageFlags &= ~NVG_IMAGE_GENERATE_MIPMAPS; } } @@ -783,10 +813,37 @@ static int glnvg__renderCreateTexture(void* uptr, int type, int w, int h, int im switch (type) { case NVG_TEXTURE_BGR: - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_BGR, GL_UNSIGNED_BYTE, data); +#if NANOVG_GLES2 + // GLES2 cannot handle GL_BGR, do local conversion to GL_RGB + tex->data = (uint8_t*)malloc(sizeof(uint8_t) * 3 * w * h); + for (uint32_t i=0; idata[i*3+0] = data[i*3+2]; + tex->data[i*3+1] = data[i*3+1]; + tex->data[i*3+2] = data[i*3+0]; + } + data = tex->data; + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, data); +#else + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_BGR, GL_UNSIGNED_BYTE, data); +#endif break; case NVG_TEXTURE_BGRA: +#if NANOVG_GLES2 + // GLES2 cannot handle GL_BGRA, do local conversion to GL_RGBA + tex->data = (uint8_t*)malloc(sizeof(uint8_t) * 4 * w * h); + for (uint32_t i=0; idata[i*3+0] = data[i*3+3]; + tex->data[i*3+1] = data[i*3+2]; + tex->data[i*3+2] = data[i*3+1]; + tex->data[i*3+3] = data[i*3+0]; + } + data = tex->data; + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, data); +#else glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, data); +#endif break; case NVG_TEXTURE_RGB: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, data); diff --git a/dpf/dgl/src/pugl-upstream/.clang-format b/dpf/dgl/src/pugl-upstream/.clang-format index 7b30bd2..4c1027c 100644 --- a/dpf/dgl/src/pugl-upstream/.clang-format +++ b/dpf/dgl/src/pugl-upstream/.clang-format @@ -24,5 +24,6 @@ StatementMacros: - PUGL_CONST_FUNC - PUGL_DEPRECATED_BY - PUGL_UNUSED + - PUGL_WARN_UNUSED_RESULT - _Pragma ... diff --git a/dpf/dgl/src/pugl-upstream/.includes.imp b/dpf/dgl/src/pugl-upstream/.includes.imp index 64472e0..f13dbd9 100644 --- a/dpf/dgl/src/pugl-upstream/.includes.imp +++ b/dpf/dgl/src/pugl-upstream/.includes.imp @@ -1,15 +1,7 @@ [ { "include": [ "", "private", "", "public", ] }, { "include": [ "", "private", "", "public", ] }, - { "symbol": [ "bool", "private", "", "public" ] }, - { "symbol": [ "int32_t", "private", "", "public" ] }, - { "symbol": [ "int64_t", "private", "", "public" ] }, + { "symbol": [ "std::uintptr_t", "private", "", "public" ] }, { "symbol": [ "timespec", "private", "", "public" ] }, - { "symbol": [ "timeval", "private", "", "public" ] }, - { "symbol": [ "uint32_t", "private", "", "public" ] }, - { "symbol": [ "uint64_t", "private", "", "public" ] }, - { "symbol": [ "uint8_t", "private", "", "public" ] }, - { "symbol": [ "uintptr_t", "private", "", "public" ] }, - - { "symbol": [ "uintptr_t", "private", "", "public" ] } + { "symbol": [ "timeval", "private", "", "public" ] } ] diff --git a/dpf/dgl/src/pugl-upstream/.reuse/dep5 b/dpf/dgl/src/pugl-upstream/.reuse/dep5 new file mode 100644 index 0000000..a90d6e8 --- /dev/null +++ b/dpf/dgl/src/pugl-upstream/.reuse/dep5 @@ -0,0 +1,16 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: pugl +Upstream-Contact: David Robillard +Source: https://gitlab.com/lv2/pugl + +Files: **/meson.build *.md */.clang* .clang* .clant.json .editorconfig .git* .includes.imp AUTHORS doc/*.in meson_options.txt resources/Info.plist.in +Copyright: 2021 David Robillard +License: CC0-1.0 OR ISC + +Files: doc/*.rst examples/glad/glad.c examples/glad/glad.h resources/pugl.ipe resources/pugl.png resources/pugl.svg +Copyright: 2021 David Robillard +License: ISC + +Files: examples/glad/khrplatform.h +Copyright: 2008-2018 The Khronos Group Inc. +License: MIT diff --git a/dpf/dgl/src/pugl-upstream/LICENSES/CC0-1.0.txt b/dpf/dgl/src/pugl-upstream/LICENSES/CC0-1.0.txt new file mode 100644 index 0000000..0e259d4 --- /dev/null +++ b/dpf/dgl/src/pugl-upstream/LICENSES/CC0-1.0.txt @@ -0,0 +1,121 @@ +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. diff --git a/dpf/dgl/src/pugl-upstream/LICENSES/ISC.txt b/dpf/dgl/src/pugl-upstream/LICENSES/ISC.txt new file mode 100644 index 0000000..2844d3c --- /dev/null +++ b/dpf/dgl/src/pugl-upstream/LICENSES/ISC.txt @@ -0,0 +1,11 @@ +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/dpf/dgl/src/pugl-upstream/LICENSES/MIT.txt b/dpf/dgl/src/pugl-upstream/LICENSES/MIT.txt new file mode 100644 index 0000000..f85e365 --- /dev/null +++ b/dpf/dgl/src/pugl-upstream/LICENSES/MIT.txt @@ -0,0 +1,17 @@ +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/dpf/dgl/src/pugl-upstream/README.md b/dpf/dgl/src/pugl-upstream/README.md index 422410f..aae05eb 100644 --- a/dpf/dgl/src/pugl-upstream/README.md +++ b/dpf/dgl/src/pugl-upstream/README.md @@ -1,12 +1,12 @@ Pugl ==== -Pugl (PlUgin Graphics Library) is a minimal portable API for GUIs which is -suitable for use in plugins. It works on X11, MacOS, and Windows, and -optionally supports Vulkan, OpenGL, and Cairo graphics contexts. +Pugl (PlUgin Graphics Library) is a minimal portability layer for GUIs which is +suitable for use in plugins. It works on X11, MacOS, and Windows, and includes +optional support for drawing with Vulkan, OpenGL, and Cairo. -Pugl is vaguely similar to libraries like GLUT and GLFW, but with some -distinguishing features: +Pugl is vaguely similar to libraries like GLUT and GLFW, but has different +goals and priorities: * Minimal in scope, providing only a thin interface to isolate platform-specific details from applications. @@ -16,18 +16,18 @@ distinguishing features: * Support for embedding in native windows, for example as a plugin or component within a larger application that is not based on Pugl. - * Simple and extensible event-based API that makes dispatching in application - or toolkit code easy with minimal boilerplate. + * Explicit context and no static data, so that several instances can be used + within a single program at once. - * Suitable not only for continuously rendering applications like games, but - also event-driven applications that only draw when necessary. + * Consistent event-based API that makes dispatching in application or toolkit + code easy with minimal boilerplate. - * Explicit context and no static data whatsoever, so that several instances - can be used within a single program at once. + * Suitable for both continuously rendering applications like games, and + event-driven applications that only draw when necessary. - * Small, liberally licensed Free Software implementation that is suitable for - vendoring and/or static linking. Pugl can be installed as a library, or - used by simply copying the headers into a project. + * Small, liberally licensed implementation that is suitable for vendoring + and/or static linking. Pugl can be installed as a library, or used by + simply copying the implementation into a project. Stability --------- @@ -37,6 +37,10 @@ being, however, the API may break occasionally. Please report any relevant feedback, or file feature requests, so that we can ensure that the released API is stable for as long as possible. +When the API changes, backwards compatibility is maintained where possible. +These compatibility shims will be removed before release, so users are +encouraged to build with `PUGL_DISABLE_DEPRECATED` defined. + Documentation ------------- @@ -62,37 +66,7 @@ all the tests at once via ninja: cd build ninja test -The `examples` directory contains several programs that serve as both manual -tests and demonstrations: - - * `pugl_embed_demo` shows a view embedded in another, and also tests - requesting attention (which happens after 5 seconds), keyboard focus - (switched by pressing tab), view moving (with the arrow keys), and view - resizing (with the arrow keys while shift is held). This program uses only - very old OpenGL and should work on any system. - - * `pugl_window_demo` demonstrates multiple top-level windows. - - * `pugl_shader_demo` demonstrates using more modern OpenGL (version 3 or 4) - where dynamic loading and shaders are required. It can also be used to test - performance by passing the number of rectangles to draw on the command line. - - * `pugl_cairo_demo` demonstrates using Cairo on top of the native windowing - system (without OpenGL), and partial redrawing. - - * `pugl_print_events` is a utility that prints all received events to the - console in a human readable format. - - * `pugl_cpp_demo` is a simple cube demo that uses the C++ API. - - * `pugl_vulkan_demo` is a simple example of using Vulkan in C that simply - clears the window. - - * `pugl_vulkan_cpp_demo` is a more advanced Vulkan demo in C++ that draws many - animated rectangles like `pugl_shader_demo`. - -All example programs support several command line options to control various -behaviours, see the output of `--help` for details. Please file an issue if -any of these programs do not work as expected on your system. +The [examples](examples) directory contains several demonstration programs that +can be used for manual testing. -- David Robillard diff --git a/dpf/dgl/src/pugl-upstream/bindings/cpp/include/.clang-tidy b/dpf/dgl/src/pugl-upstream/bindings/cpp/include/.clang-tidy deleted file mode 100644 index 20c477e..0000000 --- a/dpf/dgl/src/pugl-upstream/bindings/cpp/include/.clang-tidy +++ /dev/null @@ -1,15 +0,0 @@ -Checks: > - *, - -*-uppercase-literal-suffix, - -altera-struct-pack-align, - -clang-diagnostic-unused-macros, - -cppcoreguidelines-pro-bounds-pointer-arithmetic, - -cppcoreguidelines-pro-type-reinterpret-cast, - -google-runtime-references, - -hicpp-named-parameter, - -llvmlibc-*, - -modernize-use-trailing-return-type, - -readability-implicit-bool-conversion, - -readability-named-parameter, -FormatStyle: file -HeaderFilterRegex: 'pugl/.*' diff --git a/dpf/dgl/src/pugl-upstream/bindings/cpp/include/meson.build b/dpf/dgl/src/pugl-upstream/bindings/cpp/include/meson.build deleted file mode 100644 index 8d5c563..0000000 --- a/dpf/dgl/src/pugl-upstream/bindings/cpp/include/meson.build +++ /dev/null @@ -1,12 +0,0 @@ -cpp_headers = [ - 'pugl/pugl.hpp', - - 'pugl/cairo.hpp', - 'pugl/gl.hpp', - 'pugl/stub.hpp', - 'pugl/vulkan.hpp', -] - -cpp_header_files = files(cpp_headers) - -install_headers(cpp_headers, subdir: 'puglpp' + version_suffix / 'pugl') diff --git a/dpf/dgl/src/pugl-upstream/bindings/cpp/include/pugl/cairo.hpp b/dpf/dgl/src/pugl-upstream/bindings/cpp/include/pugl/cairo.hpp deleted file mode 100644 index b42af0d..0000000 --- a/dpf/dgl/src/pugl-upstream/bindings/cpp/include/pugl/cairo.hpp +++ /dev/null @@ -1,45 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef PUGL_CAIRO_HPP -#define PUGL_CAIRO_HPP - -#include "pugl/cairo.h" -#include "pugl/pugl.h" - -namespace pugl { - -/** - @defgroup cairopp Cairo - Cairo graphics support. - @ingroup puglpp - @{ -*/ - -/// @copydoc puglCairoBackend -inline const PuglBackend* -cairoBackend() noexcept -{ - return puglCairoBackend(); -} - -/** - @} -*/ - -} // namespace pugl - -#endif // PUGL_CAIRO_HPP diff --git a/dpf/dgl/src/pugl-upstream/bindings/cpp/include/pugl/gl.hpp b/dpf/dgl/src/pugl-upstream/bindings/cpp/include/pugl/gl.hpp deleted file mode 100644 index 3e23a57..0000000 --- a/dpf/dgl/src/pugl-upstream/bindings/cpp/include/pugl/gl.hpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef PUGL_GL_HPP -#define PUGL_GL_HPP - -#include "pugl/gl.h" -#include "pugl/pugl.h" -#include "pugl/pugl.hpp" - -namespace pugl { - -/** - @defgroup glpp OpenGL - OpenGL graphics support. - @ingroup puglpp - @{ -*/ - -/// @copydoc PuglGlFunc -using GlFunc = PuglGlFunc; - -/// @copydoc puglGetProcAddress -inline GlFunc -getProcAddress(const char* name) noexcept -{ - return puglGetProcAddress(name); -} - -/// @copydoc puglEnterContext -inline Status -enterContext(View& view) noexcept -{ - return static_cast(puglEnterContext(view.cobj())); -} - -/// @copydoc puglLeaveContext -inline Status -leaveContext(View& view) noexcept -{ - return static_cast(puglLeaveContext(view.cobj())); -} - -/// @copydoc puglGlBackend -inline const PuglBackend* -glBackend() noexcept -{ - return puglGlBackend(); -} - -/** - @} -*/ - -} // namespace pugl - -#endif // PUGL_GL_HPP diff --git a/dpf/dgl/src/pugl-upstream/bindings/cpp/include/pugl/pugl.hpp b/dpf/dgl/src/pugl-upstream/bindings/cpp/include/pugl/pugl.hpp deleted file mode 100644 index 85643ad..0000000 --- a/dpf/dgl/src/pugl-upstream/bindings/cpp/include/pugl/pugl.hpp +++ /dev/null @@ -1,734 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef PUGL_PUGL_HPP -#define PUGL_PUGL_HPP - -#include "pugl/pugl.h" - -#include - -#if defined(PUGL_HPP_THROW_FAILED_CONSTRUCTION) -# include -#elif defined(PUGL_HPP_ASSERT_CONSTRUCTION) -# include -#endif - -namespace pugl { - -/** - @defgroup puglpp Pugl C++ API - Pugl C++ API wrapper. - @{ -*/ - -namespace detail { - -/// Free function for a C object -template -using FreeFunc = void (*)(T*); - -/// Generic C++ wrapper for a C object -template Free> -class Wrapper -{ -public: - Wrapper(const Wrapper&) = delete; - Wrapper& operator=(const Wrapper&) = delete; - - Wrapper(Wrapper&& wrapper) noexcept - : _ptr{wrapper._ptr} - { - wrapper._ptr = nullptr; - } - - Wrapper& operator=(Wrapper&& wrapper) noexcept - { - _ptr = wrapper._ptr; - wrapper._ptr = nullptr; - return *this; - } - - ~Wrapper() noexcept { Free(_ptr); } - - T* cobj() noexcept { return _ptr; } - const T* cobj() const noexcept { return _ptr; } - -protected: - explicit Wrapper(T* ptr) noexcept - : _ptr{ptr} - {} - -private: - T* _ptr; -}; - -} // namespace detail - -using Rect = PuglRect; ///< @copydoc PuglRect - -/** - @defgroup eventspp Events - @{ -*/ - -/** - A strongly-typed analogue of PuglEvent. - - This is bit-for-bit identical to the corresponding PuglEvent. - - @tparam t The `type` field of the corresponding PuglEvent. - - @tparam Base The specific struct type of the corresponding PuglEvent. -*/ -template -struct Event final : Base { - /// The type of the corresponding C event structure - using BaseEvent = Base; - - /// The `type` field of the corresponding C event structure - static constexpr const PuglEventType type = t; - - explicit Event(Base base) - : Base{base} - {} - - template - explicit Event(const PuglEventFlags f, Args... args) - : Base{t, f, args...} - {} -}; - -using Mod = PuglMod; ///< @copydoc PuglMod -using Mods = PuglMods; ///< @copydoc PuglMods -using Key = PuglKey; ///< @copydoc PuglKey -using EventType = PuglEventType; ///< @copydoc PuglEventType -using EventFlag = PuglEventFlag; ///< @copydoc PuglEventFlag -using EventFlags = PuglEventFlags; ///< @copydoc PuglEventFlags -using CrossingMode = PuglCrossingMode; ///< @copydoc PuglCrossingMode - -/// @copydoc PuglCreateEvent -using CreateEvent = Event; - -/// @copydoc PuglDestroyEvent -using DestroyEvent = Event; - -/// @copydoc PuglConfigureEvent -using ConfigureEvent = Event; - -/// @copydoc PuglMapEvent -using MapEvent = Event; - -/// @copydoc PuglUnmapEvent -using UnmapEvent = Event; - -/// @copydoc PuglUpdateEvent -using UpdateEvent = Event; - -/// @copydoc PuglExposeEvent -using ExposeEvent = Event; - -/// @copydoc PuglCloseEvent -using CloseEvent = Event; - -/// @copydoc PuglFocusEvent -using FocusInEvent = Event; - -/// @copydoc PuglFocusEvent -using FocusOutEvent = Event; - -/// @copydoc PuglKeyEvent -using KeyPressEvent = Event; - -/// @copydoc PuglKeyEvent -using KeyReleaseEvent = Event; - -/// @copydoc PuglTextEvent -using TextEvent = Event; - -/// @copydoc PuglCrossingEvent -using PointerInEvent = Event; - -/// @copydoc PuglCrossingEvent -using PointerOutEvent = Event; - -/// @copydoc PuglButtonEvent -using ButtonPressEvent = Event; - -/// @copydoc PuglButtonEvent -using ButtonReleaseEvent = Event; - -/// @copydoc PuglMotionEvent -using MotionEvent = Event; - -/// @copydoc PuglScrollEvent -using ScrollEvent = Event; - -/// @copydoc PuglClientEvent -using ClientEvent = Event; - -/// @copydoc PuglTimerEvent -using TimerEvent = Event; - -/// @copydoc PuglLoopEnterEvent -using LoopEnterEvent = Event; - -/// @copydoc PuglLoopLeaveEvent -using LoopLeaveEvent = Event; - -/** - @} - @defgroup statuspp Status - @{ -*/ - -/// @copydoc PuglStatus -enum class Status { - success, ///< @copydoc PUGL_SUCCESS - failure, ///< @copydoc PUGL_FAILURE - unknownError, ///< @copydoc PUGL_UNKNOWN_ERROR - badBackend, ///< @copydoc PUGL_BAD_BACKEND - badConfiguration, ///< @copydoc PUGL_BAD_CONFIGURATION - badParameter, ///< @copydoc PUGL_BAD_PARAMETER - backendFailed, ///< @copydoc PUGL_BACKEND_FAILED - registrationFailed, ///< @copydoc PUGL_REGISTRATION_FAILED - realizeFailed, ///< @copydoc PUGL_REALIZE_FAILED - setFormatFailed, ///< @copydoc PUGL_SET_FORMAT_FAILED - createContextFailed, ///< @copydoc PUGL_CREATE_CONTEXT_FAILED - unsupportedType, ///< @copydoc PUGL_UNSUPPORTED_TYPE -}; - -static_assert(Status(PUGL_UNSUPPORTED_TYPE) == Status::unsupportedType, ""); - -/// @copydoc puglStrerror -inline const char* -strerror(const Status status) noexcept -{ - return puglStrerror(static_cast(status)); -} - -/** - @} - @defgroup worldpp World - @{ -*/ - -/// @copydoc PuglWorldType -enum class WorldType { - program, ///< @copydoc PUGL_PROGRAM - module, ///< @copydoc PUGL_MODULE -}; - -static_assert(WorldType(PUGL_MODULE) == WorldType::module, ""); - -/// @copydoc PuglWorldFlag -enum class WorldFlag { - threads = PUGL_WORLD_THREADS, ///< @copydoc PUGL_WORLD_THREADS -}; - -static_assert(WorldFlag(PUGL_WORLD_THREADS) == WorldFlag::threads, ""); - -using WorldFlags = PuglWorldFlags; ///< @copydoc PuglWorldFlags - -#if defined(PUGL_HPP_THROW_FAILED_CONSTRUCTION) - -/// An exception thrown when construction fails -class FailedConstructionError : public std::exception -{ -public: - FailedConstructionError(const char* const msg) noexcept - : _msg{msg} - {} - - virtual const char* what() const noexcept override; - -private: - const char* _msg; -}; - -# define PUGL_CHECK_CONSTRUCTION(cond, msg) \ - do { \ - if (!(cond)) { \ - throw FailedConstructionError(msg); \ - } \ - } while (0) - -#elif defined(PUGL_HPP_ASSERT_CONSTRUCTION) -# define PUGL_CHECK_CONSTRUCTION(cond, msg) assert(cond); -#else -/** - Configurable macro for handling construction failure. - - If `PUGL_HPP_THROW_FAILED_CONSTRUCTION` is defined, then this throws a - `pugl::FailedConstructionError` if construction fails. - - If `PUGL_HPP_ASSERT_CONSTRUCTION` is defined, then this asserts if - construction fails. - - Otherwise, this does nothing. -*/ -# define PUGL_CHECK_CONSTRUCTION(cond, msg) -#endif - -/// @copydoc PuglWorld -class World : public detail::Wrapper -{ -public: - World(const World&) = delete; - World& operator=(const World&) = delete; - - World(World&&) = delete; - World& operator=(World&&) = delete; - - ~World() = default; - - World(WorldType type, WorldFlag flag) - : Wrapper{puglNewWorld(static_cast(type), - static_cast(flag))} - { - PUGL_CHECK_CONSTRUCTION(cobj(), "Failed to create pugl::World"); - } - - World(WorldType type, WorldFlags flags) - : Wrapper{puglNewWorld(static_cast(type), flags)} - { - PUGL_CHECK_CONSTRUCTION(cobj(), "Failed to create pugl::World"); - } - - explicit World(WorldType type) - : World{type, WorldFlags{}} - {} - - /// @copydoc puglGetNativeWorld - void* nativeWorld() noexcept { return puglGetNativeWorld(cobj()); } - - /// @copydoc puglSetClassName - Status setClassName(const char* const name) noexcept - { - return static_cast(puglSetClassName(cobj(), name)); - } - - /// @copydoc puglGetTime - double time() const noexcept { return puglGetTime(cobj()); } - - /// @copydoc puglUpdate - Status update(const double timeout) noexcept - { - return static_cast(puglUpdate(cobj(), timeout)); - } -}; - -/** - @} - @defgroup viewpp View - @{ -*/ - -using Backend = PuglBackend; ///< @copydoc PuglBackend -using NativeView = PuglNativeView; ///< @copydoc PuglNativeView - -/// @copydoc PuglViewHint -enum class ViewHint { - useCompatProfile, ///< @copydoc PUGL_USE_COMPAT_PROFILE - useDebugContext, ///< @copydoc PUGL_USE_DEBUG_CONTEXT - contextVersionMajor, ///< @copydoc PUGL_CONTEXT_VERSION_MAJOR - contextVersionMinor, ///< @copydoc PUGL_CONTEXT_VERSION_MINOR - redBits, ///< @copydoc PUGL_RED_BITS - greenBits, ///< @copydoc PUGL_GREEN_BITS - blueBits, ///< @copydoc PUGL_BLUE_BITS - alphaBits, ///< @copydoc PUGL_ALPHA_BITS - depthBits, ///< @copydoc PUGL_DEPTH_BITS - stencilBits, ///< @copydoc PUGL_STENCIL_BITS - samples, ///< @copydoc PUGL_SAMPLES - doubleBuffer, ///< @copydoc PUGL_DOUBLE_BUFFER - swapInterval, ///< @copydoc PUGL_SWAP_INTERVAL - resizable, ///< @copydoc PUGL_RESIZABLE - ignoreKeyRepeat, ///< @copydoc PUGL_IGNORE_KEY_REPEAT - refreshRate, ///< @copydoc PUGL_REFRESH_RATE -}; - -static_assert(ViewHint(PUGL_REFRESH_RATE) == ViewHint::refreshRate, ""); - -using ViewHintValue = PuglViewHintValue; ///< @copydoc PuglViewHintValue - -/// @copydoc PuglCursor -enum class Cursor { - arrow, ///< @copydoc PUGL_CURSOR_ARROW - caret, ///< @copydoc PUGL_CURSOR_CARET - crosshair, ///< @copydoc PUGL_CURSOR_CROSSHAIR - hand, ///< @copydoc PUGL_CURSOR_HAND - no, ///< @copydoc PUGL_CURSOR_NO - leftRight, ///< @copydoc PUGL_CURSOR_LEFT_RIGHT - upDown, ///< @copydoc PUGL_CURSOR_UP_DOWN -}; - -static_assert(Cursor(PUGL_CURSOR_UP_DOWN) == Cursor::upDown, ""); - -/// @copydoc PuglView -class View : protected detail::Wrapper -{ -public: - /** - @name Setup - Methods for creating and destroying a view. - @{ - */ - - explicit View(World& world) - : Wrapper{puglNewView(world.cobj())} - , _world(world) - { - PUGL_CHECK_CONSTRUCTION(cobj(), "Failed to create pugl::View"); - } - - const World& world() const noexcept { return _world; } - World& world() noexcept { return _world; } - - /** - Set the object that will be called to handle events. - - This is a type-safe wrapper for the C functions puglSetHandle() and - puglSetEventFunc() that will automatically dispatch events to the - `onEvent` method of `handler` that takes the appropriate event type. - The handler must have such a method defined for every event type, but if - the handler is the view itself, a `using` declaration can be used to - "inherit" the default implementation to avoid having to define every - method. For example: - - @code - class MyView : public pugl::View - { - public: - explicit MyView(pugl::World& world) - : pugl::View{world} - { - setEventHandler(*this); - } - - using pugl::View::onEvent; - - pugl::Status onEvent(const pugl::ConfigureEvent& event) noexcept; - pugl::Status onEvent(const pugl::ExposeEvent& event) noexcept; - }; - @endcode - - This facility is just a convenience, applications may use the C API - directly to set a handle and event function to set up a different - approach for event handling. - */ - template - Status setEventHandler(Handler& handler) - { - puglSetHandle(cobj(), &handler); - return static_cast(puglSetEventFunc(cobj(), eventFunc)); - } - - /// @copydoc puglSetBackend - Status setBackend(const PuglBackend* backend) noexcept - { - return static_cast(puglSetBackend(cobj(), backend)); - } - - /// @copydoc puglSetViewHint - Status setHint(ViewHint hint, int value) noexcept - { - return static_cast( - puglSetViewHint(cobj(), static_cast(hint), value)); - } - - /// @copydoc puglGetViewHint - int getHint(ViewHint hint) noexcept - { - return puglGetViewHint(cobj(), static_cast(hint)); - } - - /** - @} - @name Frame - Methods for working with the position and size of a view. - @{ - */ - - /// @copydoc puglGetFrame - Rect frame() const noexcept { return puglGetFrame(cobj()); } - - /// @copydoc puglSetFrame - Status setFrame(Rect frame) noexcept - { - return static_cast(puglSetFrame(cobj(), frame)); - } - - /// @copydoc puglSetDefaultSize - Status setDefaultSize(int width, int height) noexcept - { - return static_cast(puglSetDefaultSize(cobj(), width, height)); - } - - /// @copydoc puglSetMinSize - Status setMinSize(int width, int height) noexcept - { - return static_cast(puglSetMinSize(cobj(), width, height)); - } - - /// @copydoc puglSetMaxSize - Status setMaxSize(int width, int height) noexcept - { - return static_cast(puglSetMaxSize(cobj(), width, height)); - } - - /// @copydoc puglSetAspectRatio - Status setAspectRatio(int minX, int minY, int maxX, int maxY) noexcept - { - return static_cast( - puglSetAspectRatio(cobj(), minX, minY, maxX, maxY)); - } - - /** - @} - @name Windows - Methods for working with top-level windows. - @{ - */ - - /// @copydoc puglSetWindowTitle - Status setWindowTitle(const char* title) noexcept - { - return static_cast(puglSetWindowTitle(cobj(), title)); - } - - /// @copydoc puglSetParentWindow - Status setParentWindow(NativeView parent) noexcept - { - return static_cast(puglSetParentWindow(cobj(), parent)); - } - - /// @copydoc puglSetTransientFor - Status setTransientFor(NativeView parent) noexcept - { - return static_cast(puglSetTransientFor(cobj(), parent)); - } - - /// @copydoc puglRealize - Status realize() noexcept { return static_cast(puglRealize(cobj())); } - - /// @copydoc puglShow - Status show() noexcept { return static_cast(puglShow(cobj())); } - - /// @copydoc puglHide - Status hide() noexcept { return static_cast(puglHide(cobj())); } - - /// @copydoc puglGetVisible - bool visible() const noexcept { return puglGetVisible(cobj()); } - - /// @copydoc puglGetNativeWindow - NativeView nativeWindow() noexcept { return puglGetNativeWindow(cobj()); } - - /** - @} - @name Graphics - Methods for working with the graphics context and scheduling - redisplays. - @{ - */ - - /// @copydoc puglGetContext - void* context() noexcept { return puglGetContext(cobj()); } - - /// @copydoc puglPostRedisplay - Status postRedisplay() noexcept - { - return static_cast(puglPostRedisplay(cobj())); - } - - /// @copydoc puglPostRedisplayRect - Status postRedisplayRect(const Rect rect) noexcept - { - return static_cast(puglPostRedisplayRect(cobj(), rect)); - } - - /** - @} - @name Interaction - Methods for interacting with the user and window system. - @{ - */ - - /// @copydoc puglGrabFocus - Status grabFocus() noexcept - { - return static_cast(puglGrabFocus(cobj())); - } - - /// @copydoc puglHasFocus - bool hasFocus() const noexcept { return puglHasFocus(cobj()); } - - /// @copydoc puglSetCursor - Status setCursor(const Cursor cursor) noexcept - { - return static_cast( - puglSetCursor(cobj(), static_cast(cursor))); - } - - /// @copydoc puglRequestAttention - Status requestAttention() noexcept - { - return static_cast(puglRequestAttention(cobj())); - } - - /** - Activate a repeating timer event. - - This starts a timer which will send a timer event to `view` every - `timeout` seconds. This can be used to perform some action in a view at a - regular interval with relatively low frequency. Note that the frequency - of timer events may be limited by how often update() is called. - - If the given timer already exists, it is replaced. - - @param id The identifier for this timer. This is an application-specific - ID that should be a low number, typically the value of a constant or `enum` - that starts from 0. There is a platform-specific limit to the number of - supported timers, and overhead associated with each, so applications should - create only a few timers and perform several tasks in one if necessary. - - @param timeout The period, in seconds, of this timer. This is not - guaranteed to have a resolution better than 10ms (the maximum timer - resolution on Windows) and may be rounded up if it is too short. On X11 - and MacOS, a resolution of about 1ms can usually be relied on. - - @return #PUGL_FAILURE if timers are not supported by the system, - #PUGL_UNKNOWN_ERROR if setting the timer failed. - */ - Status startTimer(const uintptr_t id, const double timeout) noexcept - { - return static_cast(puglStartTimer(cobj(), id, timeout)); - } - - /** - Stop an active timer. - - @param id The ID previously passed to startTimer(). - - @return #PUGL_FAILURE if timers are not supported by this system, - #PUGL_UNKNOWN_ERROR if stopping the timer failed. - */ - Status stopTimer(const uintptr_t id) noexcept - { - return static_cast(puglStopTimer(cobj(), id)); - } - - template - Status sendEvent(const Event& event) noexcept - { - PuglEvent cEvent{{t, 0}}; - - *reinterpret_cast(&cEvent) = event; - - return static_cast(puglSendEvent(cobj(), &cEvent)); - } - - /** - @} - */ - - PuglView* cobj() noexcept { return Wrapper::cobj(); } - const PuglView* cobj() const noexcept { return Wrapper::cobj(); } - -private: - template - static Status dispatch(Target& target, const PuglEvent* event) - { - switch (event->type) { - case PUGL_NOTHING: - return Status::success; - case PUGL_CREATE: - return target.onEvent(CreateEvent{event->any}); - case PUGL_DESTROY: - return target.onEvent(DestroyEvent{event->any}); - case PUGL_CONFIGURE: - return target.onEvent(ConfigureEvent{event->configure}); - case PUGL_MAP: - return target.onEvent(MapEvent{event->any}); - case PUGL_UNMAP: - return target.onEvent(UnmapEvent{event->any}); - case PUGL_UPDATE: - return target.onEvent(UpdateEvent{event->any}); - case PUGL_EXPOSE: - return target.onEvent(ExposeEvent{event->expose}); - case PUGL_CLOSE: - return target.onEvent(CloseEvent{event->any}); - case PUGL_FOCUS_IN: - return target.onEvent(FocusInEvent{event->focus}); - case PUGL_FOCUS_OUT: - return target.onEvent(FocusOutEvent{event->focus}); - case PUGL_KEY_PRESS: - return target.onEvent(KeyPressEvent{event->key}); - case PUGL_KEY_RELEASE: - return target.onEvent(KeyReleaseEvent{event->key}); - case PUGL_TEXT: - return target.onEvent(TextEvent{event->text}); - case PUGL_POINTER_IN: - return target.onEvent(PointerInEvent{event->crossing}); - case PUGL_POINTER_OUT: - return target.onEvent(PointerOutEvent{event->crossing}); - case PUGL_BUTTON_PRESS: - return target.onEvent(ButtonPressEvent{event->button}); - case PUGL_BUTTON_RELEASE: - return target.onEvent(ButtonReleaseEvent{event->button}); - case PUGL_MOTION: - return target.onEvent(MotionEvent{event->motion}); - case PUGL_SCROLL: - return target.onEvent(ScrollEvent{event->scroll}); - case PUGL_CLIENT: - return target.onEvent(ClientEvent{event->client}); - case PUGL_TIMER: - return target.onEvent(TimerEvent{event->timer}); - case PUGL_LOOP_ENTER: - return target.onEvent(LoopEnterEvent{event->any}); - case PUGL_LOOP_LEAVE: - return target.onEvent(LoopLeaveEvent{event->any}); - } - - return Status::failure; - } - - template - static PuglStatus eventFunc(PuglView* view, const PuglEvent* event) noexcept - { - auto* target = static_cast(puglGetHandle(view)); - -#ifdef __cpp_exceptions - try { - return static_cast(dispatch(*target, event)); - } catch (...) { - return PUGL_UNKNOWN_ERROR; - } -#else - return static_cast(pugl::dispatch(*target, event)); -#endif - } - - World& _world; -}; - -/** - @} - @} -*/ - -} // namespace pugl - -#endif // PUGL_PUGL_HPP diff --git a/dpf/dgl/src/pugl-upstream/bindings/cpp/include/pugl/stub.hpp b/dpf/dgl/src/pugl-upstream/bindings/cpp/include/pugl/stub.hpp deleted file mode 100644 index e4a33c1..0000000 --- a/dpf/dgl/src/pugl-upstream/bindings/cpp/include/pugl/stub.hpp +++ /dev/null @@ -1,45 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef PUGL_STUB_HPP -#define PUGL_STUB_HPP - -#include "pugl/pugl.h" -#include "pugl/stub.h" - -namespace pugl { - -/** - @defgroup stubpp Stub - Stub graphics support. - @ingroup puglpp - @{ -*/ - -/// @copydoc puglStubBackend -inline const PuglBackend* -stubBackend() noexcept -{ - return puglStubBackend(); -} - -/** - @} -*/ - -} // namespace pugl - -#endif // PUGL_STUB_HPP diff --git a/dpf/dgl/src/pugl-upstream/bindings/cpp/include/pugl/vulkan.hpp b/dpf/dgl/src/pugl-upstream/bindings/cpp/include/pugl/vulkan.hpp deleted file mode 100644 index d65b2d6..0000000 --- a/dpf/dgl/src/pugl-upstream/bindings/cpp/include/pugl/vulkan.hpp +++ /dev/null @@ -1,168 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/* - Note that this header includes Vulkan headers, so if you are writing a - program or plugin that dynamically loads vulkan, you should first define - `VK_NO_PROTOTYPES` before including it. -*/ - -#ifndef PUGL_VULKAN_HPP -#define PUGL_VULKAN_HPP - -#include "pugl/pugl.h" -#include "pugl/pugl.hpp" -#include "pugl/vulkan.h" - -#include - -#include - -namespace pugl { - -/** - @defgroup vulkanpp Vulkan - Vulkan graphics support. - - Note that the Pugl C++ wrapper does not use vulkan-hpp because it is a - heavyweight dependency which not everyone uses, and its design is not very - friendly to dynamic loading in plugins anyway. However, if you do use - vulkan-hpp smart handles, it is relatively straightforward to wrap the - result of createSurface() manually. - - @ingroup puglpp - @{ -*/ - -/// @copydoc PuglVulkanLoader -class VulkanLoader final - : public detail::Wrapper -{ -public: - /** - Create a new dynamic loader for Vulkan functions. - - This dynamically loads the Vulkan library and gets the load functions - from it. - - Note that this constructor does not throw exceptions, though failure is - possible. To check if the Vulkan library failed to load, test this - loader, which is explicitly convertible to `bool`. It is safe to use a - failed loader, but the accessors will always return null. - */ - explicit VulkanLoader(World& world) noexcept - : Wrapper{puglNewVulkanLoader(world.cobj())} - {} - - /** - Return the `vkGetInstanceProcAddr` function. - - @return Null if the Vulkan library failed to load, or does not contain - this function (which is unlikely and indicates a broken system). - */ - PFN_vkGetInstanceProcAddr getInstanceProcAddrFunc() const noexcept - { - return cobj() ? puglGetInstanceProcAddrFunc(cobj()) : nullptr; - } - - /** - Return the `vkGetDeviceProcAddr` function. - - @return Null if the Vulkan library failed to load, or does not contain - this function (which is unlikely and indicates a broken system). - */ - PFN_vkGetDeviceProcAddr getDeviceProcAddrFunc() const noexcept - { - return cobj() ? puglGetDeviceProcAddrFunc(cobj()) : nullptr; - } - - /// Return true if this loader is valid to use - explicit operator bool() const noexcept { return cobj(); } -}; - -/** - A simple wrapper for an array of static C strings. - - This provides a minimal API that supports iteration, like `std::vector`, but - avoids allocation, exceptions, and a dependency on the C++ standard library. -*/ -class StaticStringArray final -{ -public: - using value_type = const char*; - using const_iterator = const char* const*; - using size_type = uint32_t; - - StaticStringArray(const char* const* strings, const uint32_t size) noexcept - : _strings{strings} - , _size{size} - {} - - const char* const* begin() const noexcept { return _strings; } - const char* const* end() const noexcept { return _strings + _size; } - const char* const* data() const noexcept { return _strings; } - uint32_t size() const noexcept { return _size; } - -private: - const char* const* _strings; - uint32_t _size; -}; - -/** - Return the Vulkan instance extensions required to draw to a PuglView. - - If successful, the returned array always contains "VK_KHR_surface", along - with whatever other platform-specific extensions are required. - - @return An array of extension name strings. -*/ -inline StaticStringArray -getInstanceExtensions() noexcept -{ - uint32_t count = 0; - const char* const* const extensions = puglGetInstanceExtensions(&count); - - return StaticStringArray{extensions, count}; -} - -/// @copydoc puglCreateSurface -inline VkResult -createSurface(PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr, - View& view, - VkInstance instance, - const VkAllocationCallbacks* const allocator, - VkSurfaceKHR* const surface) noexcept -{ - const VkResult r = puglCreateSurface( - vkGetInstanceProcAddr, view.cobj(), instance, allocator, surface); - - return (!r && !surface) ? VK_ERROR_INITIALIZATION_FAILED : r; -} - -/// @copydoc puglVulkanBackend -inline const PuglBackend* -vulkanBackend() noexcept -{ - return puglVulkanBackend(); -} - -/** - @} -*/ - -} // namespace pugl - -#endif // PUGL_VULKAN_HPP diff --git a/dpf/dgl/src/pugl-upstream/bindings/cpp/meson.build b/dpf/dgl/src/pugl-upstream/bindings/cpp/meson.build deleted file mode 100644 index 7f47f43..0000000 --- a/dpf/dgl/src/pugl-upstream/bindings/cpp/meson.build +++ /dev/null @@ -1,7 +0,0 @@ -subdir('include') - -pkg.generate(name: 'Pugl++', - filebase: 'puglpp-@0@'.format(major_version), - subdirs: ['puglpp-@0@'.format(major_version)], - version: meson.project_version(), - description: 'Pugl GUI library C++ bindings') diff --git a/dpf/dgl/src/pugl-upstream/doc/_static/meson.build b/dpf/dgl/src/pugl-upstream/doc/_static/meson.build deleted file mode 100644 index fc7792c..0000000 --- a/dpf/dgl/src/pugl-upstream/doc/_static/meson.build +++ /dev/null @@ -1,2 +0,0 @@ -configure_file(copy: true, input: '../../resources/pugl.svg', output: 'pugl.svg') - diff --git a/dpf/dgl/src/pugl-upstream/doc/c/Doxyfile.in b/dpf/dgl/src/pugl-upstream/doc/c/Doxyfile.in deleted file mode 100644 index d119015..0000000 --- a/dpf/dgl/src/pugl-upstream/doc/c/Doxyfile.in +++ /dev/null @@ -1,32 +0,0 @@ -PROJECT_NAME = Pugl -PROJECT_BRIEF = "A minimal portable API for embeddable GUIs" - -QUIET = YES -WARN_AS_ERROR = YES -WARN_IF_UNDOCUMENTED = NO -WARN_NO_PARAMDOC = NO - -JAVADOC_AUTOBRIEF = YES - -FULL_PATH_NAMES = NO -CASE_SENSE_NAMES = YES -HIDE_IN_BODY_DOCS = YES -REFERENCES_LINK_SOURCE = NO - -GENERATE_HTML = NO -GENERATE_LATEX = NO -GENERATE_XML = YES -XML_PROGRAMLISTING = NO -SHOW_FILES = NO - -MACRO_EXPANSION = YES -PREDEFINED = PUGL_API \ - PUGL_DISABLE_DEPRECATED \ - PUGL_CONST_API= \ - PUGL_CONST_FUNC= - -RECURSIVE = YES -STRIP_FROM_PATH = @PUGL_SRCDIR@ -INPUT = @PUGL_SRCDIR@/include - -OUTPUT_DIRECTORY = @DOX_OUTPUT@ diff --git a/dpf/dgl/src/pugl-upstream/doc/c/api/meson.build b/dpf/dgl/src/pugl-upstream/doc/c/api/meson.build deleted file mode 100644 index 5c1e30e..0000000 --- a/dpf/dgl/src/pugl-upstream/doc/c/api/meson.build +++ /dev/null @@ -1,5 +0,0 @@ -c_pugl_rst = custom_target( - 'C API ReST Documentation', - command: [dox_to_sphinx, '-f', '@INPUT0@', 'doc/c/api'], - input: [c_index_xml] + c_rst_files, - output: 'pugl.rst') diff --git a/dpf/dgl/src/pugl-upstream/doc/c/event-loop.rst b/dpf/dgl/src/pugl-upstream/doc/c/event-loop.rst deleted file mode 100644 index be4e315..0000000 --- a/dpf/dgl/src/pugl-upstream/doc/c/event-loop.rst +++ /dev/null @@ -1,101 +0,0 @@ -.. default-domain:: c -.. highlight:: c - -###################### -Driving the Event Loop -###################### - -Pugl does not contain any threads or other event loop "magic". -For flexibility, the event loop is driven explicitly by repeatedly calling :func:`puglUpdate`, -which processes events from the window system and dispatches them to views when necessary. - -The exact use of :func:`puglUpdate` depends on the application. -Plugins should call it with a ``timeout`` of 0 in a callback driven by the host. -This avoids blocking the main loop, -since other plugins and the host itself need to run as well. - -A program can use whatever timeout is appropriate: -event-driven applications may wait forever by using a ``timeout`` of -1, -while those that draw continuously may use a significant fraction of the frame period -(with enough time left over to render). - -********* -Redrawing -********* - -Occasional redrawing can be requested by calling :func:`puglPostRedisplay` or :func:`puglPostRedisplayRect`. -After these are called, -a :struct:`PuglExposeEvent` will be dispatched on the next call to :func:`puglUpdate`. - -For continuous redrawing, -call :func:`puglPostRedisplay` while handling a :struct:`PuglUpdateEvent` event. -This event is sent just before views are redrawn, -so it can be used as a hook to expand the update region right before the view is exposed. -Anything else that needs to be done every frame can be handled similarly. - -***************** -Event Dispatching -***************** - -Ideally, pending events are dispatched during a call to :func:`puglUpdate`, -directly within the scope of that call. - -Unfortunately, this is not universally true due to differences between platforms. - -MacOS -===== - -On MacOS, drawing is handled specially and not by the normal event queue mechanism. -This means that configure and expose events, -and possibly others, -may be dispatched to a view outside the scope of a :func:`puglUpdate` call. -In general, you can not rely on coherent event dispatching semantics on MacOS: -the operating system can call into application code at "random" times, -and these calls may result in Pugl events being dispatched. - -An application that follows the Pugl guidelines should work fine, -but there is one significant inconsistency you may encounter on MacOS: -posting a redisplay will not wake up a blocked :func:`puglUpdate` call. - -Windows -======= - -On Windows, the application has relatively tight control over the event loop, -so events are typically dispatched explicitly by :func:`puglUpdate`. -Drawing is handled by events, -so posting a redisplay will wake up a blocked :func:`puglUpdate` call. - -However, it is possible for the system to dispatch events at other times. -So, -it is possible for events to be dispatched outside the scope of a :func:`puglUpdate` call, -but this does not happen in normal circumstances and can largely be ignored. - -X11 -=== - -On X11, the application strictly controls event dispatching, -and there is no way for the system to call into application code at surprising times. -So, all events are dispatched in the scope of a :func:`puglUpdate` call. - -********************* -Recursive Event Loops -********************* - -On Windows and MacOS, -the event loop is stalled while the user is resizing the window or, -on Windows, -has displayed the window menu. -This means that :func:`puglUpdate` will block until the resize is finished, -or the menu is closed. - -Pugl dispatches :struct:`PuglLoopEnterEvent` and :struct:`PuglLoopLeaveEvent` events to notify the application of this situation. -If you want to continuously redraw during resizing on these platforms, -you can schedule a timer with :func:`puglStartTimer` when the recursive loop is entered, -and post redisplays when handling the :struct:`PuglTimerEvent`. -Be sure to remove the timer with :func:`puglStopTimer` when the recursive loop is finished. - -On X11, there are no recursive event loops, -and everything works as usual while the user is resizing the window. -There is nothing special about a "live resize" on X11, -and the above loop events will never be dispatched. - diff --git a/dpf/dgl/src/pugl-upstream/doc/c/events.rst b/dpf/dgl/src/pugl-upstream/doc/c/events.rst deleted file mode 100644 index 86f7c63..0000000 --- a/dpf/dgl/src/pugl-upstream/doc/c/events.rst +++ /dev/null @@ -1,84 +0,0 @@ -.. default-domain:: c -.. highlight:: c - -*************** -Handling Events -*************** - -Events are sent to a view when it has received user input, -must be drawn, or in other situations that may need to be handled such as resizing. - -Events are sent to the event handler as a :union:`PuglEvent` union. -The ``type`` field defines the type of the event and which field of the union is active. -The application must handle at least :enumerator:`PUGL_CONFIGURE ` -and :enumerator:`PUGL_EXPOSE ` to draw anything, -but there are many other :enum:`event types `. - -For example, a basic event handler might look something like this: - -.. code-block:: c - - static PuglStatus - onEvent(PuglView* view, const PuglEvent* event) - { - MyApp* app = (MyApp*)puglGetHandle(view); - - switch (event->type) { - case PUGL_CREATE: - return setupGraphics(app); - case PUGL_DESTROY: - return teardownGraphics(app); - case PUGL_CONFIGURE: - return resize(app, event->configure.width, event->configure.height); - case PUGL_EXPOSE: - return draw(app, view); - case PUGL_CLOSE: - return quit(app); - case PUGL_BUTTON_PRESS: - return onButtonPress(app, view, event->button); - default: - break; - } - - return PUGL_SUCCESS; - } - -Using the Graphics Context -========================== - -Drawing -------- - -Note that Pugl uses a different drawing model than many libraries, -particularly those designed for game-style main loops like `SDL `_ and `GLFW `_. - -In that style of code, drawing is performed imperatively in the main loop, -but with Pugl, the application must draw only while handling an expose event. -This is because Pugl supports event-driven applications that only draw the damaged region when necessary, -and handles exposure internally to provide optimized and consistent behavior across platforms. - -Cairo Context -------------- - -A Cairo context is created for each :struct:`PuglExposeEvent`, -and only exists during the handling of that event. -Null is returned by :func:`puglGetContext` at any other time. - -OpenGL Context --------------- - -The OpenGL context is only active during the handling of these events: - -- :struct:`PuglCreateEvent` -- :struct:`PuglDestroyEvent` -- :struct:`PuglConfigureEvent` -- :struct:`PuglExposeEvent` - -As always, drawing is only possible during an expose. - -Vulkan Context --------------- - -With Vulkan, the graphics context is managed by the application rather than Pugl. -However, drawing must still only be performed during an expose. - diff --git a/dpf/dgl/src/pugl-upstream/doc/c/index.rst b/dpf/dgl/src/pugl-upstream/doc/c/index.rst deleted file mode 100644 index 020cf32..0000000 --- a/dpf/dgl/src/pugl-upstream/doc/c/index.rst +++ /dev/null @@ -1,11 +0,0 @@ -#### -Pugl -#### - -.. include:: summary.rst - -.. toctree:: - - deployment - overview - api/pugl diff --git a/dpf/dgl/src/pugl-upstream/doc/c/meson.build b/dpf/dgl/src/pugl-upstream/doc/c/meson.build deleted file mode 100644 index 65302b3..0000000 --- a/dpf/dgl/src/pugl-upstream/doc/c/meson.build +++ /dev/null @@ -1,48 +0,0 @@ -config = configuration_data() -config.set('PUGL_VERSION', meson.project_version()) - -conf_py = configure_file(configuration: config, - input: '../conf.py.in', - output: 'conf.py') - -configure_file(copy: true, input: '../deployment.rst', output: 'deployment.rst') -configure_file(copy: true, input: '../summary.rst', output: 'summary.rst') - -c_rst_files = files( - 'index.rst', - 'overview.rst', - 'world.rst', - 'view.rst', - 'events.rst', - 'event-loop.rst', - 'shutting-down.rst' -) - -foreach f : c_rst_files - configure_file(copy: true, input: f, output: '@PLAINNAME@') -endforeach - -subdir('xml') -subdir('api') - -docs = custom_target( - 'singlehtml C documentation for pugl', - command: [sphinx_build, '-M', 'singlehtml', - meson.current_build_dir(), meson.current_build_dir(), - '-E', '-q', '-t', 'singlehtml'], - input: [c_rst_files, c_pugl_rst, c_index_xml], - output: 'singlehtml', - build_by_default: true, - install: true, - install_dir: docdir / 'pugl-0') - -docs = custom_target( - 'html C documentation for pugl', - command: [sphinx_build, '-M', 'html', - meson.current_build_dir(), meson.current_build_dir(), - '-E', '-q', '-t', 'html'], - input: [c_rst_files, c_pugl_rst, c_index_xml], - output: 'html', - build_by_default: true, - install: true, - install_dir: docdir / 'pugl-0') diff --git a/dpf/dgl/src/pugl-upstream/doc/c/overview.rst b/dpf/dgl/src/pugl-upstream/doc/c/overview.rst deleted file mode 100644 index 4bd024d..0000000 --- a/dpf/dgl/src/pugl-upstream/doc/c/overview.rst +++ /dev/null @@ -1,26 +0,0 @@ -.. default-domain:: c -.. highlight:: c - -######## -Overview -######## - -The Pugl API revolves around two main objects: the `world` and the `view`. -An application creates a world to manage top-level state, -then creates one or more views to display. - -The core API (excluding backend-specific components) is declared in ``pugl.h``: - -.. code-block:: c - - #include - -.. toctree:: - - world - view - events - event-loop - shutting-down - -.. _pkg-config: https://www.freedesktop.org/wiki/Software/pkg-config/ diff --git a/dpf/dgl/src/pugl-upstream/doc/c/shutting-down.rst b/dpf/dgl/src/pugl-upstream/doc/c/shutting-down.rst deleted file mode 100644 index a04c771..0000000 --- a/dpf/dgl/src/pugl-upstream/doc/c/shutting-down.rst +++ /dev/null @@ -1,20 +0,0 @@ -.. default-domain:: c -.. highlight:: c - -############# -Shutting Down -############# - -When a view is closed, -it will receive a :struct:`PuglCloseEvent`. -An application may also set a flag based on user input or other conditions, -which can be used to break out of the main loop and stop calling :func:`puglUpdate`. - -When the main event loop has finished running, -any views and the world need to be destroyed, in that order. -For example: - -.. code-block:: c - - puglFreeView(view); - puglFreeWorld(world); diff --git a/dpf/dgl/src/pugl-upstream/doc/c/view.rst b/dpf/dgl/src/pugl-upstream/doc/c/view.rst deleted file mode 100644 index 12f146d..0000000 --- a/dpf/dgl/src/pugl-upstream/doc/c/view.rst +++ /dev/null @@ -1,321 +0,0 @@ -.. default-domain:: c -.. highlight:: c - -############### -Creating a View -############### - -A view is a drawable region that receives events. -You may think of it as a window, -though it may be embedded and not represent a top-level system window. [#f1]_ - -Creating a visible view is a multi-step process. -When a new view is created with :func:`puglNewView`, -it does not yet represent a "real" system view: - -.. code-block:: c - - PuglView* view = puglNewView(world); - -********************* -Configuring the Frame -********************* - -Before display, -the necessary :doc:`frame ` and :doc:`window ` attributes should be set. -These allow the window system (or plugin host) to arrange the view properly. -For example: - -.. code-block:: c - - const double defaultWidth = 1920.0; - const double defaultHeight = 1080.0; - - puglSetWindowTitle(view, "My Window"); - puglSetDefaultSize(view, defaultWidth, defaultHeight); - puglSetMinSize(view, defaultWidth / 4.0, defaultHeight / 4.0); - puglSetAspectRatio(view, 1, 1, 16, 9); - -There are also several :enum:`hints ` for basic attributes that can be set: - -.. code-block:: c - - puglSetViewHint(view, PUGL_RESIZABLE, PUGL_TRUE); - puglSetViewHint(view, PUGL_IGNORE_KEY_REPEAT, PUGL_TRUE); - -********* -Embedding -********* - -To embed the view in another window, -you will need to somehow get the :type:`native view handle ` for the parent, -then set it with :func:`puglSetParentWindow`. -If the parent is a Pugl view, -the native handle can be accessed with :func:`puglGetNativeWindow`. -For example: - -.. code-block:: c - - puglSetParentWindow(view, puglGetNativeWindow(parent)); - -************************ -Setting an Event Handler -************************ - -In order to actually do anything, a view must process events from the system. -Pugl dispatches all events to a single :type:`event handling function `, -which is set with :func:`puglSetEventFunc`: - -.. code-block:: c - - puglSetEventFunc(view, onEvent); - -See :doc:`events` for details on writing the event handler itself. - -***************** -Setting View Data -***************** - -Since the event handler is called with only a view pointer and an event, -there needs to be some way to access application data associated with the view. -Similar to :ref:`setting application data `, -this is done by setting an opaque handle on the view with :func:`puglSetHandle`, -for example: - -.. code-block:: c - - puglSetHandle(view, myViewData); - -The handle can be later retrieved, -likely in the event handler, -with :func:`puglGetHandle`: - -.. code-block:: c - - MyViewData* data = (MyViewData*)puglGetHandle(view); - -All non-constant data should be accessed via this handle, -to avoid problems associated with static mutable data. - -If data is also associated with the world, -it can be retrieved via the view using :func:`puglGetWorld`: - -.. code-block:: c - - PuglWorld* world = puglGetWorld(view); - MyApp* app = (MyApp*)puglGetWorldHandle(world); - -***************** -Setting a Backend -***************** - -Before being realized, the view must have a backend set with :func:`puglSetBackend`. - -The backend manages the graphics API that will be used for drawing. -Pugl includes backends and supporting API for -:doc:`Cairo `, :doc:`OpenGL `, and :doc:`Vulkan `. - -Using Cairo -=========== - -Cairo-specific API is declared in the ``cairo.h`` header: - -.. code-block:: c - - #include - -The Cairo backend is provided by :func:`puglCairoBackend()`: - -.. code-block:: c - - puglSetBackend(view, puglCairoBackend()); - -No additional configuration is required for Cairo. -To draw when handling an expose event, -the `Cairo context `_ can be accessed with :func:`puglGetContext`: - -.. code-block:: c - - cairo_t* cr = (cairo_t*)puglGetContext(view); - -Using OpenGL -============ - -OpenGL-specific API is declared in the ``gl.h`` header: - -.. code-block:: c - - #include - -The OpenGL backend is provided by :func:`puglGlBackend()`: - -.. code-block:: c - - puglSetBackend(view, puglGlBackend()); - -Some hints must also be set so that the context can be set up correctly. -For example, to use OpenGL 3.3 Core Profile: - -.. code-block:: c - - puglSetViewHint(view, PUGL_USE_COMPAT_PROFILE, PUGL_FALSE); - puglSetViewHint(view, PUGL_CONTEXT_VERSION_MAJOR, 3); - puglSetViewHint(view, PUGL_CONTEXT_VERSION_MINOR, 3); - -If you need to perform some setup using the OpenGL API, -there are two ways to do so. - -The OpenGL context is active when -:enumerator:`PUGL_CREATE ` and -:enumerator:`PUGL_DESTROY ` -events are dispatched, -so things like creating and destroying shaders and textures can be done then. - -Alternatively, if it is cumbersome to set up and tear down OpenGL in the event handler, -:func:`puglEnterContext` and :func:`puglLeaveContext` can be used to manually activate the OpenGL context during application setup. -Note, however, that unlike many other APIs, these functions must not be used for drawing. -It is only valid to use the OpenGL API for configuration in a manually entered context, -rendering will not work. -For example: - -.. code-block:: c - - puglEnterContext(view); - setupOpenGL(myApp); - puglLeaveContext(view); - - while (!myApp->quit) { - puglUpdate(world, 0.0); - } - - puglEnterContext(view); - teardownOpenGL(myApp); - puglLeaveContext(view); - -Using Vulkan -============ - -Vulkan-specific API is declared in the ``vulkan.h`` header. -This header includes Vulkan headers, -so if you are dynamically loading Vulkan at runtime, -you should define ``VK_NO_PROTOTYPES`` before including it. - -.. code-block:: c - - #define VK_NO_PROTOTYPES - - #include - -The Vulkan backend is provided by :func:`puglVulkanBackend()`: - -.. code-block:: c - - puglSetBackend(view, puglVulkanBackend()); - -Unlike OpenGL, almost all Vulkan configuration is done using the Vulkan API directly. -Pugl only provides a portable mechanism to load the Vulkan library and get the functions used to load the rest of the Vulkan API. - -Loading Vulkan --------------- - -For maximum compatibility, -it is best to not link to Vulkan at compile-time, -but instead load the Vulkan API at run-time. -To do so, first create a :struct:`PuglVulkanLoader`: - -.. code-block:: c - - PuglVulkanLoader* loader = puglNewVulkanLoader(world); - -The loader manages the dynamically loaded Vulkan library, -so it must be kept alive for as long as the application is using Vulkan. -You can get the function used to load Vulkan functions with :func:`puglGetInstanceProcAddrFunc`: - -.. code-block:: c - - PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = - puglGetInstanceProcAddrFunc(loader); - -This vkGetInstanceProcAddr_ function can be used to load the rest of the Vulkan API. -For example, you can use it to get the vkCreateInstance_ function, -then use that to create your Vulkan instance. -In practice, you will want to use some loader or wrapper API since there are many Vulkan functions. - -For advanced situations, -there is also :func:`puglGetDeviceProcAddrFunc` which retrieves the vkGetDeviceProcAddr_ function instead. - -The Vulkan loader is provided for convenience, -so that applications to not need to write platform-specific code to load Vulkan. -Its use it not mandatory and Pugl can be used with Vulkan loaded by some other method. - -Linking with Vulkan -------------------- - -If you do want to link to the Vulkan library at compile time, -note that the Pugl Vulkan backend does not depend on it, -so you will have to do so explicitly. - -Creating a Surface ------------------- - -The details of using Vulkan are far beyond the scope of this documentation, -but Pugl provides a portable function, :func:`puglCreateSurface`, -to get the Vulkan surface for a view. -Assuming you have somehow created your ``VkInstance``, -you can get the surface for a view using :func:`puglCreateSurface`: - -.. code-block:: c - - VkSurfaceKHR* surface = NULL; - puglCreateSurface(puglGetDeviceProcAddrFunc(loader), - view, - vulkanInstance, - NULL, - &surface); - -**************** -Showing the View -**************** - -Once the view is configured, it can be "realized" with :func:`puglRealize`. -This creates a "real" system view, for example: - -.. code-block:: c - - PuglStatus status = puglRealize(view); - if (status) { - fprintf(stderr, "Error realizing view (%s)\n", puglStrerror(status)); - } - -Note that realizing a view can fail for many reasons, -so the return code should always be checked. -This is generally the case for any function that interacts with the window system. -Most functions also return a :enum:`PuglStatus`, -but these checks are omitted for brevity in the rest of this documentation. - -A realized view is not initially visible, -but can be shown with :func:`puglShow`: - -.. code-block:: c - - puglShow(view); - -To create an initially visible view, -it is also possible to simply call :func:`puglShow` right away. -The view will be automatically realized if necessary. - -.. rubric:: Footnotes - -.. [#f1] MacOS has a strong distinction between - `views `_, - which may be nested, and - `windows `_, - which may not. - On Windows and X11, everything is a nestable window, - but top-level windows are configured differently. - -.. _vkCreateInstance: https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkCreateInstance.html - -.. _vkGetDeviceProcAddr: https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkGetDeviceProcAddr.html - -.. _vkGetInstanceProcAddr: https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkGetInstanceProcAddr.html diff --git a/dpf/dgl/src/pugl-upstream/doc/c/world.rst b/dpf/dgl/src/pugl-upstream/doc/c/world.rst deleted file mode 100644 index 83d9dbd..0000000 --- a/dpf/dgl/src/pugl-upstream/doc/c/world.rst +++ /dev/null @@ -1,65 +0,0 @@ -################ -Creating a World -################ - -.. default-domain:: c -.. highlight:: c - -The world is the top-level object which represents an instance of Pugl. -It handles the connection to the window system, -and manages views and the event loop. - -An application typically has a single world, -which is constructed once on startup and used to drive the main event loop. - -************ -Construction -************ - -A world must be created before any views, and it must outlive all of its views. -A world is created with :func:`puglNewWorld`, for example: - -.. code-block:: c - - PuglWorld* world = puglNewWorld(PUGL_PROGRAM, 0); - -For a plugin, specify :enumerator:`PUGL_MODULE ` instead. -In some cases, it is necessary to pass additional flags. -For example, Vulkan requires thread support: - -.. code-block:: c - - PuglWorld* world = puglNewWorld(PUGL_MODULE, PUGL_WORLD_THREADS) - -It is a good idea to set a class name for your project with :func:`puglSetClassName`. -This allows the window system to distinguish different applications and, -for example, users to set up rules to manage their windows nicely: - -.. code-block:: c - - puglSetClassName(world, "MyAwesomeProject") - -.. _setting-application-data: - -************************ -Setting Application Data -************************ - -Pugl will call an event handler in the application with only a view pointer and an event, -so there needs to be some way to access the data you use in your application. -This is done by setting an opaque handle on the world with :func:`puglSetWorldHandle`, -for example: - -.. code-block:: c - - puglSetWorldHandle(world, myApp); - -The handle can be later retrieved with :func:`puglGetWorldHandle`: - -.. code-block:: c - - MyApp* app = (MyApp*)puglGetWorldHandle(world); - -All non-constant data should be accessed via this handle, -to avoid problems associated with static mutable data. - diff --git a/dpf/dgl/src/pugl-upstream/doc/c/xml/meson.build b/dpf/dgl/src/pugl-upstream/doc/c/xml/meson.build deleted file mode 100644 index ea5df9c..0000000 --- a/dpf/dgl/src/pugl-upstream/doc/c/xml/meson.build +++ /dev/null @@ -1,19 +0,0 @@ -doxygen = find_program('doxygen') - -c_doxygen_input = [] -foreach h : c_headers - c_doxygen_input += ['..' / h] -endforeach - -config = configuration_data() -config.set('PUGL_SRCDIR', pugl_src_root) -config.set('DOX_OUTPUT', meson.current_build_dir() / '..') - -c_doxyfile = configure_file(configuration: config, - input: '../Doxyfile.in', - output: 'Doxyfile') - -c_index_xml = custom_target('c-index.xml', - command: [doxygen, '@INPUT0@'], - input: [c_doxyfile] + c_header_files, - output: 'index.xml') diff --git a/dpf/dgl/src/pugl-upstream/doc/conf.py.in b/dpf/dgl/src/pugl-upstream/doc/conf.py.in deleted file mode 100644 index 3fa8ea2..0000000 --- a/dpf/dgl/src/pugl-upstream/doc/conf.py.in +++ /dev/null @@ -1,85 +0,0 @@ -# Project information - -project = "Pugl" -copyright = "2020, David Robillard" -author = "David Robillard" -release = "@PUGL_VERSION@" - -# General configuration - -exclude_patterns = ["xml"] -language = "en" -nitpicky = True -pygments_style = "friendly" - -# Ignore everything opaque or external for nitpicky mode -_opaque = [ - "PFN_vkGetDeviceProcAddr", - "PFN_vkGetInstanceProcAddr", - "PuglBackendImpl", - "PuglViewImpl", - "PuglVulkanLoaderImpl", - "PuglWorldImpl", - "VkAllocationCallbacks", - "VkInstance", - "VkResult", - "VkSurfaceKHR", - "size_t", - "uint32_t", - "uintptr_t", -] - -_c_nitpick_ignore = map(lambda x: ("c:identifier", x), _opaque) -_cpp_nitpick_ignore = map(lambda x: ("cpp:identifier", x), _opaque) -nitpick_ignore = list(_c_nitpick_ignore) + list(_cpp_nitpick_ignore) - -# C++ - -cpp_index_common_prefix = ["pugl::"] - -# HTML output - -html_copy_source = False -html_short_title = "Pugl" -html_static_path = ["../_static"] -html_theme = "sphinx_lv2_theme" - -if tags.has('singlehtml'): - html_sidebars = { - "**": [ - "globaltoc.html", - ] - } - - html_theme_options = { - "body_max_width": "51em", - "body_min_width": "51em", - "description": "A minimal portable API for embeddable GUIs.", - "show_footer_version": True, - "show_logo_version": False, - "logo": "pugl.svg", - "logo_name": True, - "logo_width": "8em", - "nosidebar": False, - "page_width": "80em", - "sidebar_width": "16em", - "globaltoc_maxdepth": 3, - "globaltoc_collapse": False, - } - -else: - html_theme_options = { - "body_max_width": "60em", - "body_min_width": "40em", - "description": "A minimal portable API for embeddable GUIs.", - "show_footer_version": True, - "show_logo_version": False, - "logo": "pugl.svg", - "logo_name": True, - "logo_width": "8em", - "nosidebar": True, - "page_width": "60em", - "sidebar_width": "14em", - "globaltoc_maxdepth": 1, - "globaltoc_collapse": True, - } diff --git a/dpf/dgl/src/pugl-upstream/doc/cpp/Doxyfile.in b/dpf/dgl/src/pugl-upstream/doc/cpp/Doxyfile.in deleted file mode 100644 index 5e1be1c..0000000 --- a/dpf/dgl/src/pugl-upstream/doc/cpp/Doxyfile.in +++ /dev/null @@ -1,37 +0,0 @@ -PROJECT_NAME = Pugl -PROJECT_BRIEF = "A minimal portable API for embeddable GUIs" - -QUIET = YES -WARN_AS_ERROR = YES -WARN_IF_UNDOCUMENTED = NO -WARN_NO_PARAMDOC = NO - -JAVADOC_AUTOBRIEF = YES - -CASE_SENSE_NAMES = YES -EXCLUDE_SYMBOLS = pugl::detail -EXTRACT_LOCAL_CLASSES = NO -EXTRACT_PRIVATE = NO -HIDE_IN_BODY_DOCS = YES -HIDE_UNDOC_CLASSES = YES -HIDE_UNDOC_MEMBERS = YES -REFERENCES_LINK_SOURCE = NO - -GENERATE_HTML = NO -GENERATE_LATEX = NO -GENERATE_XML = YES -XML_PROGRAMLISTING = NO -SHOW_FILES = NO - -MACRO_EXPANSION = YES -PREDEFINED = PUGL_API \ - PUGL_DISABLE_DEPRECATED \ - PUGL_CONST_API= \ - PUGL_CONST_FUNC= - -RECURSIVE = YES -STRIP_FROM_PATH = @PUGL_SRCDIR@ -INPUT = @PUGL_SRCDIR@/include \ - @PUGL_SRCDIR@/bindings/cpp/include - -OUTPUT_DIRECTORY = @DOX_OUTPUT@ diff --git a/dpf/dgl/src/pugl-upstream/doc/cpp/api/meson.build b/dpf/dgl/src/pugl-upstream/doc/cpp/api/meson.build deleted file mode 100644 index 4e5bae5..0000000 --- a/dpf/dgl/src/pugl-upstream/doc/cpp/api/meson.build +++ /dev/null @@ -1,5 +0,0 @@ -cpp_pugl_rst = custom_target( - 'C++ API ReST Documentation', - command: [dox_to_sphinx, '-l', 'cpp', '-f', '@INPUT@', meson.current_build_dir()], - input: cpp_index_xml, - output: 'pugl.rst') diff --git a/dpf/dgl/src/pugl-upstream/doc/cpp/event-loop.rst b/dpf/dgl/src/pugl-upstream/doc/cpp/event-loop.rst deleted file mode 100644 index 1d2ac41..0000000 --- a/dpf/dgl/src/pugl-upstream/doc/cpp/event-loop.rst +++ /dev/null @@ -1,37 +0,0 @@ -.. default-domain:: cpp -.. highlight:: cpp -.. namespace:: pugl - -###################### -Driving the Event Loop -###################### - -Pugl does not contain any threads or other event loop "magic". -For flexibility, the event loop is driven manually by repeatedly calling :func:`World::update`, -which processes events from the window system and dispatches them to views when necessary. - -The exact use of :func:`World::update` depends on the application. -Plugins typically call it with a ``timeout`` of 0 in a callback driven by the host. -This avoids blocking the main loop, -since other plugins and the host itself need to run as well. - -A program can use whatever timeout is appropriate: -event-driven applications may wait forever by using a ``timeout`` of -1, -while those that draw continuously may use a significant fraction of the frame period -(with enough time left over to render). - -********* -Redrawing -********* - -Occasional redrawing can be requested by calling :func:`View::postRedisplay` or :func:`View::postRedisplayRect`. -After these are called, -a :type:`ExposeEvent` will be dispatched on the next call to :func:`World::update`. -Note, however, that this will not wake up a blocked :func:`World::update` call on MacOS -(which does not handle drawing via events). - -For continuous redrawing, -call :func:`View::postRedisplay` while handling a :type:`UpdateEvent`. -This event is sent just before views are redrawn, -so it can be used as a hook to expand the update region right before the view is exposed. -Anything else that needs to be done every frame can be handled similarly. diff --git a/dpf/dgl/src/pugl-upstream/doc/cpp/events.rst b/dpf/dgl/src/pugl-upstream/doc/cpp/events.rst deleted file mode 100644 index 72c396c..0000000 --- a/dpf/dgl/src/pugl-upstream/doc/cpp/events.rst +++ /dev/null @@ -1,43 +0,0 @@ -.. default-domain:: cpp -.. highlight:: cpp -.. namespace:: pugl - -############### -Handling Events -############### - -Events are sent to a view when it has received user input, -must be drawn, or in other situations that may need to be handled such as resizing. - -Events are sent to the ``onEvent`` method that takes the matching event type. -The application must handle at least :type:`ConfigureEvent` -and :type:`ExposeEvent` to draw anything, -but there are many other :type:`event types `. - -For example, basic event handling for our above class might look something like: - -.. code-block:: cpp - - pugl::Status - MyView::onEvent(const pugl::ConfigureEvent& event) noexcept - { - return resize(event.width, event.height); - } - - pugl::Status - MyView::onEvent(const pugl::ExposeEvent& event) noexcept - { - return drawMyAwesomeInterface(event.x, event.y, event.width, event.height); - } - -******* -Drawing -******* - -Note that Pugl uses a different drawing model than many libraries, -particularly those designed for game-style main loops like `SDL `_ and `GLFW `_. - -In that style of code, drawing is performed imperatively in the main loop, -but with Pugl, the application must draw only while handling an expose event. -This is because Pugl supports event-driven applications that only draw the damaged region when necessary, -and handles exposure internally to provide optimized and consistent behavior across platforms. diff --git a/dpf/dgl/src/pugl-upstream/doc/cpp/index.rst b/dpf/dgl/src/pugl-upstream/doc/cpp/index.rst deleted file mode 100644 index 76f45af..0000000 --- a/dpf/dgl/src/pugl-upstream/doc/cpp/index.rst +++ /dev/null @@ -1,12 +0,0 @@ -#### -Pugl -#### - -.. include:: summary.rst - -.. toctree:: - - deployment - overview - api/pugl - api/puglpp diff --git a/dpf/dgl/src/pugl-upstream/doc/cpp/meson.build b/dpf/dgl/src/pugl-upstream/doc/cpp/meson.build deleted file mode 100644 index 358a042..0000000 --- a/dpf/dgl/src/pugl-upstream/doc/cpp/meson.build +++ /dev/null @@ -1,47 +0,0 @@ -config = configuration_data() -config.set('PUGL_VERSION', meson.project_version()) - -conf_py = configure_file(configuration: config, - input: '../conf.py.in', - output: 'conf.py') - -configure_file(copy: true, input: '../deployment.rst', output: 'deployment.rst') -configure_file(copy: true, input: '../summary.rst', output: 'summary.rst') - -cpp_rst_files = files( - 'index.rst', - 'overview.rst', - 'world.rst', - 'view.rst', - 'events.rst', - 'event-loop.rst', -) - -foreach f : cpp_rst_files - configure_file(copy: true, input: f, output: '@PLAINNAME@') -endforeach - -subdir('xml') -subdir('api') - -docs = custom_target( - 'singlehtml C++ documentation for pugl', - command: [sphinx_build, '-M', 'singlehtml', - meson.current_build_dir(), meson.current_build_dir(), - '-E', '-q', '-t', 'singlehtml'], - input: [cpp_rst_files, cpp_pugl_rst, cpp_index_xml], - output: 'singlehtml', - build_by_default: true, - install: true, - install_dir: docdir / 'puglpp-0') - -docs = custom_target( - 'html C++ documentation for pugl', - command: [sphinx_build, '-M', 'html', - meson.current_build_dir(), meson.current_build_dir(), - '-E', '-q', '-t', 'html'], - input: [cpp_rst_files, cpp_pugl_rst, cpp_index_xml], - output: 'html', - build_by_default: true, - install: true, - install_dir: docdir / 'puglpp-0') diff --git a/dpf/dgl/src/pugl-upstream/doc/cpp/overview.rst b/dpf/dgl/src/pugl-upstream/doc/cpp/overview.rst deleted file mode 100644 index faa265d..0000000 --- a/dpf/dgl/src/pugl-upstream/doc/cpp/overview.rst +++ /dev/null @@ -1,35 +0,0 @@ -.. default-domain:: cpp -.. highlight:: cpp -.. namespace:: pugl - -######## -Overview -######## - -Pugl is a C library, -but the bindings documented here provide a more idiomatic and type-safe API for C++. -If you would rather use C, -refer instead to the `C API documentation <../../c/singlehtml/index.html>`_. - -The C++ bindings are very lightweight and do not require virtual functions, -RTTI, -exceptions, -or linking to the C++ standard library. -They are provided by the package ``puglpp-0`` which must be used in addition to the desired platform+backend package above. - -The core API (excluding backend-specific components) is declared in ``pugl.hpp``: - -.. code-block:: cpp - - #include - -The API revolves around two main objects: the `world` and the `view`. -An application creates a world to manage top-level state, -then creates one or more views to display. - -.. toctree:: - - world - view - events - event-loop diff --git a/dpf/dgl/src/pugl-upstream/doc/cpp/view.rst b/dpf/dgl/src/pugl-upstream/doc/cpp/view.rst deleted file mode 100644 index 3f5aee8..0000000 --- a/dpf/dgl/src/pugl-upstream/doc/cpp/view.rst +++ /dev/null @@ -1,299 +0,0 @@ -.. default-domain:: cpp -.. highlight:: cpp -.. namespace:: pugl - -############### -Creating a View -############### - -A `view` is a drawable region that receives events. -You may think of it as a window, -though it may be embedded and not represent a top-level system window. [#f1]_ - -Pugl communicates with views by dispatching events. -For flexibility, the event handler can be a different object than the view. -This allows using :class:`View` along with a separate event handler class. -Alternatively, a view class can inherit from :class:`View` and set itself as its event handler, -for a more object-oriented style. - -This documentation will use the latter approach, -so we will define a class for our view that contains everything needed: - -.. code-block:: cpp - - class MyView : public pugl::View - { - public: - explicit MyView(pugl::World& world) - : pugl::View{world} - { - setEventHandler(*this); - } - - pugl::Status onEvent(const pugl::ConfigureEvent& event) noexcept; - pugl::Status onEvent(const pugl::ExposeEvent& event) noexcept; - - // With other handlers here as needed... - - // Fallback handler for all other events - template - pugl::Status onEvent(const pugl::Event&) noexcept - { - return pugl::Status::success; - } - - private: - // Some data... - }; - -Pugl will call an ``onEvent`` method of the event handler (the view in this case) for every event. - -Note that Pugl uses a static dispatching mechanism rather than virtual functions to minimize overhead. -It is therefore necessary for the final class to define a handler for every event type. -A terse way to do this without writing every implementation is to define a fallback handler as a template, -as in the example above. -Alternatively, you can define an explicit handler for each event that simply returns :enumerator:`Status::success`. -This way, it will be a compile error if any event is not explicitly handled. - -********************* -Configuring the Frame -********************* - -Before display, -the necessary :doc:`frame ` and :doc:`window ` attributes should be set. -These allow the window system (or plugin host) to arrange the view properly. - -Derived classes can configure themselves during construction, -but we assume here that configuration is being done outside the view. -For example: - -.. code-block:: cpp - - const double defaultWidth = 1920.0; - const double defaultHeight = 1080.0; - - view.setWindowTitle("My Window"); - view.setDefaultSize(defaultWidth, defaultHeight); - view.setMinSize(defaultWidth / 4.0, defaultHeight / 4.0); - view.setAspectRatio(1, 1, 16, 9); - -There are also several :type:`hints ` for basic attributes that can be set: - -.. code-block:: cpp - - view.setHint(pugl::ViewHint::resizable, true); - view.setHint(pugl::ViewHint::ignoreKeyRepeat, true); - -********* -Embedding -********* - -To embed the view in another window, -you will need to somehow get the :type:`native view handle ` for the parent, -then set it with :func:`View::setParentWindow`. -If the parent is a Pugl view, -the native handle can be accessed with :func:`View::nativeWindow`. -For example: - -.. code-block:: cpp - - view.setParentWindow(view, parent.getNativeWindow()); - -***************** -Setting a Backend -***************** - -Before being realized, the view must have a backend set with :func:`View::setBackend`. - -The backend manages the graphics API that will be used for drawing. -Pugl includes backends and supporting API for -:doc:`Cairo `, :doc:`OpenGL `, and :doc:`Vulkan `. - -Using Cairo -=========== - -Cairo-specific API is declared in the ``cairo.hpp`` header: - -.. code-block:: cpp - - #include - -The Cairo backend is provided by :func:`cairoBackend()`: - -.. code-block:: cpp - - view.setBackend(pugl::cairoBackend()); - -No additional configuration is required for Cairo. -To draw when handling an expose event, -the `Cairo context `_ can be accessed with :func:`View::context`: - -.. code-block:: cpp - - cairo_t* cr = static_cast(view.context()); - -Using OpenGL -============ - -OpenGL-specific API is declared in the ``gl.hpp`` header: - -.. code-block:: cpp - - #include - -The OpenGL backend is provided by :func:`glBackend()`: - -.. code-block:: cpp - - view.setBackend(pugl::glBackend()); - -Some hints must also be set so that the context can be set up correctly. -For example, to use OpenGL 3.3 Core Profile: - -.. code-block:: cpp - - view.setHint(pugl::ViewHint::useCompatProfile, false); - view.setHint(pugl::ViewHint::contextVersionMajor, 3); - view.setHint(pugl::ViewHint::contextVersionMinor, 3); - -If you need to perform some setup using the OpenGL API, -there are two ways to do so. - -The OpenGL context is active when -:type:`CreateEvent` and -:type:`DestroyEvent` -events are dispatched, -so things like creating and destroying shaders and textures can be done then. - -Alternatively, if it is cumbersome to set up and tear down OpenGL in the event handler, -:func:`enterContext` and :func:`leaveContext` can be used to manually activate the OpenGL context during application setup. -Note, however, that unlike many other APIs, these functions must not be used for drawing. -It is only valid to use the OpenGL API for configuration in a manually entered context, -rendering will not work. -For example: - -.. code-block:: cpp - - pugl::enterContext(view); - myApp.setupOpenGL(); - pugl::leaveContext(view); - - while (!myApp.quit()) { - world.update(0.0); - } - - pugl::enterContext(view); - myApp.teardownOpenGL(); - pugl::leaveContext(view); - -Using Vulkan -============ - -Vulkan-specific API is declared in the ``vulkan.hpp`` header. -This header includes Vulkan headers, -so if you are dynamically loading Vulkan at runtime, -you should define ``VK_NO_PROTOTYPES`` before including it. - -.. code-block:: cpp - - #define VK_NO_PROTOTYPES - - #include - -The Vulkan backend is provided by :func:`vulkanBackend()`: - -.. code-block:: cpp - - view.setBackend(pugl::vulkanBackend()); - -Unlike OpenGL, almost all Vulkan configuration is done using the Vulkan API directly. -Pugl only provides a portable mechanism to load the Vulkan library and get the functions used to load the rest of the Vulkan API. - -Loading Vulkan --------------- - -For maximum compatibility, -it is best to not link to Vulkan at compile-time, -but instead load the Vulkan API at run-time. -To do so, first create a :class:`VulkanLoader`: - -.. code-block:: cpp - - pugl::VulkanLoader loader{world}; - -The loader manages the dynamically loaded Vulkan library, -so it must be kept alive for as long as the application is using Vulkan. -You can get the function used to load Vulkan functions with :func:`VulkanLoader::getInstanceProcAddrFunc`: - -.. code-block:: cpp - - auto vkGetInstanceProcAddr = loader.getInstanceProcAddrFunc(); - -It is best to use this function to load everything at run time, -rather than link to the Vulkan library at run time. -You can, for example, pass this to get the ``vkCreateInstance`` function using this, -then use that to create your Vulkan instance. -In practice, you will want to use some loader or wrapper API since there are many Vulkan functions. - -It is not necessary to use :class:`VulkanLoader`, -you can, for example, use the ``DynamicLoader`` from ``vulkan.hpp`` in the Vulkan SDK instead. - -The details of using Vulkan are far beyond the scope of this documentation, -but Pugl provides a portable function, :func:`createSurface`, -to get the Vulkan surface for a view. -Assuming you have somehow created your ``VkInstance``, -you can get the surface for a view using :func:`createSurface`: - -.. code-block:: cpp - - VkSurfaceKHR* surface = nullptr; - puglCreateSurface(loader.getDeviceProcAddrFunc(), - view, - vulkanInstance, - nullptr, - &surface); - -Pugl does not provide API that uses ``vulkan.hpp`` to avoid the onerous dependency, -but if you are using it with exceptions and unique handles, -it is straightforward to wrap the surface handle yourself. - -**************** -Showing the View -**************** - -Once the view is configured, it can be "realized" with :func:`View::realize`. -This creates a "real" system view, for example: - -.. code-block:: cpp - - pugl::Status status = view.realize(); - if (status != pugl::Status::success) { - std::cerr << "Error realizing view: " << pugl::strerror(status) << "\n"; - } - -Note that realizing a view can fail for many reasons, -so the return code should always be checked. -This is generally the case for any function that interacts with the window system. -Most functions also return a :enum:`Status`, -but these checks are omitted for brevity in the rest of this documentation. - -A realized view is not initially visible, -but can be shown with :func:`View::show`: - -.. code-block:: cpp - - view.show(); - -To create an initially visible view, -it is also possible to simply call :func:`View::show()` right away. -The view will be automatically realized if necessary. - -.. rubric:: Footnotes - -.. [#f1] MacOS has a strong distinction between - `views `_, - which may be nested, and - `windows `_, - which may not. - On Windows and X11, everything is a nestable window, - but top-level windows are configured differently. diff --git a/dpf/dgl/src/pugl-upstream/doc/cpp/world.rst b/dpf/dgl/src/pugl-upstream/doc/cpp/world.rst deleted file mode 100644 index 1a3b432..0000000 --- a/dpf/dgl/src/pugl-upstream/doc/cpp/world.rst +++ /dev/null @@ -1,41 +0,0 @@ -.. default-domain:: cpp -.. highlight:: cpp -.. namespace:: pugl - -################ -Creating a World -################ - -The world is the top-level object which represents an instance of Pugl. -It handles the connection to the window system, -and manages views and the event loop. - -An application typically has a single world, -which is constructed once on startup and used to drive the main event loop. - -************ -Construction -************ - -A world must be created before any views, and it must outlive all of its views. -The world constructor requires an argument to specify the application type: - -.. code-block:: cpp - - pugl::World world{pugl::WorldType::program}; - -For a plugin, specify :enumerator:`WorldType::module` instead. -In some cases, it is necessary to pass additional flags. -For example, Vulkan requires thread support: - -.. code-block:: cpp - - pugl::World world{pugl::WorldType::program, pugl::WorldFlag::threads}; - -It is a good idea to set a class name for your project with :func:`World::setClassName`. -This allows the window system to distinguish different applications and, -for example, users to set up rules to manage their windows nicely: - -.. code-block:: cpp - - world.setClassName("MyAwesomeProject"); diff --git a/dpf/dgl/src/pugl-upstream/doc/cpp/xml/meson.build b/dpf/dgl/src/pugl-upstream/doc/cpp/xml/meson.build deleted file mode 100644 index d23a563..0000000 --- a/dpf/dgl/src/pugl-upstream/doc/cpp/xml/meson.build +++ /dev/null @@ -1,21 +0,0 @@ -doxygen = find_program('doxygen') - -cpp_doxygen_input = [] -foreach h : c_headers + cpp_headers - cpp_doxygen_input += ['..' / h] -endforeach - -config = configuration_data() -config.set('PUGL_SRCDIR', pugl_src_root) -config.set('DOX_OUTPUT', meson.current_build_dir() / '..') - -cpp_doxyfile = configure_file(configuration: config, - input: '../Doxyfile.in', - output: 'Doxyfile') - -cpp_index_xml = custom_target( - 'cpp-index.xml', - command: [doxygen, '@INPUT0@'], - input: [cpp_doxyfile] + c_header_files + cpp_header_files, - output: 'index.xml') - diff --git a/dpf/dgl/src/pugl-upstream/doc/deployment.rst b/dpf/dgl/src/pugl-upstream/doc/deployment.rst deleted file mode 100644 index 4afc51a..0000000 --- a/dpf/dgl/src/pugl-upstream/doc/deployment.rst +++ /dev/null @@ -1,23 +0,0 @@ -##### -Usage -##### - -********************* -Building Against Pugl -********************* - -When Pugl is installed, -pkg-config_ packages are provided that link with the core platform library and desired backend: - -- ``pugl-cairo-0`` -- ``pugl-gl-0`` -- ``pugl-vulkan-0`` - -Depending on one of these packages should be all that is necessary to use Pugl, -but details on the individual libraries that are installed are available in the README. - -If you are instead including the source directly in your project, -the structure is quite simple and hopefully obvious. -It is only necessary to copy the platform and backend implementations that you need. - -.. _pkg-config: https://www.freedesktop.org/wiki/Software/pkg-config/ diff --git a/dpf/dgl/src/pugl-upstream/doc/meson.build b/dpf/dgl/src/pugl-upstream/doc/meson.build deleted file mode 100644 index 583f09d..0000000 --- a/dpf/dgl/src/pugl-upstream/doc/meson.build +++ /dev/null @@ -1,13 +0,0 @@ -docdir = get_option('datadir') / 'doc' - -doxygen = find_program('doxygen', required: get_option('docs')) -dox_to_sphinx = find_program('../scripts/dox_to_sphinx.py') -sphinx_build = find_program('sphinx-build', required: get_option('docs')) - -build_docs = doxygen.found() and sphinx_build.found() - -if build_docs - subdir('_static') - subdir('c') - subdir('cpp') -endif diff --git a/dpf/dgl/src/pugl-upstream/doc/summary.rst b/dpf/dgl/src/pugl-upstream/doc/summary.rst deleted file mode 100644 index f05515f..0000000 --- a/dpf/dgl/src/pugl-upstream/doc/summary.rst +++ /dev/null @@ -1,22 +0,0 @@ -Pugl is an API for writing portable and embeddable GUIs. -Pugl is not a toolkit or framework, -but a minimal portability layer that sets up a drawing context and delivers events. - -Compared to other libraries, -Pugl is particularly suitable for use in plugins or other loadable modules. -There is no implicit context or static data in the library, -so it may be statically linked and used multiple times in the same process. - -Pugl has a modular design that separates the core library from graphics backends. -The core library is graphics agnostic, -it implements platform support and depends only on standard system libraries. -MacOS, Windows, and X11 are currently supported as platforms. - -Graphics backends are separate so that applications only depend on the API that they use. -Pugl includes graphics backends for Cairo_, OpenGL_, and Vulkan_. -It is also possible to use some other graphics API by implementing a custom backend, -or simply accessing the native platform handle for a window. - -.. _Cairo: https://www.cairographics.org/ -.. _OpenGL: https://www.opengl.org/ -.. _Vulkan: https://www.khronos.org/vulkan/ diff --git a/dpf/dgl/src/pugl-upstream/examples/.clang-tidy b/dpf/dgl/src/pugl-upstream/examples/.clang-tidy deleted file mode 100644 index a03027e..0000000 --- a/dpf/dgl/src/pugl-upstream/examples/.clang-tidy +++ /dev/null @@ -1,43 +0,0 @@ -Checks: > - *, - -*-non-private-member-variables-in-classes, - -*avoid-c-arrays, - -*magic-numbers, - -*uppercase-literal-suffix, - -altera-struct-pack-align, - -android-cloexec-fopen, - -bugprone-macro-parentheses, - -bugprone-reserved-identifier, - -bugprone-suspicious-string-compare, - -cert-dcl37-c, - -cert-dcl51-cpp, - -cert-flp30-c, - -clang-analyzer-alpha.*, - -clang-analyzer-security.FloatLoopCounter, - -concurrency-mt-unsafe, - -cppcoreguidelines-avoid-non-const-global-variables, - -cppcoreguidelines-macro-usage, - -cppcoreguidelines-pro-bounds-array-to-pointer-decay, - -cppcoreguidelines-pro-bounds-constant-array-index, - -cppcoreguidelines-pro-bounds-pointer-arithmetic, - -cppcoreguidelines-pro-type-reinterpret-cast, - -cppcoreguidelines-pro-type-vararg, - -fuchsia-default-arguments, - -fuchsia-default-arguments-calls, - -fuchsia-overloaded-operator, - -google-runtime-references, - -hicpp-multiway-paths-covered, - -hicpp-named-parameter, - -hicpp-no-array-decay, - -hicpp-signed-bitwise, - -hicpp-vararg, - -llvm-header-guard, - -llvmlibc-*, - -misc-misplaced-const, - -modernize-use-trailing-return-type, - -performance-no-int-to-ptr, - -readability-function-cognitive-complexity, - -readability-implicit-bool-conversion, - -readability-named-parameter, -FormatStyle: file -HeaderFilterRegex: 'pugl/.*|test/.*|examples/.*' diff --git a/dpf/dgl/src/pugl-upstream/examples/cube_view.h b/dpf/dgl/src/pugl-upstream/examples/cube_view.h deleted file mode 100644 index 27d1a44..0000000 --- a/dpf/dgl/src/pugl-upstream/examples/cube_view.h +++ /dev/null @@ -1,193 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef EXAMPLES_CUBE_VIEW_H -#define EXAMPLES_CUBE_VIEW_H - -#define GL_SILENCE_DEPRECATION 1 - -#include "demo_utils.h" - -#include "pugl/gl.h" -#include "pugl/pugl.h" - -#include - -// clang-format off - -static const float cubeStripVertices[] = { - -1.0f, 1.0f, 1.0f, // Front top left - 1.0f, 1.0f, 1.0f, // Front top right - -1.0f, -1.0f, 1.0f, // Front bottom left - 1.0f, -1.0f, 1.0f, // Front bottom right - 1.0f, -1.0f, -1.0f, // Back bottom right - 1.0f, 1.0f, 1.0f, // Front top right - 1.0f, 1.0f, -1.0f, // Back top right - -1.0f, 1.0f, 1.0f, // Front top left - -1.0f, 1.0f, -1.0f, // Back top left - -1.0f, -1.0f, 1.0f, // Front bottom left - -1.0f, -1.0f, -1.0f, // Back bottom left - 1.0f, -1.0f, -1.0f, // Back bottom right - -1.0f, 1.0f, -1.0f, // Back top left - 1.0f, 1.0f, -1.0f, // Back top right -}; - -static const float cubeStripColorVertices[] = { - 0.25f, 0.75f, 0.75f, // Front top left - 0.75f, 0.75f, 0.75f, // Front top right - 0.25f, 0.25f, 0.75f, // Front bottom left - 0.75f, 0.25f, 0.75f, // Front bottom right - 0.75f, 0.25f, 0.25f, // Back bottom right - 0.75f, 0.75f, 0.75f, // Front top right - 0.75f, 0.75f, 0.25f, // Back top right - 0.25f, 0.75f, 0.75f, // Front top left - 0.25f, 0.75f, 0.25f, // Back top left - 0.25f, 0.25f, 0.75f, // Front bottom left - 0.25f, 0.25f, 0.25f, // Back bottom left - 0.75f, 0.25f, 0.25f, // Back bottom right - 0.25f, 0.75f, 0.25f, // Back top left - 0.75f, 0.75f, 0.25f, // Back top right -}; - -static const float cubeFrontLineLoop[] = { - -1.0f, 1.0f, 1.0f, // Front top left - 1.0f, 1.0f, 1.0f, // Front top right - 1.0f, -1.0f, 1.0f, // Front bottom right - -1.0f, -1.0f, 1.0f, // Front bottom left -}; - -static const float cubeFrontLineLoopColors[] = { - 0.25f, 0.75f, 0.75f, // Front top left - 0.75f, 0.75f, 0.75f, // Front top right - 0.75f, 0.25f, 0.75f, // Front bottom right - 0.25f, 0.25f, 0.75f, // Front bottom left -}; - -static const float cubeBackLineLoop[] = { - -1.0f, 1.0f, -1.0f, // Back top left - 1.0f, 1.0f, -1.0f, // Back top right - 1.0f, -1.0f, -1.0f, // Back bottom right - -1.0f, -1.0f, -1.0f, // Back bottom left -}; - -static const float cubeBackLineLoopColors[] = { - 0.25f, 0.75f, 0.25f, // Back top left - 0.75f, 0.75f, 0.25f, // Back top right - 0.75f, 0.25f, 0.25f, // Back bottom right - 0.25f, 0.25f, 0.25f, // Back bottom left -}; - -static const float cubeSideLines[] = { - -1.0f, 1.0f, 1.0f, // Front top left - -1.0f, 1.0f, -1.0f, // Back top left - - -1.0f, -1.0f, 1.0f, // Front bottom left - -1.0f, -1.0f, -1.0f, // Back bottom left - - 1.0f, 1.0f, 1.0f, // Front top right - 1.0f, 1.0f, -1.0f, // Back top right - - 1.0f, -1.0f, 1.0f, // Front bottom right - 1.0f, -1.0f, -1.0f, // Back bottom right -}; - -static const float cubeSideLineColors[] = { - 0.25f, 0.75f, 0.75f, // Front top left - 0.25f, 0.75f, 0.25f, // Back top left - - 0.25f, 0.25f, 0.75f, // Front bottom left - 0.25f, 0.25f, 0.25f, // Back bottom left - - 0.75f, 0.75f, 0.75f, // Front top right - 0.75f, 0.75f, 0.25f, // Back top right - - 0.75f, 0.25f, 0.75f, // Front bottom right - 0.75f, 0.25f, 0.25f, // Back bottom right -}; - -// clang-format on - -static inline void -reshapeCube(const float width, const float height) -{ - const float aspect = width / height; - - glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); - glFrontFace(GL_CW); - - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LESS); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glViewport(0, 0, (int)width, (int)height); - - float projection[16]; - perspective(projection, 1.8f, aspect, 1.0f, 100.0f); - glLoadMatrixf(projection); -} - -static inline void -displayCube(PuglView* const view, - const float distance, - const float xAngle, - const float yAngle, - const bool entered) -{ - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glTranslatef(0.0f, 0.0f, distance * -1.0f); - glRotatef(xAngle, 0.0f, 1.0f, 0.0f); - glRotatef(yAngle, 1.0f, 0.0f, 0.0f); - - if (entered) { - glClearColor(0.13f, 0.14f, 0.14f, 1.0f); - } else { - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - } - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - if (puglHasFocus(view)) { - // Draw cube surfaces - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, cubeStripVertices); - glColorPointer(3, GL_FLOAT, 0, cubeStripColorVertices); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 14); - glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); - - glColor3f(0.0f, 0.0f, 0.0f); - } else { - // Draw cube wireframe - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, cubeFrontLineLoop); - glColorPointer(3, GL_FLOAT, 0, cubeFrontLineLoopColors); - glDrawArrays(GL_LINE_LOOP, 0, 4); - glVertexPointer(3, GL_FLOAT, 0, cubeBackLineLoop); - glColorPointer(3, GL_FLOAT, 0, cubeBackLineLoopColors); - glDrawArrays(GL_LINE_LOOP, 0, 4); - glVertexPointer(3, GL_FLOAT, 0, cubeSideLines); - glColorPointer(3, GL_FLOAT, 0, cubeSideLineColors); - glDrawArrays(GL_LINES, 0, 8); - glDisableClientState(GL_VERTEX_ARRAY); - } -} - -#endif // EXAMPLES_CUBE_VIEW_H diff --git a/dpf/dgl/src/pugl-upstream/examples/demo_utils.h b/dpf/dgl/src/pugl-upstream/examples/demo_utils.h deleted file mode 100644 index 2dda756..0000000 --- a/dpf/dgl/src/pugl-upstream/examples/demo_utils.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - Copyright 2012-2019 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef EXAMPLES_DEMO_UTILS_H -#define EXAMPLES_DEMO_UTILS_H - -#include "pugl/pugl.h" - -#include -#include - -typedef struct { - double lastReportTime; -} PuglFpsPrinter; - -typedef float vec4[4]; -typedef vec4 mat4[4]; - -static inline void -mat4Identity(mat4 m) -{ - for (int c = 0; c < 4; ++c) { - for (int r = 0; r < 4; ++r) { - m[c][r] = c == r ? 1.0f : 0.0f; - } - } -} - -static inline void -mat4Translate(mat4 m, const float x, const float y, const float z) -{ - m[3][0] = x; - m[3][1] = y; - m[3][2] = z; -} - -static inline void -mat4Mul(mat4 m, mat4 a, mat4 b) -{ - for (int c = 0; c < 4; ++c) { - for (int r = 0; r < 4; ++r) { - m[c][r] = 0.0f; - for (int k = 0; k < 4; ++k) { - m[c][r] += a[k][r] * b[c][k]; - } - } - } -} - -static inline void -mat4Ortho(mat4 m, - const float l, - const float r, - const float b, - const float t, - const float n, - const float f) -{ - m[0][0] = 2.0f / (r - l); - m[0][1] = m[0][2] = m[0][3] = 0.0f; - - m[1][1] = 2.0f / (t - b); - m[1][0] = m[1][2] = m[1][3] = 0.0f; - - m[2][2] = -2.0f / (f - n); - m[2][0] = m[2][1] = m[2][3] = 0.0f; - - m[3][0] = -(r + l) / (r - l); - m[3][1] = -(t + b) / (t - b); - m[3][2] = -(f + n) / (f - n); - m[3][3] = 1.0f; -} - -/// Calculate a projection matrix for a given perspective -static inline void -perspective(float* m, float fov, float aspect, float zNear, float zFar) -{ - const float h = tanf(fov); - const float w = h / aspect; - const float depth = zNear - zFar; - const float q = (zFar + zNear) / depth; - const float qn = 2 * zFar * zNear / depth; - - // clang-format off - m[0] = w; m[1] = 0; m[2] = 0; m[3] = 0; - m[4] = 0; m[5] = h; m[6] = 0; m[7] = 0; - m[8] = 0; m[9] = 0; m[10] = q; m[11] = -1; - m[12] = 0; m[13] = 0; m[14] = qn; m[15] = 0; - // clang-format on -} - -static inline void -puglPrintFps(const PuglWorld* world, - PuglFpsPrinter* printer, - unsigned* const framesDrawn) -{ - const double thisTime = puglGetTime(world); - if (thisTime > printer->lastReportTime + 5) { - const double fps = *framesDrawn / (thisTime - printer->lastReportTime); - fprintf(stderr, - "FPS: %.2f (%u frames in %.0f seconds)\n", - fps, - *framesDrawn, - thisTime - printer->lastReportTime); - - printer->lastReportTime = thisTime; - *framesDrawn = 0; - } -} - -#endif // EXAMPLES_DEMO_UTILS_H diff --git a/dpf/dgl/src/pugl-upstream/examples/file_utils.c b/dpf/dgl/src/pugl-upstream/examples/file_utils.c deleted file mode 100644 index 8ecbca4..0000000 --- a/dpf/dgl/src/pugl-upstream/examples/file_utils.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - Copyright 2019-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#if !defined(__APPLE__) && !defined(_GNU_SOURCE) -# define _GNU_SOURCE -#endif - -#include "file_utils.h" - -#ifdef _WIN32 -# include -# include -# define F_OK 0 -#else -# include -# include -#endif - -#include -#include -#include - -char* -resourcePath(const char* const programPath, const char* const name) -{ - char* const binary = strdup(programPath); - -#ifdef _WIN32 - char programDir[_MAX_DIR]; - _splitpath(binary, programDir, NULL, NULL, NULL); - _splitpath(binary, NULL, programDir + strlen(programDir), NULL, NULL); - programDir[strlen(programDir) - 1] = '\0'; -#else - char* const programDir = dirname(binary); -#endif - - const size_t programDirLen = strlen(programDir); - const size_t nameLen = strlen(name); - const size_t totalLen = programDirLen + nameLen + 4; - - char* const programRelative = (char*)calloc(totalLen, 1); - snprintf(programRelative, totalLen, "%s/%s", programDir, name); - if (!access(programRelative, F_OK)) { - free(binary); - return programRelative; - } - - free(programRelative); - free(binary); - - const size_t sysPathLen = strlen(PUGL_DATA_DIR) + nameLen + 4; - char* const sysPath = (char*)calloc(sysPathLen, 1); - snprintf(sysPath, sysPathLen, "%s/%s", PUGL_DATA_DIR, name); - return sysPath; -} diff --git a/dpf/dgl/src/pugl-upstream/examples/file_utils.h b/dpf/dgl/src/pugl-upstream/examples/file_utils.h deleted file mode 100644 index 1530157..0000000 --- a/dpf/dgl/src/pugl-upstream/examples/file_utils.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - Copyright 2019-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef EXAMPLES_FILE_UTILS_H -#define EXAMPLES_FILE_UTILS_H - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Return the path to a resource file. - - This takes a name like "shaders/something.glsl" and returns the actual - path that can be used to load that resource, which may be relative to the - current executable (for running in bundles or the build directory), or a - shared system directory for installs. - - The returned path must be freed with free(). -*/ -char* -resourcePath(const char* programPath, const char* name); - -#ifdef __cplusplus -} -#endif - -#endif // EXAMPLES_FILE_UTILS_H diff --git a/dpf/dgl/src/pugl-upstream/examples/glad/glad.c b/dpf/dgl/src/pugl-upstream/examples/glad/glad.c deleted file mode 100644 index 38f442c..0000000 --- a/dpf/dgl/src/pugl-upstream/examples/glad/glad.c +++ /dev/null @@ -1,1138 +0,0 @@ -/* - - OpenGL loader generated by glad 0.1.32 on -. - - Language/Generator: C/C++ - Specification: gl - APIs: gl=3.3 - Profile: core - Extensions: - - Loader: True - Local files: True - Omit khrplatform: False - Reproducible: True - - Commandline: - --profile="core" --api="gl=3.3" --generator="c" --spec="gl" --local-files --extensions="" - Online: - https://glad.dav1d.de/#profile=core&language=c&specification=gl&loader=on&api=gl%3D3.3 -*/ - -#include -#include -#include -#include "glad.h" - -static void* get_proc(const char *namez); - -#if defined(_WIN32) || defined(__CYGWIN__) -#undef APIENTRY -#include -static HMODULE libGL; - -typedef void* (APIENTRYP PFNWGLGETPROCADDRESSPROC_PRIVATE)(const char*); -static PFNWGLGETPROCADDRESSPROC_PRIVATE gladGetProcAddressPtr; - -#ifdef _MSC_VER -#ifdef __has_include - #if __has_include() - #define HAVE_WINAPIFAMILY 1 - #endif -#elif _MSC_VER >= 1700 && !_USING_V110_SDK71_ - #define HAVE_WINAPIFAMILY 1 -#endif -#endif - -#ifdef HAVE_WINAPIFAMILY - #include - #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) - #define IS_UWP 1 - #endif -#endif - -static -int open_gl(void) { -#ifndef IS_UWP - libGL = LoadLibraryW(L"opengl32.dll"); - if(libGL != NULL) { - void (* tmp)(void); - tmp = (void(*)(void)) GetProcAddress(libGL, "wglGetProcAddress"); - gladGetProcAddressPtr = (PFNWGLGETPROCADDRESSPROC_PRIVATE) tmp; - return gladGetProcAddressPtr != NULL; - } -#endif - - return 0; -} - -static -void close_gl(void) { - if(libGL != NULL) { - FreeLibrary((HMODULE) libGL); - libGL = NULL; - } -} -#else -#include -static void* libGL; - -#if !defined(__APPLE__) && !defined(__HAIKU__) -typedef void* (APIENTRYP PFNGLXGETPROCADDRESSPROC_PRIVATE)(const char*); -static PFNGLXGETPROCADDRESSPROC_PRIVATE gladGetProcAddressPtr; -#endif - -static -int open_gl(void) { -#ifdef __APPLE__ - static const char *NAMES[] = { - "../Frameworks/OpenGL.framework/OpenGL", - "/Library/Frameworks/OpenGL.framework/OpenGL", - "/System/Library/Frameworks/OpenGL.framework/OpenGL", - "/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL" - }; -#else - static const char *NAMES[] = {"libGL.so.1", "libGL.so"}; -#endif - - unsigned int index = 0; - for(index = 0; index < (sizeof(NAMES) / sizeof(NAMES[0])); index++) { - libGL = dlopen(NAMES[index], RTLD_NOW | RTLD_GLOBAL); - - if(libGL != NULL) { -#if defined(__APPLE__) || defined(__HAIKU__) - return 1; -#else - gladGetProcAddressPtr = (PFNGLXGETPROCADDRESSPROC_PRIVATE)dlsym(libGL, - "glXGetProcAddressARB"); - return gladGetProcAddressPtr != NULL; -#endif - } - } - - return 0; -} - -static -void close_gl(void) { - if(libGL != NULL) { - dlclose(libGL); - libGL = NULL; - } -} -#endif - -static -void* get_proc(const char *namez) { - void* result = NULL; - if(libGL == NULL) return NULL; - -#if !defined(__APPLE__) && !defined(__HAIKU__) - if(gladGetProcAddressPtr != NULL) { - result = gladGetProcAddressPtr(namez); - } -#endif - if(result == NULL) { -#if defined(_WIN32) || defined(__CYGWIN__) - result = (void*)GetProcAddress((HMODULE) libGL, namez); -#else - result = dlsym(libGL, namez); -#endif - } - - return result; -} - -int gladLoadGL(void) { - int status = 0; - - if(open_gl()) { - status = gladLoadGLLoader(&get_proc); - close_gl(); - } - - return status; -} - -struct gladGLversionStruct GLVersion = { 0, 0 }; - -#if defined(GL_ES_VERSION_3_0) || defined(GL_VERSION_3_0) -#define _GLAD_IS_SOME_NEW_VERSION 1 -#endif - -static int max_loaded_major; -static int max_loaded_minor; - -static const char *exts = NULL; -static int num_exts_i = 0; -static char **exts_i = NULL; - -static int get_exts(void) { -#ifdef _GLAD_IS_SOME_NEW_VERSION - if(max_loaded_major < 3) { -#endif - exts = (const char *)glGetString(GL_EXTENSIONS); -#ifdef _GLAD_IS_SOME_NEW_VERSION - } else { - unsigned int index; - - num_exts_i = 0; - glGetIntegerv(GL_NUM_EXTENSIONS, &num_exts_i); - if (num_exts_i > 0) { - exts_i = (char **)malloc((size_t)num_exts_i * (sizeof *exts_i)); - } - - if (exts_i == NULL) { - return 0; - } - - for(index = 0; index < (unsigned)num_exts_i; index++) { - const char *gl_str_tmp = (const char*)glGetStringi(GL_EXTENSIONS, index); - size_t len = strlen(gl_str_tmp); - - char *local_str = (char*)malloc((len+1) * sizeof(char)); - if(local_str != NULL) { - memcpy(local_str, gl_str_tmp, (len+1) * sizeof(char)); - } - exts_i[index] = local_str; - } - } -#endif - return 1; -} - -static void free_exts(void) { - if (exts_i != NULL) { - int index; - for(index = 0; index < num_exts_i; index++) { - free((char *)exts_i[index]); - } - free((void *)exts_i); - exts_i = NULL; - } -} - -static int has_ext(const char *ext) { -#ifdef _GLAD_IS_SOME_NEW_VERSION - if(max_loaded_major < 3) { -#endif - const char *extensions; - const char *loc; - const char *terminator; - extensions = exts; - if(extensions == NULL || ext == NULL) { - return 0; - } - - while(1) { - loc = strstr(extensions, ext); - if(loc == NULL) { - return 0; - } - - terminator = loc + strlen(ext); - if((loc == extensions || *(loc - 1) == ' ') && - (*terminator == ' ' || *terminator == '\0')) { - return 1; - } - extensions = terminator; - } -#ifdef _GLAD_IS_SOME_NEW_VERSION - } else { - int index; - if(exts_i == NULL) return 0; - for(index = 0; index < num_exts_i; index++) { - const char *e = exts_i[index]; - - if(exts_i[index] != NULL && strcmp(e, ext) == 0) { - return 1; - } - } - } -#endif - - return 0; -} -int GLAD_GL_VERSION_1_0 = 0; -int GLAD_GL_VERSION_1_1 = 0; -int GLAD_GL_VERSION_1_2 = 0; -int GLAD_GL_VERSION_1_3 = 0; -int GLAD_GL_VERSION_1_4 = 0; -int GLAD_GL_VERSION_1_5 = 0; -int GLAD_GL_VERSION_2_0 = 0; -int GLAD_GL_VERSION_2_1 = 0; -int GLAD_GL_VERSION_3_0 = 0; -int GLAD_GL_VERSION_3_1 = 0; -int GLAD_GL_VERSION_3_2 = 0; -int GLAD_GL_VERSION_3_3 = 0; -PFNGLACTIVETEXTUREPROC glad_glActiveTexture = NULL; -PFNGLATTACHSHADERPROC glad_glAttachShader = NULL; -PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender = NULL; -PFNGLBEGINQUERYPROC glad_glBeginQuery = NULL; -PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback = NULL; -PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation = NULL; -PFNGLBINDBUFFERPROC glad_glBindBuffer = NULL; -PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase = NULL; -PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange = NULL; -PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation = NULL; -PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glad_glBindFragDataLocationIndexed = NULL; -PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer = NULL; -PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer = NULL; -PFNGLBINDSAMPLERPROC glad_glBindSampler = NULL; -PFNGLBINDTEXTUREPROC glad_glBindTexture = NULL; -PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray = NULL; -PFNGLBLENDCOLORPROC glad_glBlendColor = NULL; -PFNGLBLENDEQUATIONPROC glad_glBlendEquation = NULL; -PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate = NULL; -PFNGLBLENDFUNCPROC glad_glBlendFunc = NULL; -PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate = NULL; -PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer = NULL; -PFNGLBUFFERDATAPROC glad_glBufferData = NULL; -PFNGLBUFFERSUBDATAPROC glad_glBufferSubData = NULL; -PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus = NULL; -PFNGLCLAMPCOLORPROC glad_glClampColor = NULL; -PFNGLCLEARPROC glad_glClear = NULL; -PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi = NULL; -PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv = NULL; -PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv = NULL; -PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv = NULL; -PFNGLCLEARCOLORPROC glad_glClearColor = NULL; -PFNGLCLEARDEPTHPROC glad_glClearDepth = NULL; -PFNGLCLEARSTENCILPROC glad_glClearStencil = NULL; -PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync = NULL; -PFNGLCOLORMASKPROC glad_glColorMask = NULL; -PFNGLCOLORMASKIPROC glad_glColorMaski = NULL; -PFNGLCOLORP3UIPROC glad_glColorP3ui = NULL; -PFNGLCOLORP3UIVPROC glad_glColorP3uiv = NULL; -PFNGLCOLORP4UIPROC glad_glColorP4ui = NULL; -PFNGLCOLORP4UIVPROC glad_glColorP4uiv = NULL; -PFNGLCOMPILESHADERPROC glad_glCompileShader = NULL; -PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D = NULL; -PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D = NULL; -PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D = NULL; -PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D = NULL; -PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D = NULL; -PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D = NULL; -PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData = NULL; -PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D = NULL; -PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D = NULL; -PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D = NULL; -PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D = NULL; -PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D = NULL; -PFNGLCREATEPROGRAMPROC glad_glCreateProgram = NULL; -PFNGLCREATESHADERPROC glad_glCreateShader = NULL; -PFNGLCULLFACEPROC glad_glCullFace = NULL; -PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers = NULL; -PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers = NULL; -PFNGLDELETEPROGRAMPROC glad_glDeleteProgram = NULL; -PFNGLDELETEQUERIESPROC glad_glDeleteQueries = NULL; -PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers = NULL; -PFNGLDELETESAMPLERSPROC glad_glDeleteSamplers = NULL; -PFNGLDELETESHADERPROC glad_glDeleteShader = NULL; -PFNGLDELETESYNCPROC glad_glDeleteSync = NULL; -PFNGLDELETETEXTURESPROC glad_glDeleteTextures = NULL; -PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays = NULL; -PFNGLDEPTHFUNCPROC glad_glDepthFunc = NULL; -PFNGLDEPTHMASKPROC glad_glDepthMask = NULL; -PFNGLDEPTHRANGEPROC glad_glDepthRange = NULL; -PFNGLDETACHSHADERPROC glad_glDetachShader = NULL; -PFNGLDISABLEPROC glad_glDisable = NULL; -PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray = NULL; -PFNGLDISABLEIPROC glad_glDisablei = NULL; -PFNGLDRAWARRAYSPROC glad_glDrawArrays = NULL; -PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced = NULL; -PFNGLDRAWBUFFERPROC glad_glDrawBuffer = NULL; -PFNGLDRAWBUFFERSPROC glad_glDrawBuffers = NULL; -PFNGLDRAWELEMENTSPROC glad_glDrawElements = NULL; -PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex = NULL; -PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced = NULL; -PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex = NULL; -PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements = NULL; -PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex = NULL; -PFNGLENABLEPROC glad_glEnable = NULL; -PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray = NULL; -PFNGLENABLEIPROC glad_glEnablei = NULL; -PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender = NULL; -PFNGLENDQUERYPROC glad_glEndQuery = NULL; -PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback = NULL; -PFNGLFENCESYNCPROC glad_glFenceSync = NULL; -PFNGLFINISHPROC glad_glFinish = NULL; -PFNGLFLUSHPROC glad_glFlush = NULL; -PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange = NULL; -PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer = NULL; -PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture = NULL; -PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D = NULL; -PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D = NULL; -PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D = NULL; -PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer = NULL; -PFNGLFRONTFACEPROC glad_glFrontFace = NULL; -PFNGLGENBUFFERSPROC glad_glGenBuffers = NULL; -PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers = NULL; -PFNGLGENQUERIESPROC glad_glGenQueries = NULL; -PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers = NULL; -PFNGLGENSAMPLERSPROC glad_glGenSamplers = NULL; -PFNGLGENTEXTURESPROC glad_glGenTextures = NULL; -PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays = NULL; -PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap = NULL; -PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib = NULL; -PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform = NULL; -PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName = NULL; -PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv = NULL; -PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName = NULL; -PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv = NULL; -PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders = NULL; -PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation = NULL; -PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v = NULL; -PFNGLGETBOOLEANVPROC glad_glGetBooleanv = NULL; -PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v = NULL; -PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv = NULL; -PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv = NULL; -PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData = NULL; -PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage = NULL; -PFNGLGETDOUBLEVPROC glad_glGetDoublev = NULL; -PFNGLGETERRORPROC glad_glGetError = NULL; -PFNGLGETFLOATVPROC glad_glGetFloatv = NULL; -PFNGLGETFRAGDATAINDEXPROC glad_glGetFragDataIndex = NULL; -PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation = NULL; -PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv = NULL; -PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v = NULL; -PFNGLGETINTEGER64VPROC glad_glGetInteger64v = NULL; -PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v = NULL; -PFNGLGETINTEGERVPROC glad_glGetIntegerv = NULL; -PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv = NULL; -PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog = NULL; -PFNGLGETPROGRAMIVPROC glad_glGetProgramiv = NULL; -PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v = NULL; -PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv = NULL; -PFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v = NULL; -PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv = NULL; -PFNGLGETQUERYIVPROC glad_glGetQueryiv = NULL; -PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv = NULL; -PFNGLGETSAMPLERPARAMETERIIVPROC glad_glGetSamplerParameterIiv = NULL; -PFNGLGETSAMPLERPARAMETERIUIVPROC glad_glGetSamplerParameterIuiv = NULL; -PFNGLGETSAMPLERPARAMETERFVPROC glad_glGetSamplerParameterfv = NULL; -PFNGLGETSAMPLERPARAMETERIVPROC glad_glGetSamplerParameteriv = NULL; -PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog = NULL; -PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource = NULL; -PFNGLGETSHADERIVPROC glad_glGetShaderiv = NULL; -PFNGLGETSTRINGPROC glad_glGetString = NULL; -PFNGLGETSTRINGIPROC glad_glGetStringi = NULL; -PFNGLGETSYNCIVPROC glad_glGetSynciv = NULL; -PFNGLGETTEXIMAGEPROC glad_glGetTexImage = NULL; -PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv = NULL; -PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv = NULL; -PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv = NULL; -PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv = NULL; -PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv = NULL; -PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv = NULL; -PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying = NULL; -PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex = NULL; -PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices = NULL; -PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation = NULL; -PFNGLGETUNIFORMFVPROC glad_glGetUniformfv = NULL; -PFNGLGETUNIFORMIVPROC glad_glGetUniformiv = NULL; -PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv = NULL; -PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv = NULL; -PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv = NULL; -PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv = NULL; -PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv = NULL; -PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv = NULL; -PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv = NULL; -PFNGLHINTPROC glad_glHint = NULL; -PFNGLISBUFFERPROC glad_glIsBuffer = NULL; -PFNGLISENABLEDPROC glad_glIsEnabled = NULL; -PFNGLISENABLEDIPROC glad_glIsEnabledi = NULL; -PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer = NULL; -PFNGLISPROGRAMPROC glad_glIsProgram = NULL; -PFNGLISQUERYPROC glad_glIsQuery = NULL; -PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer = NULL; -PFNGLISSAMPLERPROC glad_glIsSampler = NULL; -PFNGLISSHADERPROC glad_glIsShader = NULL; -PFNGLISSYNCPROC glad_glIsSync = NULL; -PFNGLISTEXTUREPROC glad_glIsTexture = NULL; -PFNGLISVERTEXARRAYPROC glad_glIsVertexArray = NULL; -PFNGLLINEWIDTHPROC glad_glLineWidth = NULL; -PFNGLLINKPROGRAMPROC glad_glLinkProgram = NULL; -PFNGLLOGICOPPROC glad_glLogicOp = NULL; -PFNGLMAPBUFFERPROC glad_glMapBuffer = NULL; -PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange = NULL; -PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays = NULL; -PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements = NULL; -PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex = NULL; -PFNGLMULTITEXCOORDP1UIPROC glad_glMultiTexCoordP1ui = NULL; -PFNGLMULTITEXCOORDP1UIVPROC glad_glMultiTexCoordP1uiv = NULL; -PFNGLMULTITEXCOORDP2UIPROC glad_glMultiTexCoordP2ui = NULL; -PFNGLMULTITEXCOORDP2UIVPROC glad_glMultiTexCoordP2uiv = NULL; -PFNGLMULTITEXCOORDP3UIPROC glad_glMultiTexCoordP3ui = NULL; -PFNGLMULTITEXCOORDP3UIVPROC glad_glMultiTexCoordP3uiv = NULL; -PFNGLMULTITEXCOORDP4UIPROC glad_glMultiTexCoordP4ui = NULL; -PFNGLMULTITEXCOORDP4UIVPROC glad_glMultiTexCoordP4uiv = NULL; -PFNGLNORMALP3UIPROC glad_glNormalP3ui = NULL; -PFNGLNORMALP3UIVPROC glad_glNormalP3uiv = NULL; -PFNGLPIXELSTOREFPROC glad_glPixelStoref = NULL; -PFNGLPIXELSTOREIPROC glad_glPixelStorei = NULL; -PFNGLPOINTPARAMETERFPROC glad_glPointParameterf = NULL; -PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv = NULL; -PFNGLPOINTPARAMETERIPROC glad_glPointParameteri = NULL; -PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv = NULL; -PFNGLPOINTSIZEPROC glad_glPointSize = NULL; -PFNGLPOLYGONMODEPROC glad_glPolygonMode = NULL; -PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset = NULL; -PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex = NULL; -PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex = NULL; -PFNGLQUERYCOUNTERPROC glad_glQueryCounter = NULL; -PFNGLREADBUFFERPROC glad_glReadBuffer = NULL; -PFNGLREADPIXELSPROC glad_glReadPixels = NULL; -PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage = NULL; -PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample = NULL; -PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage = NULL; -PFNGLSAMPLEMASKIPROC glad_glSampleMaski = NULL; -PFNGLSAMPLERPARAMETERIIVPROC glad_glSamplerParameterIiv = NULL; -PFNGLSAMPLERPARAMETERIUIVPROC glad_glSamplerParameterIuiv = NULL; -PFNGLSAMPLERPARAMETERFPROC glad_glSamplerParameterf = NULL; -PFNGLSAMPLERPARAMETERFVPROC glad_glSamplerParameterfv = NULL; -PFNGLSAMPLERPARAMETERIPROC glad_glSamplerParameteri = NULL; -PFNGLSAMPLERPARAMETERIVPROC glad_glSamplerParameteriv = NULL; -PFNGLSCISSORPROC glad_glScissor = NULL; -PFNGLSECONDARYCOLORP3UIPROC glad_glSecondaryColorP3ui = NULL; -PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv = NULL; -PFNGLSHADERSOURCEPROC glad_glShaderSource = NULL; -PFNGLSTENCILFUNCPROC glad_glStencilFunc = NULL; -PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate = NULL; -PFNGLSTENCILMASKPROC glad_glStencilMask = NULL; -PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate = NULL; -PFNGLSTENCILOPPROC glad_glStencilOp = NULL; -PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate = NULL; -PFNGLTEXBUFFERPROC glad_glTexBuffer = NULL; -PFNGLTEXCOORDP1UIPROC glad_glTexCoordP1ui = NULL; -PFNGLTEXCOORDP1UIVPROC glad_glTexCoordP1uiv = NULL; -PFNGLTEXCOORDP2UIPROC glad_glTexCoordP2ui = NULL; -PFNGLTEXCOORDP2UIVPROC glad_glTexCoordP2uiv = NULL; -PFNGLTEXCOORDP3UIPROC glad_glTexCoordP3ui = NULL; -PFNGLTEXCOORDP3UIVPROC glad_glTexCoordP3uiv = NULL; -PFNGLTEXCOORDP4UIPROC glad_glTexCoordP4ui = NULL; -PFNGLTEXCOORDP4UIVPROC glad_glTexCoordP4uiv = NULL; -PFNGLTEXIMAGE1DPROC glad_glTexImage1D = NULL; -PFNGLTEXIMAGE2DPROC glad_glTexImage2D = NULL; -PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample = NULL; -PFNGLTEXIMAGE3DPROC glad_glTexImage3D = NULL; -PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample = NULL; -PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv = NULL; -PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv = NULL; -PFNGLTEXPARAMETERFPROC glad_glTexParameterf = NULL; -PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv = NULL; -PFNGLTEXPARAMETERIPROC glad_glTexParameteri = NULL; -PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv = NULL; -PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D = NULL; -PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D = NULL; -PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D = NULL; -PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings = NULL; -PFNGLUNIFORM1FPROC glad_glUniform1f = NULL; -PFNGLUNIFORM1FVPROC glad_glUniform1fv = NULL; -PFNGLUNIFORM1IPROC glad_glUniform1i = NULL; -PFNGLUNIFORM1IVPROC glad_glUniform1iv = NULL; -PFNGLUNIFORM1UIPROC glad_glUniform1ui = NULL; -PFNGLUNIFORM1UIVPROC glad_glUniform1uiv = NULL; -PFNGLUNIFORM2FPROC glad_glUniform2f = NULL; -PFNGLUNIFORM2FVPROC glad_glUniform2fv = NULL; -PFNGLUNIFORM2IPROC glad_glUniform2i = NULL; -PFNGLUNIFORM2IVPROC glad_glUniform2iv = NULL; -PFNGLUNIFORM2UIPROC glad_glUniform2ui = NULL; -PFNGLUNIFORM2UIVPROC glad_glUniform2uiv = NULL; -PFNGLUNIFORM3FPROC glad_glUniform3f = NULL; -PFNGLUNIFORM3FVPROC glad_glUniform3fv = NULL; -PFNGLUNIFORM3IPROC glad_glUniform3i = NULL; -PFNGLUNIFORM3IVPROC glad_glUniform3iv = NULL; -PFNGLUNIFORM3UIPROC glad_glUniform3ui = NULL; -PFNGLUNIFORM3UIVPROC glad_glUniform3uiv = NULL; -PFNGLUNIFORM4FPROC glad_glUniform4f = NULL; -PFNGLUNIFORM4FVPROC glad_glUniform4fv = NULL; -PFNGLUNIFORM4IPROC glad_glUniform4i = NULL; -PFNGLUNIFORM4IVPROC glad_glUniform4iv = NULL; -PFNGLUNIFORM4UIPROC glad_glUniform4ui = NULL; -PFNGLUNIFORM4UIVPROC glad_glUniform4uiv = NULL; -PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding = NULL; -PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv = NULL; -PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv = NULL; -PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv = NULL; -PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv = NULL; -PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv = NULL; -PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv = NULL; -PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv = NULL; -PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv = NULL; -PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv = NULL; -PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer = NULL; -PFNGLUSEPROGRAMPROC glad_glUseProgram = NULL; -PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram = NULL; -PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d = NULL; -PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv = NULL; -PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f = NULL; -PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv = NULL; -PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s = NULL; -PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv = NULL; -PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d = NULL; -PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv = NULL; -PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f = NULL; -PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv = NULL; -PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s = NULL; -PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv = NULL; -PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d = NULL; -PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv = NULL; -PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f = NULL; -PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv = NULL; -PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s = NULL; -PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv = NULL; -PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv = NULL; -PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv = NULL; -PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv = NULL; -PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub = NULL; -PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv = NULL; -PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv = NULL; -PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv = NULL; -PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv = NULL; -PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d = NULL; -PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv = NULL; -PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f = NULL; -PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv = NULL; -PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv = NULL; -PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s = NULL; -PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv = NULL; -PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv = NULL; -PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv = NULL; -PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv = NULL; -PFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor = NULL; -PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i = NULL; -PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv = NULL; -PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui = NULL; -PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv = NULL; -PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i = NULL; -PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv = NULL; -PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui = NULL; -PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv = NULL; -PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i = NULL; -PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv = NULL; -PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui = NULL; -PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv = NULL; -PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv = NULL; -PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i = NULL; -PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv = NULL; -PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv = NULL; -PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv = NULL; -PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui = NULL; -PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv = NULL; -PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv = NULL; -PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer = NULL; -PFNGLVERTEXATTRIBP1UIPROC glad_glVertexAttribP1ui = NULL; -PFNGLVERTEXATTRIBP1UIVPROC glad_glVertexAttribP1uiv = NULL; -PFNGLVERTEXATTRIBP2UIPROC glad_glVertexAttribP2ui = NULL; -PFNGLVERTEXATTRIBP2UIVPROC glad_glVertexAttribP2uiv = NULL; -PFNGLVERTEXATTRIBP3UIPROC glad_glVertexAttribP3ui = NULL; -PFNGLVERTEXATTRIBP3UIVPROC glad_glVertexAttribP3uiv = NULL; -PFNGLVERTEXATTRIBP4UIPROC glad_glVertexAttribP4ui = NULL; -PFNGLVERTEXATTRIBP4UIVPROC glad_glVertexAttribP4uiv = NULL; -PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer = NULL; -PFNGLVERTEXP2UIPROC glad_glVertexP2ui = NULL; -PFNGLVERTEXP2UIVPROC glad_glVertexP2uiv = NULL; -PFNGLVERTEXP3UIPROC glad_glVertexP3ui = NULL; -PFNGLVERTEXP3UIVPROC glad_glVertexP3uiv = NULL; -PFNGLVERTEXP4UIPROC glad_glVertexP4ui = NULL; -PFNGLVERTEXP4UIVPROC glad_glVertexP4uiv = NULL; -PFNGLVIEWPORTPROC glad_glViewport = NULL; -PFNGLWAITSYNCPROC glad_glWaitSync = NULL; -static void load_GL_VERSION_1_0(GLADloadproc load) { - if(!GLAD_GL_VERSION_1_0) return; - glad_glCullFace = (PFNGLCULLFACEPROC)load("glCullFace"); - glad_glFrontFace = (PFNGLFRONTFACEPROC)load("glFrontFace"); - glad_glHint = (PFNGLHINTPROC)load("glHint"); - glad_glLineWidth = (PFNGLLINEWIDTHPROC)load("glLineWidth"); - glad_glPointSize = (PFNGLPOINTSIZEPROC)load("glPointSize"); - glad_glPolygonMode = (PFNGLPOLYGONMODEPROC)load("glPolygonMode"); - glad_glScissor = (PFNGLSCISSORPROC)load("glScissor"); - glad_glTexParameterf = (PFNGLTEXPARAMETERFPROC)load("glTexParameterf"); - glad_glTexParameterfv = (PFNGLTEXPARAMETERFVPROC)load("glTexParameterfv"); - glad_glTexParameteri = (PFNGLTEXPARAMETERIPROC)load("glTexParameteri"); - glad_glTexParameteriv = (PFNGLTEXPARAMETERIVPROC)load("glTexParameteriv"); - glad_glTexImage1D = (PFNGLTEXIMAGE1DPROC)load("glTexImage1D"); - glad_glTexImage2D = (PFNGLTEXIMAGE2DPROC)load("glTexImage2D"); - glad_glDrawBuffer = (PFNGLDRAWBUFFERPROC)load("glDrawBuffer"); - glad_glClear = (PFNGLCLEARPROC)load("glClear"); - glad_glClearColor = (PFNGLCLEARCOLORPROC)load("glClearColor"); - glad_glClearStencil = (PFNGLCLEARSTENCILPROC)load("glClearStencil"); - glad_glClearDepth = (PFNGLCLEARDEPTHPROC)load("glClearDepth"); - glad_glStencilMask = (PFNGLSTENCILMASKPROC)load("glStencilMask"); - glad_glColorMask = (PFNGLCOLORMASKPROC)load("glColorMask"); - glad_glDepthMask = (PFNGLDEPTHMASKPROC)load("glDepthMask"); - glad_glDisable = (PFNGLDISABLEPROC)load("glDisable"); - glad_glEnable = (PFNGLENABLEPROC)load("glEnable"); - glad_glFinish = (PFNGLFINISHPROC)load("glFinish"); - glad_glFlush = (PFNGLFLUSHPROC)load("glFlush"); - glad_glBlendFunc = (PFNGLBLENDFUNCPROC)load("glBlendFunc"); - glad_glLogicOp = (PFNGLLOGICOPPROC)load("glLogicOp"); - glad_glStencilFunc = (PFNGLSTENCILFUNCPROC)load("glStencilFunc"); - glad_glStencilOp = (PFNGLSTENCILOPPROC)load("glStencilOp"); - glad_glDepthFunc = (PFNGLDEPTHFUNCPROC)load("glDepthFunc"); - glad_glPixelStoref = (PFNGLPIXELSTOREFPROC)load("glPixelStoref"); - glad_glPixelStorei = (PFNGLPIXELSTOREIPROC)load("glPixelStorei"); - glad_glReadBuffer = (PFNGLREADBUFFERPROC)load("glReadBuffer"); - glad_glReadPixels = (PFNGLREADPIXELSPROC)load("glReadPixels"); - glad_glGetBooleanv = (PFNGLGETBOOLEANVPROC)load("glGetBooleanv"); - glad_glGetDoublev = (PFNGLGETDOUBLEVPROC)load("glGetDoublev"); - glad_glGetError = (PFNGLGETERRORPROC)load("glGetError"); - glad_glGetFloatv = (PFNGLGETFLOATVPROC)load("glGetFloatv"); - glad_glGetIntegerv = (PFNGLGETINTEGERVPROC)load("glGetIntegerv"); - glad_glGetString = (PFNGLGETSTRINGPROC)load("glGetString"); - glad_glGetTexImage = (PFNGLGETTEXIMAGEPROC)load("glGetTexImage"); - glad_glGetTexParameterfv = (PFNGLGETTEXPARAMETERFVPROC)load("glGetTexParameterfv"); - glad_glGetTexParameteriv = (PFNGLGETTEXPARAMETERIVPROC)load("glGetTexParameteriv"); - glad_glGetTexLevelParameterfv = (PFNGLGETTEXLEVELPARAMETERFVPROC)load("glGetTexLevelParameterfv"); - glad_glGetTexLevelParameteriv = (PFNGLGETTEXLEVELPARAMETERIVPROC)load("glGetTexLevelParameteriv"); - glad_glIsEnabled = (PFNGLISENABLEDPROC)load("glIsEnabled"); - glad_glDepthRange = (PFNGLDEPTHRANGEPROC)load("glDepthRange"); - glad_glViewport = (PFNGLVIEWPORTPROC)load("glViewport"); -} -static void load_GL_VERSION_1_1(GLADloadproc load) { - if(!GLAD_GL_VERSION_1_1) return; - glad_glDrawArrays = (PFNGLDRAWARRAYSPROC)load("glDrawArrays"); - glad_glDrawElements = (PFNGLDRAWELEMENTSPROC)load("glDrawElements"); - glad_glPolygonOffset = (PFNGLPOLYGONOFFSETPROC)load("glPolygonOffset"); - glad_glCopyTexImage1D = (PFNGLCOPYTEXIMAGE1DPROC)load("glCopyTexImage1D"); - glad_glCopyTexImage2D = (PFNGLCOPYTEXIMAGE2DPROC)load("glCopyTexImage2D"); - glad_glCopyTexSubImage1D = (PFNGLCOPYTEXSUBIMAGE1DPROC)load("glCopyTexSubImage1D"); - glad_glCopyTexSubImage2D = (PFNGLCOPYTEXSUBIMAGE2DPROC)load("glCopyTexSubImage2D"); - glad_glTexSubImage1D = (PFNGLTEXSUBIMAGE1DPROC)load("glTexSubImage1D"); - glad_glTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC)load("glTexSubImage2D"); - glad_glBindTexture = (PFNGLBINDTEXTUREPROC)load("glBindTexture"); - glad_glDeleteTextures = (PFNGLDELETETEXTURESPROC)load("glDeleteTextures"); - glad_glGenTextures = (PFNGLGENTEXTURESPROC)load("glGenTextures"); - glad_glIsTexture = (PFNGLISTEXTUREPROC)load("glIsTexture"); -} -static void load_GL_VERSION_1_2(GLADloadproc load) { - if(!GLAD_GL_VERSION_1_2) return; - glad_glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)load("glDrawRangeElements"); - glad_glTexImage3D = (PFNGLTEXIMAGE3DPROC)load("glTexImage3D"); - glad_glTexSubImage3D = (PFNGLTEXSUBIMAGE3DPROC)load("glTexSubImage3D"); - glad_glCopyTexSubImage3D = (PFNGLCOPYTEXSUBIMAGE3DPROC)load("glCopyTexSubImage3D"); -} -static void load_GL_VERSION_1_3(GLADloadproc load) { - if(!GLAD_GL_VERSION_1_3) return; - glad_glActiveTexture = (PFNGLACTIVETEXTUREPROC)load("glActiveTexture"); - glad_glSampleCoverage = (PFNGLSAMPLECOVERAGEPROC)load("glSampleCoverage"); - glad_glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC)load("glCompressedTexImage3D"); - glad_glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC)load("glCompressedTexImage2D"); - glad_glCompressedTexImage1D = (PFNGLCOMPRESSEDTEXIMAGE1DPROC)load("glCompressedTexImage1D"); - glad_glCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)load("glCompressedTexSubImage3D"); - glad_glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)load("glCompressedTexSubImage2D"); - glad_glCompressedTexSubImage1D = (PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)load("glCompressedTexSubImage1D"); - glad_glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC)load("glGetCompressedTexImage"); -} -static void load_GL_VERSION_1_4(GLADloadproc load) { - if(!GLAD_GL_VERSION_1_4) return; - glad_glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC)load("glBlendFuncSeparate"); - glad_glMultiDrawArrays = (PFNGLMULTIDRAWARRAYSPROC)load("glMultiDrawArrays"); - glad_glMultiDrawElements = (PFNGLMULTIDRAWELEMENTSPROC)load("glMultiDrawElements"); - glad_glPointParameterf = (PFNGLPOINTPARAMETERFPROC)load("glPointParameterf"); - glad_glPointParameterfv = (PFNGLPOINTPARAMETERFVPROC)load("glPointParameterfv"); - glad_glPointParameteri = (PFNGLPOINTPARAMETERIPROC)load("glPointParameteri"); - glad_glPointParameteriv = (PFNGLPOINTPARAMETERIVPROC)load("glPointParameteriv"); - glad_glBlendColor = (PFNGLBLENDCOLORPROC)load("glBlendColor"); - glad_glBlendEquation = (PFNGLBLENDEQUATIONPROC)load("glBlendEquation"); -} -static void load_GL_VERSION_1_5(GLADloadproc load) { - if(!GLAD_GL_VERSION_1_5) return; - glad_glGenQueries = (PFNGLGENQUERIESPROC)load("glGenQueries"); - glad_glDeleteQueries = (PFNGLDELETEQUERIESPROC)load("glDeleteQueries"); - glad_glIsQuery = (PFNGLISQUERYPROC)load("glIsQuery"); - glad_glBeginQuery = (PFNGLBEGINQUERYPROC)load("glBeginQuery"); - glad_glEndQuery = (PFNGLENDQUERYPROC)load("glEndQuery"); - glad_glGetQueryiv = (PFNGLGETQUERYIVPROC)load("glGetQueryiv"); - glad_glGetQueryObjectiv = (PFNGLGETQUERYOBJECTIVPROC)load("glGetQueryObjectiv"); - glad_glGetQueryObjectuiv = (PFNGLGETQUERYOBJECTUIVPROC)load("glGetQueryObjectuiv"); - glad_glBindBuffer = (PFNGLBINDBUFFERPROC)load("glBindBuffer"); - glad_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)load("glDeleteBuffers"); - glad_glGenBuffers = (PFNGLGENBUFFERSPROC)load("glGenBuffers"); - glad_glIsBuffer = (PFNGLISBUFFERPROC)load("glIsBuffer"); - glad_glBufferData = (PFNGLBUFFERDATAPROC)load("glBufferData"); - glad_glBufferSubData = (PFNGLBUFFERSUBDATAPROC)load("glBufferSubData"); - glad_glGetBufferSubData = (PFNGLGETBUFFERSUBDATAPROC)load("glGetBufferSubData"); - glad_glMapBuffer = (PFNGLMAPBUFFERPROC)load("glMapBuffer"); - glad_glUnmapBuffer = (PFNGLUNMAPBUFFERPROC)load("glUnmapBuffer"); - glad_glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC)load("glGetBufferParameteriv"); - glad_glGetBufferPointerv = (PFNGLGETBUFFERPOINTERVPROC)load("glGetBufferPointerv"); -} -static void load_GL_VERSION_2_0(GLADloadproc load) { - if(!GLAD_GL_VERSION_2_0) return; - glad_glBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEPROC)load("glBlendEquationSeparate"); - glad_glDrawBuffers = (PFNGLDRAWBUFFERSPROC)load("glDrawBuffers"); - glad_glStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC)load("glStencilOpSeparate"); - glad_glStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC)load("glStencilFuncSeparate"); - glad_glStencilMaskSeparate = (PFNGLSTENCILMASKSEPARATEPROC)load("glStencilMaskSeparate"); - glad_glAttachShader = (PFNGLATTACHSHADERPROC)load("glAttachShader"); - glad_glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC)load("glBindAttribLocation"); - glad_glCompileShader = (PFNGLCOMPILESHADERPROC)load("glCompileShader"); - glad_glCreateProgram = (PFNGLCREATEPROGRAMPROC)load("glCreateProgram"); - glad_glCreateShader = (PFNGLCREATESHADERPROC)load("glCreateShader"); - glad_glDeleteProgram = (PFNGLDELETEPROGRAMPROC)load("glDeleteProgram"); - glad_glDeleteShader = (PFNGLDELETESHADERPROC)load("glDeleteShader"); - glad_glDetachShader = (PFNGLDETACHSHADERPROC)load("glDetachShader"); - glad_glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)load("glDisableVertexAttribArray"); - glad_glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)load("glEnableVertexAttribArray"); - glad_glGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC)load("glGetActiveAttrib"); - glad_glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC)load("glGetActiveUniform"); - glad_glGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC)load("glGetAttachedShaders"); - glad_glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC)load("glGetAttribLocation"); - glad_glGetProgramiv = (PFNGLGETPROGRAMIVPROC)load("glGetProgramiv"); - glad_glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)load("glGetProgramInfoLog"); - glad_glGetShaderiv = (PFNGLGETSHADERIVPROC)load("glGetShaderiv"); - glad_glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)load("glGetShaderInfoLog"); - glad_glGetShaderSource = (PFNGLGETSHADERSOURCEPROC)load("glGetShaderSource"); - glad_glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)load("glGetUniformLocation"); - glad_glGetUniformfv = (PFNGLGETUNIFORMFVPROC)load("glGetUniformfv"); - glad_glGetUniformiv = (PFNGLGETUNIFORMIVPROC)load("glGetUniformiv"); - glad_glGetVertexAttribdv = (PFNGLGETVERTEXATTRIBDVPROC)load("glGetVertexAttribdv"); - glad_glGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC)load("glGetVertexAttribfv"); - glad_glGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC)load("glGetVertexAttribiv"); - glad_glGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC)load("glGetVertexAttribPointerv"); - glad_glIsProgram = (PFNGLISPROGRAMPROC)load("glIsProgram"); - glad_glIsShader = (PFNGLISSHADERPROC)load("glIsShader"); - glad_glLinkProgram = (PFNGLLINKPROGRAMPROC)load("glLinkProgram"); - glad_glShaderSource = (PFNGLSHADERSOURCEPROC)load("glShaderSource"); - glad_glUseProgram = (PFNGLUSEPROGRAMPROC)load("glUseProgram"); - glad_glUniform1f = (PFNGLUNIFORM1FPROC)load("glUniform1f"); - glad_glUniform2f = (PFNGLUNIFORM2FPROC)load("glUniform2f"); - glad_glUniform3f = (PFNGLUNIFORM3FPROC)load("glUniform3f"); - glad_glUniform4f = (PFNGLUNIFORM4FPROC)load("glUniform4f"); - glad_glUniform1i = (PFNGLUNIFORM1IPROC)load("glUniform1i"); - glad_glUniform2i = (PFNGLUNIFORM2IPROC)load("glUniform2i"); - glad_glUniform3i = (PFNGLUNIFORM3IPROC)load("glUniform3i"); - glad_glUniform4i = (PFNGLUNIFORM4IPROC)load("glUniform4i"); - glad_glUniform1fv = (PFNGLUNIFORM1FVPROC)load("glUniform1fv"); - glad_glUniform2fv = (PFNGLUNIFORM2FVPROC)load("glUniform2fv"); - glad_glUniform3fv = (PFNGLUNIFORM3FVPROC)load("glUniform3fv"); - glad_glUniform4fv = (PFNGLUNIFORM4FVPROC)load("glUniform4fv"); - glad_glUniform1iv = (PFNGLUNIFORM1IVPROC)load("glUniform1iv"); - glad_glUniform2iv = (PFNGLUNIFORM2IVPROC)load("glUniform2iv"); - glad_glUniform3iv = (PFNGLUNIFORM3IVPROC)load("glUniform3iv"); - glad_glUniform4iv = (PFNGLUNIFORM4IVPROC)load("glUniform4iv"); - glad_glUniformMatrix2fv = (PFNGLUNIFORMMATRIX2FVPROC)load("glUniformMatrix2fv"); - glad_glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC)load("glUniformMatrix3fv"); - glad_glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)load("glUniformMatrix4fv"); - glad_glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)load("glValidateProgram"); - glad_glVertexAttrib1d = (PFNGLVERTEXATTRIB1DPROC)load("glVertexAttrib1d"); - glad_glVertexAttrib1dv = (PFNGLVERTEXATTRIB1DVPROC)load("glVertexAttrib1dv"); - glad_glVertexAttrib1f = (PFNGLVERTEXATTRIB1FPROC)load("glVertexAttrib1f"); - glad_glVertexAttrib1fv = (PFNGLVERTEXATTRIB1FVPROC)load("glVertexAttrib1fv"); - glad_glVertexAttrib1s = (PFNGLVERTEXATTRIB1SPROC)load("glVertexAttrib1s"); - glad_glVertexAttrib1sv = (PFNGLVERTEXATTRIB1SVPROC)load("glVertexAttrib1sv"); - glad_glVertexAttrib2d = (PFNGLVERTEXATTRIB2DPROC)load("glVertexAttrib2d"); - glad_glVertexAttrib2dv = (PFNGLVERTEXATTRIB2DVPROC)load("glVertexAttrib2dv"); - glad_glVertexAttrib2f = (PFNGLVERTEXATTRIB2FPROC)load("glVertexAttrib2f"); - glad_glVertexAttrib2fv = (PFNGLVERTEXATTRIB2FVPROC)load("glVertexAttrib2fv"); - glad_glVertexAttrib2s = (PFNGLVERTEXATTRIB2SPROC)load("glVertexAttrib2s"); - glad_glVertexAttrib2sv = (PFNGLVERTEXATTRIB2SVPROC)load("glVertexAttrib2sv"); - glad_glVertexAttrib3d = (PFNGLVERTEXATTRIB3DPROC)load("glVertexAttrib3d"); - glad_glVertexAttrib3dv = (PFNGLVERTEXATTRIB3DVPROC)load("glVertexAttrib3dv"); - glad_glVertexAttrib3f = (PFNGLVERTEXATTRIB3FPROC)load("glVertexAttrib3f"); - glad_glVertexAttrib3fv = (PFNGLVERTEXATTRIB3FVPROC)load("glVertexAttrib3fv"); - glad_glVertexAttrib3s = (PFNGLVERTEXATTRIB3SPROC)load("glVertexAttrib3s"); - glad_glVertexAttrib3sv = (PFNGLVERTEXATTRIB3SVPROC)load("glVertexAttrib3sv"); - glad_glVertexAttrib4Nbv = (PFNGLVERTEXATTRIB4NBVPROC)load("glVertexAttrib4Nbv"); - glad_glVertexAttrib4Niv = (PFNGLVERTEXATTRIB4NIVPROC)load("glVertexAttrib4Niv"); - glad_glVertexAttrib4Nsv = (PFNGLVERTEXATTRIB4NSVPROC)load("glVertexAttrib4Nsv"); - glad_glVertexAttrib4Nub = (PFNGLVERTEXATTRIB4NUBPROC)load("glVertexAttrib4Nub"); - glad_glVertexAttrib4Nubv = (PFNGLVERTEXATTRIB4NUBVPROC)load("glVertexAttrib4Nubv"); - glad_glVertexAttrib4Nuiv = (PFNGLVERTEXATTRIB4NUIVPROC)load("glVertexAttrib4Nuiv"); - glad_glVertexAttrib4Nusv = (PFNGLVERTEXATTRIB4NUSVPROC)load("glVertexAttrib4Nusv"); - glad_glVertexAttrib4bv = (PFNGLVERTEXATTRIB4BVPROC)load("glVertexAttrib4bv"); - glad_glVertexAttrib4d = (PFNGLVERTEXATTRIB4DPROC)load("glVertexAttrib4d"); - glad_glVertexAttrib4dv = (PFNGLVERTEXATTRIB4DVPROC)load("glVertexAttrib4dv"); - glad_glVertexAttrib4f = (PFNGLVERTEXATTRIB4FPROC)load("glVertexAttrib4f"); - glad_glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC)load("glVertexAttrib4fv"); - glad_glVertexAttrib4iv = (PFNGLVERTEXATTRIB4IVPROC)load("glVertexAttrib4iv"); - glad_glVertexAttrib4s = (PFNGLVERTEXATTRIB4SPROC)load("glVertexAttrib4s"); - glad_glVertexAttrib4sv = (PFNGLVERTEXATTRIB4SVPROC)load("glVertexAttrib4sv"); - glad_glVertexAttrib4ubv = (PFNGLVERTEXATTRIB4UBVPROC)load("glVertexAttrib4ubv"); - glad_glVertexAttrib4uiv = (PFNGLVERTEXATTRIB4UIVPROC)load("glVertexAttrib4uiv"); - glad_glVertexAttrib4usv = (PFNGLVERTEXATTRIB4USVPROC)load("glVertexAttrib4usv"); - glad_glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)load("glVertexAttribPointer"); -} -static void load_GL_VERSION_2_1(GLADloadproc load) { - if(!GLAD_GL_VERSION_2_1) return; - glad_glUniformMatrix2x3fv = (PFNGLUNIFORMMATRIX2X3FVPROC)load("glUniformMatrix2x3fv"); - glad_glUniformMatrix3x2fv = (PFNGLUNIFORMMATRIX3X2FVPROC)load("glUniformMatrix3x2fv"); - glad_glUniformMatrix2x4fv = (PFNGLUNIFORMMATRIX2X4FVPROC)load("glUniformMatrix2x4fv"); - glad_glUniformMatrix4x2fv = (PFNGLUNIFORMMATRIX4X2FVPROC)load("glUniformMatrix4x2fv"); - glad_glUniformMatrix3x4fv = (PFNGLUNIFORMMATRIX3X4FVPROC)load("glUniformMatrix3x4fv"); - glad_glUniformMatrix4x3fv = (PFNGLUNIFORMMATRIX4X3FVPROC)load("glUniformMatrix4x3fv"); -} -static void load_GL_VERSION_3_0(GLADloadproc load) { - if(!GLAD_GL_VERSION_3_0) return; - glad_glColorMaski = (PFNGLCOLORMASKIPROC)load("glColorMaski"); - glad_glGetBooleani_v = (PFNGLGETBOOLEANI_VPROC)load("glGetBooleani_v"); - glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC)load("glGetIntegeri_v"); - glad_glEnablei = (PFNGLENABLEIPROC)load("glEnablei"); - glad_glDisablei = (PFNGLDISABLEIPROC)load("glDisablei"); - glad_glIsEnabledi = (PFNGLISENABLEDIPROC)load("glIsEnabledi"); - glad_glBeginTransformFeedback = (PFNGLBEGINTRANSFORMFEEDBACKPROC)load("glBeginTransformFeedback"); - glad_glEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC)load("glEndTransformFeedback"); - glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC)load("glBindBufferRange"); - glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC)load("glBindBufferBase"); - glad_glTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC)load("glTransformFeedbackVaryings"); - glad_glGetTransformFeedbackVarying = (PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)load("glGetTransformFeedbackVarying"); - glad_glClampColor = (PFNGLCLAMPCOLORPROC)load("glClampColor"); - glad_glBeginConditionalRender = (PFNGLBEGINCONDITIONALRENDERPROC)load("glBeginConditionalRender"); - glad_glEndConditionalRender = (PFNGLENDCONDITIONALRENDERPROC)load("glEndConditionalRender"); - glad_glVertexAttribIPointer = (PFNGLVERTEXATTRIBIPOINTERPROC)load("glVertexAttribIPointer"); - glad_glGetVertexAttribIiv = (PFNGLGETVERTEXATTRIBIIVPROC)load("glGetVertexAttribIiv"); - glad_glGetVertexAttribIuiv = (PFNGLGETVERTEXATTRIBIUIVPROC)load("glGetVertexAttribIuiv"); - glad_glVertexAttribI1i = (PFNGLVERTEXATTRIBI1IPROC)load("glVertexAttribI1i"); - glad_glVertexAttribI2i = (PFNGLVERTEXATTRIBI2IPROC)load("glVertexAttribI2i"); - glad_glVertexAttribI3i = (PFNGLVERTEXATTRIBI3IPROC)load("glVertexAttribI3i"); - glad_glVertexAttribI4i = (PFNGLVERTEXATTRIBI4IPROC)load("glVertexAttribI4i"); - glad_glVertexAttribI1ui = (PFNGLVERTEXATTRIBI1UIPROC)load("glVertexAttribI1ui"); - glad_glVertexAttribI2ui = (PFNGLVERTEXATTRIBI2UIPROC)load("glVertexAttribI2ui"); - glad_glVertexAttribI3ui = (PFNGLVERTEXATTRIBI3UIPROC)load("glVertexAttribI3ui"); - glad_glVertexAttribI4ui = (PFNGLVERTEXATTRIBI4UIPROC)load("glVertexAttribI4ui"); - glad_glVertexAttribI1iv = (PFNGLVERTEXATTRIBI1IVPROC)load("glVertexAttribI1iv"); - glad_glVertexAttribI2iv = (PFNGLVERTEXATTRIBI2IVPROC)load("glVertexAttribI2iv"); - glad_glVertexAttribI3iv = (PFNGLVERTEXATTRIBI3IVPROC)load("glVertexAttribI3iv"); - glad_glVertexAttribI4iv = (PFNGLVERTEXATTRIBI4IVPROC)load("glVertexAttribI4iv"); - glad_glVertexAttribI1uiv = (PFNGLVERTEXATTRIBI1UIVPROC)load("glVertexAttribI1uiv"); - glad_glVertexAttribI2uiv = (PFNGLVERTEXATTRIBI2UIVPROC)load("glVertexAttribI2uiv"); - glad_glVertexAttribI3uiv = (PFNGLVERTEXATTRIBI3UIVPROC)load("glVertexAttribI3uiv"); - glad_glVertexAttribI4uiv = (PFNGLVERTEXATTRIBI4UIVPROC)load("glVertexAttribI4uiv"); - glad_glVertexAttribI4bv = (PFNGLVERTEXATTRIBI4BVPROC)load("glVertexAttribI4bv"); - glad_glVertexAttribI4sv = (PFNGLVERTEXATTRIBI4SVPROC)load("glVertexAttribI4sv"); - glad_glVertexAttribI4ubv = (PFNGLVERTEXATTRIBI4UBVPROC)load("glVertexAttribI4ubv"); - glad_glVertexAttribI4usv = (PFNGLVERTEXATTRIBI4USVPROC)load("glVertexAttribI4usv"); - glad_glGetUniformuiv = (PFNGLGETUNIFORMUIVPROC)load("glGetUniformuiv"); - glad_glBindFragDataLocation = (PFNGLBINDFRAGDATALOCATIONPROC)load("glBindFragDataLocation"); - glad_glGetFragDataLocation = (PFNGLGETFRAGDATALOCATIONPROC)load("glGetFragDataLocation"); - glad_glUniform1ui = (PFNGLUNIFORM1UIPROC)load("glUniform1ui"); - glad_glUniform2ui = (PFNGLUNIFORM2UIPROC)load("glUniform2ui"); - glad_glUniform3ui = (PFNGLUNIFORM3UIPROC)load("glUniform3ui"); - glad_glUniform4ui = (PFNGLUNIFORM4UIPROC)load("glUniform4ui"); - glad_glUniform1uiv = (PFNGLUNIFORM1UIVPROC)load("glUniform1uiv"); - glad_glUniform2uiv = (PFNGLUNIFORM2UIVPROC)load("glUniform2uiv"); - glad_glUniform3uiv = (PFNGLUNIFORM3UIVPROC)load("glUniform3uiv"); - glad_glUniform4uiv = (PFNGLUNIFORM4UIVPROC)load("glUniform4uiv"); - glad_glTexParameterIiv = (PFNGLTEXPARAMETERIIVPROC)load("glTexParameterIiv"); - glad_glTexParameterIuiv = (PFNGLTEXPARAMETERIUIVPROC)load("glTexParameterIuiv"); - glad_glGetTexParameterIiv = (PFNGLGETTEXPARAMETERIIVPROC)load("glGetTexParameterIiv"); - glad_glGetTexParameterIuiv = (PFNGLGETTEXPARAMETERIUIVPROC)load("glGetTexParameterIuiv"); - glad_glClearBufferiv = (PFNGLCLEARBUFFERIVPROC)load("glClearBufferiv"); - glad_glClearBufferuiv = (PFNGLCLEARBUFFERUIVPROC)load("glClearBufferuiv"); - glad_glClearBufferfv = (PFNGLCLEARBUFFERFVPROC)load("glClearBufferfv"); - glad_glClearBufferfi = (PFNGLCLEARBUFFERFIPROC)load("glClearBufferfi"); - glad_glGetStringi = (PFNGLGETSTRINGIPROC)load("glGetStringi"); - glad_glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC)load("glIsRenderbuffer"); - glad_glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)load("glBindRenderbuffer"); - glad_glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)load("glDeleteRenderbuffers"); - glad_glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)load("glGenRenderbuffers"); - glad_glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)load("glRenderbufferStorage"); - glad_glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC)load("glGetRenderbufferParameteriv"); - glad_glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC)load("glIsFramebuffer"); - glad_glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)load("glBindFramebuffer"); - glad_glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)load("glDeleteFramebuffers"); - glad_glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)load("glGenFramebuffers"); - glad_glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)load("glCheckFramebufferStatus"); - glad_glFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DPROC)load("glFramebufferTexture1D"); - glad_glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)load("glFramebufferTexture2D"); - glad_glFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DPROC)load("glFramebufferTexture3D"); - glad_glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)load("glFramebufferRenderbuffer"); - glad_glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)load("glGetFramebufferAttachmentParameteriv"); - glad_glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC)load("glGenerateMipmap"); - glad_glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC)load("glBlitFramebuffer"); - glad_glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)load("glRenderbufferStorageMultisample"); - glad_glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC)load("glFramebufferTextureLayer"); - glad_glMapBufferRange = (PFNGLMAPBUFFERRANGEPROC)load("glMapBufferRange"); - glad_glFlushMappedBufferRange = (PFNGLFLUSHMAPPEDBUFFERRANGEPROC)load("glFlushMappedBufferRange"); - glad_glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)load("glBindVertexArray"); - glad_glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)load("glDeleteVertexArrays"); - glad_glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)load("glGenVertexArrays"); - glad_glIsVertexArray = (PFNGLISVERTEXARRAYPROC)load("glIsVertexArray"); -} -static void load_GL_VERSION_3_1(GLADloadproc load) { - if(!GLAD_GL_VERSION_3_1) return; - glad_glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDPROC)load("glDrawArraysInstanced"); - glad_glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDPROC)load("glDrawElementsInstanced"); - glad_glTexBuffer = (PFNGLTEXBUFFERPROC)load("glTexBuffer"); - glad_glPrimitiveRestartIndex = (PFNGLPRIMITIVERESTARTINDEXPROC)load("glPrimitiveRestartIndex"); - glad_glCopyBufferSubData = (PFNGLCOPYBUFFERSUBDATAPROC)load("glCopyBufferSubData"); - glad_glGetUniformIndices = (PFNGLGETUNIFORMINDICESPROC)load("glGetUniformIndices"); - glad_glGetActiveUniformsiv = (PFNGLGETACTIVEUNIFORMSIVPROC)load("glGetActiveUniformsiv"); - glad_glGetActiveUniformName = (PFNGLGETACTIVEUNIFORMNAMEPROC)load("glGetActiveUniformName"); - glad_glGetUniformBlockIndex = (PFNGLGETUNIFORMBLOCKINDEXPROC)load("glGetUniformBlockIndex"); - glad_glGetActiveUniformBlockiv = (PFNGLGETACTIVEUNIFORMBLOCKIVPROC)load("glGetActiveUniformBlockiv"); - glad_glGetActiveUniformBlockName = (PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)load("glGetActiveUniformBlockName"); - glad_glUniformBlockBinding = (PFNGLUNIFORMBLOCKBINDINGPROC)load("glUniformBlockBinding"); - glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC)load("glBindBufferRange"); - glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC)load("glBindBufferBase"); - glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC)load("glGetIntegeri_v"); -} -static void load_GL_VERSION_3_2(GLADloadproc load) { - if(!GLAD_GL_VERSION_3_2) return; - glad_glDrawElementsBaseVertex = (PFNGLDRAWELEMENTSBASEVERTEXPROC)load("glDrawElementsBaseVertex"); - glad_glDrawRangeElementsBaseVertex = (PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC)load("glDrawRangeElementsBaseVertex"); - glad_glDrawElementsInstancedBaseVertex = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)load("glDrawElementsInstancedBaseVertex"); - glad_glMultiDrawElementsBaseVertex = (PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC)load("glMultiDrawElementsBaseVertex"); - glad_glProvokingVertex = (PFNGLPROVOKINGVERTEXPROC)load("glProvokingVertex"); - glad_glFenceSync = (PFNGLFENCESYNCPROC)load("glFenceSync"); - glad_glIsSync = (PFNGLISSYNCPROC)load("glIsSync"); - glad_glDeleteSync = (PFNGLDELETESYNCPROC)load("glDeleteSync"); - glad_glClientWaitSync = (PFNGLCLIENTWAITSYNCPROC)load("glClientWaitSync"); - glad_glWaitSync = (PFNGLWAITSYNCPROC)load("glWaitSync"); - glad_glGetInteger64v = (PFNGLGETINTEGER64VPROC)load("glGetInteger64v"); - glad_glGetSynciv = (PFNGLGETSYNCIVPROC)load("glGetSynciv"); - glad_glGetInteger64i_v = (PFNGLGETINTEGER64I_VPROC)load("glGetInteger64i_v"); - glad_glGetBufferParameteri64v = (PFNGLGETBUFFERPARAMETERI64VPROC)load("glGetBufferParameteri64v"); - glad_glFramebufferTexture = (PFNGLFRAMEBUFFERTEXTUREPROC)load("glFramebufferTexture"); - glad_glTexImage2DMultisample = (PFNGLTEXIMAGE2DMULTISAMPLEPROC)load("glTexImage2DMultisample"); - glad_glTexImage3DMultisample = (PFNGLTEXIMAGE3DMULTISAMPLEPROC)load("glTexImage3DMultisample"); - glad_glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC)load("glGetMultisamplefv"); - glad_glSampleMaski = (PFNGLSAMPLEMASKIPROC)load("glSampleMaski"); -} -static void load_GL_VERSION_3_3(GLADloadproc load) { - if(!GLAD_GL_VERSION_3_3) return; - glad_glBindFragDataLocationIndexed = (PFNGLBINDFRAGDATALOCATIONINDEXEDPROC)load("glBindFragDataLocationIndexed"); - glad_glGetFragDataIndex = (PFNGLGETFRAGDATAINDEXPROC)load("glGetFragDataIndex"); - glad_glGenSamplers = (PFNGLGENSAMPLERSPROC)load("glGenSamplers"); - glad_glDeleteSamplers = (PFNGLDELETESAMPLERSPROC)load("glDeleteSamplers"); - glad_glIsSampler = (PFNGLISSAMPLERPROC)load("glIsSampler"); - glad_glBindSampler = (PFNGLBINDSAMPLERPROC)load("glBindSampler"); - glad_glSamplerParameteri = (PFNGLSAMPLERPARAMETERIPROC)load("glSamplerParameteri"); - glad_glSamplerParameteriv = (PFNGLSAMPLERPARAMETERIVPROC)load("glSamplerParameteriv"); - glad_glSamplerParameterf = (PFNGLSAMPLERPARAMETERFPROC)load("glSamplerParameterf"); - glad_glSamplerParameterfv = (PFNGLSAMPLERPARAMETERFVPROC)load("glSamplerParameterfv"); - glad_glSamplerParameterIiv = (PFNGLSAMPLERPARAMETERIIVPROC)load("glSamplerParameterIiv"); - glad_glSamplerParameterIuiv = (PFNGLSAMPLERPARAMETERIUIVPROC)load("glSamplerParameterIuiv"); - glad_glGetSamplerParameteriv = (PFNGLGETSAMPLERPARAMETERIVPROC)load("glGetSamplerParameteriv"); - glad_glGetSamplerParameterIiv = (PFNGLGETSAMPLERPARAMETERIIVPROC)load("glGetSamplerParameterIiv"); - glad_glGetSamplerParameterfv = (PFNGLGETSAMPLERPARAMETERFVPROC)load("glGetSamplerParameterfv"); - glad_glGetSamplerParameterIuiv = (PFNGLGETSAMPLERPARAMETERIUIVPROC)load("glGetSamplerParameterIuiv"); - glad_glQueryCounter = (PFNGLQUERYCOUNTERPROC)load("glQueryCounter"); - glad_glGetQueryObjecti64v = (PFNGLGETQUERYOBJECTI64VPROC)load("glGetQueryObjecti64v"); - glad_glGetQueryObjectui64v = (PFNGLGETQUERYOBJECTUI64VPROC)load("glGetQueryObjectui64v"); - glad_glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISORPROC)load("glVertexAttribDivisor"); - glad_glVertexAttribP1ui = (PFNGLVERTEXATTRIBP1UIPROC)load("glVertexAttribP1ui"); - glad_glVertexAttribP1uiv = (PFNGLVERTEXATTRIBP1UIVPROC)load("glVertexAttribP1uiv"); - glad_glVertexAttribP2ui = (PFNGLVERTEXATTRIBP2UIPROC)load("glVertexAttribP2ui"); - glad_glVertexAttribP2uiv = (PFNGLVERTEXATTRIBP2UIVPROC)load("glVertexAttribP2uiv"); - glad_glVertexAttribP3ui = (PFNGLVERTEXATTRIBP3UIPROC)load("glVertexAttribP3ui"); - glad_glVertexAttribP3uiv = (PFNGLVERTEXATTRIBP3UIVPROC)load("glVertexAttribP3uiv"); - glad_glVertexAttribP4ui = (PFNGLVERTEXATTRIBP4UIPROC)load("glVertexAttribP4ui"); - glad_glVertexAttribP4uiv = (PFNGLVERTEXATTRIBP4UIVPROC)load("glVertexAttribP4uiv"); - glad_glVertexP2ui = (PFNGLVERTEXP2UIPROC)load("glVertexP2ui"); - glad_glVertexP2uiv = (PFNGLVERTEXP2UIVPROC)load("glVertexP2uiv"); - glad_glVertexP3ui = (PFNGLVERTEXP3UIPROC)load("glVertexP3ui"); - glad_glVertexP3uiv = (PFNGLVERTEXP3UIVPROC)load("glVertexP3uiv"); - glad_glVertexP4ui = (PFNGLVERTEXP4UIPROC)load("glVertexP4ui"); - glad_glVertexP4uiv = (PFNGLVERTEXP4UIVPROC)load("glVertexP4uiv"); - glad_glTexCoordP1ui = (PFNGLTEXCOORDP1UIPROC)load("glTexCoordP1ui"); - glad_glTexCoordP1uiv = (PFNGLTEXCOORDP1UIVPROC)load("glTexCoordP1uiv"); - glad_glTexCoordP2ui = (PFNGLTEXCOORDP2UIPROC)load("glTexCoordP2ui"); - glad_glTexCoordP2uiv = (PFNGLTEXCOORDP2UIVPROC)load("glTexCoordP2uiv"); - glad_glTexCoordP3ui = (PFNGLTEXCOORDP3UIPROC)load("glTexCoordP3ui"); - glad_glTexCoordP3uiv = (PFNGLTEXCOORDP3UIVPROC)load("glTexCoordP3uiv"); - glad_glTexCoordP4ui = (PFNGLTEXCOORDP4UIPROC)load("glTexCoordP4ui"); - glad_glTexCoordP4uiv = (PFNGLTEXCOORDP4UIVPROC)load("glTexCoordP4uiv"); - glad_glMultiTexCoordP1ui = (PFNGLMULTITEXCOORDP1UIPROC)load("glMultiTexCoordP1ui"); - glad_glMultiTexCoordP1uiv = (PFNGLMULTITEXCOORDP1UIVPROC)load("glMultiTexCoordP1uiv"); - glad_glMultiTexCoordP2ui = (PFNGLMULTITEXCOORDP2UIPROC)load("glMultiTexCoordP2ui"); - glad_glMultiTexCoordP2uiv = (PFNGLMULTITEXCOORDP2UIVPROC)load("glMultiTexCoordP2uiv"); - glad_glMultiTexCoordP3ui = (PFNGLMULTITEXCOORDP3UIPROC)load("glMultiTexCoordP3ui"); - glad_glMultiTexCoordP3uiv = (PFNGLMULTITEXCOORDP3UIVPROC)load("glMultiTexCoordP3uiv"); - glad_glMultiTexCoordP4ui = (PFNGLMULTITEXCOORDP4UIPROC)load("glMultiTexCoordP4ui"); - glad_glMultiTexCoordP4uiv = (PFNGLMULTITEXCOORDP4UIVPROC)load("glMultiTexCoordP4uiv"); - glad_glNormalP3ui = (PFNGLNORMALP3UIPROC)load("glNormalP3ui"); - glad_glNormalP3uiv = (PFNGLNORMALP3UIVPROC)load("glNormalP3uiv"); - glad_glColorP3ui = (PFNGLCOLORP3UIPROC)load("glColorP3ui"); - glad_glColorP3uiv = (PFNGLCOLORP3UIVPROC)load("glColorP3uiv"); - glad_glColorP4ui = (PFNGLCOLORP4UIPROC)load("glColorP4ui"); - glad_glColorP4uiv = (PFNGLCOLORP4UIVPROC)load("glColorP4uiv"); - glad_glSecondaryColorP3ui = (PFNGLSECONDARYCOLORP3UIPROC)load("glSecondaryColorP3ui"); - glad_glSecondaryColorP3uiv = (PFNGLSECONDARYCOLORP3UIVPROC)load("glSecondaryColorP3uiv"); -} -static int find_extensionsGL(void) { - if (!get_exts()) return 0; - (void)&has_ext; - free_exts(); - return 1; -} - -static void find_coreGL(void) { - - /* Thank you @elmindreda - * https://github.com/elmindreda/greg/blob/master/templates/greg.c.in#L176 - * https://github.com/glfw/glfw/blob/master/src/context.c#L36 - */ - int i, major, minor; - - const char* version; - const char* prefixes[] = { - "OpenGL ES-CM ", - "OpenGL ES-CL ", - "OpenGL ES ", - NULL - }; - - version = (const char*) glGetString(GL_VERSION); - if (!version) return; - - for (i = 0; prefixes[i]; i++) { - const size_t length = strlen(prefixes[i]); - if (strncmp(version, prefixes[i], length) == 0) { - version += length; - break; - } - } - -/* PR #18 */ -#ifdef _MSC_VER - sscanf_s(version, "%d.%d", &major, &minor); -#else - sscanf(version, "%d.%d", &major, &minor); -#endif - - GLVersion.major = major; GLVersion.minor = minor; - max_loaded_major = major; max_loaded_minor = minor; - GLAD_GL_VERSION_1_0 = (major == 1 && minor >= 0) || major > 1; - GLAD_GL_VERSION_1_1 = (major == 1 && minor >= 1) || major > 1; - GLAD_GL_VERSION_1_2 = (major == 1 && minor >= 2) || major > 1; - GLAD_GL_VERSION_1_3 = (major == 1 && minor >= 3) || major > 1; - GLAD_GL_VERSION_1_4 = (major == 1 && minor >= 4) || major > 1; - GLAD_GL_VERSION_1_5 = (major == 1 && minor >= 5) || major > 1; - GLAD_GL_VERSION_2_0 = (major == 2 && minor >= 0) || major > 2; - GLAD_GL_VERSION_2_1 = (major == 2 && minor >= 1) || major > 2; - GLAD_GL_VERSION_3_0 = (major == 3 && minor >= 0) || major > 3; - GLAD_GL_VERSION_3_1 = (major == 3 && minor >= 1) || major > 3; - GLAD_GL_VERSION_3_2 = (major == 3 && minor >= 2) || major > 3; - GLAD_GL_VERSION_3_3 = (major == 3 && minor >= 3) || major > 3; - if (GLVersion.major > 3 || (GLVersion.major >= 3 && GLVersion.minor >= 3)) { - max_loaded_major = 3; - max_loaded_minor = 3; - } -} - -int gladLoadGLLoader(GLADloadproc load) { - GLVersion.major = 0; GLVersion.minor = 0; - glGetString = (PFNGLGETSTRINGPROC)load("glGetString"); - if(glGetString == NULL) return 0; - if(glGetString(GL_VERSION) == NULL) return 0; - find_coreGL(); - load_GL_VERSION_1_0(load); - load_GL_VERSION_1_1(load); - load_GL_VERSION_1_2(load); - load_GL_VERSION_1_3(load); - load_GL_VERSION_1_4(load); - load_GL_VERSION_1_5(load); - load_GL_VERSION_2_0(load); - load_GL_VERSION_2_1(load); - load_GL_VERSION_3_0(load); - load_GL_VERSION_3_1(load); - load_GL_VERSION_3_2(load); - load_GL_VERSION_3_3(load); - - if (!find_extensionsGL()) return 0; - return GLVersion.major != 0 || GLVersion.minor != 0; -} - diff --git a/dpf/dgl/src/pugl-upstream/examples/glad/glad.h b/dpf/dgl/src/pugl-upstream/examples/glad/glad.h deleted file mode 100644 index 9efb229..0000000 --- a/dpf/dgl/src/pugl-upstream/examples/glad/glad.h +++ /dev/null @@ -1,2127 +0,0 @@ -/* - - OpenGL loader generated by glad 0.1.32 on -. - - Language/Generator: C/C++ - Specification: gl - APIs: gl=3.3 - Profile: core - Extensions: - - Loader: True - Local files: True - Omit khrplatform: False - Reproducible: True - - Commandline: - --profile="core" --api="gl=3.3" --generator="c" --spec="gl" --local-files --extensions="" - Online: - https://glad.dav1d.de/#profile=core&language=c&specification=gl&loader=on&api=gl%3D3.3 -*/ - - -#ifndef __glad_h_ -#define __glad_h_ - -#ifdef __gl_h_ -#error OpenGL header already included, remove this include, glad already provides it -#endif -#define __gl_h_ - -#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) -#define APIENTRY __stdcall -#endif - -#ifndef APIENTRY -#define APIENTRY -#endif -#ifndef APIENTRYP -#define APIENTRYP APIENTRY * -#endif - -#ifndef GLAPIENTRY -#define GLAPIENTRY APIENTRY -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -struct gladGLversionStruct { - int major; - int minor; -}; - -typedef void* (* GLADloadproc)(const char *name); - -#ifndef GLAPI -# if defined(GLAD_GLAPI_EXPORT) -# if defined(_WIN32) || defined(__CYGWIN__) -# if defined(GLAD_GLAPI_EXPORT_BUILD) -# if defined(__GNUC__) -# define GLAPI __attribute__ ((dllexport)) extern -# else -# define GLAPI __declspec(dllexport) extern -# endif -# else -# if defined(__GNUC__) -# define GLAPI __attribute__ ((dllimport)) extern -# else -# define GLAPI __declspec(dllimport) extern -# endif -# endif -# elif defined(__GNUC__) && defined(GLAD_GLAPI_EXPORT_BUILD) -# define GLAPI __attribute__ ((visibility ("default"))) extern -# else -# define GLAPI extern -# endif -# else -# define GLAPI extern -# endif -#endif - -GLAPI struct gladGLversionStruct GLVersion; - -GLAPI int gladLoadGL(void); - -GLAPI int gladLoadGLLoader(GLADloadproc); - -#include "khrplatform.h" -typedef unsigned int GLenum; -typedef unsigned char GLboolean; -typedef unsigned int GLbitfield; -typedef void GLvoid; -typedef khronos_int8_t GLbyte; -typedef khronos_uint8_t GLubyte; -typedef khronos_int16_t GLshort; -typedef khronos_uint16_t GLushort; -typedef int GLint; -typedef unsigned int GLuint; -typedef khronos_int32_t GLclampx; -typedef int GLsizei; -typedef khronos_float_t GLfloat; -typedef khronos_float_t GLclampf; -typedef double GLdouble; -typedef double GLclampd; -typedef void *GLeglClientBufferEXT; -typedef void *GLeglImageOES; -typedef char GLchar; -typedef char GLcharARB; -#ifdef __APPLE__ -typedef void *GLhandleARB; -#else -typedef unsigned int GLhandleARB; -#endif -typedef khronos_uint16_t GLhalf; -typedef khronos_uint16_t GLhalfARB; -typedef khronos_int32_t GLfixed; -typedef khronos_intptr_t GLintptr; -typedef khronos_intptr_t GLintptrARB; -typedef khronos_ssize_t GLsizeiptr; -typedef khronos_ssize_t GLsizeiptrARB; -typedef khronos_int64_t GLint64; -typedef khronos_int64_t GLint64EXT; -typedef khronos_uint64_t GLuint64; -typedef khronos_uint64_t GLuint64EXT; -typedef struct __GLsync *GLsync; -typedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); -typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); -typedef void (APIENTRY *GLDEBUGPROCKHR)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); -typedef void (APIENTRY *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam); -typedef unsigned short GLhalfNV; -typedef GLintptr GLvdpauSurfaceNV; -typedef void (APIENTRY *GLVULKANPROCNV)(void); -#define GL_DEPTH_BUFFER_BIT 0x00000100 -#define GL_STENCIL_BUFFER_BIT 0x00000400 -#define GL_COLOR_BUFFER_BIT 0x00004000 -#define GL_FALSE 0 -#define GL_TRUE 1 -#define GL_POINTS 0x0000 -#define GL_LINES 0x0001 -#define GL_LINE_LOOP 0x0002 -#define GL_LINE_STRIP 0x0003 -#define GL_TRIANGLES 0x0004 -#define GL_TRIANGLE_STRIP 0x0005 -#define GL_TRIANGLE_FAN 0x0006 -#define GL_NEVER 0x0200 -#define GL_LESS 0x0201 -#define GL_EQUAL 0x0202 -#define GL_LEQUAL 0x0203 -#define GL_GREATER 0x0204 -#define GL_NOTEQUAL 0x0205 -#define GL_GEQUAL 0x0206 -#define GL_ALWAYS 0x0207 -#define GL_ZERO 0 -#define GL_ONE 1 -#define GL_SRC_COLOR 0x0300 -#define GL_ONE_MINUS_SRC_COLOR 0x0301 -#define GL_SRC_ALPHA 0x0302 -#define GL_ONE_MINUS_SRC_ALPHA 0x0303 -#define GL_DST_ALPHA 0x0304 -#define GL_ONE_MINUS_DST_ALPHA 0x0305 -#define GL_DST_COLOR 0x0306 -#define GL_ONE_MINUS_DST_COLOR 0x0307 -#define GL_SRC_ALPHA_SATURATE 0x0308 -#define GL_NONE 0 -#define GL_FRONT_LEFT 0x0400 -#define GL_FRONT_RIGHT 0x0401 -#define GL_BACK_LEFT 0x0402 -#define GL_BACK_RIGHT 0x0403 -#define GL_FRONT 0x0404 -#define GL_BACK 0x0405 -#define GL_LEFT 0x0406 -#define GL_RIGHT 0x0407 -#define GL_FRONT_AND_BACK 0x0408 -#define GL_NO_ERROR 0 -#define GL_INVALID_ENUM 0x0500 -#define GL_INVALID_VALUE 0x0501 -#define GL_INVALID_OPERATION 0x0502 -#define GL_OUT_OF_MEMORY 0x0505 -#define GL_CW 0x0900 -#define GL_CCW 0x0901 -#define GL_POINT_SIZE 0x0B11 -#define GL_POINT_SIZE_RANGE 0x0B12 -#define GL_POINT_SIZE_GRANULARITY 0x0B13 -#define GL_LINE_SMOOTH 0x0B20 -#define GL_LINE_WIDTH 0x0B21 -#define GL_LINE_WIDTH_RANGE 0x0B22 -#define GL_LINE_WIDTH_GRANULARITY 0x0B23 -#define GL_POLYGON_MODE 0x0B40 -#define GL_POLYGON_SMOOTH 0x0B41 -#define GL_CULL_FACE 0x0B44 -#define GL_CULL_FACE_MODE 0x0B45 -#define GL_FRONT_FACE 0x0B46 -#define GL_DEPTH_RANGE 0x0B70 -#define GL_DEPTH_TEST 0x0B71 -#define GL_DEPTH_WRITEMASK 0x0B72 -#define GL_DEPTH_CLEAR_VALUE 0x0B73 -#define GL_DEPTH_FUNC 0x0B74 -#define GL_STENCIL_TEST 0x0B90 -#define GL_STENCIL_CLEAR_VALUE 0x0B91 -#define GL_STENCIL_FUNC 0x0B92 -#define GL_STENCIL_VALUE_MASK 0x0B93 -#define GL_STENCIL_FAIL 0x0B94 -#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 -#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 -#define GL_STENCIL_REF 0x0B97 -#define GL_STENCIL_WRITEMASK 0x0B98 -#define GL_VIEWPORT 0x0BA2 -#define GL_DITHER 0x0BD0 -#define GL_BLEND_DST 0x0BE0 -#define GL_BLEND_SRC 0x0BE1 -#define GL_BLEND 0x0BE2 -#define GL_LOGIC_OP_MODE 0x0BF0 -#define GL_DRAW_BUFFER 0x0C01 -#define GL_READ_BUFFER 0x0C02 -#define GL_SCISSOR_BOX 0x0C10 -#define GL_SCISSOR_TEST 0x0C11 -#define GL_COLOR_CLEAR_VALUE 0x0C22 -#define GL_COLOR_WRITEMASK 0x0C23 -#define GL_DOUBLEBUFFER 0x0C32 -#define GL_STEREO 0x0C33 -#define GL_LINE_SMOOTH_HINT 0x0C52 -#define GL_POLYGON_SMOOTH_HINT 0x0C53 -#define GL_UNPACK_SWAP_BYTES 0x0CF0 -#define GL_UNPACK_LSB_FIRST 0x0CF1 -#define GL_UNPACK_ROW_LENGTH 0x0CF2 -#define GL_UNPACK_SKIP_ROWS 0x0CF3 -#define GL_UNPACK_SKIP_PIXELS 0x0CF4 -#define GL_UNPACK_ALIGNMENT 0x0CF5 -#define GL_PACK_SWAP_BYTES 0x0D00 -#define GL_PACK_LSB_FIRST 0x0D01 -#define GL_PACK_ROW_LENGTH 0x0D02 -#define GL_PACK_SKIP_ROWS 0x0D03 -#define GL_PACK_SKIP_PIXELS 0x0D04 -#define GL_PACK_ALIGNMENT 0x0D05 -#define GL_MAX_TEXTURE_SIZE 0x0D33 -#define GL_MAX_VIEWPORT_DIMS 0x0D3A -#define GL_SUBPIXEL_BITS 0x0D50 -#define GL_TEXTURE_1D 0x0DE0 -#define GL_TEXTURE_2D 0x0DE1 -#define GL_TEXTURE_WIDTH 0x1000 -#define GL_TEXTURE_HEIGHT 0x1001 -#define GL_TEXTURE_BORDER_COLOR 0x1004 -#define GL_DONT_CARE 0x1100 -#define GL_FASTEST 0x1101 -#define GL_NICEST 0x1102 -#define GL_BYTE 0x1400 -#define GL_UNSIGNED_BYTE 0x1401 -#define GL_SHORT 0x1402 -#define GL_UNSIGNED_SHORT 0x1403 -#define GL_INT 0x1404 -#define GL_UNSIGNED_INT 0x1405 -#define GL_FLOAT 0x1406 -#define GL_CLEAR 0x1500 -#define GL_AND 0x1501 -#define GL_AND_REVERSE 0x1502 -#define GL_COPY 0x1503 -#define GL_AND_INVERTED 0x1504 -#define GL_NOOP 0x1505 -#define GL_XOR 0x1506 -#define GL_OR 0x1507 -#define GL_NOR 0x1508 -#define GL_EQUIV 0x1509 -#define GL_INVERT 0x150A -#define GL_OR_REVERSE 0x150B -#define GL_COPY_INVERTED 0x150C -#define GL_OR_INVERTED 0x150D -#define GL_NAND 0x150E -#define GL_SET 0x150F -#define GL_TEXTURE 0x1702 -#define GL_COLOR 0x1800 -#define GL_DEPTH 0x1801 -#define GL_STENCIL 0x1802 -#define GL_STENCIL_INDEX 0x1901 -#define GL_DEPTH_COMPONENT 0x1902 -#define GL_RED 0x1903 -#define GL_GREEN 0x1904 -#define GL_BLUE 0x1905 -#define GL_ALPHA 0x1906 -#define GL_RGB 0x1907 -#define GL_RGBA 0x1908 -#define GL_POINT 0x1B00 -#define GL_LINE 0x1B01 -#define GL_FILL 0x1B02 -#define GL_KEEP 0x1E00 -#define GL_REPLACE 0x1E01 -#define GL_INCR 0x1E02 -#define GL_DECR 0x1E03 -#define GL_VENDOR 0x1F00 -#define GL_RENDERER 0x1F01 -#define GL_VERSION 0x1F02 -#define GL_EXTENSIONS 0x1F03 -#define GL_NEAREST 0x2600 -#define GL_LINEAR 0x2601 -#define GL_NEAREST_MIPMAP_NEAREST 0x2700 -#define GL_LINEAR_MIPMAP_NEAREST 0x2701 -#define GL_NEAREST_MIPMAP_LINEAR 0x2702 -#define GL_LINEAR_MIPMAP_LINEAR 0x2703 -#define GL_TEXTURE_MAG_FILTER 0x2800 -#define GL_TEXTURE_MIN_FILTER 0x2801 -#define GL_TEXTURE_WRAP_S 0x2802 -#define GL_TEXTURE_WRAP_T 0x2803 -#define GL_REPEAT 0x2901 -#define GL_COLOR_LOGIC_OP 0x0BF2 -#define GL_POLYGON_OFFSET_UNITS 0x2A00 -#define GL_POLYGON_OFFSET_POINT 0x2A01 -#define GL_POLYGON_OFFSET_LINE 0x2A02 -#define GL_POLYGON_OFFSET_FILL 0x8037 -#define GL_POLYGON_OFFSET_FACTOR 0x8038 -#define GL_TEXTURE_BINDING_1D 0x8068 -#define GL_TEXTURE_BINDING_2D 0x8069 -#define GL_TEXTURE_INTERNAL_FORMAT 0x1003 -#define GL_TEXTURE_RED_SIZE 0x805C -#define GL_TEXTURE_GREEN_SIZE 0x805D -#define GL_TEXTURE_BLUE_SIZE 0x805E -#define GL_TEXTURE_ALPHA_SIZE 0x805F -#define GL_DOUBLE 0x140A -#define GL_PROXY_TEXTURE_1D 0x8063 -#define GL_PROXY_TEXTURE_2D 0x8064 -#define GL_R3_G3_B2 0x2A10 -#define GL_RGB4 0x804F -#define GL_RGB5 0x8050 -#define GL_RGB8 0x8051 -#define GL_RGB10 0x8052 -#define GL_RGB12 0x8053 -#define GL_RGB16 0x8054 -#define GL_RGBA2 0x8055 -#define GL_RGBA4 0x8056 -#define GL_RGB5_A1 0x8057 -#define GL_RGBA8 0x8058 -#define GL_RGB10_A2 0x8059 -#define GL_RGBA12 0x805A -#define GL_RGBA16 0x805B -#define GL_UNSIGNED_BYTE_3_3_2 0x8032 -#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 -#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 -#define GL_UNSIGNED_INT_8_8_8_8 0x8035 -#define GL_UNSIGNED_INT_10_10_10_2 0x8036 -#define GL_TEXTURE_BINDING_3D 0x806A -#define GL_PACK_SKIP_IMAGES 0x806B -#define GL_PACK_IMAGE_HEIGHT 0x806C -#define GL_UNPACK_SKIP_IMAGES 0x806D -#define GL_UNPACK_IMAGE_HEIGHT 0x806E -#define GL_TEXTURE_3D 0x806F -#define GL_PROXY_TEXTURE_3D 0x8070 -#define GL_TEXTURE_DEPTH 0x8071 -#define GL_TEXTURE_WRAP_R 0x8072 -#define GL_MAX_3D_TEXTURE_SIZE 0x8073 -#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 -#define GL_UNSIGNED_SHORT_5_6_5 0x8363 -#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 -#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 -#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 -#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 -#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 -#define GL_BGR 0x80E0 -#define GL_BGRA 0x80E1 -#define GL_MAX_ELEMENTS_VERTICES 0x80E8 -#define GL_MAX_ELEMENTS_INDICES 0x80E9 -#define GL_CLAMP_TO_EDGE 0x812F -#define GL_TEXTURE_MIN_LOD 0x813A -#define GL_TEXTURE_MAX_LOD 0x813B -#define GL_TEXTURE_BASE_LEVEL 0x813C -#define GL_TEXTURE_MAX_LEVEL 0x813D -#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12 -#define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13 -#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22 -#define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23 -#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E -#define GL_TEXTURE0 0x84C0 -#define GL_TEXTURE1 0x84C1 -#define GL_TEXTURE2 0x84C2 -#define GL_TEXTURE3 0x84C3 -#define GL_TEXTURE4 0x84C4 -#define GL_TEXTURE5 0x84C5 -#define GL_TEXTURE6 0x84C6 -#define GL_TEXTURE7 0x84C7 -#define GL_TEXTURE8 0x84C8 -#define GL_TEXTURE9 0x84C9 -#define GL_TEXTURE10 0x84CA -#define GL_TEXTURE11 0x84CB -#define GL_TEXTURE12 0x84CC -#define GL_TEXTURE13 0x84CD -#define GL_TEXTURE14 0x84CE -#define GL_TEXTURE15 0x84CF -#define GL_TEXTURE16 0x84D0 -#define GL_TEXTURE17 0x84D1 -#define GL_TEXTURE18 0x84D2 -#define GL_TEXTURE19 0x84D3 -#define GL_TEXTURE20 0x84D4 -#define GL_TEXTURE21 0x84D5 -#define GL_TEXTURE22 0x84D6 -#define GL_TEXTURE23 0x84D7 -#define GL_TEXTURE24 0x84D8 -#define GL_TEXTURE25 0x84D9 -#define GL_TEXTURE26 0x84DA -#define GL_TEXTURE27 0x84DB -#define GL_TEXTURE28 0x84DC -#define GL_TEXTURE29 0x84DD -#define GL_TEXTURE30 0x84DE -#define GL_TEXTURE31 0x84DF -#define GL_ACTIVE_TEXTURE 0x84E0 -#define GL_MULTISAMPLE 0x809D -#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E -#define GL_SAMPLE_ALPHA_TO_ONE 0x809F -#define GL_SAMPLE_COVERAGE 0x80A0 -#define GL_SAMPLE_BUFFERS 0x80A8 -#define GL_SAMPLES 0x80A9 -#define GL_SAMPLE_COVERAGE_VALUE 0x80AA -#define GL_SAMPLE_COVERAGE_INVERT 0x80AB -#define GL_TEXTURE_CUBE_MAP 0x8513 -#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A -#define GL_PROXY_TEXTURE_CUBE_MAP 0x851B -#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C -#define GL_COMPRESSED_RGB 0x84ED -#define GL_COMPRESSED_RGBA 0x84EE -#define GL_TEXTURE_COMPRESSION_HINT 0x84EF -#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0 -#define GL_TEXTURE_COMPRESSED 0x86A1 -#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 -#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 -#define GL_CLAMP_TO_BORDER 0x812D -#define GL_BLEND_DST_RGB 0x80C8 -#define GL_BLEND_SRC_RGB 0x80C9 -#define GL_BLEND_DST_ALPHA 0x80CA -#define GL_BLEND_SRC_ALPHA 0x80CB -#define GL_POINT_FADE_THRESHOLD_SIZE 0x8128 -#define GL_DEPTH_COMPONENT16 0x81A5 -#define GL_DEPTH_COMPONENT24 0x81A6 -#define GL_DEPTH_COMPONENT32 0x81A7 -#define GL_MIRRORED_REPEAT 0x8370 -#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD -#define GL_TEXTURE_LOD_BIAS 0x8501 -#define GL_INCR_WRAP 0x8507 -#define GL_DECR_WRAP 0x8508 -#define GL_TEXTURE_DEPTH_SIZE 0x884A -#define GL_TEXTURE_COMPARE_MODE 0x884C -#define GL_TEXTURE_COMPARE_FUNC 0x884D -#define GL_BLEND_COLOR 0x8005 -#define GL_BLEND_EQUATION 0x8009 -#define GL_CONSTANT_COLOR 0x8001 -#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 -#define GL_CONSTANT_ALPHA 0x8003 -#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 -#define GL_FUNC_ADD 0x8006 -#define GL_FUNC_REVERSE_SUBTRACT 0x800B -#define GL_FUNC_SUBTRACT 0x800A -#define GL_MIN 0x8007 -#define GL_MAX 0x8008 -#define GL_BUFFER_SIZE 0x8764 -#define GL_BUFFER_USAGE 0x8765 -#define GL_QUERY_COUNTER_BITS 0x8864 -#define GL_CURRENT_QUERY 0x8865 -#define GL_QUERY_RESULT 0x8866 -#define GL_QUERY_RESULT_AVAILABLE 0x8867 -#define GL_ARRAY_BUFFER 0x8892 -#define GL_ELEMENT_ARRAY_BUFFER 0x8893 -#define GL_ARRAY_BUFFER_BINDING 0x8894 -#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 -#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F -#define GL_READ_ONLY 0x88B8 -#define GL_WRITE_ONLY 0x88B9 -#define GL_READ_WRITE 0x88BA -#define GL_BUFFER_ACCESS 0x88BB -#define GL_BUFFER_MAPPED 0x88BC -#define GL_BUFFER_MAP_POINTER 0x88BD -#define GL_STREAM_DRAW 0x88E0 -#define GL_STREAM_READ 0x88E1 -#define GL_STREAM_COPY 0x88E2 -#define GL_STATIC_DRAW 0x88E4 -#define GL_STATIC_READ 0x88E5 -#define GL_STATIC_COPY 0x88E6 -#define GL_DYNAMIC_DRAW 0x88E8 -#define GL_DYNAMIC_READ 0x88E9 -#define GL_DYNAMIC_COPY 0x88EA -#define GL_SAMPLES_PASSED 0x8914 -#define GL_SRC1_ALPHA 0x8589 -#define GL_BLEND_EQUATION_RGB 0x8009 -#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 -#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 -#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 -#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 -#define GL_CURRENT_VERTEX_ATTRIB 0x8626 -#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 -#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 -#define GL_STENCIL_BACK_FUNC 0x8800 -#define GL_STENCIL_BACK_FAIL 0x8801 -#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 -#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 -#define GL_MAX_DRAW_BUFFERS 0x8824 -#define GL_DRAW_BUFFER0 0x8825 -#define GL_DRAW_BUFFER1 0x8826 -#define GL_DRAW_BUFFER2 0x8827 -#define GL_DRAW_BUFFER3 0x8828 -#define GL_DRAW_BUFFER4 0x8829 -#define GL_DRAW_BUFFER5 0x882A -#define GL_DRAW_BUFFER6 0x882B -#define GL_DRAW_BUFFER7 0x882C -#define GL_DRAW_BUFFER8 0x882D -#define GL_DRAW_BUFFER9 0x882E -#define GL_DRAW_BUFFER10 0x882F -#define GL_DRAW_BUFFER11 0x8830 -#define GL_DRAW_BUFFER12 0x8831 -#define GL_DRAW_BUFFER13 0x8832 -#define GL_DRAW_BUFFER14 0x8833 -#define GL_DRAW_BUFFER15 0x8834 -#define GL_BLEND_EQUATION_ALPHA 0x883D -#define GL_MAX_VERTEX_ATTRIBS 0x8869 -#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A -#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 -#define GL_FRAGMENT_SHADER 0x8B30 -#define GL_VERTEX_SHADER 0x8B31 -#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 -#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A -#define GL_MAX_VARYING_FLOATS 0x8B4B -#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C -#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D -#define GL_SHADER_TYPE 0x8B4F -#define GL_FLOAT_VEC2 0x8B50 -#define GL_FLOAT_VEC3 0x8B51 -#define GL_FLOAT_VEC4 0x8B52 -#define GL_INT_VEC2 0x8B53 -#define GL_INT_VEC3 0x8B54 -#define GL_INT_VEC4 0x8B55 -#define GL_BOOL 0x8B56 -#define GL_BOOL_VEC2 0x8B57 -#define GL_BOOL_VEC3 0x8B58 -#define GL_BOOL_VEC4 0x8B59 -#define GL_FLOAT_MAT2 0x8B5A -#define GL_FLOAT_MAT3 0x8B5B -#define GL_FLOAT_MAT4 0x8B5C -#define GL_SAMPLER_1D 0x8B5D -#define GL_SAMPLER_2D 0x8B5E -#define GL_SAMPLER_3D 0x8B5F -#define GL_SAMPLER_CUBE 0x8B60 -#define GL_SAMPLER_1D_SHADOW 0x8B61 -#define GL_SAMPLER_2D_SHADOW 0x8B62 -#define GL_DELETE_STATUS 0x8B80 -#define GL_COMPILE_STATUS 0x8B81 -#define GL_LINK_STATUS 0x8B82 -#define GL_VALIDATE_STATUS 0x8B83 -#define GL_INFO_LOG_LENGTH 0x8B84 -#define GL_ATTACHED_SHADERS 0x8B85 -#define GL_ACTIVE_UNIFORMS 0x8B86 -#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 -#define GL_SHADER_SOURCE_LENGTH 0x8B88 -#define GL_ACTIVE_ATTRIBUTES 0x8B89 -#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A -#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B -#define GL_SHADING_LANGUAGE_VERSION 0x8B8C -#define GL_CURRENT_PROGRAM 0x8B8D -#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 -#define GL_LOWER_LEFT 0x8CA1 -#define GL_UPPER_LEFT 0x8CA2 -#define GL_STENCIL_BACK_REF 0x8CA3 -#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 -#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 -#define GL_PIXEL_PACK_BUFFER 0x88EB -#define GL_PIXEL_UNPACK_BUFFER 0x88EC -#define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED -#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF -#define GL_FLOAT_MAT2x3 0x8B65 -#define GL_FLOAT_MAT2x4 0x8B66 -#define GL_FLOAT_MAT3x2 0x8B67 -#define GL_FLOAT_MAT3x4 0x8B68 -#define GL_FLOAT_MAT4x2 0x8B69 -#define GL_FLOAT_MAT4x3 0x8B6A -#define GL_SRGB 0x8C40 -#define GL_SRGB8 0x8C41 -#define GL_SRGB_ALPHA 0x8C42 -#define GL_SRGB8_ALPHA8 0x8C43 -#define GL_COMPRESSED_SRGB 0x8C48 -#define GL_COMPRESSED_SRGB_ALPHA 0x8C49 -#define GL_COMPARE_REF_TO_TEXTURE 0x884E -#define GL_CLIP_DISTANCE0 0x3000 -#define GL_CLIP_DISTANCE1 0x3001 -#define GL_CLIP_DISTANCE2 0x3002 -#define GL_CLIP_DISTANCE3 0x3003 -#define GL_CLIP_DISTANCE4 0x3004 -#define GL_CLIP_DISTANCE5 0x3005 -#define GL_CLIP_DISTANCE6 0x3006 -#define GL_CLIP_DISTANCE7 0x3007 -#define GL_MAX_CLIP_DISTANCES 0x0D32 -#define GL_MAJOR_VERSION 0x821B -#define GL_MINOR_VERSION 0x821C -#define GL_NUM_EXTENSIONS 0x821D -#define GL_CONTEXT_FLAGS 0x821E -#define GL_COMPRESSED_RED 0x8225 -#define GL_COMPRESSED_RG 0x8226 -#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001 -#define GL_RGBA32F 0x8814 -#define GL_RGB32F 0x8815 -#define GL_RGBA16F 0x881A -#define GL_RGB16F 0x881B -#define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD -#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF -#define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904 -#define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905 -#define GL_CLAMP_READ_COLOR 0x891C -#define GL_FIXED_ONLY 0x891D -#define GL_MAX_VARYING_COMPONENTS 0x8B4B -#define GL_TEXTURE_1D_ARRAY 0x8C18 -#define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19 -#define GL_TEXTURE_2D_ARRAY 0x8C1A -#define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B -#define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C -#define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D -#define GL_R11F_G11F_B10F 0x8C3A -#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B -#define GL_RGB9_E5 0x8C3D -#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E -#define GL_TEXTURE_SHARED_SIZE 0x8C3F -#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76 -#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F -#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80 -#define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83 -#define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84 -#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85 -#define GL_PRIMITIVES_GENERATED 0x8C87 -#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88 -#define GL_RASTERIZER_DISCARD 0x8C89 -#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A -#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B -#define GL_INTERLEAVED_ATTRIBS 0x8C8C -#define GL_SEPARATE_ATTRIBS 0x8C8D -#define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E -#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F -#define GL_RGBA32UI 0x8D70 -#define GL_RGB32UI 0x8D71 -#define GL_RGBA16UI 0x8D76 -#define GL_RGB16UI 0x8D77 -#define GL_RGBA8UI 0x8D7C -#define GL_RGB8UI 0x8D7D -#define GL_RGBA32I 0x8D82 -#define GL_RGB32I 0x8D83 -#define GL_RGBA16I 0x8D88 -#define GL_RGB16I 0x8D89 -#define GL_RGBA8I 0x8D8E -#define GL_RGB8I 0x8D8F -#define GL_RED_INTEGER 0x8D94 -#define GL_GREEN_INTEGER 0x8D95 -#define GL_BLUE_INTEGER 0x8D96 -#define GL_RGB_INTEGER 0x8D98 -#define GL_RGBA_INTEGER 0x8D99 -#define GL_BGR_INTEGER 0x8D9A -#define GL_BGRA_INTEGER 0x8D9B -#define GL_SAMPLER_1D_ARRAY 0x8DC0 -#define GL_SAMPLER_2D_ARRAY 0x8DC1 -#define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3 -#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4 -#define GL_SAMPLER_CUBE_SHADOW 0x8DC5 -#define GL_UNSIGNED_INT_VEC2 0x8DC6 -#define GL_UNSIGNED_INT_VEC3 0x8DC7 -#define GL_UNSIGNED_INT_VEC4 0x8DC8 -#define GL_INT_SAMPLER_1D 0x8DC9 -#define GL_INT_SAMPLER_2D 0x8DCA -#define GL_INT_SAMPLER_3D 0x8DCB -#define GL_INT_SAMPLER_CUBE 0x8DCC -#define GL_INT_SAMPLER_1D_ARRAY 0x8DCE -#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF -#define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1 -#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2 -#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3 -#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4 -#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6 -#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7 -#define GL_QUERY_WAIT 0x8E13 -#define GL_QUERY_NO_WAIT 0x8E14 -#define GL_QUERY_BY_REGION_WAIT 0x8E15 -#define GL_QUERY_BY_REGION_NO_WAIT 0x8E16 -#define GL_BUFFER_ACCESS_FLAGS 0x911F -#define GL_BUFFER_MAP_LENGTH 0x9120 -#define GL_BUFFER_MAP_OFFSET 0x9121 -#define GL_DEPTH_COMPONENT32F 0x8CAC -#define GL_DEPTH32F_STENCIL8 0x8CAD -#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD -#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 -#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210 -#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211 -#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212 -#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213 -#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214 -#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215 -#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216 -#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217 -#define GL_FRAMEBUFFER_DEFAULT 0x8218 -#define GL_FRAMEBUFFER_UNDEFINED 0x8219 -#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A -#define GL_MAX_RENDERBUFFER_SIZE 0x84E8 -#define GL_DEPTH_STENCIL 0x84F9 -#define GL_UNSIGNED_INT_24_8 0x84FA -#define GL_DEPTH24_STENCIL8 0x88F0 -#define GL_TEXTURE_STENCIL_SIZE 0x88F1 -#define GL_TEXTURE_RED_TYPE 0x8C10 -#define GL_TEXTURE_GREEN_TYPE 0x8C11 -#define GL_TEXTURE_BLUE_TYPE 0x8C12 -#define GL_TEXTURE_ALPHA_TYPE 0x8C13 -#define GL_TEXTURE_DEPTH_TYPE 0x8C16 -#define GL_UNSIGNED_NORMALIZED 0x8C17 -#define GL_FRAMEBUFFER_BINDING 0x8CA6 -#define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6 -#define GL_RENDERBUFFER_BINDING 0x8CA7 -#define GL_READ_FRAMEBUFFER 0x8CA8 -#define GL_DRAW_FRAMEBUFFER 0x8CA9 -#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA -#define GL_RENDERBUFFER_SAMPLES 0x8CAB -#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 -#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4 -#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 -#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 -#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 -#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB -#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC -#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD -#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF -#define GL_COLOR_ATTACHMENT0 0x8CE0 -#define GL_COLOR_ATTACHMENT1 0x8CE1 -#define GL_COLOR_ATTACHMENT2 0x8CE2 -#define GL_COLOR_ATTACHMENT3 0x8CE3 -#define GL_COLOR_ATTACHMENT4 0x8CE4 -#define GL_COLOR_ATTACHMENT5 0x8CE5 -#define GL_COLOR_ATTACHMENT6 0x8CE6 -#define GL_COLOR_ATTACHMENT7 0x8CE7 -#define GL_COLOR_ATTACHMENT8 0x8CE8 -#define GL_COLOR_ATTACHMENT9 0x8CE9 -#define GL_COLOR_ATTACHMENT10 0x8CEA -#define GL_COLOR_ATTACHMENT11 0x8CEB -#define GL_COLOR_ATTACHMENT12 0x8CEC -#define GL_COLOR_ATTACHMENT13 0x8CED -#define GL_COLOR_ATTACHMENT14 0x8CEE -#define GL_COLOR_ATTACHMENT15 0x8CEF -#define GL_COLOR_ATTACHMENT16 0x8CF0 -#define GL_COLOR_ATTACHMENT17 0x8CF1 -#define GL_COLOR_ATTACHMENT18 0x8CF2 -#define GL_COLOR_ATTACHMENT19 0x8CF3 -#define GL_COLOR_ATTACHMENT20 0x8CF4 -#define GL_COLOR_ATTACHMENT21 0x8CF5 -#define GL_COLOR_ATTACHMENT22 0x8CF6 -#define GL_COLOR_ATTACHMENT23 0x8CF7 -#define GL_COLOR_ATTACHMENT24 0x8CF8 -#define GL_COLOR_ATTACHMENT25 0x8CF9 -#define GL_COLOR_ATTACHMENT26 0x8CFA -#define GL_COLOR_ATTACHMENT27 0x8CFB -#define GL_COLOR_ATTACHMENT28 0x8CFC -#define GL_COLOR_ATTACHMENT29 0x8CFD -#define GL_COLOR_ATTACHMENT30 0x8CFE -#define GL_COLOR_ATTACHMENT31 0x8CFF -#define GL_DEPTH_ATTACHMENT 0x8D00 -#define GL_STENCIL_ATTACHMENT 0x8D20 -#define GL_FRAMEBUFFER 0x8D40 -#define GL_RENDERBUFFER 0x8D41 -#define GL_RENDERBUFFER_WIDTH 0x8D42 -#define GL_RENDERBUFFER_HEIGHT 0x8D43 -#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 -#define GL_STENCIL_INDEX1 0x8D46 -#define GL_STENCIL_INDEX4 0x8D47 -#define GL_STENCIL_INDEX8 0x8D48 -#define GL_STENCIL_INDEX16 0x8D49 -#define GL_RENDERBUFFER_RED_SIZE 0x8D50 -#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 -#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 -#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 -#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 -#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 -#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 -#define GL_MAX_SAMPLES 0x8D57 -#define GL_FRAMEBUFFER_SRGB 0x8DB9 -#define GL_HALF_FLOAT 0x140B -#define GL_MAP_READ_BIT 0x0001 -#define GL_MAP_WRITE_BIT 0x0002 -#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004 -#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 -#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010 -#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020 -#define GL_COMPRESSED_RED_RGTC1 0x8DBB -#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC -#define GL_COMPRESSED_RG_RGTC2 0x8DBD -#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE -#define GL_RG 0x8227 -#define GL_RG_INTEGER 0x8228 -#define GL_R8 0x8229 -#define GL_R16 0x822A -#define GL_RG8 0x822B -#define GL_RG16 0x822C -#define GL_R16F 0x822D -#define GL_R32F 0x822E -#define GL_RG16F 0x822F -#define GL_RG32F 0x8230 -#define GL_R8I 0x8231 -#define GL_R8UI 0x8232 -#define GL_R16I 0x8233 -#define GL_R16UI 0x8234 -#define GL_R32I 0x8235 -#define GL_R32UI 0x8236 -#define GL_RG8I 0x8237 -#define GL_RG8UI 0x8238 -#define GL_RG16I 0x8239 -#define GL_RG16UI 0x823A -#define GL_RG32I 0x823B -#define GL_RG32UI 0x823C -#define GL_VERTEX_ARRAY_BINDING 0x85B5 -#define GL_SAMPLER_2D_RECT 0x8B63 -#define GL_SAMPLER_2D_RECT_SHADOW 0x8B64 -#define GL_SAMPLER_BUFFER 0x8DC2 -#define GL_INT_SAMPLER_2D_RECT 0x8DCD -#define GL_INT_SAMPLER_BUFFER 0x8DD0 -#define GL_UNSIGNED_INT_SAMPLER_2D_RECT 0x8DD5 -#define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8 -#define GL_TEXTURE_BUFFER 0x8C2A -#define GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B -#define GL_TEXTURE_BINDING_BUFFER 0x8C2C -#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING 0x8C2D -#define GL_TEXTURE_RECTANGLE 0x84F5 -#define GL_TEXTURE_BINDING_RECTANGLE 0x84F6 -#define GL_PROXY_TEXTURE_RECTANGLE 0x84F7 -#define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8 -#define GL_R8_SNORM 0x8F94 -#define GL_RG8_SNORM 0x8F95 -#define GL_RGB8_SNORM 0x8F96 -#define GL_RGBA8_SNORM 0x8F97 -#define GL_R16_SNORM 0x8F98 -#define GL_RG16_SNORM 0x8F99 -#define GL_RGB16_SNORM 0x8F9A -#define GL_RGBA16_SNORM 0x8F9B -#define GL_SIGNED_NORMALIZED 0x8F9C -#define GL_PRIMITIVE_RESTART 0x8F9D -#define GL_PRIMITIVE_RESTART_INDEX 0x8F9E -#define GL_COPY_READ_BUFFER 0x8F36 -#define GL_COPY_WRITE_BUFFER 0x8F37 -#define GL_UNIFORM_BUFFER 0x8A11 -#define GL_UNIFORM_BUFFER_BINDING 0x8A28 -#define GL_UNIFORM_BUFFER_START 0x8A29 -#define GL_UNIFORM_BUFFER_SIZE 0x8A2A -#define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B -#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C -#define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D -#define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E -#define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F -#define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30 -#define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31 -#define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32 -#define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33 -#define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34 -#define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35 -#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36 -#define GL_UNIFORM_TYPE 0x8A37 -#define GL_UNIFORM_SIZE 0x8A38 -#define GL_UNIFORM_NAME_LENGTH 0x8A39 -#define GL_UNIFORM_BLOCK_INDEX 0x8A3A -#define GL_UNIFORM_OFFSET 0x8A3B -#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C -#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D -#define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E -#define GL_UNIFORM_BLOCK_BINDING 0x8A3F -#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40 -#define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41 -#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42 -#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43 -#define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44 -#define GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45 -#define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46 -#define GL_INVALID_INDEX 0xFFFFFFFF -#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001 -#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002 -#define GL_LINES_ADJACENCY 0x000A -#define GL_LINE_STRIP_ADJACENCY 0x000B -#define GL_TRIANGLES_ADJACENCY 0x000C -#define GL_TRIANGLE_STRIP_ADJACENCY 0x000D -#define GL_PROGRAM_POINT_SIZE 0x8642 -#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29 -#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7 -#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8 -#define GL_GEOMETRY_SHADER 0x8DD9 -#define GL_GEOMETRY_VERTICES_OUT 0x8916 -#define GL_GEOMETRY_INPUT_TYPE 0x8917 -#define GL_GEOMETRY_OUTPUT_TYPE 0x8918 -#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF -#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0 -#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1 -#define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122 -#define GL_MAX_GEOMETRY_INPUT_COMPONENTS 0x9123 -#define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS 0x9124 -#define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125 -#define GL_CONTEXT_PROFILE_MASK 0x9126 -#define GL_DEPTH_CLAMP 0x864F -#define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION 0x8E4C -#define GL_FIRST_VERTEX_CONVENTION 0x8E4D -#define GL_LAST_VERTEX_CONVENTION 0x8E4E -#define GL_PROVOKING_VERTEX 0x8E4F -#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F -#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111 -#define GL_OBJECT_TYPE 0x9112 -#define GL_SYNC_CONDITION 0x9113 -#define GL_SYNC_STATUS 0x9114 -#define GL_SYNC_FLAGS 0x9115 -#define GL_SYNC_FENCE 0x9116 -#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 -#define GL_UNSIGNALED 0x9118 -#define GL_SIGNALED 0x9119 -#define GL_ALREADY_SIGNALED 0x911A -#define GL_TIMEOUT_EXPIRED 0x911B -#define GL_CONDITION_SATISFIED 0x911C -#define GL_WAIT_FAILED 0x911D -#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFF -#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 -#define GL_SAMPLE_POSITION 0x8E50 -#define GL_SAMPLE_MASK 0x8E51 -#define GL_SAMPLE_MASK_VALUE 0x8E52 -#define GL_MAX_SAMPLE_MASK_WORDS 0x8E59 -#define GL_TEXTURE_2D_MULTISAMPLE 0x9100 -#define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101 -#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102 -#define GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103 -#define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104 -#define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105 -#define GL_TEXTURE_SAMPLES 0x9106 -#define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107 -#define GL_SAMPLER_2D_MULTISAMPLE 0x9108 -#define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109 -#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A -#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B -#define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C -#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D -#define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E -#define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F -#define GL_MAX_INTEGER_SAMPLES 0x9110 -#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE -#define GL_SRC1_COLOR 0x88F9 -#define GL_ONE_MINUS_SRC1_COLOR 0x88FA -#define GL_ONE_MINUS_SRC1_ALPHA 0x88FB -#define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS 0x88FC -#define GL_ANY_SAMPLES_PASSED 0x8C2F -#define GL_SAMPLER_BINDING 0x8919 -#define GL_RGB10_A2UI 0x906F -#define GL_TEXTURE_SWIZZLE_R 0x8E42 -#define GL_TEXTURE_SWIZZLE_G 0x8E43 -#define GL_TEXTURE_SWIZZLE_B 0x8E44 -#define GL_TEXTURE_SWIZZLE_A 0x8E45 -#define GL_TEXTURE_SWIZZLE_RGBA 0x8E46 -#define GL_TIME_ELAPSED 0x88BF -#define GL_TIMESTAMP 0x8E28 -#define GL_INT_2_10_10_10_REV 0x8D9F -#ifndef GL_VERSION_1_0 -#define GL_VERSION_1_0 1 -GLAPI int GLAD_GL_VERSION_1_0; -typedef void (APIENTRYP PFNGLCULLFACEPROC)(GLenum mode); -GLAPI PFNGLCULLFACEPROC glad_glCullFace; -#define glCullFace glad_glCullFace -typedef void (APIENTRYP PFNGLFRONTFACEPROC)(GLenum mode); -GLAPI PFNGLFRONTFACEPROC glad_glFrontFace; -#define glFrontFace glad_glFrontFace -typedef void (APIENTRYP PFNGLHINTPROC)(GLenum target, GLenum mode); -GLAPI PFNGLHINTPROC glad_glHint; -#define glHint glad_glHint -typedef void (APIENTRYP PFNGLLINEWIDTHPROC)(GLfloat width); -GLAPI PFNGLLINEWIDTHPROC glad_glLineWidth; -#define glLineWidth glad_glLineWidth -typedef void (APIENTRYP PFNGLPOINTSIZEPROC)(GLfloat size); -GLAPI PFNGLPOINTSIZEPROC glad_glPointSize; -#define glPointSize glad_glPointSize -typedef void (APIENTRYP PFNGLPOLYGONMODEPROC)(GLenum face, GLenum mode); -GLAPI PFNGLPOLYGONMODEPROC glad_glPolygonMode; -#define glPolygonMode glad_glPolygonMode -typedef void (APIENTRYP PFNGLSCISSORPROC)(GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI PFNGLSCISSORPROC glad_glScissor; -#define glScissor glad_glScissor -typedef void (APIENTRYP PFNGLTEXPARAMETERFPROC)(GLenum target, GLenum pname, GLfloat param); -GLAPI PFNGLTEXPARAMETERFPROC glad_glTexParameterf; -#define glTexParameterf glad_glTexParameterf -typedef void (APIENTRYP PFNGLTEXPARAMETERFVPROC)(GLenum target, GLenum pname, const GLfloat *params); -GLAPI PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv; -#define glTexParameterfv glad_glTexParameterfv -typedef void (APIENTRYP PFNGLTEXPARAMETERIPROC)(GLenum target, GLenum pname, GLint param); -GLAPI PFNGLTEXPARAMETERIPROC glad_glTexParameteri; -#define glTexParameteri glad_glTexParameteri -typedef void (APIENTRYP PFNGLTEXPARAMETERIVPROC)(GLenum target, GLenum pname, const GLint *params); -GLAPI PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv; -#define glTexParameteriv glad_glTexParameteriv -typedef void (APIENTRYP PFNGLTEXIMAGE1DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels); -GLAPI PFNGLTEXIMAGE1DPROC glad_glTexImage1D; -#define glTexImage1D glad_glTexImage1D -typedef void (APIENTRYP PFNGLTEXIMAGE2DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); -GLAPI PFNGLTEXIMAGE2DPROC glad_glTexImage2D; -#define glTexImage2D glad_glTexImage2D -typedef void (APIENTRYP PFNGLDRAWBUFFERPROC)(GLenum buf); -GLAPI PFNGLDRAWBUFFERPROC glad_glDrawBuffer; -#define glDrawBuffer glad_glDrawBuffer -typedef void (APIENTRYP PFNGLCLEARPROC)(GLbitfield mask); -GLAPI PFNGLCLEARPROC glad_glClear; -#define glClear glad_glClear -typedef void (APIENTRYP PFNGLCLEARCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); -GLAPI PFNGLCLEARCOLORPROC glad_glClearColor; -#define glClearColor glad_glClearColor -typedef void (APIENTRYP PFNGLCLEARSTENCILPROC)(GLint s); -GLAPI PFNGLCLEARSTENCILPROC glad_glClearStencil; -#define glClearStencil glad_glClearStencil -typedef void (APIENTRYP PFNGLCLEARDEPTHPROC)(GLdouble depth); -GLAPI PFNGLCLEARDEPTHPROC glad_glClearDepth; -#define glClearDepth glad_glClearDepth -typedef void (APIENTRYP PFNGLSTENCILMASKPROC)(GLuint mask); -GLAPI PFNGLSTENCILMASKPROC glad_glStencilMask; -#define glStencilMask glad_glStencilMask -typedef void (APIENTRYP PFNGLCOLORMASKPROC)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); -GLAPI PFNGLCOLORMASKPROC glad_glColorMask; -#define glColorMask glad_glColorMask -typedef void (APIENTRYP PFNGLDEPTHMASKPROC)(GLboolean flag); -GLAPI PFNGLDEPTHMASKPROC glad_glDepthMask; -#define glDepthMask glad_glDepthMask -typedef void (APIENTRYP PFNGLDISABLEPROC)(GLenum cap); -GLAPI PFNGLDISABLEPROC glad_glDisable; -#define glDisable glad_glDisable -typedef void (APIENTRYP PFNGLENABLEPROC)(GLenum cap); -GLAPI PFNGLENABLEPROC glad_glEnable; -#define glEnable glad_glEnable -typedef void (APIENTRYP PFNGLFINISHPROC)(void); -GLAPI PFNGLFINISHPROC glad_glFinish; -#define glFinish glad_glFinish -typedef void (APIENTRYP PFNGLFLUSHPROC)(void); -GLAPI PFNGLFLUSHPROC glad_glFlush; -#define glFlush glad_glFlush -typedef void (APIENTRYP PFNGLBLENDFUNCPROC)(GLenum sfactor, GLenum dfactor); -GLAPI PFNGLBLENDFUNCPROC glad_glBlendFunc; -#define glBlendFunc glad_glBlendFunc -typedef void (APIENTRYP PFNGLLOGICOPPROC)(GLenum opcode); -GLAPI PFNGLLOGICOPPROC glad_glLogicOp; -#define glLogicOp glad_glLogicOp -typedef void (APIENTRYP PFNGLSTENCILFUNCPROC)(GLenum func, GLint ref, GLuint mask); -GLAPI PFNGLSTENCILFUNCPROC glad_glStencilFunc; -#define glStencilFunc glad_glStencilFunc -typedef void (APIENTRYP PFNGLSTENCILOPPROC)(GLenum fail, GLenum zfail, GLenum zpass); -GLAPI PFNGLSTENCILOPPROC glad_glStencilOp; -#define glStencilOp glad_glStencilOp -typedef void (APIENTRYP PFNGLDEPTHFUNCPROC)(GLenum func); -GLAPI PFNGLDEPTHFUNCPROC glad_glDepthFunc; -#define glDepthFunc glad_glDepthFunc -typedef void (APIENTRYP PFNGLPIXELSTOREFPROC)(GLenum pname, GLfloat param); -GLAPI PFNGLPIXELSTOREFPROC glad_glPixelStoref; -#define glPixelStoref glad_glPixelStoref -typedef void (APIENTRYP PFNGLPIXELSTOREIPROC)(GLenum pname, GLint param); -GLAPI PFNGLPIXELSTOREIPROC glad_glPixelStorei; -#define glPixelStorei glad_glPixelStorei -typedef void (APIENTRYP PFNGLREADBUFFERPROC)(GLenum src); -GLAPI PFNGLREADBUFFERPROC glad_glReadBuffer; -#define glReadBuffer glad_glReadBuffer -typedef void (APIENTRYP PFNGLREADPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels); -GLAPI PFNGLREADPIXELSPROC glad_glReadPixels; -#define glReadPixels glad_glReadPixels -typedef void (APIENTRYP PFNGLGETBOOLEANVPROC)(GLenum pname, GLboolean *data); -GLAPI PFNGLGETBOOLEANVPROC glad_glGetBooleanv; -#define glGetBooleanv glad_glGetBooleanv -typedef void (APIENTRYP PFNGLGETDOUBLEVPROC)(GLenum pname, GLdouble *data); -GLAPI PFNGLGETDOUBLEVPROC glad_glGetDoublev; -#define glGetDoublev glad_glGetDoublev -typedef GLenum (APIENTRYP PFNGLGETERRORPROC)(void); -GLAPI PFNGLGETERRORPROC glad_glGetError; -#define glGetError glad_glGetError -typedef void (APIENTRYP PFNGLGETFLOATVPROC)(GLenum pname, GLfloat *data); -GLAPI PFNGLGETFLOATVPROC glad_glGetFloatv; -#define glGetFloatv glad_glGetFloatv -typedef void (APIENTRYP PFNGLGETINTEGERVPROC)(GLenum pname, GLint *data); -GLAPI PFNGLGETINTEGERVPROC glad_glGetIntegerv; -#define glGetIntegerv glad_glGetIntegerv -typedef const GLubyte * (APIENTRYP PFNGLGETSTRINGPROC)(GLenum name); -GLAPI PFNGLGETSTRINGPROC glad_glGetString; -#define glGetString glad_glGetString -typedef void (APIENTRYP PFNGLGETTEXIMAGEPROC)(GLenum target, GLint level, GLenum format, GLenum type, void *pixels); -GLAPI PFNGLGETTEXIMAGEPROC glad_glGetTexImage; -#define glGetTexImage glad_glGetTexImage -typedef void (APIENTRYP PFNGLGETTEXPARAMETERFVPROC)(GLenum target, GLenum pname, GLfloat *params); -GLAPI PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv; -#define glGetTexParameterfv glad_glGetTexParameterfv -typedef void (APIENTRYP PFNGLGETTEXPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params); -GLAPI PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv; -#define glGetTexParameteriv glad_glGetTexParameteriv -typedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERFVPROC)(GLenum target, GLint level, GLenum pname, GLfloat *params); -GLAPI PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv; -#define glGetTexLevelParameterfv glad_glGetTexLevelParameterfv -typedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERIVPROC)(GLenum target, GLint level, GLenum pname, GLint *params); -GLAPI PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv; -#define glGetTexLevelParameteriv glad_glGetTexLevelParameteriv -typedef GLboolean (APIENTRYP PFNGLISENABLEDPROC)(GLenum cap); -GLAPI PFNGLISENABLEDPROC glad_glIsEnabled; -#define glIsEnabled glad_glIsEnabled -typedef void (APIENTRYP PFNGLDEPTHRANGEPROC)(GLdouble n, GLdouble f); -GLAPI PFNGLDEPTHRANGEPROC glad_glDepthRange; -#define glDepthRange glad_glDepthRange -typedef void (APIENTRYP PFNGLVIEWPORTPROC)(GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI PFNGLVIEWPORTPROC glad_glViewport; -#define glViewport glad_glViewport -#endif -#ifndef GL_VERSION_1_1 -#define GL_VERSION_1_1 1 -GLAPI int GLAD_GL_VERSION_1_1; -typedef void (APIENTRYP PFNGLDRAWARRAYSPROC)(GLenum mode, GLint first, GLsizei count); -GLAPI PFNGLDRAWARRAYSPROC glad_glDrawArrays; -#define glDrawArrays glad_glDrawArrays -typedef void (APIENTRYP PFNGLDRAWELEMENTSPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices); -GLAPI PFNGLDRAWELEMENTSPROC glad_glDrawElements; -#define glDrawElements glad_glDrawElements -typedef void (APIENTRYP PFNGLPOLYGONOFFSETPROC)(GLfloat factor, GLfloat units); -GLAPI PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset; -#define glPolygonOffset glad_glPolygonOffset -typedef void (APIENTRYP PFNGLCOPYTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); -GLAPI PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D; -#define glCopyTexImage1D glad_glCopyTexImage1D -typedef void (APIENTRYP PFNGLCOPYTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); -GLAPI PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D; -#define glCopyTexImage2D glad_glCopyTexImage2D -typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); -GLAPI PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D; -#define glCopyTexSubImage1D glad_glCopyTexSubImage1D -typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D; -#define glCopyTexSubImage2D glad_glCopyTexSubImage2D -typedef void (APIENTRYP PFNGLTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); -GLAPI PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D; -#define glTexSubImage1D glad_glTexSubImage1D -typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); -GLAPI PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D; -#define glTexSubImage2D glad_glTexSubImage2D -typedef void (APIENTRYP PFNGLBINDTEXTUREPROC)(GLenum target, GLuint texture); -GLAPI PFNGLBINDTEXTUREPROC glad_glBindTexture; -#define glBindTexture glad_glBindTexture -typedef void (APIENTRYP PFNGLDELETETEXTURESPROC)(GLsizei n, const GLuint *textures); -GLAPI PFNGLDELETETEXTURESPROC glad_glDeleteTextures; -#define glDeleteTextures glad_glDeleteTextures -typedef void (APIENTRYP PFNGLGENTEXTURESPROC)(GLsizei n, GLuint *textures); -GLAPI PFNGLGENTEXTURESPROC glad_glGenTextures; -#define glGenTextures glad_glGenTextures -typedef GLboolean (APIENTRYP PFNGLISTEXTUREPROC)(GLuint texture); -GLAPI PFNGLISTEXTUREPROC glad_glIsTexture; -#define glIsTexture glad_glIsTexture -#endif -#ifndef GL_VERSION_1_2 -#define GL_VERSION_1_2 1 -GLAPI int GLAD_GL_VERSION_1_2; -typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); -GLAPI PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements; -#define glDrawRangeElements glad_glDrawRangeElements -typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); -GLAPI PFNGLTEXIMAGE3DPROC glad_glTexImage3D; -#define glTexImage3D glad_glTexImage3D -typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); -GLAPI PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D; -#define glTexSubImage3D glad_glTexSubImage3D -typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D; -#define glCopyTexSubImage3D glad_glCopyTexSubImage3D -#endif -#ifndef GL_VERSION_1_3 -#define GL_VERSION_1_3 1 -GLAPI int GLAD_GL_VERSION_1_3; -typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC)(GLenum texture); -GLAPI PFNGLACTIVETEXTUREPROC glad_glActiveTexture; -#define glActiveTexture glad_glActiveTexture -typedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC)(GLfloat value, GLboolean invert); -GLAPI PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage; -#define glSampleCoverage glad_glSampleCoverage -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); -GLAPI PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D; -#define glCompressedTexImage3D glad_glCompressedTexImage3D -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); -GLAPI PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D; -#define glCompressedTexImage2D glad_glCompressedTexImage2D -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data); -GLAPI PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D; -#define glCompressedTexImage1D glad_glCompressedTexImage1D -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); -GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D; -#define glCompressedTexSubImage3D glad_glCompressedTexSubImage3D -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); -GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D; -#define glCompressedTexSubImage2D glad_glCompressedTexSubImage2D -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); -GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D; -#define glCompressedTexSubImage1D glad_glCompressedTexSubImage1D -typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC)(GLenum target, GLint level, void *img); -GLAPI PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage; -#define glGetCompressedTexImage glad_glGetCompressedTexImage -#endif -#ifndef GL_VERSION_1_4 -#define GL_VERSION_1_4 1 -GLAPI int GLAD_GL_VERSION_1_4; -typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC)(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); -GLAPI PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate; -#define glBlendFuncSeparate glad_glBlendFuncSeparate -typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSPROC)(GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount); -GLAPI PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays; -#define glMultiDrawArrays glad_glMultiDrawArrays -typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSPROC)(GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount); -GLAPI PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements; -#define glMultiDrawElements glad_glMultiDrawElements -typedef void (APIENTRYP PFNGLPOINTPARAMETERFPROC)(GLenum pname, GLfloat param); -GLAPI PFNGLPOINTPARAMETERFPROC glad_glPointParameterf; -#define glPointParameterf glad_glPointParameterf -typedef void (APIENTRYP PFNGLPOINTPARAMETERFVPROC)(GLenum pname, const GLfloat *params); -GLAPI PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv; -#define glPointParameterfv glad_glPointParameterfv -typedef void (APIENTRYP PFNGLPOINTPARAMETERIPROC)(GLenum pname, GLint param); -GLAPI PFNGLPOINTPARAMETERIPROC glad_glPointParameteri; -#define glPointParameteri glad_glPointParameteri -typedef void (APIENTRYP PFNGLPOINTPARAMETERIVPROC)(GLenum pname, const GLint *params); -GLAPI PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv; -#define glPointParameteriv glad_glPointParameteriv -typedef void (APIENTRYP PFNGLBLENDCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); -GLAPI PFNGLBLENDCOLORPROC glad_glBlendColor; -#define glBlendColor glad_glBlendColor -typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC)(GLenum mode); -GLAPI PFNGLBLENDEQUATIONPROC glad_glBlendEquation; -#define glBlendEquation glad_glBlendEquation -#endif -#ifndef GL_VERSION_1_5 -#define GL_VERSION_1_5 1 -GLAPI int GLAD_GL_VERSION_1_5; -typedef void (APIENTRYP PFNGLGENQUERIESPROC)(GLsizei n, GLuint *ids); -GLAPI PFNGLGENQUERIESPROC glad_glGenQueries; -#define glGenQueries glad_glGenQueries -typedef void (APIENTRYP PFNGLDELETEQUERIESPROC)(GLsizei n, const GLuint *ids); -GLAPI PFNGLDELETEQUERIESPROC glad_glDeleteQueries; -#define glDeleteQueries glad_glDeleteQueries -typedef GLboolean (APIENTRYP PFNGLISQUERYPROC)(GLuint id); -GLAPI PFNGLISQUERYPROC glad_glIsQuery; -#define glIsQuery glad_glIsQuery -typedef void (APIENTRYP PFNGLBEGINQUERYPROC)(GLenum target, GLuint id); -GLAPI PFNGLBEGINQUERYPROC glad_glBeginQuery; -#define glBeginQuery glad_glBeginQuery -typedef void (APIENTRYP PFNGLENDQUERYPROC)(GLenum target); -GLAPI PFNGLENDQUERYPROC glad_glEndQuery; -#define glEndQuery glad_glEndQuery -typedef void (APIENTRYP PFNGLGETQUERYIVPROC)(GLenum target, GLenum pname, GLint *params); -GLAPI PFNGLGETQUERYIVPROC glad_glGetQueryiv; -#define glGetQueryiv glad_glGetQueryiv -typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVPROC)(GLuint id, GLenum pname, GLint *params); -GLAPI PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv; -#define glGetQueryObjectiv glad_glGetQueryObjectiv -typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVPROC)(GLuint id, GLenum pname, GLuint *params); -GLAPI PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv; -#define glGetQueryObjectuiv glad_glGetQueryObjectuiv -typedef void (APIENTRYP PFNGLBINDBUFFERPROC)(GLenum target, GLuint buffer); -GLAPI PFNGLBINDBUFFERPROC glad_glBindBuffer; -#define glBindBuffer glad_glBindBuffer -typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC)(GLsizei n, const GLuint *buffers); -GLAPI PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers; -#define glDeleteBuffers glad_glDeleteBuffers -typedef void (APIENTRYP PFNGLGENBUFFERSPROC)(GLsizei n, GLuint *buffers); -GLAPI PFNGLGENBUFFERSPROC glad_glGenBuffers; -#define glGenBuffers glad_glGenBuffers -typedef GLboolean (APIENTRYP PFNGLISBUFFERPROC)(GLuint buffer); -GLAPI PFNGLISBUFFERPROC glad_glIsBuffer; -#define glIsBuffer glad_glIsBuffer -typedef void (APIENTRYP PFNGLBUFFERDATAPROC)(GLenum target, GLsizeiptr size, const void *data, GLenum usage); -GLAPI PFNGLBUFFERDATAPROC glad_glBufferData; -#define glBufferData glad_glBufferData -typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, const void *data); -GLAPI PFNGLBUFFERSUBDATAPROC glad_glBufferSubData; -#define glBufferSubData glad_glBufferSubData -typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, void *data); -GLAPI PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData; -#define glGetBufferSubData glad_glGetBufferSubData -typedef void * (APIENTRYP PFNGLMAPBUFFERPROC)(GLenum target, GLenum access); -GLAPI PFNGLMAPBUFFERPROC glad_glMapBuffer; -#define glMapBuffer glad_glMapBuffer -typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC)(GLenum target); -GLAPI PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer; -#define glUnmapBuffer glad_glUnmapBuffer -typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params); -GLAPI PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv; -#define glGetBufferParameteriv glad_glGetBufferParameteriv -typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC)(GLenum target, GLenum pname, void **params); -GLAPI PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv; -#define glGetBufferPointerv glad_glGetBufferPointerv -#endif -#ifndef GL_VERSION_2_0 -#define GL_VERSION_2_0 1 -GLAPI int GLAD_GL_VERSION_2_0; -typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC)(GLenum modeRGB, GLenum modeAlpha); -GLAPI PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate; -#define glBlendEquationSeparate glad_glBlendEquationSeparate -typedef void (APIENTRYP PFNGLDRAWBUFFERSPROC)(GLsizei n, const GLenum *bufs); -GLAPI PFNGLDRAWBUFFERSPROC glad_glDrawBuffers; -#define glDrawBuffers glad_glDrawBuffers -typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEPROC)(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); -GLAPI PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate; -#define glStencilOpSeparate glad_glStencilOpSeparate -typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC)(GLenum face, GLenum func, GLint ref, GLuint mask); -GLAPI PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate; -#define glStencilFuncSeparate glad_glStencilFuncSeparate -typedef void (APIENTRYP PFNGLSTENCILMASKSEPARATEPROC)(GLenum face, GLuint mask); -GLAPI PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate; -#define glStencilMaskSeparate glad_glStencilMaskSeparate -typedef void (APIENTRYP PFNGLATTACHSHADERPROC)(GLuint program, GLuint shader); -GLAPI PFNGLATTACHSHADERPROC glad_glAttachShader; -#define glAttachShader glad_glAttachShader -typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC)(GLuint program, GLuint index, const GLchar *name); -GLAPI PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation; -#define glBindAttribLocation glad_glBindAttribLocation -typedef void (APIENTRYP PFNGLCOMPILESHADERPROC)(GLuint shader); -GLAPI PFNGLCOMPILESHADERPROC glad_glCompileShader; -#define glCompileShader glad_glCompileShader -typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC)(void); -GLAPI PFNGLCREATEPROGRAMPROC glad_glCreateProgram; -#define glCreateProgram glad_glCreateProgram -typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC)(GLenum type); -GLAPI PFNGLCREATESHADERPROC glad_glCreateShader; -#define glCreateShader glad_glCreateShader -typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC)(GLuint program); -GLAPI PFNGLDELETEPROGRAMPROC glad_glDeleteProgram; -#define glDeleteProgram glad_glDeleteProgram -typedef void (APIENTRYP PFNGLDELETESHADERPROC)(GLuint shader); -GLAPI PFNGLDELETESHADERPROC glad_glDeleteShader; -#define glDeleteShader glad_glDeleteShader -typedef void (APIENTRYP PFNGLDETACHSHADERPROC)(GLuint program, GLuint shader); -GLAPI PFNGLDETACHSHADERPROC glad_glDetachShader; -#define glDetachShader glad_glDetachShader -typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC)(GLuint index); -GLAPI PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray; -#define glDisableVertexAttribArray glad_glDisableVertexAttribArray -typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC)(GLuint index); -GLAPI PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray; -#define glEnableVertexAttribArray glad_glEnableVertexAttribArray -typedef void (APIENTRYP PFNGLGETACTIVEATTRIBPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); -GLAPI PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib; -#define glGetActiveAttrib glad_glGetActiveAttrib -typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); -GLAPI PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform; -#define glGetActiveUniform glad_glGetActiveUniform -typedef void (APIENTRYP PFNGLGETATTACHEDSHADERSPROC)(GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders); -GLAPI PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders; -#define glGetAttachedShaders glad_glGetAttachedShaders -typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC)(GLuint program, const GLchar *name); -GLAPI PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation; -#define glGetAttribLocation glad_glGetAttribLocation -typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC)(GLuint program, GLenum pname, GLint *params); -GLAPI PFNGLGETPROGRAMIVPROC glad_glGetProgramiv; -#define glGetProgramiv glad_glGetProgramiv -typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC)(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); -GLAPI PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog; -#define glGetProgramInfoLog glad_glGetProgramInfoLog -typedef void (APIENTRYP PFNGLGETSHADERIVPROC)(GLuint shader, GLenum pname, GLint *params); -GLAPI PFNGLGETSHADERIVPROC glad_glGetShaderiv; -#define glGetShaderiv glad_glGetShaderiv -typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); -GLAPI PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog; -#define glGetShaderInfoLog glad_glGetShaderInfoLog -typedef void (APIENTRYP PFNGLGETSHADERSOURCEPROC)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); -GLAPI PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource; -#define glGetShaderSource glad_glGetShaderSource -typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC)(GLuint program, const GLchar *name); -GLAPI PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation; -#define glGetUniformLocation glad_glGetUniformLocation -typedef void (APIENTRYP PFNGLGETUNIFORMFVPROC)(GLuint program, GLint location, GLfloat *params); -GLAPI PFNGLGETUNIFORMFVPROC glad_glGetUniformfv; -#define glGetUniformfv glad_glGetUniformfv -typedef void (APIENTRYP PFNGLGETUNIFORMIVPROC)(GLuint program, GLint location, GLint *params); -GLAPI PFNGLGETUNIFORMIVPROC glad_glGetUniformiv; -#define glGetUniformiv glad_glGetUniformiv -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVPROC)(GLuint index, GLenum pname, GLdouble *params); -GLAPI PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv; -#define glGetVertexAttribdv glad_glGetVertexAttribdv -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVPROC)(GLuint index, GLenum pname, GLfloat *params); -GLAPI PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv; -#define glGetVertexAttribfv glad_glGetVertexAttribfv -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC)(GLuint index, GLenum pname, GLint *params); -GLAPI PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv; -#define glGetVertexAttribiv glad_glGetVertexAttribiv -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC)(GLuint index, GLenum pname, void **pointer); -GLAPI PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv; -#define glGetVertexAttribPointerv glad_glGetVertexAttribPointerv -typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC)(GLuint program); -GLAPI PFNGLISPROGRAMPROC glad_glIsProgram; -#define glIsProgram glad_glIsProgram -typedef GLboolean (APIENTRYP PFNGLISSHADERPROC)(GLuint shader); -GLAPI PFNGLISSHADERPROC glad_glIsShader; -#define glIsShader glad_glIsShader -typedef void (APIENTRYP PFNGLLINKPROGRAMPROC)(GLuint program); -GLAPI PFNGLLINKPROGRAMPROC glad_glLinkProgram; -#define glLinkProgram glad_glLinkProgram -typedef void (APIENTRYP PFNGLSHADERSOURCEPROC)(GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length); -GLAPI PFNGLSHADERSOURCEPROC glad_glShaderSource; -#define glShaderSource glad_glShaderSource -typedef void (APIENTRYP PFNGLUSEPROGRAMPROC)(GLuint program); -GLAPI PFNGLUSEPROGRAMPROC glad_glUseProgram; -#define glUseProgram glad_glUseProgram -typedef void (APIENTRYP PFNGLUNIFORM1FPROC)(GLint location, GLfloat v0); -GLAPI PFNGLUNIFORM1FPROC glad_glUniform1f; -#define glUniform1f glad_glUniform1f -typedef void (APIENTRYP PFNGLUNIFORM2FPROC)(GLint location, GLfloat v0, GLfloat v1); -GLAPI PFNGLUNIFORM2FPROC glad_glUniform2f; -#define glUniform2f glad_glUniform2f -typedef void (APIENTRYP PFNGLUNIFORM3FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -GLAPI PFNGLUNIFORM3FPROC glad_glUniform3f; -#define glUniform3f glad_glUniform3f -typedef void (APIENTRYP PFNGLUNIFORM4FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -GLAPI PFNGLUNIFORM4FPROC glad_glUniform4f; -#define glUniform4f glad_glUniform4f -typedef void (APIENTRYP PFNGLUNIFORM1IPROC)(GLint location, GLint v0); -GLAPI PFNGLUNIFORM1IPROC glad_glUniform1i; -#define glUniform1i glad_glUniform1i -typedef void (APIENTRYP PFNGLUNIFORM2IPROC)(GLint location, GLint v0, GLint v1); -GLAPI PFNGLUNIFORM2IPROC glad_glUniform2i; -#define glUniform2i glad_glUniform2i -typedef void (APIENTRYP PFNGLUNIFORM3IPROC)(GLint location, GLint v0, GLint v1, GLint v2); -GLAPI PFNGLUNIFORM3IPROC glad_glUniform3i; -#define glUniform3i glad_glUniform3i -typedef void (APIENTRYP PFNGLUNIFORM4IPROC)(GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -GLAPI PFNGLUNIFORM4IPROC glad_glUniform4i; -#define glUniform4i glad_glUniform4i -typedef void (APIENTRYP PFNGLUNIFORM1FVPROC)(GLint location, GLsizei count, const GLfloat *value); -GLAPI PFNGLUNIFORM1FVPROC glad_glUniform1fv; -#define glUniform1fv glad_glUniform1fv -typedef void (APIENTRYP PFNGLUNIFORM2FVPROC)(GLint location, GLsizei count, const GLfloat *value); -GLAPI PFNGLUNIFORM2FVPROC glad_glUniform2fv; -#define glUniform2fv glad_glUniform2fv -typedef void (APIENTRYP PFNGLUNIFORM3FVPROC)(GLint location, GLsizei count, const GLfloat *value); -GLAPI PFNGLUNIFORM3FVPROC glad_glUniform3fv; -#define glUniform3fv glad_glUniform3fv -typedef void (APIENTRYP PFNGLUNIFORM4FVPROC)(GLint location, GLsizei count, const GLfloat *value); -GLAPI PFNGLUNIFORM4FVPROC glad_glUniform4fv; -#define glUniform4fv glad_glUniform4fv -typedef void (APIENTRYP PFNGLUNIFORM1IVPROC)(GLint location, GLsizei count, const GLint *value); -GLAPI PFNGLUNIFORM1IVPROC glad_glUniform1iv; -#define glUniform1iv glad_glUniform1iv -typedef void (APIENTRYP PFNGLUNIFORM2IVPROC)(GLint location, GLsizei count, const GLint *value); -GLAPI PFNGLUNIFORM2IVPROC glad_glUniform2iv; -#define glUniform2iv glad_glUniform2iv -typedef void (APIENTRYP PFNGLUNIFORM3IVPROC)(GLint location, GLsizei count, const GLint *value); -GLAPI PFNGLUNIFORM3IVPROC glad_glUniform3iv; -#define glUniform3iv glad_glUniform3iv -typedef void (APIENTRYP PFNGLUNIFORM4IVPROC)(GLint location, GLsizei count, const GLint *value); -GLAPI PFNGLUNIFORM4IVPROC glad_glUniform4iv; -#define glUniform4iv glad_glUniform4iv -typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv; -#define glUniformMatrix2fv glad_glUniformMatrix2fv -typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv; -#define glUniformMatrix3fv glad_glUniformMatrix3fv -typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv; -#define glUniformMatrix4fv glad_glUniformMatrix4fv -typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC)(GLuint program); -GLAPI PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram; -#define glValidateProgram glad_glValidateProgram -typedef void (APIENTRYP PFNGLVERTEXATTRIB1DPROC)(GLuint index, GLdouble x); -GLAPI PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d; -#define glVertexAttrib1d glad_glVertexAttrib1d -typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVPROC)(GLuint index, const GLdouble *v); -GLAPI PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv; -#define glVertexAttrib1dv glad_glVertexAttrib1dv -typedef void (APIENTRYP PFNGLVERTEXATTRIB1FPROC)(GLuint index, GLfloat x); -GLAPI PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f; -#define glVertexAttrib1f glad_glVertexAttrib1f -typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVPROC)(GLuint index, const GLfloat *v); -GLAPI PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv; -#define glVertexAttrib1fv glad_glVertexAttrib1fv -typedef void (APIENTRYP PFNGLVERTEXATTRIB1SPROC)(GLuint index, GLshort x); -GLAPI PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s; -#define glVertexAttrib1s glad_glVertexAttrib1s -typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVPROC)(GLuint index, const GLshort *v); -GLAPI PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv; -#define glVertexAttrib1sv glad_glVertexAttrib1sv -typedef void (APIENTRYP PFNGLVERTEXATTRIB2DPROC)(GLuint index, GLdouble x, GLdouble y); -GLAPI PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d; -#define glVertexAttrib2d glad_glVertexAttrib2d -typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVPROC)(GLuint index, const GLdouble *v); -GLAPI PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv; -#define glVertexAttrib2dv glad_glVertexAttrib2dv -typedef void (APIENTRYP PFNGLVERTEXATTRIB2FPROC)(GLuint index, GLfloat x, GLfloat y); -GLAPI PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f; -#define glVertexAttrib2f glad_glVertexAttrib2f -typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVPROC)(GLuint index, const GLfloat *v); -GLAPI PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv; -#define glVertexAttrib2fv glad_glVertexAttrib2fv -typedef void (APIENTRYP PFNGLVERTEXATTRIB2SPROC)(GLuint index, GLshort x, GLshort y); -GLAPI PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s; -#define glVertexAttrib2s glad_glVertexAttrib2s -typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVPROC)(GLuint index, const GLshort *v); -GLAPI PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv; -#define glVertexAttrib2sv glad_glVertexAttrib2sv -typedef void (APIENTRYP PFNGLVERTEXATTRIB3DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z); -GLAPI PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d; -#define glVertexAttrib3d glad_glVertexAttrib3d -typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVPROC)(GLuint index, const GLdouble *v); -GLAPI PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv; -#define glVertexAttrib3dv glad_glVertexAttrib3dv -typedef void (APIENTRYP PFNGLVERTEXATTRIB3FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z); -GLAPI PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f; -#define glVertexAttrib3f glad_glVertexAttrib3f -typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVPROC)(GLuint index, const GLfloat *v); -GLAPI PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv; -#define glVertexAttrib3fv glad_glVertexAttrib3fv -typedef void (APIENTRYP PFNGLVERTEXATTRIB3SPROC)(GLuint index, GLshort x, GLshort y, GLshort z); -GLAPI PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s; -#define glVertexAttrib3s glad_glVertexAttrib3s -typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVPROC)(GLuint index, const GLshort *v); -GLAPI PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv; -#define glVertexAttrib3sv glad_glVertexAttrib3sv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVPROC)(GLuint index, const GLbyte *v); -GLAPI PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv; -#define glVertexAttrib4Nbv glad_glVertexAttrib4Nbv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVPROC)(GLuint index, const GLint *v); -GLAPI PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv; -#define glVertexAttrib4Niv glad_glVertexAttrib4Niv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVPROC)(GLuint index, const GLshort *v); -GLAPI PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv; -#define glVertexAttrib4Nsv glad_glVertexAttrib4Nsv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBPROC)(GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); -GLAPI PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub; -#define glVertexAttrib4Nub glad_glVertexAttrib4Nub -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVPROC)(GLuint index, const GLubyte *v); -GLAPI PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv; -#define glVertexAttrib4Nubv glad_glVertexAttrib4Nubv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVPROC)(GLuint index, const GLuint *v); -GLAPI PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv; -#define glVertexAttrib4Nuiv glad_glVertexAttrib4Nuiv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVPROC)(GLuint index, const GLushort *v); -GLAPI PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv; -#define glVertexAttrib4Nusv glad_glVertexAttrib4Nusv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVPROC)(GLuint index, const GLbyte *v); -GLAPI PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv; -#define glVertexAttrib4bv glad_glVertexAttrib4bv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d; -#define glVertexAttrib4d glad_glVertexAttrib4d -typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVPROC)(GLuint index, const GLdouble *v); -GLAPI PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv; -#define glVertexAttrib4dv glad_glVertexAttrib4dv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f; -#define glVertexAttrib4f glad_glVertexAttrib4f -typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVPROC)(GLuint index, const GLfloat *v); -GLAPI PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv; -#define glVertexAttrib4fv glad_glVertexAttrib4fv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVPROC)(GLuint index, const GLint *v); -GLAPI PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv; -#define glVertexAttrib4iv glad_glVertexAttrib4iv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4SPROC)(GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); -GLAPI PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s; -#define glVertexAttrib4s glad_glVertexAttrib4s -typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVPROC)(GLuint index, const GLshort *v); -GLAPI PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv; -#define glVertexAttrib4sv glad_glVertexAttrib4sv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVPROC)(GLuint index, const GLubyte *v); -GLAPI PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv; -#define glVertexAttrib4ubv glad_glVertexAttrib4ubv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVPROC)(GLuint index, const GLuint *v); -GLAPI PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv; -#define glVertexAttrib4uiv glad_glVertexAttrib4uiv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVPROC)(GLuint index, const GLushort *v); -GLAPI PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv; -#define glVertexAttrib4usv glad_glVertexAttrib4usv -typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); -GLAPI PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer; -#define glVertexAttribPointer glad_glVertexAttribPointer -#endif -#ifndef GL_VERSION_2_1 -#define GL_VERSION_2_1 1 -GLAPI int GLAD_GL_VERSION_2_1; -typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv; -#define glUniformMatrix2x3fv glad_glUniformMatrix2x3fv -typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv; -#define glUniformMatrix3x2fv glad_glUniformMatrix3x2fv -typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv; -#define glUniformMatrix2x4fv glad_glUniformMatrix2x4fv -typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv; -#define glUniformMatrix4x2fv glad_glUniformMatrix4x2fv -typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv; -#define glUniformMatrix3x4fv glad_glUniformMatrix3x4fv -typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv; -#define glUniformMatrix4x3fv glad_glUniformMatrix4x3fv -#endif -#ifndef GL_VERSION_3_0 -#define GL_VERSION_3_0 1 -GLAPI int GLAD_GL_VERSION_3_0; -typedef void (APIENTRYP PFNGLCOLORMASKIPROC)(GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); -GLAPI PFNGLCOLORMASKIPROC glad_glColorMaski; -#define glColorMaski glad_glColorMaski -typedef void (APIENTRYP PFNGLGETBOOLEANI_VPROC)(GLenum target, GLuint index, GLboolean *data); -GLAPI PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v; -#define glGetBooleani_v glad_glGetBooleani_v -typedef void (APIENTRYP PFNGLGETINTEGERI_VPROC)(GLenum target, GLuint index, GLint *data); -GLAPI PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v; -#define glGetIntegeri_v glad_glGetIntegeri_v -typedef void (APIENTRYP PFNGLENABLEIPROC)(GLenum target, GLuint index); -GLAPI PFNGLENABLEIPROC glad_glEnablei; -#define glEnablei glad_glEnablei -typedef void (APIENTRYP PFNGLDISABLEIPROC)(GLenum target, GLuint index); -GLAPI PFNGLDISABLEIPROC glad_glDisablei; -#define glDisablei glad_glDisablei -typedef GLboolean (APIENTRYP PFNGLISENABLEDIPROC)(GLenum target, GLuint index); -GLAPI PFNGLISENABLEDIPROC glad_glIsEnabledi; -#define glIsEnabledi glad_glIsEnabledi -typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKPROC)(GLenum primitiveMode); -GLAPI PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback; -#define glBeginTransformFeedback glad_glBeginTransformFeedback -typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKPROC)(void); -GLAPI PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback; -#define glEndTransformFeedback glad_glEndTransformFeedback -typedef void (APIENTRYP PFNGLBINDBUFFERRANGEPROC)(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); -GLAPI PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange; -#define glBindBufferRange glad_glBindBufferRange -typedef void (APIENTRYP PFNGLBINDBUFFERBASEPROC)(GLenum target, GLuint index, GLuint buffer); -GLAPI PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase; -#define glBindBufferBase glad_glBindBufferBase -typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSPROC)(GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); -GLAPI PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings; -#define glTransformFeedbackVaryings glad_glTransformFeedbackVaryings -typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); -GLAPI PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying; -#define glGetTransformFeedbackVarying glad_glGetTransformFeedbackVarying -typedef void (APIENTRYP PFNGLCLAMPCOLORPROC)(GLenum target, GLenum clamp); -GLAPI PFNGLCLAMPCOLORPROC glad_glClampColor; -#define glClampColor glad_glClampColor -typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERPROC)(GLuint id, GLenum mode); -GLAPI PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender; -#define glBeginConditionalRender glad_glBeginConditionalRender -typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERPROC)(void); -GLAPI PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender; -#define glEndConditionalRender glad_glEndConditionalRender -typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC)(GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); -GLAPI PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer; -#define glVertexAttribIPointer glad_glVertexAttribIPointer -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVPROC)(GLuint index, GLenum pname, GLint *params); -GLAPI PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv; -#define glGetVertexAttribIiv glad_glGetVertexAttribIiv -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVPROC)(GLuint index, GLenum pname, GLuint *params); -GLAPI PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv; -#define glGetVertexAttribIuiv glad_glGetVertexAttribIuiv -typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IPROC)(GLuint index, GLint x); -GLAPI PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i; -#define glVertexAttribI1i glad_glVertexAttribI1i -typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IPROC)(GLuint index, GLint x, GLint y); -GLAPI PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i; -#define glVertexAttribI2i glad_glVertexAttribI2i -typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IPROC)(GLuint index, GLint x, GLint y, GLint z); -GLAPI PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i; -#define glVertexAttribI3i glad_glVertexAttribI3i -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IPROC)(GLuint index, GLint x, GLint y, GLint z, GLint w); -GLAPI PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i; -#define glVertexAttribI4i glad_glVertexAttribI4i -typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIPROC)(GLuint index, GLuint x); -GLAPI PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui; -#define glVertexAttribI1ui glad_glVertexAttribI1ui -typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIPROC)(GLuint index, GLuint x, GLuint y); -GLAPI PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui; -#define glVertexAttribI2ui glad_glVertexAttribI2ui -typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z); -GLAPI PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui; -#define glVertexAttribI3ui glad_glVertexAttribI3ui -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); -GLAPI PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui; -#define glVertexAttribI4ui glad_glVertexAttribI4ui -typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVPROC)(GLuint index, const GLint *v); -GLAPI PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv; -#define glVertexAttribI1iv glad_glVertexAttribI1iv -typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVPROC)(GLuint index, const GLint *v); -GLAPI PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv; -#define glVertexAttribI2iv glad_glVertexAttribI2iv -typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVPROC)(GLuint index, const GLint *v); -GLAPI PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv; -#define glVertexAttribI3iv glad_glVertexAttribI3iv -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVPROC)(GLuint index, const GLint *v); -GLAPI PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv; -#define glVertexAttribI4iv glad_glVertexAttribI4iv -typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVPROC)(GLuint index, const GLuint *v); -GLAPI PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv; -#define glVertexAttribI1uiv glad_glVertexAttribI1uiv -typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVPROC)(GLuint index, const GLuint *v); -GLAPI PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv; -#define glVertexAttribI2uiv glad_glVertexAttribI2uiv -typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVPROC)(GLuint index, const GLuint *v); -GLAPI PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv; -#define glVertexAttribI3uiv glad_glVertexAttribI3uiv -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVPROC)(GLuint index, const GLuint *v); -GLAPI PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv; -#define glVertexAttribI4uiv glad_glVertexAttribI4uiv -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVPROC)(GLuint index, const GLbyte *v); -GLAPI PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv; -#define glVertexAttribI4bv glad_glVertexAttribI4bv -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVPROC)(GLuint index, const GLshort *v); -GLAPI PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv; -#define glVertexAttribI4sv glad_glVertexAttribI4sv -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVPROC)(GLuint index, const GLubyte *v); -GLAPI PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv; -#define glVertexAttribI4ubv glad_glVertexAttribI4ubv -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVPROC)(GLuint index, const GLushort *v); -GLAPI PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv; -#define glVertexAttribI4usv glad_glVertexAttribI4usv -typedef void (APIENTRYP PFNGLGETUNIFORMUIVPROC)(GLuint program, GLint location, GLuint *params); -GLAPI PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv; -#define glGetUniformuiv glad_glGetUniformuiv -typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONPROC)(GLuint program, GLuint color, const GLchar *name); -GLAPI PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation; -#define glBindFragDataLocation glad_glBindFragDataLocation -typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONPROC)(GLuint program, const GLchar *name); -GLAPI PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation; -#define glGetFragDataLocation glad_glGetFragDataLocation -typedef void (APIENTRYP PFNGLUNIFORM1UIPROC)(GLint location, GLuint v0); -GLAPI PFNGLUNIFORM1UIPROC glad_glUniform1ui; -#define glUniform1ui glad_glUniform1ui -typedef void (APIENTRYP PFNGLUNIFORM2UIPROC)(GLint location, GLuint v0, GLuint v1); -GLAPI PFNGLUNIFORM2UIPROC glad_glUniform2ui; -#define glUniform2ui glad_glUniform2ui -typedef void (APIENTRYP PFNGLUNIFORM3UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2); -GLAPI PFNGLUNIFORM3UIPROC glad_glUniform3ui; -#define glUniform3ui glad_glUniform3ui -typedef void (APIENTRYP PFNGLUNIFORM4UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); -GLAPI PFNGLUNIFORM4UIPROC glad_glUniform4ui; -#define glUniform4ui glad_glUniform4ui -typedef void (APIENTRYP PFNGLUNIFORM1UIVPROC)(GLint location, GLsizei count, const GLuint *value); -GLAPI PFNGLUNIFORM1UIVPROC glad_glUniform1uiv; -#define glUniform1uiv glad_glUniform1uiv -typedef void (APIENTRYP PFNGLUNIFORM2UIVPROC)(GLint location, GLsizei count, const GLuint *value); -GLAPI PFNGLUNIFORM2UIVPROC glad_glUniform2uiv; -#define glUniform2uiv glad_glUniform2uiv -typedef void (APIENTRYP PFNGLUNIFORM3UIVPROC)(GLint location, GLsizei count, const GLuint *value); -GLAPI PFNGLUNIFORM3UIVPROC glad_glUniform3uiv; -#define glUniform3uiv glad_glUniform3uiv -typedef void (APIENTRYP PFNGLUNIFORM4UIVPROC)(GLint location, GLsizei count, const GLuint *value); -GLAPI PFNGLUNIFORM4UIVPROC glad_glUniform4uiv; -#define glUniform4uiv glad_glUniform4uiv -typedef void (APIENTRYP PFNGLTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, const GLint *params); -GLAPI PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv; -#define glTexParameterIiv glad_glTexParameterIiv -typedef void (APIENTRYP PFNGLTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, const GLuint *params); -GLAPI PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv; -#define glTexParameterIuiv glad_glTexParameterIuiv -typedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, GLint *params); -GLAPI PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv; -#define glGetTexParameterIiv glad_glGetTexParameterIiv -typedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, GLuint *params); -GLAPI PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv; -#define glGetTexParameterIuiv glad_glGetTexParameterIuiv -typedef void (APIENTRYP PFNGLCLEARBUFFERIVPROC)(GLenum buffer, GLint drawbuffer, const GLint *value); -GLAPI PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv; -#define glClearBufferiv glad_glClearBufferiv -typedef void (APIENTRYP PFNGLCLEARBUFFERUIVPROC)(GLenum buffer, GLint drawbuffer, const GLuint *value); -GLAPI PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv; -#define glClearBufferuiv glad_glClearBufferuiv -typedef void (APIENTRYP PFNGLCLEARBUFFERFVPROC)(GLenum buffer, GLint drawbuffer, const GLfloat *value); -GLAPI PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv; -#define glClearBufferfv glad_glClearBufferfv -typedef void (APIENTRYP PFNGLCLEARBUFFERFIPROC)(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); -GLAPI PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi; -#define glClearBufferfi glad_glClearBufferfi -typedef const GLubyte * (APIENTRYP PFNGLGETSTRINGIPROC)(GLenum name, GLuint index); -GLAPI PFNGLGETSTRINGIPROC glad_glGetStringi; -#define glGetStringi glad_glGetStringi -typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFERPROC)(GLuint renderbuffer); -GLAPI PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer; -#define glIsRenderbuffer glad_glIsRenderbuffer -typedef void (APIENTRYP PFNGLBINDRENDERBUFFERPROC)(GLenum target, GLuint renderbuffer); -GLAPI PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer; -#define glBindRenderbuffer glad_glBindRenderbuffer -typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSPROC)(GLsizei n, const GLuint *renderbuffers); -GLAPI PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers; -#define glDeleteRenderbuffers glad_glDeleteRenderbuffers -typedef void (APIENTRYP PFNGLGENRENDERBUFFERSPROC)(GLsizei n, GLuint *renderbuffers); -GLAPI PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers; -#define glGenRenderbuffers glad_glGenRenderbuffers -typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEPROC)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); -GLAPI PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage; -#define glRenderbufferStorage glad_glRenderbufferStorage -typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params); -GLAPI PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv; -#define glGetRenderbufferParameteriv glad_glGetRenderbufferParameteriv -typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFERPROC)(GLuint framebuffer); -GLAPI PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer; -#define glIsFramebuffer glad_glIsFramebuffer -typedef void (APIENTRYP PFNGLBINDFRAMEBUFFERPROC)(GLenum target, GLuint framebuffer); -GLAPI PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer; -#define glBindFramebuffer glad_glBindFramebuffer -typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC)(GLsizei n, const GLuint *framebuffers); -GLAPI PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers; -#define glDeleteFramebuffers glad_glDeleteFramebuffers -typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSPROC)(GLsizei n, GLuint *framebuffers); -GLAPI PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers; -#define glGenFramebuffers glad_glGenFramebuffers -typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSPROC)(GLenum target); -GLAPI PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus; -#define glCheckFramebufferStatus glad_glCheckFramebufferStatus -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -GLAPI PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D; -#define glFramebufferTexture1D glad_glFramebufferTexture1D -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -GLAPI PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D; -#define glFramebufferTexture2D glad_glFramebufferTexture2D -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); -GLAPI PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D; -#define glFramebufferTexture3D glad_glFramebufferTexture3D -typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFERPROC)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); -GLAPI PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer; -#define glFramebufferRenderbuffer glad_glFramebufferRenderbuffer -typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)(GLenum target, GLenum attachment, GLenum pname, GLint *params); -GLAPI PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv; -#define glGetFramebufferAttachmentParameteriv glad_glGetFramebufferAttachmentParameteriv -typedef void (APIENTRYP PFNGLGENERATEMIPMAPPROC)(GLenum target); -GLAPI PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap; -#define glGenerateMipmap glad_glGenerateMipmap -typedef void (APIENTRYP PFNGLBLITFRAMEBUFFERPROC)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); -GLAPI PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer; -#define glBlitFramebuffer glad_glBlitFramebuffer -typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); -GLAPI PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample; -#define glRenderbufferStorageMultisample glad_glRenderbufferStorageMultisample -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); -GLAPI PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer; -#define glFramebufferTextureLayer glad_glFramebufferTextureLayer -typedef void * (APIENTRYP PFNGLMAPBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); -GLAPI PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange; -#define glMapBufferRange glad_glMapBufferRange -typedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length); -GLAPI PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange; -#define glFlushMappedBufferRange glad_glFlushMappedBufferRange -typedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC)(GLuint array); -GLAPI PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray; -#define glBindVertexArray glad_glBindVertexArray -typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC)(GLsizei n, const GLuint *arrays); -GLAPI PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays; -#define glDeleteVertexArrays glad_glDeleteVertexArrays -typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC)(GLsizei n, GLuint *arrays); -GLAPI PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays; -#define glGenVertexArrays glad_glGenVertexArrays -typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYPROC)(GLuint array); -GLAPI PFNGLISVERTEXARRAYPROC glad_glIsVertexArray; -#define glIsVertexArray glad_glIsVertexArray -#endif -#ifndef GL_VERSION_3_1 -#define GL_VERSION_3_1 1 -GLAPI int GLAD_GL_VERSION_3_1; -typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount); -GLAPI PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced; -#define glDrawArraysInstanced glad_glDrawArraysInstanced -typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount); -GLAPI PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced; -#define glDrawElementsInstanced glad_glDrawElementsInstanced -typedef void (APIENTRYP PFNGLTEXBUFFERPROC)(GLenum target, GLenum internalformat, GLuint buffer); -GLAPI PFNGLTEXBUFFERPROC glad_glTexBuffer; -#define glTexBuffer glad_glTexBuffer -typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXPROC)(GLuint index); -GLAPI PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex; -#define glPrimitiveRestartIndex glad_glPrimitiveRestartIndex -typedef void (APIENTRYP PFNGLCOPYBUFFERSUBDATAPROC)(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); -GLAPI PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData; -#define glCopyBufferSubData glad_glCopyBufferSubData -typedef void (APIENTRYP PFNGLGETUNIFORMINDICESPROC)(GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices); -GLAPI PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices; -#define glGetUniformIndices glad_glGetUniformIndices -typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMSIVPROC)(GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params); -GLAPI PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv; -#define glGetActiveUniformsiv glad_glGetActiveUniformsiv -typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMNAMEPROC)(GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName); -GLAPI PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName; -#define glGetActiveUniformName glad_glGetActiveUniformName -typedef GLuint (APIENTRYP PFNGLGETUNIFORMBLOCKINDEXPROC)(GLuint program, const GLchar *uniformBlockName); -GLAPI PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex; -#define glGetUniformBlockIndex glad_glGetUniformBlockIndex -typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKIVPROC)(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); -GLAPI PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv; -#define glGetActiveUniformBlockiv glad_glGetActiveUniformBlockiv -typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName); -GLAPI PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName; -#define glGetActiveUniformBlockName glad_glGetActiveUniformBlockName -typedef void (APIENTRYP PFNGLUNIFORMBLOCKBINDINGPROC)(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); -GLAPI PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding; -#define glUniformBlockBinding glad_glUniformBlockBinding -#endif -#ifndef GL_VERSION_3_2 -#define GL_VERSION_3_2 1 -GLAPI int GLAD_GL_VERSION_3_2; -typedef void (APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex); -GLAPI PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex; -#define glDrawElementsBaseVertex glad_glDrawElementsBaseVertex -typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex); -GLAPI PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex; -#define glDrawRangeElementsBaseVertex glad_glDrawRangeElementsBaseVertex -typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex); -GLAPI PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex; -#define glDrawElementsInstancedBaseVertex glad_glDrawElementsInstancedBaseVertex -typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount, const GLint *basevertex); -GLAPI PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex; -#define glMultiDrawElementsBaseVertex glad_glMultiDrawElementsBaseVertex -typedef void (APIENTRYP PFNGLPROVOKINGVERTEXPROC)(GLenum mode); -GLAPI PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex; -#define glProvokingVertex glad_glProvokingVertex -typedef GLsync (APIENTRYP PFNGLFENCESYNCPROC)(GLenum condition, GLbitfield flags); -GLAPI PFNGLFENCESYNCPROC glad_glFenceSync; -#define glFenceSync glad_glFenceSync -typedef GLboolean (APIENTRYP PFNGLISSYNCPROC)(GLsync sync); -GLAPI PFNGLISSYNCPROC glad_glIsSync; -#define glIsSync glad_glIsSync -typedef void (APIENTRYP PFNGLDELETESYNCPROC)(GLsync sync); -GLAPI PFNGLDELETESYNCPROC glad_glDeleteSync; -#define glDeleteSync glad_glDeleteSync -typedef GLenum (APIENTRYP PFNGLCLIENTWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout); -GLAPI PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync; -#define glClientWaitSync glad_glClientWaitSync -typedef void (APIENTRYP PFNGLWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout); -GLAPI PFNGLWAITSYNCPROC glad_glWaitSync; -#define glWaitSync glad_glWaitSync -typedef void (APIENTRYP PFNGLGETINTEGER64VPROC)(GLenum pname, GLint64 *data); -GLAPI PFNGLGETINTEGER64VPROC glad_glGetInteger64v; -#define glGetInteger64v glad_glGetInteger64v -typedef void (APIENTRYP PFNGLGETSYNCIVPROC)(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); -GLAPI PFNGLGETSYNCIVPROC glad_glGetSynciv; -#define glGetSynciv glad_glGetSynciv -typedef void (APIENTRYP PFNGLGETINTEGER64I_VPROC)(GLenum target, GLuint index, GLint64 *data); -GLAPI PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v; -#define glGetInteger64i_v glad_glGetInteger64i_v -typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERI64VPROC)(GLenum target, GLenum pname, GLint64 *params); -GLAPI PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v; -#define glGetBufferParameteri64v glad_glGetBufferParameteri64v -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level); -GLAPI PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture; -#define glFramebufferTexture glad_glFramebufferTexture -typedef void (APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); -GLAPI PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample; -#define glTexImage2DMultisample glad_glTexImage2DMultisample -typedef void (APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); -GLAPI PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample; -#define glTexImage3DMultisample glad_glTexImage3DMultisample -typedef void (APIENTRYP PFNGLGETMULTISAMPLEFVPROC)(GLenum pname, GLuint index, GLfloat *val); -GLAPI PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv; -#define glGetMultisamplefv glad_glGetMultisamplefv -typedef void (APIENTRYP PFNGLSAMPLEMASKIPROC)(GLuint maskNumber, GLbitfield mask); -GLAPI PFNGLSAMPLEMASKIPROC glad_glSampleMaski; -#define glSampleMaski glad_glSampleMaski -#endif -#ifndef GL_VERSION_3_3 -#define GL_VERSION_3_3 1 -GLAPI int GLAD_GL_VERSION_3_3; -typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONINDEXEDPROC)(GLuint program, GLuint colorNumber, GLuint index, const GLchar *name); -GLAPI PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glad_glBindFragDataLocationIndexed; -#define glBindFragDataLocationIndexed glad_glBindFragDataLocationIndexed -typedef GLint (APIENTRYP PFNGLGETFRAGDATAINDEXPROC)(GLuint program, const GLchar *name); -GLAPI PFNGLGETFRAGDATAINDEXPROC glad_glGetFragDataIndex; -#define glGetFragDataIndex glad_glGetFragDataIndex -typedef void (APIENTRYP PFNGLGENSAMPLERSPROC)(GLsizei count, GLuint *samplers); -GLAPI PFNGLGENSAMPLERSPROC glad_glGenSamplers; -#define glGenSamplers glad_glGenSamplers -typedef void (APIENTRYP PFNGLDELETESAMPLERSPROC)(GLsizei count, const GLuint *samplers); -GLAPI PFNGLDELETESAMPLERSPROC glad_glDeleteSamplers; -#define glDeleteSamplers glad_glDeleteSamplers -typedef GLboolean (APIENTRYP PFNGLISSAMPLERPROC)(GLuint sampler); -GLAPI PFNGLISSAMPLERPROC glad_glIsSampler; -#define glIsSampler glad_glIsSampler -typedef void (APIENTRYP PFNGLBINDSAMPLERPROC)(GLuint unit, GLuint sampler); -GLAPI PFNGLBINDSAMPLERPROC glad_glBindSampler; -#define glBindSampler glad_glBindSampler -typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIPROC)(GLuint sampler, GLenum pname, GLint param); -GLAPI PFNGLSAMPLERPARAMETERIPROC glad_glSamplerParameteri; -#define glSamplerParameteri glad_glSamplerParameteri -typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIVPROC)(GLuint sampler, GLenum pname, const GLint *param); -GLAPI PFNGLSAMPLERPARAMETERIVPROC glad_glSamplerParameteriv; -#define glSamplerParameteriv glad_glSamplerParameteriv -typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFPROC)(GLuint sampler, GLenum pname, GLfloat param); -GLAPI PFNGLSAMPLERPARAMETERFPROC glad_glSamplerParameterf; -#define glSamplerParameterf glad_glSamplerParameterf -typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFVPROC)(GLuint sampler, GLenum pname, const GLfloat *param); -GLAPI PFNGLSAMPLERPARAMETERFVPROC glad_glSamplerParameterfv; -#define glSamplerParameterfv glad_glSamplerParameterfv -typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIIVPROC)(GLuint sampler, GLenum pname, const GLint *param); -GLAPI PFNGLSAMPLERPARAMETERIIVPROC glad_glSamplerParameterIiv; -#define glSamplerParameterIiv glad_glSamplerParameterIiv -typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIUIVPROC)(GLuint sampler, GLenum pname, const GLuint *param); -GLAPI PFNGLSAMPLERPARAMETERIUIVPROC glad_glSamplerParameterIuiv; -#define glSamplerParameterIuiv glad_glSamplerParameterIuiv -typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIVPROC)(GLuint sampler, GLenum pname, GLint *params); -GLAPI PFNGLGETSAMPLERPARAMETERIVPROC glad_glGetSamplerParameteriv; -#define glGetSamplerParameteriv glad_glGetSamplerParameteriv -typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIIVPROC)(GLuint sampler, GLenum pname, GLint *params); -GLAPI PFNGLGETSAMPLERPARAMETERIIVPROC glad_glGetSamplerParameterIiv; -#define glGetSamplerParameterIiv glad_glGetSamplerParameterIiv -typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERFVPROC)(GLuint sampler, GLenum pname, GLfloat *params); -GLAPI PFNGLGETSAMPLERPARAMETERFVPROC glad_glGetSamplerParameterfv; -#define glGetSamplerParameterfv glad_glGetSamplerParameterfv -typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIUIVPROC)(GLuint sampler, GLenum pname, GLuint *params); -GLAPI PFNGLGETSAMPLERPARAMETERIUIVPROC glad_glGetSamplerParameterIuiv; -#define glGetSamplerParameterIuiv glad_glGetSamplerParameterIuiv -typedef void (APIENTRYP PFNGLQUERYCOUNTERPROC)(GLuint id, GLenum target); -GLAPI PFNGLQUERYCOUNTERPROC glad_glQueryCounter; -#define glQueryCounter glad_glQueryCounter -typedef void (APIENTRYP PFNGLGETQUERYOBJECTI64VPROC)(GLuint id, GLenum pname, GLint64 *params); -GLAPI PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v; -#define glGetQueryObjecti64v glad_glGetQueryObjecti64v -typedef void (APIENTRYP PFNGLGETQUERYOBJECTUI64VPROC)(GLuint id, GLenum pname, GLuint64 *params); -GLAPI PFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v; -#define glGetQueryObjectui64v glad_glGetQueryObjectui64v -typedef void (APIENTRYP PFNGLVERTEXATTRIBDIVISORPROC)(GLuint index, GLuint divisor); -GLAPI PFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor; -#define glVertexAttribDivisor glad_glVertexAttribDivisor -typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value); -GLAPI PFNGLVERTEXATTRIBP1UIPROC glad_glVertexAttribP1ui; -#define glVertexAttribP1ui glad_glVertexAttribP1ui -typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint *value); -GLAPI PFNGLVERTEXATTRIBP1UIVPROC glad_glVertexAttribP1uiv; -#define glVertexAttribP1uiv glad_glVertexAttribP1uiv -typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value); -GLAPI PFNGLVERTEXATTRIBP2UIPROC glad_glVertexAttribP2ui; -#define glVertexAttribP2ui glad_glVertexAttribP2ui -typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint *value); -GLAPI PFNGLVERTEXATTRIBP2UIVPROC glad_glVertexAttribP2uiv; -#define glVertexAttribP2uiv glad_glVertexAttribP2uiv -typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value); -GLAPI PFNGLVERTEXATTRIBP3UIPROC glad_glVertexAttribP3ui; -#define glVertexAttribP3ui glad_glVertexAttribP3ui -typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint *value); -GLAPI PFNGLVERTEXATTRIBP3UIVPROC glad_glVertexAttribP3uiv; -#define glVertexAttribP3uiv glad_glVertexAttribP3uiv -typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value); -GLAPI PFNGLVERTEXATTRIBP4UIPROC glad_glVertexAttribP4ui; -#define glVertexAttribP4ui glad_glVertexAttribP4ui -typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint *value); -GLAPI PFNGLVERTEXATTRIBP4UIVPROC glad_glVertexAttribP4uiv; -#define glVertexAttribP4uiv glad_glVertexAttribP4uiv -typedef void (APIENTRYP PFNGLVERTEXP2UIPROC)(GLenum type, GLuint value); -GLAPI PFNGLVERTEXP2UIPROC glad_glVertexP2ui; -#define glVertexP2ui glad_glVertexP2ui -typedef void (APIENTRYP PFNGLVERTEXP2UIVPROC)(GLenum type, const GLuint *value); -GLAPI PFNGLVERTEXP2UIVPROC glad_glVertexP2uiv; -#define glVertexP2uiv glad_glVertexP2uiv -typedef void (APIENTRYP PFNGLVERTEXP3UIPROC)(GLenum type, GLuint value); -GLAPI PFNGLVERTEXP3UIPROC glad_glVertexP3ui; -#define glVertexP3ui glad_glVertexP3ui -typedef void (APIENTRYP PFNGLVERTEXP3UIVPROC)(GLenum type, const GLuint *value); -GLAPI PFNGLVERTEXP3UIVPROC glad_glVertexP3uiv; -#define glVertexP3uiv glad_glVertexP3uiv -typedef void (APIENTRYP PFNGLVERTEXP4UIPROC)(GLenum type, GLuint value); -GLAPI PFNGLVERTEXP4UIPROC glad_glVertexP4ui; -#define glVertexP4ui glad_glVertexP4ui -typedef void (APIENTRYP PFNGLVERTEXP4UIVPROC)(GLenum type, const GLuint *value); -GLAPI PFNGLVERTEXP4UIVPROC glad_glVertexP4uiv; -#define glVertexP4uiv glad_glVertexP4uiv -typedef void (APIENTRYP PFNGLTEXCOORDP1UIPROC)(GLenum type, GLuint coords); -GLAPI PFNGLTEXCOORDP1UIPROC glad_glTexCoordP1ui; -#define glTexCoordP1ui glad_glTexCoordP1ui -typedef void (APIENTRYP PFNGLTEXCOORDP1UIVPROC)(GLenum type, const GLuint *coords); -GLAPI PFNGLTEXCOORDP1UIVPROC glad_glTexCoordP1uiv; -#define glTexCoordP1uiv glad_glTexCoordP1uiv -typedef void (APIENTRYP PFNGLTEXCOORDP2UIPROC)(GLenum type, GLuint coords); -GLAPI PFNGLTEXCOORDP2UIPROC glad_glTexCoordP2ui; -#define glTexCoordP2ui glad_glTexCoordP2ui -typedef void (APIENTRYP PFNGLTEXCOORDP2UIVPROC)(GLenum type, const GLuint *coords); -GLAPI PFNGLTEXCOORDP2UIVPROC glad_glTexCoordP2uiv; -#define glTexCoordP2uiv glad_glTexCoordP2uiv -typedef void (APIENTRYP PFNGLTEXCOORDP3UIPROC)(GLenum type, GLuint coords); -GLAPI PFNGLTEXCOORDP3UIPROC glad_glTexCoordP3ui; -#define glTexCoordP3ui glad_glTexCoordP3ui -typedef void (APIENTRYP PFNGLTEXCOORDP3UIVPROC)(GLenum type, const GLuint *coords); -GLAPI PFNGLTEXCOORDP3UIVPROC glad_glTexCoordP3uiv; -#define glTexCoordP3uiv glad_glTexCoordP3uiv -typedef void (APIENTRYP PFNGLTEXCOORDP4UIPROC)(GLenum type, GLuint coords); -GLAPI PFNGLTEXCOORDP4UIPROC glad_glTexCoordP4ui; -#define glTexCoordP4ui glad_glTexCoordP4ui -typedef void (APIENTRYP PFNGLTEXCOORDP4UIVPROC)(GLenum type, const GLuint *coords); -GLAPI PFNGLTEXCOORDP4UIVPROC glad_glTexCoordP4uiv; -#define glTexCoordP4uiv glad_glTexCoordP4uiv -typedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIPROC)(GLenum texture, GLenum type, GLuint coords); -GLAPI PFNGLMULTITEXCOORDP1UIPROC glad_glMultiTexCoordP1ui; -#define glMultiTexCoordP1ui glad_glMultiTexCoordP1ui -typedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIVPROC)(GLenum texture, GLenum type, const GLuint *coords); -GLAPI PFNGLMULTITEXCOORDP1UIVPROC glad_glMultiTexCoordP1uiv; -#define glMultiTexCoordP1uiv glad_glMultiTexCoordP1uiv -typedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIPROC)(GLenum texture, GLenum type, GLuint coords); -GLAPI PFNGLMULTITEXCOORDP2UIPROC glad_glMultiTexCoordP2ui; -#define glMultiTexCoordP2ui glad_glMultiTexCoordP2ui -typedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIVPROC)(GLenum texture, GLenum type, const GLuint *coords); -GLAPI PFNGLMULTITEXCOORDP2UIVPROC glad_glMultiTexCoordP2uiv; -#define glMultiTexCoordP2uiv glad_glMultiTexCoordP2uiv -typedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIPROC)(GLenum texture, GLenum type, GLuint coords); -GLAPI PFNGLMULTITEXCOORDP3UIPROC glad_glMultiTexCoordP3ui; -#define glMultiTexCoordP3ui glad_glMultiTexCoordP3ui -typedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIVPROC)(GLenum texture, GLenum type, const GLuint *coords); -GLAPI PFNGLMULTITEXCOORDP3UIVPROC glad_glMultiTexCoordP3uiv; -#define glMultiTexCoordP3uiv glad_glMultiTexCoordP3uiv -typedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIPROC)(GLenum texture, GLenum type, GLuint coords); -GLAPI PFNGLMULTITEXCOORDP4UIPROC glad_glMultiTexCoordP4ui; -#define glMultiTexCoordP4ui glad_glMultiTexCoordP4ui -typedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIVPROC)(GLenum texture, GLenum type, const GLuint *coords); -GLAPI PFNGLMULTITEXCOORDP4UIVPROC glad_glMultiTexCoordP4uiv; -#define glMultiTexCoordP4uiv glad_glMultiTexCoordP4uiv -typedef void (APIENTRYP PFNGLNORMALP3UIPROC)(GLenum type, GLuint coords); -GLAPI PFNGLNORMALP3UIPROC glad_glNormalP3ui; -#define glNormalP3ui glad_glNormalP3ui -typedef void (APIENTRYP PFNGLNORMALP3UIVPROC)(GLenum type, const GLuint *coords); -GLAPI PFNGLNORMALP3UIVPROC glad_glNormalP3uiv; -#define glNormalP3uiv glad_glNormalP3uiv -typedef void (APIENTRYP PFNGLCOLORP3UIPROC)(GLenum type, GLuint color); -GLAPI PFNGLCOLORP3UIPROC glad_glColorP3ui; -#define glColorP3ui glad_glColorP3ui -typedef void (APIENTRYP PFNGLCOLORP3UIVPROC)(GLenum type, const GLuint *color); -GLAPI PFNGLCOLORP3UIVPROC glad_glColorP3uiv; -#define glColorP3uiv glad_glColorP3uiv -typedef void (APIENTRYP PFNGLCOLORP4UIPROC)(GLenum type, GLuint color); -GLAPI PFNGLCOLORP4UIPROC glad_glColorP4ui; -#define glColorP4ui glad_glColorP4ui -typedef void (APIENTRYP PFNGLCOLORP4UIVPROC)(GLenum type, const GLuint *color); -GLAPI PFNGLCOLORP4UIVPROC glad_glColorP4uiv; -#define glColorP4uiv glad_glColorP4uiv -typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIPROC)(GLenum type, GLuint color); -GLAPI PFNGLSECONDARYCOLORP3UIPROC glad_glSecondaryColorP3ui; -#define glSecondaryColorP3ui glad_glSecondaryColorP3ui -typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIVPROC)(GLenum type, const GLuint *color); -GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv; -#define glSecondaryColorP3uiv glad_glSecondaryColorP3uiv -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/dpf/dgl/src/pugl-upstream/examples/glad/khrplatform.h b/dpf/dgl/src/pugl-upstream/examples/glad/khrplatform.h deleted file mode 100644 index 5b55ea2..0000000 --- a/dpf/dgl/src/pugl-upstream/examples/glad/khrplatform.h +++ /dev/null @@ -1,290 +0,0 @@ -#ifndef __khrplatform_h_ -#define __khrplatform_h_ - -/* -** Copyright (c) 2008-2018 The Khronos Group Inc. -** -** Permission is hereby granted, free of charge, to any person obtaining a -** copy of this software and/or associated documentation files (the -** "Materials"), to deal in the Materials without restriction, including -** without limitation the rights to use, copy, modify, merge, publish, -** distribute, sublicense, and/or sell copies of the Materials, and to -** permit persons to whom the Materials are furnished to do so, subject to -** the following conditions: -** -** The above copyright notice and this permission notice shall be included -** in all copies or substantial portions of the Materials. -** -** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. -*/ - -/* Khronos platform-specific types and definitions. - * - * The master copy of khrplatform.h is maintained in the Khronos EGL - * Registry repository at https://github.com/KhronosGroup/EGL-Registry - * The last semantic modification to khrplatform.h was at commit ID: - * 67a3e0864c2d75ea5287b9f3d2eb74a745936692 - * - * Adopters may modify this file to suit their platform. Adopters are - * encouraged to submit platform specific modifications to the Khronos - * group so that they can be included in future versions of this file. - * Please submit changes by filing pull requests or issues on - * the EGL Registry repository linked above. - * - * - * See the Implementer's Guidelines for information about where this file - * should be located on your system and for more details of its use: - * http://www.khronos.org/registry/implementers_guide.pdf - * - * This file should be included as - * #include - * by Khronos client API header files that use its types and defines. - * - * The types in khrplatform.h should only be used to define API-specific types. - * - * Types defined in khrplatform.h: - * khronos_int8_t signed 8 bit - * khronos_uint8_t unsigned 8 bit - * khronos_int16_t signed 16 bit - * khronos_uint16_t unsigned 16 bit - * khronos_int32_t signed 32 bit - * khronos_uint32_t unsigned 32 bit - * khronos_int64_t signed 64 bit - * khronos_uint64_t unsigned 64 bit - * khronos_intptr_t signed same number of bits as a pointer - * khronos_uintptr_t unsigned same number of bits as a pointer - * khronos_ssize_t signed size - * khronos_usize_t unsigned size - * khronos_float_t signed 32 bit floating point - * khronos_time_ns_t unsigned 64 bit time in nanoseconds - * khronos_utime_nanoseconds_t unsigned time interval or absolute time in - * nanoseconds - * khronos_stime_nanoseconds_t signed time interval in nanoseconds - * khronos_boolean_enum_t enumerated boolean type. This should - * only be used as a base type when a client API's boolean type is - * an enum. Client APIs which use an integer or other type for - * booleans cannot use this as the base type for their boolean. - * - * Tokens defined in khrplatform.h: - * - * KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values. - * - * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0. - * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0. - * - * Calling convention macros defined in this file: - * KHRONOS_APICALL - * KHRONOS_APIENTRY - * KHRONOS_APIATTRIBUTES - * - * These may be used in function prototypes as: - * - * KHRONOS_APICALL void KHRONOS_APIENTRY funcname( - * int arg1, - * int arg2) KHRONOS_APIATTRIBUTES; - */ - -#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC) -# define KHRONOS_STATIC 1 -#endif - -/*------------------------------------------------------------------------- - * Definition of KHRONOS_APICALL - *------------------------------------------------------------------------- - * This precedes the return type of the function in the function prototype. - */ -#if defined(KHRONOS_STATIC) - /* If the preprocessor constant KHRONOS_STATIC is defined, make the - * header compatible with static linking. */ -# define KHRONOS_APICALL -#elif defined(_WIN32) -# define KHRONOS_APICALL __declspec(dllimport) -#elif defined (__SYMBIAN32__) -# define KHRONOS_APICALL IMPORT_C -#elif defined(__ANDROID__) -# define KHRONOS_APICALL __attribute__((visibility("default"))) -#else -# define KHRONOS_APICALL -#endif - -/*------------------------------------------------------------------------- - * Definition of KHRONOS_APIENTRY - *------------------------------------------------------------------------- - * This follows the return type of the function and precedes the function - * name in the function prototype. - */ -#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(KHRONOS_STATIC) - /* Win32 but not WinCE */ -# define KHRONOS_APIENTRY __stdcall -#else -# define KHRONOS_APIENTRY -#endif - -/*------------------------------------------------------------------------- - * Definition of KHRONOS_APIATTRIBUTES - *------------------------------------------------------------------------- - * This follows the closing parenthesis of the function prototype arguments. - */ -#if defined (__ARMCC_2__) -#define KHRONOS_APIATTRIBUTES __softfp -#else -#define KHRONOS_APIATTRIBUTES -#endif - -/*------------------------------------------------------------------------- - * basic type definitions - *-----------------------------------------------------------------------*/ -#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__) - - -/* - * Using - */ -#include -typedef int32_t khronos_int32_t; -typedef uint32_t khronos_uint32_t; -typedef int64_t khronos_int64_t; -typedef uint64_t khronos_uint64_t; -#define KHRONOS_SUPPORT_INT64 1 -#define KHRONOS_SUPPORT_FLOAT 1 - -#elif defined(__VMS ) || defined(__sgi) - -/* - * Using - */ -#include -typedef int32_t khronos_int32_t; -typedef uint32_t khronos_uint32_t; -typedef int64_t khronos_int64_t; -typedef uint64_t khronos_uint64_t; -#define KHRONOS_SUPPORT_INT64 1 -#define KHRONOS_SUPPORT_FLOAT 1 - -#elif defined(_WIN32) && !defined(__SCITECH_SNAP__) - -/* - * Win32 - */ -typedef __int32 khronos_int32_t; -typedef unsigned __int32 khronos_uint32_t; -typedef __int64 khronos_int64_t; -typedef unsigned __int64 khronos_uint64_t; -#define KHRONOS_SUPPORT_INT64 1 -#define KHRONOS_SUPPORT_FLOAT 1 - -#elif defined(__sun__) || defined(__digital__) - -/* - * Sun or Digital - */ -typedef int khronos_int32_t; -typedef unsigned int khronos_uint32_t; -#if defined(__arch64__) || defined(_LP64) -typedef long int khronos_int64_t; -typedef unsigned long int khronos_uint64_t; -#else -typedef long long int khronos_int64_t; -typedef unsigned long long int khronos_uint64_t; -#endif /* __arch64__ */ -#define KHRONOS_SUPPORT_INT64 1 -#define KHRONOS_SUPPORT_FLOAT 1 - -#elif 0 - -/* - * Hypothetical platform with no float or int64 support - */ -typedef int khronos_int32_t; -typedef unsigned int khronos_uint32_t; -#define KHRONOS_SUPPORT_INT64 0 -#define KHRONOS_SUPPORT_FLOAT 0 - -#else - -/* - * Generic fallback - */ -#include -typedef int32_t khronos_int32_t; -typedef uint32_t khronos_uint32_t; -typedef int64_t khronos_int64_t; -typedef uint64_t khronos_uint64_t; -#define KHRONOS_SUPPORT_INT64 1 -#define KHRONOS_SUPPORT_FLOAT 1 - -#endif - - -/* - * Types that are (so far) the same on all platforms - */ -typedef signed char khronos_int8_t; -typedef unsigned char khronos_uint8_t; -typedef signed short int khronos_int16_t; -typedef unsigned short int khronos_uint16_t; - -/* - * Types that differ between LLP64 and LP64 architectures - in LLP64, - * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears - * to be the only LLP64 architecture in current use. - */ -#ifdef _WIN64 -typedef signed long long int khronos_intptr_t; -typedef unsigned long long int khronos_uintptr_t; -typedef signed long long int khronos_ssize_t; -typedef unsigned long long int khronos_usize_t; -#else -typedef signed long int khronos_intptr_t; -typedef unsigned long int khronos_uintptr_t; -typedef signed long int khronos_ssize_t; -typedef unsigned long int khronos_usize_t; -#endif - -#if KHRONOS_SUPPORT_FLOAT -/* - * Float type - */ -typedef float khronos_float_t; -#endif - -#if KHRONOS_SUPPORT_INT64 -/* Time types - * - * These types can be used to represent a time interval in nanoseconds or - * an absolute Unadjusted System Time. Unadjusted System Time is the number - * of nanoseconds since some arbitrary system event (e.g. since the last - * time the system booted). The Unadjusted System Time is an unsigned - * 64 bit value that wraps back to 0 every 584 years. Time intervals - * may be either signed or unsigned. - */ -typedef khronos_uint64_t khronos_utime_nanoseconds_t; -typedef khronos_int64_t khronos_stime_nanoseconds_t; -#endif - -/* - * Dummy value used to pad enum types to 32 bits. - */ -#ifndef KHRONOS_MAX_ENUM -#define KHRONOS_MAX_ENUM 0x7FFFFFFF -#endif - -/* - * Enumerated boolean type - * - * Values other than zero should be considered to be true. Therefore - * comparisons should not be made against KHRONOS_TRUE. - */ -typedef enum { - KHRONOS_FALSE = 0, - KHRONOS_TRUE = 1, - KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM -} khronos_boolean_enum_t; - -#endif /* __khrplatform_h_ */ diff --git a/dpf/dgl/src/pugl-upstream/examples/meson.build b/dpf/dgl/src/pugl-upstream/examples/meson.build deleted file mode 100644 index 6984033..0000000 --- a/dpf/dgl/src/pugl-upstream/examples/meson.build +++ /dev/null @@ -1,124 +0,0 @@ -data_dir = get_option('prefix') / get_option('datadir') / 'pugl-0' -example_defines = ['-DPUGL_DATA_DIR="@0@"'.format(data_dir)] - -gl_examples = [ - 'pugl_cpp_demo.cpp', - 'pugl_embed_demo.c', - 'pugl_print_events.c', - 'pugl_shader_demo.c', - 'pugl_window_demo.c', -] - -cairo_examples = [ - 'pugl_cairo_demo.c' -] - -vulkan_examples = [ - 'pugl_vulkan_cpp_demo.cpp', - 'pugl_vulkan_demo.c', -] - -includes = include_directories( - '..', - '../bindings/cpp/include', - '../include', -) - -# Suppress some additional C warnings in examples -example_c_args = [] -if get_option('strict') - if cc.get_id() == 'clang' - example_c_args += [ - '-Wno-float-equal', - '-Wno-padded', - ] - elif cc.get_id() == 'gcc' - example_c_args += [ - '-Wno-float-equal', - '-Wno-padded', - ] - endif - - example_c_args = cc.get_supported_arguments(example_c_args) -endif - -# Suppress some additional C++ warnings in examples -example_cpp_args = [] -if is_variable('cpp') - if cpp.get_id() == 'clang' - example_cpp_args += [ - '-Wno-documentation', # Cairo - '-Wno-documentation-unknown-command', # Cairo - '-Wno-old-style-cast', - '-Wno-padded', - '-Wno-reserved-id-macro', - '-Wno-switch-enum', - ] - elif cpp.get_id() == 'gcc' - example_cpp_args += [ - '-Wno-effc++', - '-Wno-old-style-cast', - '-Wno-padded', - '-Wno-switch-default', - '-Wno-switch-enum', - '-Wno-unused-const-variable', - '-Wno-useless-cast', - ] - endif - - example_cpp_args = cpp.get_supported_arguments(example_cpp_args) -endif - -subdir('shaders') - -# Build GL examples -if opengl_dep.found() - foreach example : gl_examples - source = [example] - target = example.split('.')[0] - dependencies = [gl_backend_dep] - - if target == 'pugl_shader_demo' - source += ['file_utils.c', 'glad/glad.c'] - dependencies += [dl_dep] - elif target == 'pugl_print_events' - dependencies += [stub_backend_dep] - endif - - executable(target, source, - include_directories: includes, - c_args: example_defines + example_c_args, - cpp_args: example_defines + example_cpp_args, - dependencies: dependencies) - endforeach -endif - -# Build Cairo examples -if cairo_dep.found() - foreach example : cairo_examples - target = example.split('.')[0] - executable(target, example, - include_directories: includes, - c_args: example_defines + example_c_args, - dependencies: [pugl_dep, cairo_backend_dep]) - endforeach -endif - -# Build Vulkan examples -if vulkan_dep.found() - foreach example : vulkan_examples - source = [example] - target = example.split('.')[0] - dependencies = [dl_dep, vulkan_backend_dep] - - if target == 'pugl_vulkan_cpp_demo' - source += ['file_utils.c'] - endif - - executable(target, source, - include_directories: includes, - c_args: example_defines + example_c_args, - cpp_args: example_defines + example_cpp_args, - dependencies: dependencies) - endforeach -endif diff --git a/dpf/dgl/src/pugl-upstream/examples/pugl_cairo_demo.c b/dpf/dgl/src/pugl-upstream/examples/pugl_cairo_demo.c deleted file mode 100644 index 1d998a8..0000000 --- a/dpf/dgl/src/pugl-upstream/examples/pugl_cairo_demo.c +++ /dev/null @@ -1,261 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#include "demo_utils.h" -#include "test/test_utils.h" - -#include "pugl/cairo.h" -#include "pugl/pugl.h" - -#include - -#include -#include -#include -#include - -typedef struct { - PuglWorld* world; - PuglTestOptions opts; - unsigned framesDrawn; - int quit; - bool entered; - bool mouseDown; -} PuglTestApp; - -typedef struct { - int x; - int y; - int w; - int h; - const char* label; -} Button; - -static const Button buttons[] = {{128, 128, 64, 64, "1"}, - {384, 128, 64, 64, "2"}, - {128, 384, 64, 64, "3"}, - {384, 384, 64, 64, "4"}, - {0, 0, 0, 0, NULL}}; - -static void -roundedBox(cairo_t* cr, double x, double y, double w, double h) -{ - static const double radius = 10; - static const double degrees = 3.14159265 / 180.0; - - cairo_new_sub_path(cr); - cairo_arc(cr, x + w - radius, y + radius, radius, -90 * degrees, 0 * degrees); - - cairo_arc( - cr, x + w - radius, y + h - radius, radius, 0 * degrees, 90 * degrees); - - cairo_arc( - cr, x + radius, y + h - radius, radius, 90 * degrees, 180 * degrees); - - cairo_arc(cr, x + radius, y + radius, radius, 180 * degrees, 270 * degrees); - cairo_close_path(cr); -} - -static void -buttonDraw(PuglTestApp* app, cairo_t* cr, const Button* but, const double time) -{ - cairo_save(cr); - cairo_translate(cr, but->x, but->y); - cairo_rotate(cr, sin(time) * 3.141592); - - // Draw base - if (app->mouseDown) { - cairo_set_source_rgba(cr, 0.4, 0.9, 0.1, 1); - } else { - cairo_set_source_rgba(cr, 0.3, 0.5, 0.1, 1); - } - roundedBox(cr, 0, 0, but->w, but->h); - cairo_fill_preserve(cr); - - // Draw border - cairo_set_source_rgba(cr, 0.4, 0.9, 0.1, 1); - cairo_set_line_width(cr, 4.0); - cairo_stroke(cr); - - // Draw label - cairo_text_extents_t extents; - cairo_set_font_size(cr, 32.0); - cairo_text_extents(cr, but->label, &extents); - cairo_move_to(cr, - (but->w / 2.0) - extents.width / 2, - (but->h / 2.0) + extents.height / 2); - cairo_set_source_rgba(cr, 0, 0, 0, 1); - cairo_show_text(cr, but->label); - - cairo_restore(cr); -} - -static void -postButtonRedisplay(PuglView* view) -{ - const PuglRect frame = puglGetFrame(view); - const double width = frame.width; - const double height = frame.height; - const double scaleX = (width - (512 / width)) / 512.0; - const double scaleY = (height - (512 / height)) / 512.0; - - for (const Button* b = buttons; b->label; ++b) { - const double span = sqrt(b->w * b->w + b->h * b->h); - const PuglRect rect = {(b->x - span) * scaleX, - (b->y - span) * scaleY, - span * 2.0 * scaleX, - span * 2.0 * scaleY}; - - puglPostRedisplayRect(view, rect); - } -} - -static void -onDisplay(PuglTestApp* app, PuglView* view, const PuglExposeEvent* event) -{ - cairo_t* cr = (cairo_t*)puglGetContext(view); - - cairo_rectangle(cr, event->x, event->y, event->width, event->height); - cairo_clip_preserve(cr); - - // Draw background - const PuglRect frame = puglGetFrame(view); - const double width = frame.width; - const double height = frame.height; - if (app->entered) { - cairo_set_source_rgb(cr, 0.1, 0.1, 0.1); - } else { - cairo_set_source_rgb(cr, 0, 0, 0); - } - cairo_fill(cr); - - // Scale to view size - const double scaleX = (width - (512 / width)) / 512.0; - const double scaleY = (height - (512 / height)) / 512.0; - cairo_scale(cr, scaleX, scaleY); - - // Draw button - for (const Button* b = buttons; b->label; ++b) { - buttonDraw( - app, cr, b, app->opts.continuous ? puglGetTime(app->world) : 0.0); - } - - ++app->framesDrawn; -} - -static void -onClose(PuglView* view) -{ - PuglTestApp* app = (PuglTestApp*)puglGetHandle(view); - - app->quit = 1; -} - -static PuglStatus -onEvent(PuglView* view, const PuglEvent* event) -{ - PuglTestApp* app = (PuglTestApp*)puglGetHandle(view); - - printEvent(event, "Event: ", app->opts.verbose); - - switch (event->type) { - case PUGL_KEY_PRESS: - if (event->key.key == 'q' || event->key.key == PUGL_KEY_ESCAPE) { - app->quit = 1; - } - break; - case PUGL_BUTTON_PRESS: - app->mouseDown = true; - postButtonRedisplay(view); - break; - case PUGL_BUTTON_RELEASE: - app->mouseDown = false; - postButtonRedisplay(view); - break; - case PUGL_POINTER_IN: - app->entered = true; - puglPostRedisplay(view); - break; - case PUGL_POINTER_OUT: - app->entered = false; - puglPostRedisplay(view); - break; - case PUGL_UPDATE: - if (app->opts.continuous) { - puglPostRedisplay(view); - } - break; - case PUGL_EXPOSE: - onDisplay(app, view, &event->expose); - break; - case PUGL_CLOSE: - onClose(view); - break; - default: - break; - } - - return PUGL_SUCCESS; -} - -int -main(int argc, char** argv) -{ - PuglTestApp app; - memset(&app, 0, sizeof(app)); - - app.opts = puglParseTestOptions(&argc, &argv); - if (app.opts.help) { - puglPrintTestUsage("pugl_test", ""); - return 1; - } - - app.world = puglNewWorld(PUGL_PROGRAM, 0); - puglSetClassName(app.world, "PuglCairoTest"); - - PuglView* view = puglNewView(app.world); - - puglSetWindowTitle(view, "Pugl Cairo Demo"); - puglSetDefaultSize(view, 512, 512); - puglSetMinSize(view, 256, 256); - puglSetMaxSize(view, 2048, 2048); - puglSetViewHint(view, PUGL_RESIZABLE, app.opts.resizable); - puglSetHandle(view, &app); - puglSetBackend(view, puglCairoBackend()); - puglSetViewHint(view, PUGL_IGNORE_KEY_REPEAT, app.opts.ignoreKeyRepeat); - puglSetEventFunc(view, onEvent); - - PuglStatus st = puglRealize(view); - if (st) { - return logError("Failed to create window (%s)\n", puglStrerror(st)); - } - - puglShow(view); - - PuglFpsPrinter fpsPrinter = {puglGetTime(app.world)}; - const double timeout = app.opts.continuous ? (1 / 60.0) : -1.0; - while (!app.quit) { - puglUpdate(app.world, timeout); - - if (app.opts.continuous) { - puglPrintFps(app.world, &fpsPrinter, &app.framesDrawn); - } - } - - puglFreeView(view); - puglFreeWorld(app.world); - return 0; -} diff --git a/dpf/dgl/src/pugl-upstream/examples/pugl_cpp_demo.cpp b/dpf/dgl/src/pugl-upstream/examples/pugl_cpp_demo.cpp deleted file mode 100644 index 552094f..0000000 --- a/dpf/dgl/src/pugl-upstream/examples/pugl_cpp_demo.cpp +++ /dev/null @@ -1,153 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#include "cube_view.h" -#include "demo_utils.h" -#include "test/test_utils.h" - -#include "pugl/gl.hpp" -#include "pugl/pugl.h" -#include "pugl/pugl.hpp" - -#include - -class CubeView : public pugl::View -{ -public: - explicit CubeView(pugl::World& world) - : pugl::View{world} - { - setEventHandler(*this); - } - - template - pugl::Status onEvent(const pugl::Event&) noexcept - { - return pugl::Status::success; - } - - static pugl::Status onEvent(const pugl::ConfigureEvent& event) noexcept; - pugl::Status onEvent(const pugl::UpdateEvent& event) noexcept; - pugl::Status onEvent(const pugl::ExposeEvent& event) noexcept; - pugl::Status onEvent(const pugl::KeyPressEvent& event) noexcept; - pugl::Status onEvent(const pugl::CloseEvent& event) noexcept; - - bool quit() const { return _quit; } - -private: - double _xAngle{0.0}; - double _yAngle{0.0}; - double _lastDrawTime{0.0}; - bool _quit{false}; -}; - -pugl::Status -CubeView::onEvent(const pugl::ConfigureEvent& event) noexcept -{ - reshapeCube(static_cast(event.width), - static_cast(event.height)); - - return pugl::Status::success; -} - -pugl::Status -CubeView::onEvent(const pugl::UpdateEvent&) noexcept -{ - // Normally, we would post a redisplay: - // return postRedisplay(); - - // But for testing, use sendEvent() instead: - return sendEvent( - pugl::ExposeEvent{0u, 0.0, 0.0, frame().width, frame().height}); -} - -pugl::Status -CubeView::onEvent(const pugl::ExposeEvent&) noexcept -{ - const double thisTime = world().time(); - const double dTime = thisTime - _lastDrawTime; - const double dAngle = dTime * 100.0; - - _xAngle = fmod(_xAngle + dAngle, 360.0); - _yAngle = fmod(_yAngle + dAngle, 360.0); - displayCube(cobj(), - 8.0f, - static_cast(_xAngle), - static_cast(_yAngle), - false); - - _lastDrawTime = thisTime; - - return pugl::Status::success; -} - -pugl::Status -CubeView::onEvent(const pugl::KeyPressEvent& event) noexcept -{ - if (event.key == PUGL_KEY_ESCAPE || event.key == 'q') { - _quit = true; - } - - return pugl::Status::success; -} - -pugl::Status -CubeView::onEvent(const pugl::CloseEvent&) noexcept -{ - _quit = true; - - return pugl::Status::success; -} - -int -main(int argc, char** argv) -{ - const PuglTestOptions opts = puglParseTestOptions(&argc, &argv); - if (opts.help) { - puglPrintTestUsage("pugl_cpp_demo", ""); - return 1; - } - - pugl::World world{pugl::WorldType::program}; - CubeView view{world}; - PuglFpsPrinter fpsPrinter{}; - - world.setClassName("PuglCppTest"); - - view.setWindowTitle("Pugl C++ Test"); - view.setDefaultSize(512, 512); - view.setMinSize(64, 64); - view.setMaxSize(256, 256); - view.setAspectRatio(1, 1, 16, 9); - view.setBackend(pugl::glBackend()); - view.setHint(pugl::ViewHint::resizable, opts.resizable); - view.setHint(pugl::ViewHint::samples, opts.samples); - view.setHint(pugl::ViewHint::doubleBuffer, opts.doubleBuffer); - view.setHint(pugl::ViewHint::swapInterval, opts.sync); - view.setHint(pugl::ViewHint::ignoreKeyRepeat, opts.ignoreKeyRepeat); - view.realize(); - view.show(); - - unsigned framesDrawn = 0; - while (!view.quit()) { - world.update(0.0); - - ++framesDrawn; - puglPrintFps(world.cobj(), &fpsPrinter, &framesDrawn); - } - - return 0; -} diff --git a/dpf/dgl/src/pugl-upstream/examples/pugl_cursor_demo.c b/dpf/dgl/src/pugl-upstream/examples/pugl_cursor_demo.c deleted file mode 100644 index 97e3b9f..0000000 --- a/dpf/dgl/src/pugl-upstream/examples/pugl_cursor_demo.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#include "test/test_utils.h" - -#include "pugl/gl.h" -#include "pugl/pugl.h" - -#include - -static const int N_CURSORS = 7; -static const int N_ROWS = 2; -static const int N_COLS = 4; - -typedef struct { - PuglWorld* world; - PuglTestOptions opts; - bool quit; -} PuglTestApp; - -static void -onConfigure(const double width, const double height) -{ - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LESS); - glClearColor(0.2f, 0.2f, 0.2f, 1.0f); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glViewport(0, 0, (int)width, (int)height); -} - -static void -onExpose(void) -{ - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glColor3f(0.6f, 0.6f, 0.6f); - - for (int row = 1; row < N_ROWS; ++row) { - const float y = (float)row * (2.0f / (float)N_ROWS) - 1.0f; - glBegin(GL_LINES); - glVertex2f(-1.0f, y); - glVertex2f(1.0f, y); - glEnd(); - } - - for (int col = 1; col < N_COLS; ++col) { - const float x = (float)col * (2.0f / (float)N_COLS) - 1.0f; - glBegin(GL_LINES); - glVertex2f(x, -1.0f); - glVertex2f(x, 1.0f); - glEnd(); - } -} - -static void -onMotion(PuglView* view, double x, double y) -{ - const PuglRect frame = puglGetFrame(view); - int row = (int)(y * N_ROWS / frame.height); - int col = (int)(x * N_COLS / frame.width); - - row = (row < 0) ? 0 : (row >= N_ROWS) ? (N_ROWS - 1) : row; - col = (col < 0) ? 0 : (col >= N_COLS) ? (N_COLS - 1) : col; - - const PuglCursor cursor = (PuglCursor)((row * N_COLS + col) % N_CURSORS); - puglSetCursor(view, cursor); -} - -static PuglStatus -onEvent(PuglView* view, const PuglEvent* event) -{ - PuglTestApp* app = (PuglTestApp*)puglGetHandle(view); - - printEvent(event, "Event: ", app->opts.verbose); - - switch (event->type) { - case PUGL_CONFIGURE: - onConfigure(event->configure.width, event->configure.height); - break; - case PUGL_KEY_PRESS: - if (event->key.key == 'q' || event->key.key == PUGL_KEY_ESCAPE) { - app->quit = 1; - } - break; - case PUGL_MOTION: - onMotion(view, event->motion.x, event->motion.y); - break; - case PUGL_EXPOSE: - onExpose(); - break; - case PUGL_POINTER_OUT: - puglSetCursor(view, PUGL_CURSOR_ARROW); - break; - case PUGL_CLOSE: - app->quit = 1; - break; - default: - break; - } - - return PUGL_SUCCESS; -} - -int -main(int argc, char** argv) -{ - PuglTestApp app = {0}; - - app.opts = puglParseTestOptions(&argc, &argv); - if (app.opts.help) { - puglPrintTestUsage(argv[0], ""); - return 1; - } - - app.world = puglNewWorld(PUGL_PROGRAM, 0); - - puglSetWorldHandle(app.world, &app); - puglSetClassName(app.world, "Pugl Test"); - - PuglView* view = puglNewView(app.world); - - puglSetWindowTitle(view, "Pugl Window Demo"); - puglSetDefaultSize(view, 512, 256); - puglSetMinSize(view, 128, 64); - puglSetMaxSize(view, 512, 256); - puglSetBackend(view, puglGlBackend()); - - puglSetViewHint(view, PUGL_USE_DEBUG_CONTEXT, app.opts.errorChecking); - puglSetViewHint(view, PUGL_RESIZABLE, app.opts.resizable); - puglSetViewHint(view, PUGL_SAMPLES, app.opts.samples); - puglSetViewHint(view, PUGL_DOUBLE_BUFFER, app.opts.doubleBuffer); - puglSetViewHint(view, PUGL_SWAP_INTERVAL, app.opts.sync); - puglSetViewHint(view, PUGL_IGNORE_KEY_REPEAT, app.opts.ignoreKeyRepeat); - puglSetHandle(view, &app); - puglSetEventFunc(view, onEvent); - - const PuglStatus st = puglRealize(view); - if (st) { - return logError("Failed to create window (%s)\n", puglStrerror(st)); - } - - puglShow(view); - - while (!app.quit) { - puglUpdate(app.world, -1.0); - } - - puglFreeView(view); - puglFreeWorld(app.world); - - return 0; -} diff --git a/dpf/dgl/src/pugl-upstream/examples/pugl_embed_demo.c b/dpf/dgl/src/pugl-upstream/examples/pugl_embed_demo.c deleted file mode 100644 index 311ab3b..0000000 --- a/dpf/dgl/src/pugl-upstream/examples/pugl_embed_demo.c +++ /dev/null @@ -1,363 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#include "cube_view.h" -#include "demo_utils.h" -#include "test/test_utils.h" - -#include "pugl/gl.h" -#include "pugl/pugl.h" - -#include -#include -#include -#include -#include - -static const int borderWidth = 64; -static const uintptr_t reverseTimerId = 1u; - -typedef struct { - PuglWorld* world; - PuglView* parent; - PuglView* child; - double xAngle; - double yAngle; - double lastMouseX; - double lastMouseY; - double lastDrawTime; - float dist; - int quit; - bool continuous; - bool mouseEntered; - bool verbose; - bool reversing; -} PuglTestApp; - -// clang-format off - -static const float backgroundVertices[] = { - -1.0f, 1.0f, -1.0f, // Top left - 1.0f, 1.0f, -1.0f, // Top right - -1.0f, -1.0f, -1.0f, // Bottom left - 1.0f, -1.0f, -1.0f, // Bottom right -}; - -static const float backgroundColorVertices[] = { - 0.25f, 0.25f, 0.25f, // Top left - 0.25f, 0.50f, 0.25f, // Top right - 0.25f, 0.50f, 0.25f, // Bottom left - 0.25f, 0.75f, 0.5f, // Bottom right -}; - -// clang-format on - -static PuglRect -getChildFrame(const PuglRect parentFrame) -{ - const PuglRect childFrame = {borderWidth, - borderWidth, - parentFrame.width - 2 * borderWidth, - parentFrame.height - 2 * borderWidth}; - - return childFrame; -} - -static void -onDisplay(PuglView* view) -{ - PuglTestApp* app = (PuglTestApp*)puglGetHandle(view); - - const double thisTime = puglGetTime(app->world); - if (app->continuous) { - const double dTime = - (thisTime - app->lastDrawTime) * (app->reversing ? -1.0 : 1.0); - - app->xAngle = fmod(app->xAngle + dTime * 100.0, 360.0); - app->yAngle = fmod(app->yAngle + dTime * 100.0, 360.0); - } - - displayCube( - view, app->dist, (float)app->xAngle, (float)app->yAngle, app->mouseEntered); - - app->lastDrawTime = thisTime; -} - -static void -swapFocus(PuglTestApp* app) -{ - if (puglHasFocus(app->parent)) { - puglGrabFocus(app->child); - } else { - puglGrabFocus(app->parent); - } - - if (!app->continuous) { - puglPostRedisplay(app->parent); - puglPostRedisplay(app->child); - } -} - -static void -onKeyPress(PuglView* view, const PuglKeyEvent* event, const char* prefix) -{ - PuglTestApp* app = (PuglTestApp*)puglGetHandle(view); - PuglRect frame = puglGetFrame(view); - - if (event->key == '\t') { - swapFocus(app); - } else if (event->key == 'q' || event->key == PUGL_KEY_ESCAPE) { - app->quit = 1; - } else if (event->state & PUGL_MOD_CTRL && event->key == 'c') { - puglSetClipboard(view, NULL, "Pugl test", strlen("Pugl test") + 1); - fprintf(stderr, "%sCopy \"Pugl test\"\n", prefix); - } else if (event->state & PUGL_MOD_CTRL && event->key == 'v') { - const char* type = NULL; - size_t len = 0; - const char* text = (const char*)puglGetClipboard(view, &type, &len); - fprintf(stderr, "%sPaste \"%s\"\n", prefix, text); - } else if (event->state & PUGL_MOD_SHIFT) { - if (event->key == PUGL_KEY_UP) { - frame.height += 10; - } else if (event->key == PUGL_KEY_DOWN) { - frame.height -= 10; - } else if (event->key == PUGL_KEY_LEFT) { - frame.width -= 10; - } else if (event->key == PUGL_KEY_RIGHT) { - frame.width += 10; - } else { - return; - } - puglSetFrame(view, frame); - } else { - if (event->key == PUGL_KEY_UP) { - frame.y -= 10; - } else if (event->key == PUGL_KEY_DOWN) { - frame.y += 10; - } else if (event->key == PUGL_KEY_LEFT) { - frame.x -= 10; - } else if (event->key == PUGL_KEY_RIGHT) { - frame.x += 10; - } else { - return; - } - puglSetFrame(view, frame); - } -} - -static PuglStatus -onParentEvent(PuglView* view, const PuglEvent* event) -{ - PuglTestApp* app = (PuglTestApp*)puglGetHandle(view); - const PuglRect parentFrame = puglGetFrame(view); - - printEvent(event, "Parent: ", app->verbose); - - switch (event->type) { - case PUGL_CONFIGURE: - reshapeCube((float)event->configure.width, (float)event->configure.height); - - puglSetFrame(app->child, getChildFrame(parentFrame)); - break; - case PUGL_UPDATE: - if (app->continuous) { - puglPostRedisplay(view); - } - break; - case PUGL_EXPOSE: - if (puglHasFocus(app->parent)) { - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, backgroundVertices); - glColorPointer(3, GL_FLOAT, 0, backgroundColorVertices); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); - } else { - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } - break; - case PUGL_KEY_PRESS: - onKeyPress(view, &event->key, "Parent: "); - break; - case PUGL_MOTION: - break; - case PUGL_CLOSE: - app->quit = 1; - break; - default: - break; - } - - return PUGL_SUCCESS; -} - -static PuglStatus -onEvent(PuglView* view, const PuglEvent* event) -{ - PuglTestApp* app = (PuglTestApp*)puglGetHandle(view); - - printEvent(event, "Child: ", app->verbose); - - switch (event->type) { - case PUGL_CONFIGURE: - reshapeCube((float)event->configure.width, (float)event->configure.height); - break; - case PUGL_UPDATE: - if (app->continuous) { - puglPostRedisplay(view); - } - break; - case PUGL_EXPOSE: - onDisplay(view); - break; - case PUGL_CLOSE: - app->quit = 1; - break; - case PUGL_KEY_PRESS: - onKeyPress(view, &event->key, "Child: "); - break; - case PUGL_MOTION: - app->xAngle -= event->motion.x - app->lastMouseX; - app->yAngle += event->motion.y - app->lastMouseY; - app->lastMouseX = event->motion.x; - app->lastMouseY = event->motion.y; - if (!app->continuous) { - puglPostRedisplay(view); - puglPostRedisplay(app->parent); - } - break; - case PUGL_SCROLL: - app->dist = fmaxf(10.0f, app->dist + (float)event->scroll.dy); - if (!app->continuous) { - puglPostRedisplay(view); - } - break; - case PUGL_POINTER_IN: - app->mouseEntered = true; - break; - case PUGL_POINTER_OUT: - app->mouseEntered = false; - break; - case PUGL_TIMER: - app->reversing = !app->reversing; - break; - default: - break; - } - - return PUGL_SUCCESS; -} - -int -main(int argc, char** argv) -{ - PuglTestApp app = {0}; - - app.dist = 10; - - const PuglTestOptions opts = puglParseTestOptions(&argc, &argv); - if (opts.help) { - puglPrintTestUsage("pugl_test", ""); - return 1; - } - - app.continuous = opts.continuous; - app.verbose = opts.verbose; - - app.world = puglNewWorld(PUGL_PROGRAM, 0); - app.parent = puglNewView(app.world); - app.child = puglNewView(app.world); - - puglSetClassName(app.world, "Pugl Test"); - - const PuglRect parentFrame = {0, 0, 512, 512}; - puglSetDefaultSize(app.parent, 512, 512); - puglSetMinSize(app.parent, borderWidth * 3, borderWidth * 3); - puglSetMaxSize(app.parent, 1024, 1024); - puglSetAspectRatio(app.parent, 1, 1, 16, 9); - puglSetBackend(app.parent, puglGlBackend()); - - puglSetViewHint(app.parent, PUGL_USE_DEBUG_CONTEXT, opts.errorChecking); - puglSetViewHint(app.parent, PUGL_RESIZABLE, opts.resizable); - puglSetViewHint(app.parent, PUGL_SAMPLES, opts.samples); - puglSetViewHint(app.parent, PUGL_DOUBLE_BUFFER, opts.doubleBuffer); - puglSetViewHint(app.parent, PUGL_SWAP_INTERVAL, opts.sync); - puglSetViewHint(app.parent, PUGL_IGNORE_KEY_REPEAT, opts.ignoreKeyRepeat); - puglSetHandle(app.parent, &app); - puglSetEventFunc(app.parent, onParentEvent); - - PuglStatus st = PUGL_SUCCESS; - const uint8_t title[] = { - 'P', 'u', 'g', 'l', ' ', 'P', 'r', 0xC3, 0xBC, 'f', 'u', 'n', 'g', 0}; - - puglSetWindowTitle(app.parent, (const char*)title); - - if ((st = puglRealize(app.parent))) { - return logError("Failed to create parent window (%s)\n", puglStrerror(st)); - } - - puglSetFrame(app.child, getChildFrame(parentFrame)); - puglSetParentWindow(app.child, puglGetNativeWindow(app.parent)); - - puglSetViewHint(app.child, PUGL_USE_DEBUG_CONTEXT, opts.errorChecking); - puglSetViewHint(app.child, PUGL_SAMPLES, opts.samples); - puglSetViewHint(app.child, PUGL_DOUBLE_BUFFER, opts.doubleBuffer); - puglSetViewHint(app.child, PUGL_SWAP_INTERVAL, opts.sync); - puglSetBackend(app.child, puglGlBackend()); - puglSetViewHint(app.child, PUGL_IGNORE_KEY_REPEAT, opts.ignoreKeyRepeat); - puglSetHandle(app.child, &app); - puglSetEventFunc(app.child, onEvent); - - if ((st = puglRealize(app.child))) { - return logError("Failed to create child window (%s)\n", puglStrerror(st)); - } - - puglShow(app.parent); - puglShow(app.child); - - puglStartTimer(app.child, reverseTimerId, 3.6); - - PuglFpsPrinter fpsPrinter = {puglGetTime(app.world)}; - unsigned framesDrawn = 0; - bool requestedAttention = false; - while (!app.quit) { - const double thisTime = puglGetTime(app.world); - - puglUpdate(app.world, app.continuous ? 0.0 : -1.0); - ++framesDrawn; - - if (!requestedAttention && thisTime > 5.0) { - puglRequestAttention(app.parent); - requestedAttention = true; - } - - if (app.continuous) { - puglPrintFps(app.world, &fpsPrinter, &framesDrawn); - } - } - - puglFreeView(app.child); - puglFreeView(app.parent); - puglFreeWorld(app.world); - - return 0; -} diff --git a/dpf/dgl/src/pugl-upstream/examples/pugl_print_events.c b/dpf/dgl/src/pugl-upstream/examples/pugl_print_events.c deleted file mode 100644 index dfa217e..0000000 --- a/dpf/dgl/src/pugl-upstream/examples/pugl_print_events.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#include "test/test_utils.h" - -#include "pugl/pugl.h" -#include "pugl/stub.h" - -#include -#include - -typedef struct { - PuglWorld* world; - PuglView* view; - int quit; -} PuglPrintEventsApp; - -static PuglStatus -onEvent(PuglView* view, const PuglEvent* event) -{ - PuglPrintEventsApp* app = (PuglPrintEventsApp*)puglGetHandle(view); - - printEvent(event, "Event: ", true); - - switch (event->type) { - case PUGL_CLOSE: - app->quit = 1; - break; - default: - break; - } - - return PUGL_SUCCESS; -} - -int -main(void) -{ - PuglPrintEventsApp app = {NULL, NULL, 0}; - - app.world = puglNewWorld(PUGL_PROGRAM, 0); - app.view = puglNewView(app.world); - - puglSetClassName(app.world, "Pugl Print Events"); - puglSetWindowTitle(app.view, "Pugl Event Printer"); - puglSetDefaultSize(app.view, 512, 512); - puglSetBackend(app.view, puglStubBackend()); - puglSetHandle(app.view, &app); - puglSetEventFunc(app.view, onEvent); - - PuglStatus st = puglRealize(app.view); - if (st) { - return logError("Failed to create window (%s)\n", puglStrerror(st)); - } - - puglShow(app.view); - - while (!app.quit) { - puglUpdate(app.world, -1.0); - } - - puglFreeView(app.view); - puglFreeWorld(app.world); - - return 0; -} diff --git a/dpf/dgl/src/pugl-upstream/examples/pugl_shader_demo.c b/dpf/dgl/src/pugl-upstream/examples/pugl_shader_demo.c deleted file mode 100644 index 2fd9a57..0000000 --- a/dpf/dgl/src/pugl-upstream/examples/pugl_shader_demo.c +++ /dev/null @@ -1,480 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/* - An example of drawing with OpenGL 3/4. - - This is an example of using OpenGL for pixel-perfect 2D drawing. It uses - pixel coordinates for positions and sizes so that things work roughly like a - typical 2D graphics API. - - The program draws a bunch of rectangles with borders, using instancing. - Each rectangle has origin, size, and fill color attributes, which are shared - for all four vertices. On each frame, a single buffer with all the - rectangle data is sent to the GPU, and everything is drawn with a single - draw call. - - This is not particularly realistic or optimal, but serves as a decent rough - benchmark for how much simple geometry you can draw. The number of - rectangles can be given on the command line. For reference, it begins to - struggle to maintain 60 FPS on my machine (1950x + Vega64) with more than - about 100000 rectangles. -*/ - -#include "demo_utils.h" -#include "file_utils.h" -#include "rects.h" -#include "shader_utils.h" -#include "test/test_utils.h" - -#include "glad/glad.h" - -#include "pugl/gl.h" -#include "pugl/pugl.h" - -#include -#include -#include -#include -#include -#include - -static const int defaultWidth = 512; -static const int defaultHeight = 512; -static const uintptr_t resizeTimerId = 1u; - -typedef struct { - mat4 projection; -} RectUniforms; - -typedef struct { - const char* programPath; - PuglWorld* world; - PuglView* view; - PuglTestOptions opts; - size_t numRects; - Rect* rects; - Program drawRect; - GLuint vao; - GLuint vbo; - GLuint instanceVbo; - GLuint ibo; - double lastDrawDuration; - double lastFrameEndTime; - unsigned framesDrawn; - int glMajorVersion; - int glMinorVersion; - int quit; -} PuglTestApp; - -static PuglStatus -setupGl(PuglTestApp* app); - -static void -teardownGl(PuglTestApp* app); - -static void -onConfigure(PuglView* view, double width, double height) -{ - (void)view; - - glEnable(GL_BLEND); - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO); - glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD); - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - glViewport(0, 0, (int)width, (int)height); -} - -static void -onExpose(PuglView* view) -{ - PuglTestApp* app = (PuglTestApp*)puglGetHandle(view); - const PuglRect frame = puglGetFrame(view); - const float width = (float)frame.width; - const float height = (float)frame.height; - const double time = puglGetTime(puglGetWorld(view)); - - // Construct projection matrix for 2D window surface (in pixels) - mat4 proj; - mat4Ortho( - proj, 0.0f, (float)frame.width, 0.0f, (float)frame.height, -1.0f, 1.0f); - - // Clear and bind everything that is the same for every rect - glClear(GL_COLOR_BUFFER_BIT); - glUseProgram(app->drawRect.program); - glBindVertexArray(app->vao); - - for (size_t i = 0; i < app->numRects; ++i) { - moveRect(&app->rects[i], i, app->numRects, width, height, time); - } - - glBufferData(GL_UNIFORM_BUFFER, sizeof(proj), &proj, GL_STREAM_DRAW); - - glBufferSubData( - GL_ARRAY_BUFFER, 0, (GLsizeiptr)(app->numRects * sizeof(Rect)), app->rects); - - glDrawElementsInstanced( - GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, NULL, (GLsizei)(app->numRects * 4)); - - ++app->framesDrawn; - - app->lastFrameEndTime = puglGetTime(puglGetWorld(view)); - app->lastDrawDuration = app->lastFrameEndTime - time; -} - -static PuglStatus -onEvent(PuglView* view, const PuglEvent* event) -{ - PuglTestApp* app = (PuglTestApp*)puglGetHandle(view); - - printEvent(event, "Event: ", app->opts.verbose); - - switch (event->type) { - case PUGL_CREATE: - setupGl(app); - break; - case PUGL_DESTROY: - teardownGl(app); - break; - case PUGL_CONFIGURE: - onConfigure(view, event->configure.width, event->configure.height); - break; - case PUGL_UPDATE: - puglPostRedisplay(view); - break; - case PUGL_EXPOSE: - onExpose(view); - break; - case PUGL_CLOSE: - app->quit = 1; - break; - case PUGL_LOOP_ENTER: - puglStartTimer(view, - resizeTimerId, - 1.0 / (double)puglGetViewHint(view, PUGL_REFRESH_RATE)); - break; - case PUGL_LOOP_LEAVE: - puglStopTimer(view, resizeTimerId); - break; - case PUGL_KEY_PRESS: - if (event->key.key == 'q' || event->key.key == PUGL_KEY_ESCAPE) { - app->quit = 1; - } - break; - case PUGL_TIMER: - if (event->timer.id == resizeTimerId) { - puglPostRedisplay(view); - } - break; - default: - break; - } - - return PUGL_SUCCESS; -} - -static Rect* -makeRects(const size_t numRects) -{ - Rect* rects = (Rect*)calloc(numRects, sizeof(Rect)); - for (size_t i = 0; i < numRects; ++i) { - rects[i] = makeRect(i, (float)defaultWidth); - } - - return rects; -} - -static char* -loadShader(const char* const programPath, const char* const name) -{ - char* const path = resourcePath(programPath, name); - fprintf(stderr, "Loading shader %s\n", path); - - FILE* const file = fopen(path, "r"); - if (!file) { - logError("Failed to open '%s'\n", path); - return NULL; - } - - free(path); - fseek(file, 0, SEEK_END); - const size_t fileSize = (size_t)ftell(file); - - fseek(file, 0, SEEK_SET); - char* source = (char*)calloc(1, fileSize + 1u); - - fread(source, 1, fileSize, file); - fclose(file); - - return source; -} - -static int -parseOptions(PuglTestApp* app, int argc, char** argv) -{ - char* endptr = NULL; - - // Parse command line options - app->numRects = 1024; - app->opts = puglParseTestOptions(&argc, &argv); - if (app->opts.help) { - return 1; - } - - // Parse number of rectangles argument, if given - if (argc >= 1) { - app->numRects = (size_t)strtol(argv[0], &endptr, 10); - if (endptr != argv[0] + strlen(argv[0])) { - logError("Invalid number of rectangles: %s\n", argv[0]); - return 1; - } - } - - // Parse OpenGL major version argument, if given - if (argc >= 2) { - app->glMajorVersion = (int)strtol(argv[1], &endptr, 10); - if (endptr != argv[1] + strlen(argv[1])) { - logError("Invalid GL major version: %s\n", argv[1]); - return 1; - } - - if (app->glMajorVersion == 4) { - app->glMinorVersion = 2; - } else if (app->glMajorVersion != 3) { - logError("Unsupported GL major version %d\n", app->glMajorVersion); - return 1; - } - } - - return 0; -} - -static void -setupPugl(PuglTestApp* app) -{ - // Create world, view, and rect data - app->world = puglNewWorld(PUGL_PROGRAM, 0); - app->view = puglNewView(app->world); - app->rects = makeRects(app->numRects); - - // Set up world and view - puglSetClassName(app->world, "PuglGL3Demo"); - puglSetWindowTitle(app->view, "Pugl OpenGL 3"); - puglSetDefaultSize(app->view, defaultWidth, defaultHeight); - puglSetMinSize(app->view, defaultWidth / 4, defaultHeight / 4); - puglSetMaxSize(app->view, defaultWidth * 4, defaultHeight * 4); - puglSetAspectRatio(app->view, 1, 1, 16, 9); - puglSetBackend(app->view, puglGlBackend()); - puglSetViewHint(app->view, PUGL_USE_COMPAT_PROFILE, PUGL_FALSE); - puglSetViewHint(app->view, PUGL_USE_DEBUG_CONTEXT, app->opts.errorChecking); - puglSetViewHint(app->view, PUGL_CONTEXT_VERSION_MAJOR, app->glMajorVersion); - puglSetViewHint(app->view, PUGL_CONTEXT_VERSION_MINOR, app->glMinorVersion); - puglSetViewHint(app->view, PUGL_RESIZABLE, app->opts.resizable); - puglSetViewHint(app->view, PUGL_SAMPLES, app->opts.samples); - puglSetViewHint(app->view, PUGL_DOUBLE_BUFFER, app->opts.doubleBuffer); - puglSetViewHint(app->view, PUGL_SWAP_INTERVAL, app->opts.sync); - puglSetViewHint(app->view, PUGL_IGNORE_KEY_REPEAT, PUGL_TRUE); - puglSetHandle(app->view, app); - puglSetEventFunc(app->view, onEvent); -} - -static PuglStatus -setupGl(PuglTestApp* app) -{ - // Load GL functions via GLAD - if (!gladLoadGLLoader((GLADloadproc)&puglGetProcAddress)) { - logError("Failed to load GL\n"); - return PUGL_FAILURE; - } - - const char* const headerFile = - (app->glMajorVersion == 3 ? "shaders/header_330.glsl" - : "shaders/header_420.glsl"); - - // Load shader sources - char* const headerSource = loadShader(app->programPath, headerFile); - - char* const vertexSource = loadShader(app->programPath, "shaders/rect.vert"); - - char* const fragmentSource = - loadShader(app->programPath, "shaders/rect.frag"); - - if (!vertexSource || !fragmentSource) { - logError("Failed to load shader sources\n"); - return PUGL_FAILURE; - } - - // Compile rectangle shaders and program - app->drawRect = compileProgram(headerSource, vertexSource, fragmentSource); - free(fragmentSource); - free(vertexSource); - free(headerSource); - if (!app->drawRect.program) { - return PUGL_FAILURE; - } - - // Get location of rectangle shader uniform block - const GLuint globalsIndex = - glGetUniformBlockIndex(app->drawRect.program, "UniformBufferObject"); - - // Generate/bind a uniform buffer for setting rectangle properties - GLuint uboHandle = 0; - glGenBuffers(1, &uboHandle); - glBindBuffer(GL_UNIFORM_BUFFER, uboHandle); - glBindBufferBase(GL_UNIFORM_BUFFER, globalsIndex, uboHandle); - - // Generate/bind a VAO to track state - glGenVertexArrays(1, &app->vao); - glBindVertexArray(app->vao); - - // Generate/bind a VBO to store vertex position data - glGenBuffers(1, &app->vbo); - glBindBuffer(GL_ARRAY_BUFFER, app->vbo); - glBufferData( - GL_ARRAY_BUFFER, sizeof(rectVertices), rectVertices, GL_STATIC_DRAW); - - // Attribute 0 is position, 2 floats from the VBO - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), NULL); - - // Generate/bind a VBO to store instance attribute data - glGenBuffers(1, &app->instanceVbo); - glBindBuffer(GL_ARRAY_BUFFER, app->instanceVbo); - glBufferData(GL_ARRAY_BUFFER, - (GLsizeiptr)(app->numRects * sizeof(Rect)), - app->rects, - GL_STREAM_DRAW); - - // Attribute 1 is Rect::position - glEnableVertexAttribArray(1); - glVertexAttribDivisor(1, 4); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Rect), NULL); - - // Attribute 2 is Rect::size - glEnableVertexAttribArray(2); - glVertexAttribDivisor(2, 4); - glVertexAttribPointer( - 2, 2, GL_FLOAT, GL_FALSE, sizeof(Rect), (const void*)offsetof(Rect, size)); - - // Attribute 3 is Rect::fillColor - glEnableVertexAttribArray(3); - glVertexAttribDivisor(3, 4); - glVertexAttribPointer(3, - 4, - GL_FLOAT, - GL_FALSE, - sizeof(Rect), - (const void*)offsetof(Rect, fillColor)); - - // Set up the IBO to index into the VBO - glGenBuffers(1, &app->ibo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, app->ibo); - glBufferData( - GL_ELEMENT_ARRAY_BUFFER, sizeof(rectIndices), rectIndices, GL_STATIC_DRAW); - - return PUGL_SUCCESS; -} - -static void -teardownGl(PuglTestApp* app) -{ - glDeleteBuffers(1, &app->ibo); - glDeleteBuffers(1, &app->vbo); - glDeleteBuffers(1, &app->instanceVbo); - glDeleteVertexArrays(1, &app->vao); - deleteProgram(app->drawRect); -} - -static double -updateTimeout(const PuglTestApp* const app) -{ - if (!puglGetVisible(app->view)) { - return -1.0; // View is invisible (minimized), wait until something happens - } - - if (!app->opts.sync) { - return 0.0; // VSync explicitly disabled, run as fast as possible - } - - /* To minimize input latency and get smooth performance during window - resizing, we want to poll for events as long as possible before starting - to draw the next frame. This ensures that as many events are consumed as - possible before starting to draw, or, equivalently, that the next rendered - frame represents the latest events possible. This is particularly - important for mouse input and "live" window resizing, where many events - tend to pile up within a frame. - - To do this, we keep track of the time when the last frame was finished - drawing, and how long it took to expose (and assume this is relatively - stable). Then, we can calculate how much time there is from now until the - time when we should start drawing to not miss the deadline, and use that - as the timeout for puglUpdate(). - */ - - const int refreshRate = puglGetViewHint(app->view, PUGL_REFRESH_RATE); - const double now = puglGetTime(app->world); - const double nextFrameEndTime = app->lastFrameEndTime + (1.0 / refreshRate); - const double nextExposeTime = nextFrameEndTime - app->lastDrawDuration; - const double timeUntilNext = nextExposeTime - now; - - return timeUntilNext; -} - -int -main(int argc, char** argv) -{ - PuglTestApp app = {0}; - - app.programPath = argv[0]; - app.glMajorVersion = 3; - app.glMinorVersion = 3; - - // Parse command line options - if (parseOptions(&app, argc, argv)) { - puglPrintTestUsage("pugl_shader_demo", "[NUM_RECTS] [GL_MAJOR]"); - return 1; - } - - // Create and configure world and view - setupPugl(&app); - - // Create window (which will send a PUGL_CREATE event) - const PuglStatus st = puglRealize(app.view); - if (st) { - return logError("Failed to create window (%s)\n", puglStrerror(st)); - } - - // Show window - printViewHints(app.view); - puglShow(app.view); - - // Grind away, drawing continuously - const double startTime = puglGetTime(app.world); - PuglFpsPrinter fpsPrinter = {startTime}; - while (!app.quit) { - puglUpdate(app.world, fmax(0.0, updateTimeout(&app))); - puglPrintFps(app.world, &fpsPrinter, &app.framesDrawn); - } - - // Destroy window (which will send a PUGL_DESTROY event) - puglFreeView(app.view); - - // Free everything else - puglFreeWorld(app.world); - free(app.rects); - - return 0; -} diff --git a/dpf/dgl/src/pugl-upstream/examples/pugl_vulkan_cpp_demo.cpp b/dpf/dgl/src/pugl-upstream/examples/pugl_vulkan_cpp_demo.cpp deleted file mode 100644 index d92e652..0000000 --- a/dpf/dgl/src/pugl-upstream/examples/pugl_vulkan_cpp_demo.cpp +++ /dev/null @@ -1,1826 +0,0 @@ -/* - Copyright 2019-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/* - An example of drawing with Vulkan. - - This is an example of using Vulkan for pixel-perfect 2D drawing. It uses - the same data and shaders as pugl_shader_demo.c and attempts to draw the - same thing, except using Vulkan. - - Since Vulkan is a complicated and very verbose API, this example is - unfortunately much larger than the others. You should not use this as a - resource to learn Vulkan, but it provides a decent demo of using Vulkan with - Pugl that works nicely on all supported platforms. -*/ - -#include "demo_utils.h" -#include "file_utils.h" -#include "rects.h" -#include "test/test_utils.h" - -#include "sybok.hpp" - -#include "pugl/pugl.h" -#include "pugl/pugl.hpp" -#include "pugl/vulkan.hpp" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace { - -constexpr uintptr_t resizeTimerId = 1u; - -struct PhysicalDeviceSelection { - sk::PhysicalDevice physicalDevice; - uint32_t graphicsFamilyIndex; -}; - -/// Basic Vulkan context associated with the window -struct VulkanContext { - VkResult init(pugl::VulkanLoader& loader, const PuglTestOptions& opts); - - sk::VulkanApi vk; - sk::Instance instance; - sk::DebugReportCallbackEXT debugCallback; -}; - -/// Basic setup of graphics device -struct GraphicsDevice { - VkResult init(const pugl::VulkanLoader& loader, - const VulkanContext& context, - pugl::View& view, - const PuglTestOptions& opts); - - sk::SurfaceKHR surface; - sk::PhysicalDevice physicalDevice{}; - uint32_t graphicsIndex{}; - VkSurfaceFormatKHR surfaceFormat{}; - VkPresentModeKHR presentMode{}; - VkPresentModeKHR resizePresentMode{}; - sk::Device device{}; - sk::Queue graphicsQueue{}; - sk::CommandPool commandPool{}; -}; - -/// Buffer allocated on the GPU -struct Buffer { - VkResult init(const sk::VulkanApi& vk, - const GraphicsDevice& gpu, - VkDeviceSize size, - VkBufferUsageFlags usage, - VkMemoryPropertyFlags properties); - - sk::Buffer buffer; - sk::DeviceMemory deviceMemory; -}; - -/// A set of frames that can be rendered concurrently -struct Swapchain { - VkResult init(const sk::VulkanApi& vk, - const GraphicsDevice& gpu, - VkSurfaceCapabilitiesKHR capabilities, - VkExtent2D extent, - VkSwapchainKHR oldSwapchain, - bool resizing); - - VkSurfaceCapabilitiesKHR capabilities{}; - VkExtent2D extent{}; - sk::SwapchainKHR swapchain{}; - std::vector imageViews{}; -}; - -/// A pass that renders to a target -struct RenderPass { - VkResult init(const sk::VulkanApi& vk, - const GraphicsDevice& gpu, - const Swapchain& swapchain); - - sk::RenderPass renderPass; - std::vector framebuffers; - sk::CommandBuffers> commandBuffers; -}; - -/// Uniform buffer for constant data used in shaders -struct UniformBufferObject { - mat4 projection; -}; - -/// Rectangle data that does not depend on renderer configuration -struct RectData { - VkResult init(const sk::VulkanApi& vk, - const GraphicsDevice& gpu, - size_t nRects); - - sk::DescriptorSetLayout descriptorSetLayout{}; - Buffer uniformBuffer{}; - sk::MappedMemory uniformData{}; - Buffer modelBuffer{}; - Buffer instanceBuffer{}; - sk::MappedMemory vertexData{}; - size_t numRects{}; -}; - -/// Shader modules for drawing rectangles -struct RectShaders { - VkResult init(const sk::VulkanApi& vk, - const GraphicsDevice& gpu, - const std::string& programPath); - - sk::ShaderModule vert{}; - sk::ShaderModule frag{}; -}; - -/// A pipeline to render rectangles with our shaders -struct RectPipeline { - VkResult init(const sk::VulkanApi& vk, - const GraphicsDevice& gpu, - const RectData& rectData, - const RectShaders& shaders, - const Swapchain& swapchain, - const RenderPass& renderPass); - - sk::DescriptorPool descriptorPool{}; - sk::DescriptorSets> descriptorSets{}; - sk::PipelineLayout pipelineLayout{}; - std::array pipelines{}; - uint32_t numImages{}; -}; - -/// Synchronization primitives used to coordinate drawing frames -struct RenderSync { - VkResult init(const sk::VulkanApi& vk, - const sk::Device& device, - uint32_t numImages); - - std::vector imageAvailable{}; - std::vector renderFinished{}; - std::vector inFlight{}; - size_t currentFrame{}; -}; - -/// Renderer that owns the above and everything required to draw -struct Renderer { - VkResult init(const sk::VulkanApi& vk, - const GraphicsDevice& gpu, - const RectData& rectData, - const RectShaders& rectShaders, - VkExtent2D extent, - bool resizing); - - VkResult recreate(const sk::VulkanApi& vk, - const sk::SurfaceKHR& surface, - const GraphicsDevice& gpu, - const RectData& rectData, - const RectShaders& rectShaders, - VkExtent2D extent, - bool resizing); - - Swapchain swapchain; - RenderPass renderPass; - RectPipeline rectPipeline; - RenderSync sync; -}; - -VkResult -selectSurfaceFormat(const sk::VulkanApi& vk, - const sk::PhysicalDevice& physicalDevice, - const sk::SurfaceKHR& surface, - VkSurfaceFormatKHR& surfaceFormat) -{ - std::vector formats; - if (VkResult r = vk.getPhysicalDeviceSurfaceFormatsKHR( - physicalDevice, surface, formats)) { - return r; - } - - for (const auto& format : formats) { - if (format.format == VK_FORMAT_B8G8R8A8_UNORM && - format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { - surfaceFormat = format; - return VK_SUCCESS; - } - } - - return VK_ERROR_FORMAT_NOT_SUPPORTED; -} - -VkResult -selectPresentMode(const sk::VulkanApi& vk, - const sk::PhysicalDevice& physicalDevice, - const sk::SurfaceKHR& surface, - const bool multiBuffer, - const bool sync, - VkPresentModeKHR& presentMode) -{ - // Map command line options to mode priorities - static constexpr VkPresentModeKHR priorities[][2][4] = { - { - // No double buffer, no sync - {VK_PRESENT_MODE_IMMEDIATE_KHR, - VK_PRESENT_MODE_MAILBOX_KHR, - VK_PRESENT_MODE_FIFO_RELAXED_KHR, - VK_PRESENT_MODE_FIFO_KHR}, - - // No double buffer, sync (nonsense, map to FIFO relaxed) - {VK_PRESENT_MODE_FIFO_RELAXED_KHR, - VK_PRESENT_MODE_FIFO_KHR, - VK_PRESENT_MODE_MAILBOX_KHR, - VK_PRESENT_MODE_IMMEDIATE_KHR}, - }, - { - // Double buffer, no sync - { - VK_PRESENT_MODE_MAILBOX_KHR, - VK_PRESENT_MODE_IMMEDIATE_KHR, - VK_PRESENT_MODE_FIFO_RELAXED_KHR, - VK_PRESENT_MODE_FIFO_KHR, - }, - - // Double buffer, sync - {VK_PRESENT_MODE_FIFO_KHR, - VK_PRESENT_MODE_FIFO_RELAXED_KHR, - VK_PRESENT_MODE_MAILBOX_KHR, - VK_PRESENT_MODE_IMMEDIATE_KHR}, - }, - }; - - std::vector modes; - if (VkResult r = vk.getPhysicalDeviceSurfacePresentModesKHR( - physicalDevice, surface, modes)) { - return r; - } - - const auto& tryModes = priorities[bool(multiBuffer)][bool(sync)]; - for (const auto m : tryModes) { - if (std::find(modes.begin(), modes.end(), m) != modes.end()) { - presentMode = m; - return VK_SUCCESS; - } - } - - return VK_ERROR_INCOMPATIBLE_DRIVER; -} - -VkResult -openDevice(const sk::VulkanApi& vk, - const sk::PhysicalDevice& physicalDevice, - const uint32_t graphicsFamilyIndex, - sk::Device& device) -{ - const float graphicsQueuePriority = 1.0f; - const char* const swapchainName = "VK_KHR_swapchain"; - - const VkDeviceQueueCreateInfo queueCreateInfo{ - VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, - nullptr, - 0u, - graphicsFamilyIndex, - SK_COUNTED(1u, &graphicsQueuePriority), - }; - - const VkDeviceCreateInfo createInfo{VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, - nullptr, - 0u, - SK_COUNTED(1u, &queueCreateInfo), - SK_COUNTED(0u, nullptr), // Deprecated - SK_COUNTED(1u, &swapchainName), - nullptr}; - - return vk.createDevice(physicalDevice, createInfo, device); -} - -/// Return whether the physical device supports the extensions we require -VkResult -deviceSupportsRequiredExtensions(const sk::VulkanApi& vk, - const sk::PhysicalDevice& device, - bool& supported) -{ - VkResult r = VK_SUCCESS; - - std::vector props; - if ((r = vk.enumerateDeviceExtensionProperties(device, props))) { - return r; - } - - supported = std::any_of( - props.begin(), props.end(), [&](const VkExtensionProperties& e) { - return !strcmp(e.extensionName, "VK_KHR_swapchain"); - }); - - return VK_SUCCESS; -} - -/// Return the index of the graphics queue, if there is one -VkResult -findGraphicsQueue(const sk::VulkanApi& vk, - const sk::SurfaceKHR& surface, - const sk::PhysicalDevice& device, - uint32_t& queueIndex) -{ - VkResult r = VK_SUCCESS; - - std::vector queueProps; - if ((r = vk.getPhysicalDeviceQueueFamilyProperties(device, queueProps))) { - return r; - } - - for (uint32_t q = 0u; q < queueProps.size(); ++q) { - if (queueProps[q].queueFlags & VK_QUEUE_GRAPHICS_BIT) { - bool supported = false; - if ((r = vk.getPhysicalDeviceSurfaceSupportKHR( - device, q, surface, supported))) { - return r; - } - - if (supported) { - queueIndex = q; - return VK_SUCCESS; - } - } - } - - return VK_ERROR_FEATURE_NOT_PRESENT; -} - -/// Select a physical graphics device to use (simply the first found) -VkResult -selectPhysicalDevice(const sk::VulkanApi& vk, - const sk::Instance& instance, - const sk::SurfaceKHR& surface, - PhysicalDeviceSelection& selection) -{ - VkResult r = VK_SUCCESS; - - std::vector devices; - if ((r = vk.enumeratePhysicalDevices(instance, devices))) { - return r; - } - - for (const auto& device : devices) { - auto supported = false; - if ((r = deviceSupportsRequiredExtensions(vk, device, supported))) { - return r; - } - - if (supported) { - auto queueIndex = 0u; - if ((r = findGraphicsQueue(vk, surface, device, queueIndex))) { - return r; - } - - selection = PhysicalDeviceSelection{device, queueIndex}; - return VK_SUCCESS; - } - } - - return VK_ERROR_INCOMPATIBLE_DISPLAY_KHR; -} - -VkResult -GraphicsDevice::init(const pugl::VulkanLoader& loader, - const VulkanContext& context, - pugl::View& view, - const PuglTestOptions& opts) -{ - const auto& vk = context.vk; - VkResult r = VK_SUCCESS; - - // Create a Vulkan surface for the window using the Pugl API - VkSurfaceKHR surfaceHandle = {}; - if ((r = pugl::createSurface(loader.getInstanceProcAddrFunc(), - view, - context.instance, - nullptr, - &surfaceHandle))) { - return r; - } - - // Wrap surface in a safe RAII handle - surface = - sk::SurfaceKHR{surfaceHandle, {context.instance, vk.vkDestroySurfaceKHR}}; - - PhysicalDeviceSelection physicalDeviceSelection = {}; - // Select a physical device to use - if ((r = selectPhysicalDevice( - vk, context.instance, surface, physicalDeviceSelection))) { - return r; - } - - physicalDevice = physicalDeviceSelection.physicalDevice; - graphicsIndex = physicalDeviceSelection.graphicsFamilyIndex; - - if ((r = selectSurfaceFormat(vk, physicalDevice, surface, surfaceFormat)) || - (r = selectPresentMode(vk, - physicalDevice, - surface, - opts.doubleBuffer, - opts.sync, - presentMode)) || - (r = selectPresentMode( - vk, physicalDevice, surface, true, false, resizePresentMode)) || - (r = openDevice(vk, physicalDevice, graphicsIndex, device))) { - return r; - } - - const VkCommandPoolCreateInfo commandPoolInfo{ - VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, nullptr, {}, graphicsIndex}; - - if ((r = vk.createCommandPool(device, commandPoolInfo, commandPool))) { - return r; - } - - graphicsQueue = vk.getDeviceQueue(device, graphicsIndex, 0); - return VK_SUCCESS; -} - -uint32_t -findMemoryType(const sk::VulkanApi& vk, - const sk::PhysicalDevice& physicalDevice, - const uint32_t typeFilter, - const VkMemoryPropertyFlags& properties) -{ - VkPhysicalDeviceMemoryProperties memProperties = - vk.getPhysicalDeviceMemoryProperties(physicalDevice); - - for (uint32_t i = 0; i < memProperties.memoryTypeCount; ++i) { - if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & - properties) == properties) { - return i; - } - } - - return UINT32_MAX; -} - -VkResult -Buffer::init(const sk::VulkanApi& vk, - const GraphicsDevice& gpu, - const VkDeviceSize size, - const VkBufferUsageFlags usage, - const VkMemoryPropertyFlags properties) -{ - const VkBufferCreateInfo bufferInfo{VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, - nullptr, - {}, - size, - usage, - VK_SHARING_MODE_EXCLUSIVE, - SK_COUNTED(0, nullptr)}; - - const auto& device = gpu.device; - - VkResult r = VK_SUCCESS; - if ((r = vk.createBuffer(device, bufferInfo, buffer))) { - return r; - } - - const auto requirements = vk.getBufferMemoryRequirements(device, buffer); - const auto memoryTypeIndex = findMemoryType( - vk, gpu.physicalDevice, requirements.memoryTypeBits, properties); - - if (memoryTypeIndex == UINT32_MAX) { - return VK_ERROR_FEATURE_NOT_PRESENT; - } - - const VkMemoryAllocateInfo allocInfo{VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, - nullptr, - requirements.size, - memoryTypeIndex}; - - if ((r = vk.allocateMemory(device, allocInfo, deviceMemory)) || - (r = vk.bindBufferMemory(device, buffer, deviceMemory, 0))) { - return r; - } - - return VK_SUCCESS; -} - -VkResult -Swapchain::init(const sk::VulkanApi& vk, - const GraphicsDevice& gpu, - const VkSurfaceCapabilitiesKHR surfaceCapabilities, - const VkExtent2D surfaceExtent, - VkSwapchainKHR oldSwapchain, - bool resizing) -{ - capabilities = surfaceCapabilities; - extent = surfaceExtent; - - const auto minNumImages = - (!capabilities.maxImageCount || capabilities.maxImageCount >= 3u) - ? 3u - : capabilities.maxImageCount; - - const VkSwapchainCreateInfoKHR swapchainCreateInfo{ - VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, - nullptr, - {}, - gpu.surface, - minNumImages, - gpu.surfaceFormat.format, - gpu.surfaceFormat.colorSpace, - surfaceExtent, - 1, - (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT), - VK_SHARING_MODE_EXCLUSIVE, - SK_COUNTED(0, nullptr), - capabilities.currentTransform, - VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR, - resizing ? gpu.resizePresentMode : gpu.presentMode, - VK_TRUE, - oldSwapchain}; - - VkResult r = VK_SUCCESS; - std::vector images; - if ((r = vk.createSwapchainKHR(gpu.device, swapchainCreateInfo, swapchain)) || - (r = vk.getSwapchainImagesKHR(gpu.device, swapchain, images))) { - return r; - } - - imageViews = std::vector(images.size()); - for (size_t i = 0; i < images.size(); ++i) { - const VkImageViewCreateInfo imageViewCreateInfo{ - VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, - nullptr, - {}, - images[i], - VK_IMAGE_VIEW_TYPE_2D, - gpu.surfaceFormat.format, - {}, - {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}}; - - if ((r = vk.createImageView( - gpu.device, imageViewCreateInfo, imageViews[i]))) { - return r; - } - } - - return VK_SUCCESS; -} - -VkResult -RenderPass::init(const sk::VulkanApi& vk, - const GraphicsDevice& gpu, - const Swapchain& swapchain) -{ - const auto numImages = static_cast(swapchain.imageViews.size()); - - assert(numImages > 0); - - // Create command buffers - const VkCommandBufferAllocateInfo commandBufferAllocateInfo{ - VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, - nullptr, - gpu.commandPool, - VK_COMMAND_BUFFER_LEVEL_PRIMARY, - numImages}; - - VkResult r = VK_SUCCESS; - if ((r = vk.allocateCommandBuffers( - gpu.device, commandBufferAllocateInfo, commandBuffers))) { - return r; - } - - static constexpr VkAttachmentReference colorAttachmentRef{ - 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; - - static constexpr VkSubpassDescription subpass{ - {}, - VK_PIPELINE_BIND_POINT_GRAPHICS, - SK_COUNTED(0, nullptr), - SK_COUNTED(1, &colorAttachmentRef, nullptr, nullptr), - SK_COUNTED(0u, nullptr)}; - - static constexpr VkSubpassDependency dependency{ - VK_SUBPASS_EXTERNAL, - 0, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT), - {}, - {}}; - - const VkAttachmentDescription colorAttachment{ - {}, - gpu.surfaceFormat.format, - VK_SAMPLE_COUNT_1_BIT, - VK_ATTACHMENT_LOAD_OP_CLEAR, - VK_ATTACHMENT_STORE_OP_STORE, - VK_ATTACHMENT_LOAD_OP_DONT_CARE, - VK_ATTACHMENT_STORE_OP_DONT_CARE, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, - }; - - const VkRenderPassCreateInfo renderPassCreateInfo{ - VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, - nullptr, - {}, - SK_COUNTED(1, &colorAttachment), - SK_COUNTED(1, &subpass), - SK_COUNTED(1, &dependency)}; - - if ((r = vk.createRenderPass(gpu.device, renderPassCreateInfo, renderPass))) { - return r; - } - - // Create framebuffers - framebuffers = std::vector(numImages); - for (uint32_t i = 0; i < numImages; ++i) { - const VkFramebufferCreateInfo framebufferCreateInfo{ - VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, - nullptr, - {}, - renderPass, - SK_COUNTED(1, &swapchain.imageViews[i].get()), - swapchain.extent.width, - swapchain.extent.height, - 1}; - - if ((r = vk.createFramebuffer( - gpu.device, framebufferCreateInfo, framebuffers[i]))) { - return r; - } - } - - return VK_SUCCESS; -} - -std::vector -readFile(const char* const programPath, const std::string& filename) -{ - std::unique_ptr path{ - resourcePath(programPath, filename.c_str()), &free}; - - std::cerr << "Loading shader: " << path.get() << std::endl; - - std::unique_ptr file{fopen(path.get(), "rb"), - &fclose}; - - if (!file) { - std::cerr << "Failed to open file '" << filename << "'\n"; - return {}; - } - - fseek(file.get(), 0, SEEK_END); - const auto fileSize = static_cast(ftell(file.get())); - fseek(file.get(), 0, SEEK_SET); - - const auto numWords = fileSize / sizeof(uint32_t); - std::vector buffer(numWords); - - fread(buffer.data(), sizeof(uint32_t), numWords, file.get()); - - return buffer; -} - -VkResult -createShaderModule(const sk::VulkanApi& vk, - const GraphicsDevice& gpu, - const std::vector& code, - sk::ShaderModule& shaderModule) -{ - const VkShaderModuleCreateInfo createInfo{ - VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, - nullptr, - {}, - code.size() * sizeof(uint32_t), - code.data()}; - - return vk.createShaderModule(gpu.device, createInfo, shaderModule); -} - -VkResult -RectShaders::init(const sk::VulkanApi& vk, - const GraphicsDevice& gpu, - const std::string& programPath) -{ - auto vertShaderCode = readFile(programPath.c_str(), "shaders/rect.vert.spv"); - - auto fragShaderCode = readFile(programPath.c_str(), "shaders/rect.frag.spv"); - - if (vertShaderCode.empty() || fragShaderCode.empty()) { - return VK_ERROR_INITIALIZATION_FAILED; - } - - VkResult r = VK_SUCCESS; - if ((r = createShaderModule(vk, gpu, vertShaderCode, vert)) || - (r = createShaderModule(vk, gpu, fragShaderCode, frag))) { - return r; - } - - return VK_SUCCESS; -} - -VkResult -RectPipeline::init(const sk::VulkanApi& vk, - const GraphicsDevice& gpu, - const RectData& rectData, - const RectShaders& shaders, - const Swapchain& swapchain, - const RenderPass& renderPass) -{ - const auto oldNumImages = numImages; - VkResult r = VK_SUCCESS; - - numImages = static_cast(swapchain.imageViews.size()); - pipelines = {}; - pipelineLayout = {}; - descriptorSets = {}; - - if (numImages != oldNumImages) { - // Create layout descriptor pool - - const VkDescriptorPoolSize poolSize{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - numImages}; - - const VkDescriptorPoolCreateInfo descriptorPoolCreateInfo{ - VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, - nullptr, - VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, - numImages, - 1u, - &poolSize}; - if ((r = vk.createDescriptorPool( - gpu.device, descriptorPoolCreateInfo, descriptorPool))) { - return r; - } - } - - const std::vector layouts( - numImages, rectData.descriptorSetLayout.get()); - - const VkDescriptorSetAllocateInfo descriptorSetAllocateInfo{ - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, - nullptr, - descriptorPool, - numImages, - layouts.data()}; - if ((r = vk.allocateDescriptorSets( - gpu.device, descriptorSetAllocateInfo, descriptorSets))) { - return r; - } - - const VkDescriptorBufferInfo bufferInfo{ - rectData.uniformBuffer.buffer, 0, sizeof(UniformBufferObject)}; - - const std::array descriptorWrites{ - {{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - nullptr, - descriptorSets[0], - 0, - 0, - 1, - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - nullptr, - &bufferInfo, - nullptr}}}; - - const std::array descriptorCopies{}; - - vk.updateDescriptorSets(gpu.device, descriptorWrites, descriptorCopies); - - static constexpr std::array - vertexAttributeDescriptions{ - {// Model - {0u, 0u, VK_FORMAT_R32G32_SFLOAT, 0}, - - // Rect instance attributes - {1u, 1u, VK_FORMAT_R32G32_SFLOAT, offsetof(Rect, pos)}, - {2u, 1u, VK_FORMAT_R32G32_SFLOAT, offsetof(Rect, size)}, - {3u, 1u, VK_FORMAT_R32G32B32A32_SFLOAT, offsetof(Rect, fillColor)}}}; - - static constexpr std::array - vertexBindingDescriptions{ - VkVertexInputBindingDescription{ - 0, sizeof(vec2), VK_VERTEX_INPUT_RATE_VERTEX}, - VkVertexInputBindingDescription{ - 1u, sizeof(Rect), VK_VERTEX_INPUT_RATE_INSTANCE}}; - - static constexpr VkPipelineInputAssemblyStateCreateInfo inputAssembly{ - VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, - nullptr, - {}, - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, - false}; - - static constexpr VkPipelineRasterizationStateCreateInfo rasterizer{ - VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, - nullptr, - {}, - 0, - 0, - VK_POLYGON_MODE_FILL, - VK_CULL_MODE_BACK_BIT, - VK_FRONT_FACE_CLOCKWISE, - 0, - 0, - 0, - 0, - 1.0f}; - - static constexpr VkPipelineMultisampleStateCreateInfo multisampling{ - VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, - nullptr, - {}, - VK_SAMPLE_COUNT_1_BIT, - false, - 0.0f, - nullptr, - false, - false}; - - static constexpr VkPipelineColorBlendAttachmentState colorBlendAttachment{ - true, - VK_BLEND_FACTOR_SRC_ALPHA, - VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, - VK_BLEND_OP_ADD, - VK_BLEND_FACTOR_ONE, - VK_BLEND_FACTOR_ZERO, - VK_BLEND_OP_ADD, - (VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | - VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT)}; - - const VkPipelineShaderStageCreateInfo shaderStages[] = { - {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, - nullptr, - {}, - VK_SHADER_STAGE_VERTEX_BIT, - shaders.vert.get(), - "main", - nullptr}, - {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, - nullptr, - {}, - VK_SHADER_STAGE_FRAGMENT_BIT, - shaders.frag.get(), - "main", - nullptr}}; - - const VkPipelineVertexInputStateCreateInfo vertexInputInfo{ - VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, - nullptr, - {}, - SK_COUNTED(static_cast(vertexBindingDescriptions.size()), - vertexBindingDescriptions.data()), - SK_COUNTED(static_cast(vertexAttributeDescriptions.size()), - vertexAttributeDescriptions.data())}; - - const VkViewport viewport{0.0f, - 0.0f, - float(swapchain.extent.width), - float(swapchain.extent.height), - 0.0f, - 1.0f}; - - const VkRect2D scissor{{0, 0}, swapchain.extent}; - - const VkPipelineViewportStateCreateInfo viewportState{ - VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, - nullptr, - {}, - SK_COUNTED(1, &viewport), - SK_COUNTED(1, &scissor)}; - - const VkPipelineColorBlendStateCreateInfo colorBlending{ - VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, - nullptr, - {}, - false, - VK_LOGIC_OP_COPY, - SK_COUNTED(1, &colorBlendAttachment), - {1.0f, 0.0f, 0.0f, 0.0f}}; - - const VkPipelineLayoutCreateInfo layoutInfo{ - VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, - nullptr, - {}, - SK_COUNTED(1, &rectData.descriptorSetLayout.get()), - SK_COUNTED(0, nullptr)}; - - if ((r = vk.createPipelineLayout(gpu.device, layoutInfo, pipelineLayout))) { - return r; - } - - const std::array pipelineInfos{ - {{VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, - nullptr, - {}, - SK_COUNTED(2, shaderStages), - &vertexInputInfo, - &inputAssembly, - nullptr, - &viewportState, - &rasterizer, - &multisampling, - nullptr, - &colorBlending, - nullptr, - pipelineLayout, - renderPass.renderPass, - 0u, - {}, - 0}}}; - - if ((r = vk.createGraphicsPipelines( - gpu.device, {}, pipelineInfos, pipelines))) { - return r; - } - - return VK_SUCCESS; -} - -VkResult -RectData::init(const sk::VulkanApi& vk, - const GraphicsDevice& gpu, - const size_t nRects) -{ - numRects = nRects; - - static constexpr VkDescriptorSetLayoutBinding uboLayoutBinding{ - 0, - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - 1, - VK_SHADER_STAGE_VERTEX_BIT, - nullptr}; - - const VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo{ - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, - nullptr, - {}, - 1, - &uboLayoutBinding}; - - VkResult r = VK_SUCCESS; - if ((r = vk.createDescriptorSetLayout( - gpu.device, descriptorSetLayoutInfo, descriptorSetLayout)) || - (r = uniformBuffer.init(vk, - gpu, - sizeof(UniformBufferObject), - VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) || - (r = vk.mapMemory(gpu.device, - uniformBuffer.deviceMemory, - 0, - sizeof(UniformBufferObject), - {}, - uniformData))) { - return r; - } - - const VkBufferUsageFlags usageFlags = - (VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | - VK_BUFFER_USAGE_TRANSFER_DST_BIT); - - const VkMemoryPropertyFlags propertyFlags = - (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - - if ((r = modelBuffer.init( - vk, gpu, sizeof(rectVertices), usageFlags, propertyFlags))) { - return r; - } - - { - // Copy model vertices (directly, we do this only once) - sk::MappedMemory modelData; - if ((r = vk.mapMemory(gpu.device, - modelBuffer.deviceMemory, - 0, - static_cast(sizeof(rectVertices)), - {}, - modelData))) { - return r; - } - - memcpy(modelData.get(), rectVertices, sizeof(rectVertices)); - } - - if ((r = instanceBuffer.init( - vk, gpu, sizeof(Rect) * numRects, usageFlags, propertyFlags))) { - return r; - } - - // Map attribute vertices (we will update them every frame) - const auto rectsSize = static_cast(sizeof(Rect) * numRects); - if ((r = vk.mapMemory(gpu.device, - instanceBuffer.deviceMemory, - 0, - rectsSize, - {}, - vertexData))) { - return r; - } - - return VK_SUCCESS; -} - -VkResult -RenderSync::init(const sk::VulkanApi& vk, - const sk::Device& device, - const uint32_t numImages) -{ - const auto maxInFlight = std::max(1u, numImages - 1u); - VkResult r = VK_SUCCESS; - - imageAvailable = std::vector(numImages); - renderFinished = std::vector(numImages); - for (uint32_t i = 0; i < numImages; ++i) { - static constexpr VkSemaphoreCreateInfo semaphoreInfo{ - VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, nullptr, {}}; - - if ((r = vk.createSemaphore(device, semaphoreInfo, imageAvailable[i])) || - (r = vk.createSemaphore(device, semaphoreInfo, renderFinished[i]))) { - return r; - } - } - - inFlight = std::vector(maxInFlight); - for (uint32_t i = 0; i < maxInFlight; ++i) { - static constexpr VkFenceCreateInfo fenceInfo{ - VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, - nullptr, - VK_FENCE_CREATE_SIGNALED_BIT}; - - if ((r = vk.createFence(device, fenceInfo, inFlight[i]))) { - return r; - } - } - - return VK_SUCCESS; -} - -VkResult -Renderer::init(const sk::VulkanApi& vk, - const GraphicsDevice& gpu, - const RectData& rectData, - const RectShaders& rectShaders, - const VkExtent2D extent, - bool resizing) -{ - VkResult r = VK_SUCCESS; - VkSurfaceCapabilitiesKHR capabilities = {}; - - if ((r = vk.getPhysicalDeviceSurfaceCapabilitiesKHR( - gpu.physicalDevice, gpu.surface, capabilities)) || - (r = swapchain.init(vk, gpu, capabilities, extent, {}, resizing)) || - (r = renderPass.init(vk, gpu, swapchain)) || - (r = rectPipeline.init( - vk, gpu, rectData, rectShaders, swapchain, renderPass))) { - return r; - } - - const auto numFrames = static_cast(swapchain.imageViews.size()); - return sync.init(vk, gpu.device, numFrames); -} - -VkResult -Renderer::recreate(const sk::VulkanApi& vk, - const sk::SurfaceKHR& surface, - const GraphicsDevice& gpu, - const RectData& rectData, - const RectShaders& rectShaders, - const VkExtent2D extent, - bool resizing) -{ - VkResult r = VK_SUCCESS; - const auto oldNumImages = swapchain.imageViews.size(); - - VkSurfaceCapabilitiesKHR capabilities = {}; - if ((r = vk.getPhysicalDeviceSurfaceCapabilitiesKHR( - gpu.physicalDevice, surface, capabilities)) || - (r = swapchain.init( - vk, gpu, capabilities, extent, swapchain.swapchain, resizing)) || - (r = renderPass.init(vk, gpu, swapchain)) || - (r = rectPipeline.init( - vk, gpu, rectData, rectShaders, swapchain, renderPass))) { - return r; - } - - const auto numFrames = static_cast(swapchain.imageViews.size()); - if (swapchain.imageViews.size() != oldNumImages) { - return sync.init(vk, gpu.device, numFrames); - } - - return VK_SUCCESS; -} - -VKAPI_ATTR -VkBool32 VKAPI_CALL -debugCallback(VkDebugReportFlagsEXT flags, - VkDebugReportObjectTypeEXT, - uint64_t, - size_t, - int32_t, - const char* layerPrefix, - const char* msg, - void*) -{ - std::cerr << sk::string(static_cast(flags)) << ": " - << layerPrefix << ": " << msg << std::endl; - - return VK_FALSE; -} - -bool -hasExtension(const char* name, - const std::vector& properties) -{ - for (const auto& p : properties) { - if (!strcmp(p.extensionName, name)) { - return true; - } - } - - return false; -} - -bool -hasLayer(const char* name, const std::vector& properties) -{ - for (const auto& p : properties) { - if (!strcmp(p.layerName, name)) { - return true; - } - } - - return false; -} - -template -void -logInfo(const char* heading, const Value& value) -{ - std::cout << std::setw(26) << std::left << (std::string(heading) + ":") - << value << std::endl; -} - -VkResult -createInstance(sk::VulkanInitApi& initApi, - const PuglTestOptions& opts, - sk::Instance& instance) -{ - VkResult r = VK_SUCCESS; - - std::vector layerProps; - std::vector extProps; - if ((r = initApi.enumerateInstanceLayerProperties(layerProps)) || - (r = initApi.enumerateInstanceExtensionProperties(extProps))) { - return r; - } - - const auto puglExtensions = pugl::getInstanceExtensions(); - auto extensions = - std::vector(puglExtensions.begin(), puglExtensions.end()); - - // Add extra extensions we want to use if they are supported - if (hasExtension("VK_EXT_debug_report", extProps)) { - extensions.push_back("VK_EXT_debug_report"); - } - - // Add validation layers if error checking is enabled - std::vector layers; - if (opts.errorChecking) { - for (const char* l : {"VK_LAYER_KHRONOS_validation", - "VK_LAYER_LUNARG_standard_validation"}) { - if (hasLayer(l, layerProps)) { - layers.push_back(l); - } - } - } - - for (const auto& e : extensions) { - logInfo("Using instance extension", e); - } - - for (const auto& l : layers) { - logInfo("Using instance layer", l); - } - - static constexpr VkApplicationInfo appInfo{ - VK_STRUCTURE_TYPE_APPLICATION_INFO, - nullptr, - "Pugl Vulkan Demo", - 0, - nullptr, - 0, - VK_MAKE_VERSION(1, 0, 0), - }; - - const VkInstanceCreateInfo createInfo{ - VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, - nullptr, - VkInstanceCreateFlags{}, - &appInfo, - SK_COUNTED(uint32_t(layers.size()), layers.data()), - SK_COUNTED(uint32_t(extensions.size()), extensions.data())}; - - return initApi.createInstance(createInfo, instance); -} - -VkResult -getDebugReportCallback(sk::VulkanApi& api, - sk::Instance& instance, - const bool verbose, - sk::DebugReportCallbackEXT& callback) -{ - if (api.vkCreateDebugReportCallbackEXT) { - VkDebugReportFlagsEXT flags = (VK_DEBUG_REPORT_WARNING_BIT_EXT | - VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT | - VK_DEBUG_REPORT_ERROR_BIT_EXT); - - if (verbose) { - flags |= VK_DEBUG_REPORT_INFORMATION_BIT_EXT; - flags |= VK_DEBUG_REPORT_DEBUG_BIT_EXT; - } - - const VkDebugReportCallbackCreateInfoEXT createInfo{ - VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT, - nullptr, - flags, - debugCallback, - nullptr}; - - return api.createDebugReportCallbackEXT(instance, createInfo, callback); - } - - return VK_ERROR_FEATURE_NOT_PRESENT; -} - -void -recordCommandBuffer(sk::CommandScope& cmd, - const Swapchain& swapchain, - const RenderPass& renderPass, - const RectPipeline& rectPipeline, - const RectData& rectData, - const size_t imageIndex) -{ - const VkClearColorValue clearColorValue{{0.0f, 0.0f, 0.0f, 1.0f}}; - const VkClearValue clearValue{clearColorValue}; - - const VkRenderPassBeginInfo renderPassBegin{ - VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, - nullptr, - renderPass.renderPass, - renderPass.framebuffers[imageIndex], - VkRect2D{{0, 0}, swapchain.extent}, - SK_COUNTED(1, &clearValue)}; - - auto pass = cmd.beginRenderPass(renderPassBegin, VK_SUBPASS_CONTENTS_INLINE); - - pass.bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, rectPipeline.pipelines[0]); - - const std::array offsets{0}; - pass.bindVertexBuffers( - 0u, SK_COUNTED(1u, &rectData.modelBuffer.buffer.get(), offsets.data())); - - pass.bindVertexBuffers( - 1u, SK_COUNTED(1u, &rectData.instanceBuffer.buffer.get(), offsets.data())); - - pass.bindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, - rectPipeline.pipelineLayout, - 0u, - SK_COUNTED(1u, rectPipeline.descriptorSets.get()), - 0u, - nullptr); - - pass.draw(4u, static_cast(rectData.numRects), 0u, 0u); -} - -VkResult -recordCommandBuffers(const sk::VulkanApi& vk, - const Swapchain& swapchain, - const RenderPass& renderPass, - const RectPipeline& rectPipeline, - const RectData& rectData) -{ - VkResult r = VK_SUCCESS; - - for (size_t i = 0; i < swapchain.imageViews.size(); ++i) { - const VkCommandBufferBeginInfo beginInfo{ - VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, - nullptr, - VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, - nullptr}; - - auto* const commandBuffer = renderPass.commandBuffers[i]; - auto cmd = vk.beginCommandBuffer(commandBuffer, beginInfo); - if (!cmd) { - return cmd.error(); - } - - recordCommandBuffer(cmd, swapchain, renderPass, rectPipeline, rectData, i); - - if ((r = cmd.end())) { - return r; - } - } - - return VK_SUCCESS; -} - -class PuglVulkanDemo; - -class View : public pugl::View -{ -public: - View(pugl::World& world, PuglVulkanDemo& app) - : pugl::View{world} - , _app{app} - { - setEventHandler(*this); - } - - template - pugl::Status onEvent(const pugl::Event&) noexcept - { - return pugl::Status::success; - } - - pugl::Status onEvent(const pugl::ConfigureEvent& event); - pugl::Status onEvent(const pugl::UpdateEvent& event); - pugl::Status onEvent(const pugl::ExposeEvent& event); - pugl::Status onEvent(const pugl::LoopEnterEvent& event); - pugl::Status onEvent(const pugl::TimerEvent& event); - pugl::Status onEvent(const pugl::LoopLeaveEvent& event); - pugl::Status onEvent(const pugl::KeyPressEvent& event); - pugl::Status onEvent(const pugl::CloseEvent& event); - -private: - PuglVulkanDemo& _app; -}; - -class PuglVulkanDemo -{ -public: - PuglVulkanDemo(const char* executablePath, - const PuglTestOptions& o, - size_t numRects); - - const char* programPath; - PuglTestOptions opts; - pugl::World world; - pugl::VulkanLoader loader; - View view; - VulkanContext vulkan; - GraphicsDevice gpu; - Renderer renderer; - RectData rectData; - RectShaders rectShaders; - uint32_t framesDrawn{0}; - VkExtent2D extent{512u, 512u}; - std::vector rects; - bool resizing{false}; - bool quit{false}; -}; - -std::vector -makeRects(const size_t numRects, const uint32_t windowWidth) -{ - std::vector rects(numRects); - for (size_t i = 0; i < numRects; ++i) { - rects[i] = makeRect(i, static_cast(windowWidth)); - } - - return rects; -} - -PuglVulkanDemo::PuglVulkanDemo(const char* const executablePath, - const PuglTestOptions& o, - const size_t numRects) - : programPath{executablePath} - , opts{o} - , world{pugl::WorldType::program, pugl::WorldFlag::threads} - , loader{world} - , view{world, *this} - , rects{makeRects(numRects, extent.width)} -{} - -VkResult -recreateRenderer(PuglVulkanDemo& app, - const sk::VulkanApi& vk, - const GraphicsDevice& gpu, - const VkExtent2D extent, - const RectData& rectData, - const RectShaders& rectShaders) -{ - VkResult r = VK_SUCCESS; - VkSurfaceCapabilitiesKHR capabilities = {}; - if ((r = vk.getPhysicalDeviceSurfaceCapabilitiesKHR( - gpu.physicalDevice, gpu.surface, capabilities))) { - return r; - } - - // There is a known race issue here, so we clamp and hope for the best - const VkExtent2D clampedExtent{ - std::min(capabilities.maxImageExtent.width, - std::max(capabilities.minImageExtent.width, extent.width)), - std::min(capabilities.maxImageExtent.height, - std::max(capabilities.minImageExtent.height, extent.height))}; - - if ((r = vk.deviceWaitIdle(gpu.device)) || - (r = app.renderer.recreate(vk, - gpu.surface, - gpu, - rectData, - rectShaders, - clampedExtent, - app.resizing))) { - return r; - } - - // Reset current (initially signaled) fence because we already waited - vk.resetFence(gpu.device, - app.renderer.sync.inFlight[app.renderer.sync.currentFrame]); - - // Record new command buffers - return recordCommandBuffers(vk, - app.renderer.swapchain, - app.renderer.renderPass, - app.renderer.rectPipeline, - rectData); -} - -pugl::Status -View::onEvent(const pugl::ConfigureEvent& event) -{ - // We just record the size here and lazily resize the surface when exposed - _app.extent = {static_cast(event.width), - static_cast(event.height)}; - - return pugl::Status::success; -} - -pugl::Status -View::onEvent(const pugl::UpdateEvent&) -{ - return postRedisplay(); -} - -VkResult -beginFrame(PuglVulkanDemo& app, const sk::Device& device, uint32_t& imageIndex) -{ - const auto& vk = app.vulkan.vk; - - VkResult r = VK_SUCCESS; - - // Wait until we can start rendering the next frame - if ((r = vk.waitForFence( - device, app.renderer.sync.inFlight[app.renderer.sync.currentFrame])) || - (r = vk.resetFence( - device, app.renderer.sync.inFlight[app.renderer.sync.currentFrame]))) { - return r; - } - - // Rebuild the renderer first if the window size has changed - if (app.extent.width != app.renderer.swapchain.extent.width || - app.extent.height != app.renderer.swapchain.extent.height) { - if ((r = recreateRenderer( - app, vk, app.gpu, app.extent, app.rectData, app.rectShaders))) { - return r; - } - } - - // Acquire the next image to render, rebuilding if necessary - while ((r = vk.acquireNextImageKHR( - device, - app.renderer.swapchain.swapchain, - UINT64_MAX, - app.renderer.sync.imageAvailable[app.renderer.sync.currentFrame], - {}, - &imageIndex))) { - switch (r) { - case VK_SUBOPTIMAL_KHR: - case VK_ERROR_OUT_OF_DATE_KHR: - if ((r = recreateRenderer(app, - vk, - app.gpu, - app.renderer.swapchain.extent, - app.rectData, - app.rectShaders))) { - return r; - } - continue; - default: - return r; - } - } - - return VK_SUCCESS; -} - -void -update(PuglVulkanDemo& app, const double time) -{ - // Animate rectangles - for (size_t i = 0; i < app.rects.size(); ++i) { - moveRect(&app.rects[i], - i, - app.rects.size(), - static_cast(app.extent.width), - static_cast(app.extent.height), - time); - } - - // Update vertex buffer - memcpy(app.rectData.vertexData.get(), - app.rects.data(), - sizeof(Rect) * app.rects.size()); - - // Update uniform buffer - UniformBufferObject ubo = {{}}; - mat4Ortho(ubo.projection, - 0.0f, - float(app.renderer.swapchain.extent.width), - 0.0f, - float(app.renderer.swapchain.extent.height), - -1.0f, - 1.0f); - - memcpy(app.rectData.uniformData.get(), &ubo, sizeof(ubo)); -} - -VkResult -endFrame(const sk::VulkanApi& vk, - const GraphicsDevice& gpu, - const Renderer& renderer, - const uint32_t imageIndex) -{ - const auto currentFrame = renderer.sync.currentFrame; - VkResult r = VK_SUCCESS; - - static constexpr VkPipelineStageFlags waitStage = - VK_PIPELINE_STAGE_TRANSFER_BIT; - - const VkSubmitInfo submitInfo{ - VK_STRUCTURE_TYPE_SUBMIT_INFO, - nullptr, - SK_COUNTED(1, &renderer.sync.imageAvailable[currentFrame].get()), - &waitStage, - SK_COUNTED(1, &renderer.renderPass.commandBuffers[imageIndex]), - SK_COUNTED(1, &renderer.sync.renderFinished[imageIndex].get())}; - - if ((r = vk.queueSubmit(gpu.graphicsQueue, - submitInfo, - renderer.sync.inFlight[currentFrame]))) { - return r; - } - - const VkPresentInfoKHR presentInfo{ - VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, - nullptr, - SK_COUNTED(1, &renderer.sync.renderFinished[imageIndex].get()), - SK_COUNTED(1, &renderer.swapchain.swapchain.get(), &imageIndex), - nullptr}; - - switch ((r = vk.queuePresentKHR(gpu.graphicsQueue, presentInfo))) { - case VK_SUCCESS: // Sucessfully presented - case VK_SUBOPTIMAL_KHR: // Probably a resize race, ignore - case VK_ERROR_OUT_OF_DATE_KHR: // Probably a resize race, ignore - break; - default: - return r; - } - - return VK_SUCCESS; -} - -pugl::Status -View::onEvent(const pugl::ExposeEvent&) -{ - const auto& vk = _app.vulkan.vk; - const auto& gpu = _app.gpu; - - // Acquire the next image, waiting and/or rebuilding if necessary - auto nextImageIndex = 0u; - if (beginFrame(_app, gpu.device, nextImageIndex)) { - return pugl::Status::unknownError; - } - - // Ready to go, update the data to the current time - update(_app, world().time()); - - // Submit the frame to the queue and present it - endFrame(vk, gpu, _app.renderer, nextImageIndex); - - ++_app.framesDrawn; - ++_app.renderer.sync.currentFrame; - _app.renderer.sync.currentFrame %= _app.renderer.sync.inFlight.size(); - - return pugl::Status::success; -} - -pugl::Status -View::onEvent(const pugl::LoopEnterEvent&) -{ - _app.resizing = true; - startTimer(resizeTimerId, - 1.0 / static_cast(getHint(pugl::ViewHint::refreshRate))); - - return pugl::Status::success; -} - -pugl::Status -View::onEvent(const pugl::TimerEvent&) -{ - return postRedisplay(); -} - -pugl::Status -View::onEvent(const pugl::LoopLeaveEvent&) -{ - stopTimer(resizeTimerId); - - // Trigger a swapchain recreation with the normal present mode - _app.renderer.swapchain.extent = {}; - _app.resizing = false; - - return pugl::Status::success; -} - -pugl::Status -View::onEvent(const pugl::KeyPressEvent& event) -{ - if (event.key == PUGL_KEY_ESCAPE || event.key == 'q') { - _app.quit = true; - } - - return pugl::Status::success; -} - -pugl::Status -View::onEvent(const pugl::CloseEvent&) -{ - _app.quit = true; - - return pugl::Status::success; -} - -VkResult -VulkanContext::init(pugl::VulkanLoader& loader, const PuglTestOptions& opts) -{ - VkResult r = VK_SUCCESS; - - sk::VulkanInitApi initApi{}; - - // Load Vulkan API and set up the fundamentals - if ((r = initApi.init(loader.getInstanceProcAddrFunc())) || - (r = createInstance(initApi, opts, instance)) || - (r = vk.init(initApi, instance)) || - (r = getDebugReportCallback(vk, instance, opts.verbose, debugCallback))) { - return r; - } - - return VK_SUCCESS; -} - -int -run(const char* const programPath, - const PuglTestOptions opts, - const size_t numRects) -{ - PuglVulkanDemo app{programPath, opts, numRects}; - - VkResult r = VK_SUCCESS; - const auto width = static_cast(app.extent.width); - const auto height = static_cast(app.extent.height); - - // Realize window so we can set up Vulkan - app.world.setClassName("PuglVulkanDemo"); - app.view.setWindowTitle("Pugl Vulkan Demo"); - app.view.setAspectRatio(1, 1, 16, 9); - app.view.setDefaultSize(width, height); - app.view.setMinSize(width / 4, height / 4); - app.view.setMaxSize(width * 4, height * 4); - app.view.setBackend(pugl::vulkanBackend()); - app.view.setHint(pugl::ViewHint::resizable, opts.resizable); - const pugl::Status st = app.view.realize(); - if (st != pugl::Status::success) { - return logError("Failed to create window (%s)\n", pugl::strerror(st)); - } - - if (!app.loader) { - return logError("Failed to load Vulkan library\n"); - } - - // Load Vulkan for the view - if ((r = app.vulkan.init(app.loader, opts))) { - return logError("Failed to set up Vulkan API (%s)\n", sk::string(r)); - } - - const auto& vk = app.vulkan.vk; - - // Set up the graphics device - if ((r = app.gpu.init(app.loader, app.vulkan, app.view, opts))) { - return logError("Failed to set up device (%s)\n", sk::string(r)); - } - - logInfo("Present mode", sk::string(app.gpu.presentMode)); - logInfo("Resize present mode", sk::string(app.gpu.resizePresentMode)); - - // Set up the rectangle data we will render every frame - if ((r = app.rectData.init(vk, app.gpu, app.rects.size()))) { - return logError("Failed to allocate render data (%s)\n", sk::string(r)); - } - - // Load shader modules - if ((r = app.rectShaders.init(vk, app.gpu, app.programPath))) { - return logError("Failed to load shaders (%s)\n", sk::string(r)); - } - - if ((r = app.renderer.init(app.vulkan.vk, - app.gpu, - app.rectData, - app.rectShaders, - app.extent, - false))) { - return logError("Failed to create renderer (%s)\n", sk::string(r)); - } - - logInfo("Swapchain frames", - std::to_string(app.renderer.swapchain.imageViews.size())); - logInfo("Frames in flight", - std::to_string(app.renderer.sync.inFlight.size())); - - recordCommandBuffers(app.vulkan.vk, - app.renderer.swapchain, - app.renderer.renderPass, - app.renderer.rectPipeline, - app.rectData); - - const int refreshRate = app.view.getHint(pugl::ViewHint::refreshRate); - const double frameDuration = 1.0 / static_cast(refreshRate); - const double timeout = app.opts.sync ? frameDuration : 0.0; - - PuglFpsPrinter fpsPrinter = {app.world.time()}; - app.view.show(); - while (!app.quit) { - app.world.update(timeout); - puglPrintFps(app.world.cobj(), &fpsPrinter, &app.framesDrawn); - } - - if ((r = app.vulkan.vk.deviceWaitIdle(app.gpu.device))) { - return logError("Failed to wait for device idle (%s)\n", sk::string(r)); - } - - return 0; -} - -} // namespace - -int -main(int argc, char** argv) -{ - // Parse command line options - const char* const programPath = argv[0]; - const PuglTestOptions opts = puglParseTestOptions(&argc, &argv); - if (opts.help) { - puglPrintTestUsage(programPath, ""); - return 0; - } - - // Parse number of rectangles argument, if given - int64_t numRects = 1000; - if (argc >= 1) { - char* endptr = nullptr; - numRects = strtol(argv[0], &endptr, 10); - if (endptr != argv[0] + strlen(argv[0]) || numRects < 1) { - logError("Invalid number of rectangles: %s\n", argv[0]); - return 1; - } - } - - // Run application - return run(programPath, opts, static_cast(numRects)); -} diff --git a/dpf/dgl/src/pugl-upstream/examples/pugl_vulkan_demo.c b/dpf/dgl/src/pugl-upstream/examples/pugl_vulkan_demo.c deleted file mode 100644 index 801b74b..0000000 --- a/dpf/dgl/src/pugl-upstream/examples/pugl_vulkan_demo.c +++ /dev/null @@ -1,1127 +0,0 @@ -/* - Copyright 2019-2020 David Robillard - Copyright 2019 Jordan Halase - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/* - A simple example of drawing with Vulkan. - - For a more advanced demo that actually draws something interesting, see - pugl_vulkan_cpp_demo.cpp. -*/ - -#include "demo_utils.h" -#include "test/test_utils.h" - -#include "pugl/pugl.h" -#include "pugl/vulkan.h" - -#include -#include - -#include -#include -#include -#include -#include - -#define CLAMP(x, l, h) ((x) <= (l) ? (l) : (x) >= (h) ? (h) : (x)) - -// Vulkan allocation callbacks which can be used for debugging -#define ALLOC_VK NULL - -// Helper macro for allocating arrays by type, with C++ compatible cast -#define AALLOC(size, Type) ((Type*)calloc(size, sizeof(Type))) - -// Helper macro for counted array arguments to make clang-format behave -#define COUNTED(count, ...) count, __VA_ARGS__ - -/// Dynamically loaded Vulkan API functions -typedef struct { - PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT; - PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT; -} InstanceAPI; - -/// Vulkan swapchain and everything that depends on it -typedef struct { - VkSwapchainKHR rawSwapchain; - uint32_t nImages; - VkExtent2D extent; - VkImage* images; - VkImageView* imageViews; - VkFence* fences; - VkCommandBuffer* commandBuffers; -} Swapchain; - -/// Synchronization semaphores -typedef struct { - VkSemaphore presentComplete; - VkSemaphore renderFinished; -} Sync; - -/// Vulkan state, purely Vulkan functions can depend on only this -typedef struct { - InstanceAPI api; - VkInstance instance; - VkDebugReportCallbackEXT debugCallback; - VkSurfaceKHR surface; - VkSurfaceFormatKHR surfaceFormat; - VkPresentModeKHR presentMode; - VkPhysicalDeviceProperties deviceProperties; - VkPhysicalDevice physicalDevice; - uint32_t graphicsIndex; - VkDevice device; - VkQueue graphicsQueue; - VkCommandPool commandPool; - Swapchain* swapchain; - Sync sync; -} VulkanState; - -/// Complete application -typedef struct { - PuglTestOptions opts; - PuglWorld* world; - PuglView* view; - VulkanState vk; - uint32_t framesDrawn; - uint32_t width; - uint32_t height; - bool quit; -} VulkanApp; - -static VKAPI_ATTR VkBool32 VKAPI_CALL -debugCallback(VkDebugReportFlagsEXT flags, - VkDebugReportObjectTypeEXT objType, - uint64_t obj, - size_t location, - int32_t code, - const char* layerPrefix, - const char* msg, - void* userData) -{ - (void)userData; - (void)objType; - (void)obj; - (void)location; - (void)code; - - if (flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) { - fprintf(stderr, "note: "); - } else if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) { - fprintf(stderr, "warning: "); - } else if (flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) { - fprintf(stderr, "performance warning: "); - } else if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) { - fprintf(stderr, "error: "); - } else if (flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) { - fprintf(stderr, "debug: "); - } - - fprintf(stderr, "%s: ", layerPrefix); - fprintf(stderr, "%s\n", msg); - return VK_FALSE; -} - -static bool -hasExtension(const char* const name, - const VkExtensionProperties* const properties, - const uint32_t count) -{ - for (uint32_t i = 0; i < count; ++i) { - if (!strcmp(properties[i].extensionName, name)) { - return true; - } - } - - return false; -} - -static bool -hasLayer(const char* const name, - const VkLayerProperties* const properties, - const uint32_t count) -{ - for (uint32_t i = 0; i < count; ++i) { - if (!strcmp(properties[i].layerName, name)) { - return true; - } - } - - return false; -} - -static void -pushString(const char*** const array, - uint32_t* const count, - const char* const string) -{ - *array = (const char**)realloc(*array, (*count + 1) * sizeof(const char*)); - (*array)[*count] = string; - ++*count; -} - -static VkResult -createInstance(VulkanApp* const app) -{ - const VkApplicationInfo appInfo = { - VK_STRUCTURE_TYPE_APPLICATION_INFO, - NULL, - "Pugl Vulkan Test", - VK_MAKE_VERSION(0, 1, 0), - "Pugl Vulkan Test Engine", - VK_MAKE_VERSION(0, 1, 0), - VK_MAKE_VERSION(1, 0, 0), - }; - - // Get the number of supported extensions and layers - VkResult vr = VK_SUCCESS; - uint32_t nExtProps = 0; - uint32_t nLayerProps = 0; - if ((vr = vkEnumerateInstanceLayerProperties(&nLayerProps, NULL)) || - (vr = vkEnumerateInstanceExtensionProperties(NULL, &nExtProps, NULL))) { - return vr; - } - - // Get properties of supported extensions - VkExtensionProperties* extProps = AALLOC(nExtProps, VkExtensionProperties); - vkEnumerateInstanceExtensionProperties(NULL, &nExtProps, extProps); - - uint32_t nExtensions = 0; - const char** extensions = NULL; - - // Add extensions required by pugl - uint32_t nPuglExts = 0; - const char* const* puglExts = puglGetInstanceExtensions(&nPuglExts); - for (uint32_t i = 0; i < nPuglExts; ++i) { - pushString(&extensions, &nExtensions, puglExts[i]); - } - - // Add extra extensions we want to use if they are supported - if (hasExtension("VK_EXT_debug_report", extProps, nExtProps)) { - pushString(&extensions, &nExtensions, "VK_EXT_debug_report"); - } - - // Get properties of supported layers - VkLayerProperties* layerProps = AALLOC(nLayerProps, VkLayerProperties); - vkEnumerateInstanceLayerProperties(&nLayerProps, layerProps); - - // Add validation layers if error checking is enabled - uint32_t nLayers = 0; - const char** layers = NULL; - if (app->opts.errorChecking) { - const char* debugLayers[] = {"VK_LAYER_KHRONOS_validation", - "VK_LAYER_LUNARG_standard_validation", - NULL}; - - for (const char** l = debugLayers; *l; ++l) { - if (hasLayer(*l, layerProps, nLayerProps)) { - pushString(&layers, &nLayers, *l); - } - } - } - - for (uint32_t i = 0; i < nExtensions; ++i) { - printf("Using instance extension: %s\n", extensions[i]); - } - - for (uint32_t i = 0; i < nLayers; ++i) { - printf("Using instance layer: %s\n", layers[i]); - } - - const VkInstanceCreateInfo createInfo = { - VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, - NULL, - 0, - &appInfo, - COUNTED(nLayers, layers), - COUNTED(nExtensions, extensions), - }; - - if ((vr = vkCreateInstance(&createInfo, ALLOC_VK, &app->vk.instance))) { - logError("Could not create Vulkan Instance: %d\n", vr); - } - - free(layers); - free(extensions); - free(layerProps); - free(extProps); - - return vr; -} - -static VkResult -enableDebugging(VulkanState* const vk) -{ - vk->api.vkCreateDebugReportCallbackEXT = - (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr( - vk->instance, "vkCreateDebugReportCallbackEXT"); - - vk->api.vkDestroyDebugReportCallbackEXT = - (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr( - vk->instance, "vkDestroyDebugReportCallbackEXT"); - - if (vk->api.vkCreateDebugReportCallbackEXT) { - const VkDebugReportCallbackCreateInfoEXT info = { - VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT, - NULL, - VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT, - debugCallback, - NULL, - }; - - VkResult vr = VK_SUCCESS; - if ((vr = vk->api.vkCreateDebugReportCallbackEXT( - vk->instance, &info, ALLOC_VK, &vk->debugCallback))) { - logError("Could not create debug reporter: %d\n", vr); - return vr; - } - } - - return VK_SUCCESS; -} - -static VkResult -getGraphicsQueueIndex(VkSurfaceKHR surface, - VkPhysicalDevice device, - uint32_t* graphicsIndex) -{ - VkResult r = VK_SUCCESS; - - uint32_t nProps = 0; - vkGetPhysicalDeviceQueueFamilyProperties(device, &nProps, NULL); - - VkQueueFamilyProperties* props = AALLOC(nProps, VkQueueFamilyProperties); - vkGetPhysicalDeviceQueueFamilyProperties(device, &nProps, props); - - for (uint32_t q = 0; q < nProps; ++q) { - if (props[q].queueFlags & VK_QUEUE_GRAPHICS_BIT) { - VkBool32 supported = false; - if ((r = vkGetPhysicalDeviceSurfaceSupportKHR( - device, q, surface, &supported))) { - free(props); - return r; - } - - if (supported) { - *graphicsIndex = q; - free(props); - return VK_SUCCESS; - } - } - } - - free(props); - return VK_ERROR_FEATURE_NOT_PRESENT; -} - -static bool -supportsRequiredExtensions(const VkPhysicalDevice device) -{ - uint32_t nExtProps = 0; - vkEnumerateDeviceExtensionProperties(device, NULL, &nExtProps, NULL); - - VkExtensionProperties* extProps = AALLOC(nExtProps, VkExtensionProperties); - vkEnumerateDeviceExtensionProperties(device, NULL, &nExtProps, extProps); - - for (uint32_t i = 0; i < nExtProps; ++i) { - if (!strcmp(extProps[i].extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME)) { - free(extProps); - return true; - } - } - - free(extProps); - return false; -} - -static bool -isDeviceSuitable(const VulkanState* const vk, - const VkPhysicalDevice device, - uint32_t* const graphicsIndex) -{ - if (!supportsRequiredExtensions(device) || - getGraphicsQueueIndex(vk->surface, device, graphicsIndex)) { - return false; - } - - return true; -} - -/** - Selects a physical graphics device. - - This doesn't try to be clever, and just selects the first suitable device. -*/ -static VkResult -selectPhysicalDevice(VulkanState* const vk) -{ - VkResult vr = VK_SUCCESS; - if (!vk->surface) { - logError("Cannot select a physical device without a surface\n"); - return VK_ERROR_SURFACE_LOST_KHR; - } - - uint32_t nDevices = 0; - if ((vr = vkEnumeratePhysicalDevices(vk->instance, &nDevices, NULL))) { - logError("Failed to get count of physical devices: %d\n", vr); - return vr; - } - - if (!nDevices) { - logError("No physical devices found\n"); - return VK_ERROR_DEVICE_LOST; - } - - VkPhysicalDevice* devices = AALLOC(nDevices, VkPhysicalDevice); - if ((vr = vkEnumeratePhysicalDevices(vk->instance, &nDevices, devices))) { - logError("Failed to enumerate physical devices: %d\n", vr); - free(devices); - return vr; - } - - uint32_t i = 0; - for (i = 0; i < nDevices; ++i) { - VkPhysicalDeviceProperties deviceProps = {0}; - vkGetPhysicalDeviceProperties(devices[i], &deviceProps); - - uint32_t graphicsIndex = 0; - if (isDeviceSuitable(vk, devices[i], &graphicsIndex)) { - printf("Using device %u/%u: \"%s\"\n", - i + 1, - nDevices, - deviceProps.deviceName); - vk->deviceProperties = deviceProps; - vk->physicalDevice = devices[i]; - vk->graphicsIndex = graphicsIndex; - printf("Using graphics queue family: %u\n", vk->graphicsIndex); - break; - } - - printf("Device \"%s\" not suitable\n", deviceProps.deviceName); - } - - if (i >= nDevices) { - logError("No suitable devices found\n"); - vr = VK_ERROR_DEVICE_LOST; - } - - free(devices); - return vr; -} - -/// Opens the logical device and sets up the queue and command pool -static VkResult -openDevice(VulkanState* const vk) -{ - if (vk->device) { - logError("Renderer already has an opened device\n"); - return VK_NOT_READY; - } - - const float graphicsQueuePriority = 1.0f; - const char* const swapchainName = VK_KHR_SWAPCHAIN_EXTENSION_NAME; - - const VkDeviceQueueCreateInfo queueCreateInfo = { - VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, - NULL, - 0, - vk->graphicsIndex, - COUNTED(1, &graphicsQueuePriority), - }; - - const VkDeviceCreateInfo createInfo = { - VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, - NULL, - 0, - COUNTED(1, &queueCreateInfo), - COUNTED(0, NULL), - COUNTED(1, &swapchainName), - NULL, - }; - - VkDevice device = NULL; - VkResult vr = VK_SUCCESS; - if ((vr = - vkCreateDevice(vk->physicalDevice, &createInfo, ALLOC_VK, &device))) { - logError("Could not open device \"%s\": %d\n", - vk->deviceProperties.deviceName, - vr); - return vr; - } - - vk->device = device; - vkGetDeviceQueue(vk->device, vk->graphicsIndex, 0, &vk->graphicsQueue); - - const VkCommandPoolCreateInfo commandInfo = { - VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, - NULL, - 0, - vk->graphicsIndex, - }; - - if ((vr = vkCreateCommandPool( - vk->device, &commandInfo, ALLOC_VK, &vk->commandPool))) { - logError("Could not create command pool: %d\n", vr); - return vr; - } - - return VK_SUCCESS; -} - -static const char* -presentModeString(const VkPresentModeKHR presentMode) -{ - switch (presentMode) { - case VK_PRESENT_MODE_IMMEDIATE_KHR: - return "Immediate"; - case VK_PRESENT_MODE_MAILBOX_KHR: - return "Mailbox"; - case VK_PRESENT_MODE_FIFO_KHR: - return "FIFO"; - case VK_PRESENT_MODE_FIFO_RELAXED_KHR: - return "FIFO relaxed"; - default: - return "Other"; - } -} - -static bool -hasPresentMode(const VkPresentModeKHR mode, - const VkPresentModeKHR* const presentModes, - const uint32_t nPresentModes) -{ - for (uint32_t i = 0; i < nPresentModes; ++i) { - if (presentModes[i] == mode) { - return true; - } - } - - return false; -} - -/// Configure the surface for the currently opened device -static VkResult -configureSurface(VulkanState* const vk) -{ - uint32_t nFormats = 0; - vkGetPhysicalDeviceSurfaceFormatsKHR( - vk->physicalDevice, vk->surface, &nFormats, NULL); - if (!nFormats) { - logError("No surface formats available\n"); - return VK_ERROR_FORMAT_NOT_SUPPORTED; - } - - VkSurfaceFormatKHR* surfaceFormats = AALLOC(nFormats, VkSurfaceFormatKHR); - vkGetPhysicalDeviceSurfaceFormatsKHR( - vk->physicalDevice, vk->surface, &nFormats, surfaceFormats); - - const VkSurfaceFormatKHR want = {VK_FORMAT_B8G8R8A8_UNORM, - VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}; - - uint32_t formatIndex = 0; - for (formatIndex = 0; formatIndex < nFormats; ++formatIndex) { - if (surfaceFormats[formatIndex].format == want.format && - surfaceFormats[formatIndex].colorSpace == want.colorSpace) { - vk->surfaceFormat = want; - break; - } - } - free(surfaceFormats); - if (formatIndex >= nFormats) { - logError("Could not find a suitable surface format\n"); - return VK_ERROR_FORMAT_NOT_SUPPORTED; - } - - uint32_t nPresentModes = 0; - vkGetPhysicalDeviceSurfacePresentModesKHR( - vk->physicalDevice, vk->surface, &nPresentModes, NULL); - if (!nPresentModes) { - logError("No present modes available\n"); - return VK_ERROR_FORMAT_NOT_SUPPORTED; - } - - VkPresentModeKHR* presentModes = AALLOC(nPresentModes, VkPresentModeKHR); - vkGetPhysicalDeviceSurfacePresentModesKHR( - vk->physicalDevice, vk->surface, &nPresentModes, presentModes); - - const VkPresentModeKHR tryModes[] = { - VK_PRESENT_MODE_MAILBOX_KHR, - VK_PRESENT_MODE_FIFO_RELAXED_KHR, - VK_PRESENT_MODE_FIFO_KHR, - VK_PRESENT_MODE_IMMEDIATE_KHR, - }; - - VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR; - for (uint32_t i = 0; i < sizeof(tryModes) / sizeof(VkPresentModeKHR); ++i) { - if (hasPresentMode(tryModes[i], presentModes, nPresentModes)) { - presentMode = tryModes[i]; - break; - } - } - - free(presentModes); - vk->presentMode = presentMode; - printf("Using present mode: \"%s\" (%u)\n", - presentModeString(presentMode), - presentMode); - - return VK_SUCCESS; -} - -static VkResult -createRawSwapchain(VulkanState* const vk, - const uint32_t width, - const uint32_t height) -{ - VkSurfaceCapabilitiesKHR surfaceCapabilities; - VkResult vr = VK_SUCCESS; - if ((vr = vkGetPhysicalDeviceSurfaceCapabilitiesKHR( - vk->physicalDevice, vk->surface, &surfaceCapabilities))) { - logError("Could not get surface capabilities: %d\n", vr); - return vr; - } - - /* There is a known race condition with window/surface sizes, so we clamp - to what Vulkan reports and hope for the best. */ - - vk->swapchain->extent.width = CLAMP(width, - surfaceCapabilities.minImageExtent.width, - surfaceCapabilities.maxImageExtent.width); - - vk->swapchain->extent.height = - CLAMP(height, - surfaceCapabilities.minImageExtent.height, - surfaceCapabilities.maxImageExtent.height); - - vk->swapchain->nImages = surfaceCapabilities.minImageCount; - - const VkSwapchainCreateInfoKHR createInfo = { - VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, - NULL, - 0, - vk->surface, - vk->swapchain->nImages, - vk->surfaceFormat.format, - VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, - vk->swapchain->extent, - 1, - (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT), - VK_SHARING_MODE_EXCLUSIVE, - COUNTED(0, NULL), - surfaceCapabilities.currentTransform, - VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, - vk->presentMode, - VK_TRUE, - 0, - }; - - if ((vr = vkCreateSwapchainKHR( - vk->device, &createInfo, ALLOC_VK, &vk->swapchain->rawSwapchain))) { - logError("Could not create swapchain: %d\n", vr); - return vr; - } - - return VK_SUCCESS; -} - -static VkResult -recordCommandBuffers(VulkanState* const vk) -{ - const VkClearColorValue clearValue = {{ - 0xA4 / (float)0x100, // R - 0x1E / (float)0x100, // G - 0x22 / (float)0x100, // B - 0xFF / (float)0x100, // A - }}; - - const VkImageSubresourceRange range = { - VK_IMAGE_ASPECT_COLOR_BIT, - 0, - 1, - 0, - 1, - }; - - const VkCommandBufferBeginInfo beginInfo = { - VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, - NULL, - VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, - NULL, - }; - - for (uint32_t i = 0; i < vk->swapchain->nImages; ++i) { - const VkImageMemoryBarrier toClearBarrier = { - VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - NULL, - VK_ACCESS_MEMORY_READ_BIT, - VK_ACCESS_TRANSFER_WRITE_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - vk->graphicsIndex, - vk->graphicsIndex, - vk->swapchain->images[i], - range, - }; - - const VkImageMemoryBarrier toPresentBarrier = { - VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - NULL, - VK_ACCESS_TRANSFER_WRITE_BIT, - VK_ACCESS_MEMORY_READ_BIT, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, - vk->graphicsIndex, - vk->graphicsIndex, - vk->swapchain->images[i], - range, - }; - - vkBeginCommandBuffer(vk->swapchain->commandBuffers[i], &beginInfo); - - vkCmdPipelineBarrier(vk->swapchain->commandBuffers[i], - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT, - 0, - COUNTED(0, NULL), - COUNTED(0, NULL), - COUNTED(1, &toClearBarrier)); - - vkCmdClearColorImage(vk->swapchain->commandBuffers[i], - vk->swapchain->images[i], - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - &clearValue, - COUNTED(1, &range)); - - vkCmdPipelineBarrier(vk->swapchain->commandBuffers[i], - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, - 0, - COUNTED(0, NULL), - COUNTED(0, NULL), - COUNTED(1, &toPresentBarrier)); - - vkEndCommandBuffer(vk->swapchain->commandBuffers[i]); - } - - return VK_SUCCESS; -} - -static VkResult -createSwapchain(VulkanState* const vk, - const uint32_t width, - const uint32_t height) -{ - VkResult vr = VK_SUCCESS; - - vk->swapchain = AALLOC(1, Swapchain); - if ((vr = createRawSwapchain(vk, width, height))) { - return vr; - } - - if ((vr = vkGetSwapchainImagesKHR(vk->device, - vk->swapchain->rawSwapchain, - &vk->swapchain->nImages, - NULL))) { - logError("Failed to query swapchain images: %d\n", vr); - return vr; - } - - vk->swapchain->images = AALLOC(vk->swapchain->nImages, VkImage); - if ((vr = vkGetSwapchainImagesKHR(vk->device, - vk->swapchain->rawSwapchain, - &vk->swapchain->nImages, - vk->swapchain->images))) { - logError("Failed to get swapchain images: %d\n", vr); - return vr; - } - - const VkCommandBufferAllocateInfo allocInfo = { - VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, - NULL, - vk->commandPool, - VK_COMMAND_BUFFER_LEVEL_PRIMARY, - vk->swapchain->nImages, - }; - - vk->swapchain->commandBuffers = - AALLOC(vk->swapchain->nImages, VkCommandBuffer); - - if ((vr = vkAllocateCommandBuffers( - vk->device, &allocInfo, vk->swapchain->commandBuffers))) { - logError("Could not allocate command buffers: %d\n", vr); - return vr; - } - - const VkFenceCreateInfo fenceInfo = { - VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, - NULL, - VK_FENCE_CREATE_SIGNALED_BIT, - }; - vk->swapchain->fences = AALLOC(vk->swapchain->nImages, VkFence); - - for (uint32_t i = 0; i < vk->swapchain->nImages; ++i) { - if ((vr = vkCreateFence( - vk->device, &fenceInfo, ALLOC_VK, &vk->swapchain->fences[i]))) { - logError("Could not create render finished fence: %d\n", vr); - return vr; - } - } - - if ((vr = recordCommandBuffers(vk))) { - logError("Failed to record command buffers\n"); - return vr; - } - - return VK_SUCCESS; -} - -static void -destroySwapchain(VulkanState* const vk, Swapchain* const swapchain) -{ - if (!swapchain) { - return; - } - - for (uint32_t i = 0; i < swapchain->nImages; ++i) { - if (swapchain->fences[i]) { - vkDestroyFence(vk->device, swapchain->fences[i], ALLOC_VK); - } - - if (swapchain->imageViews && swapchain->imageViews[i]) { - vkDestroyImageView(vk->device, swapchain->imageViews[i], ALLOC_VK); - } - } - - free(swapchain->fences); - swapchain->fences = NULL; - free(swapchain->imageViews); - swapchain->imageViews = NULL; - - if (swapchain->images) { - free(swapchain->images); - swapchain->images = NULL; - } - - if (swapchain->commandBuffers) { - vkFreeCommandBuffers(vk->device, - vk->commandPool, - swapchain->nImages, - swapchain->commandBuffers); - free(swapchain->commandBuffers); - } - - if (swapchain->rawSwapchain) { - vkDestroySwapchainKHR(vk->device, swapchain->rawSwapchain, ALLOC_VK); - } - - free(swapchain); -} - -static VkResult -createSyncObjects(VulkanState* const vk) -{ - const VkSemaphoreCreateInfo info = { - VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, - NULL, - 0, - }; - - vkCreateSemaphore(vk->device, &info, ALLOC_VK, &vk->sync.presentComplete); - vkCreateSemaphore(vk->device, &info, ALLOC_VK, &vk->sync.renderFinished); - return VK_SUCCESS; -} - -static void -destroySyncObjects(VulkanState* const vk) -{ - if (vk->sync.renderFinished) { - vkDestroySemaphore(vk->device, vk->sync.renderFinished, ALLOC_VK); - vk->sync.renderFinished = VK_NULL_HANDLE; - } - if (vk->sync.presentComplete) { - vkDestroySemaphore(vk->device, vk->sync.presentComplete, ALLOC_VK); - vk->sync.presentComplete = VK_NULL_HANDLE; - } -} - -static void -closeDevice(VulkanState* const vk) -{ - if (vk->device) { - vkDeviceWaitIdle(vk->device); - destroySyncObjects(vk); - destroySwapchain(vk, vk->swapchain); - if (vk->commandPool) { - vkDestroyCommandPool(vk->device, vk->commandPool, ALLOC_VK); - vk->commandPool = VK_NULL_HANDLE; - } - vk->graphicsQueue = VK_NULL_HANDLE; - vkDestroyDevice(vk->device, ALLOC_VK); - vk->device = VK_NULL_HANDLE; - } -} - -static void -destroyWorld(VulkanApp* const app) -{ - VulkanState* vk = &app->vk; - - if (vk) { - closeDevice(vk); - - if (app->view) { - puglHide(app->view); - puglFreeView(app->view); - app->view = NULL; - } - if (vk->debugCallback && vk->api.vkDestroyDebugReportCallbackEXT) { - vk->api.vkDestroyDebugReportCallbackEXT( - vk->instance, vk->debugCallback, ALLOC_VK); - vk->debugCallback = VK_NULL_HANDLE; - } - if (vk->surface) { - vkDestroySurfaceKHR(vk->instance, vk->surface, ALLOC_VK); - vk->surface = VK_NULL_HANDLE; - } - if (vk->instance) { - fflush(stderr); - vkDestroyInstance(vk->instance, ALLOC_VK); - vk->instance = VK_NULL_HANDLE; - } - if (app->world) { - puglFreeWorld(app->world); - app->world = NULL; - } - } -} - -static PuglStatus -onConfigure(PuglView* const view, const double width, const double height) -{ - VulkanApp* const app = (VulkanApp*)puglGetHandle(view); - - // We just record the size here and lazily resize the surface when exposed - app->width = (uint32_t)width; - app->height = (uint32_t)height; - - return PUGL_SUCCESS; -} - -static PuglStatus -recreateSwapchain(VulkanState* const vk, - const uint32_t width, - const uint32_t height) -{ - vkDeviceWaitIdle(vk->device); - destroySwapchain(vk, vk->swapchain); - - if (createSwapchain(vk, width, height)) { - logError("Failed to recreate swapchain\n"); - return PUGL_UNKNOWN_ERROR; - } - - return PUGL_SUCCESS; -} - -static PuglStatus -onExpose(PuglView* const view) -{ - VulkanApp* app = (VulkanApp*)puglGetHandle(view); - VulkanState* vk = &app->vk; - uint32_t imageIndex = 0; - VkResult result = VK_SUCCESS; - - // Recreate swapchain if the window size has changed - const Swapchain* swapchain = vk->swapchain; - if (swapchain->extent.width != app->width || - swapchain->extent.height != app->height) { - recreateSwapchain(vk, app->width, app->height); - } - - // Acquire the next image to render, rebuilding if necessary - while ((result = vkAcquireNextImageKHR(vk->device, - vk->swapchain->rawSwapchain, - UINT64_MAX, - vk->sync.presentComplete, - VK_NULL_HANDLE, - &imageIndex))) { - switch (result) { - case VK_SUCCESS: - break; - case VK_SUBOPTIMAL_KHR: - case VK_ERROR_OUT_OF_DATE_KHR: - recreateSwapchain(vk, app->width, app->height); - continue; - default: - logError("Could not acquire swapchain image: %d\n", result); - return PUGL_UNKNOWN_ERROR; - } - } - - // Wait until we can start rendering this frame - vkWaitForFences(vk->device, - COUNTED(1, &vk->swapchain->fences[imageIndex]), - VK_TRUE, - UINT64_MAX); - vkResetFences(vk->device, 1, &vk->swapchain->fences[imageIndex]); - - const VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_TRANSFER_BIT; - - // Submit command buffer to render this frame - const VkSubmitInfo submitInfo = { - VK_STRUCTURE_TYPE_SUBMIT_INFO, - NULL, - COUNTED(1, &vk->sync.presentComplete), - &waitStage, - COUNTED(1, &vk->swapchain->commandBuffers[imageIndex]), - COUNTED(1, &vk->sync.renderFinished)}; - if ((result = vkQueueSubmit(vk->graphicsQueue, - 1, - &submitInfo, - vk->swapchain->fences[imageIndex]))) { - logError("Could not submit to queue: %d\n", result); - return PUGL_FAILURE; - } - - // Present this frame - const VkPresentInfoKHR presentInfo = { - VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, - NULL, - COUNTED(1, &vk->sync.renderFinished), - COUNTED(1, &vk->swapchain->rawSwapchain, &imageIndex, NULL), - }; - if ((result = vkQueuePresentKHR(vk->graphicsQueue, &presentInfo))) { - logError("Could not present image: %d\n", result); - } - - if (app->opts.continuous) { - ++app->framesDrawn; - } - - return PUGL_SUCCESS; -} - -static PuglStatus -onEvent(PuglView* const view, const PuglEvent* const e) -{ - VulkanApp* const app = (VulkanApp*)puglGetHandle(view); - - printEvent(e, "Event: ", app->opts.verbose); - - switch (e->type) { - case PUGL_EXPOSE: - return onExpose(view); - case PUGL_CONFIGURE: - return onConfigure(view, e->configure.width, e->configure.height); - case PUGL_CLOSE: - app->quit = 1; - break; - case PUGL_KEY_PRESS: - switch (e->key.key) { - case PUGL_KEY_ESCAPE: - case 'q': - app->quit = 1; - break; - } - break; - default: - break; - } - return PUGL_SUCCESS; -} - -int -main(int argc, char** argv) -{ - VulkanApp app = {0}; - VulkanState* vk = &app.vk; - const uint32_t defaultWidth = 640; - const uint32_t defaultHeight = 360; - const PuglRect frame = {0, 0, defaultWidth, defaultHeight}; - - // Parse command line options - app.opts = puglParseTestOptions(&argc, &argv); - if (app.opts.help) { - puglPrintTestUsage(argv[0], ""); - return 0; - } - - // Create world and view - if (!(app.world = puglNewWorld(PUGL_PROGRAM, PUGL_WORLD_THREADS))) { - return logError("Failed to create world\n"); - } - - if (!(app.view = puglNewView(app.world))) { - puglFreeWorld(app.world); - return logError("Failed to create Pugl World and View\n"); - } - - // Create Vulkan instance - if (createInstance(&app)) { - puglFreeWorld(app.world); - return logError("Failed to create instance\n"); - } - - // Create window - puglSetWindowTitle(app.view, "Pugl Vulkan"); - puglSetFrame(app.view, frame); - puglSetHandle(app.view, &app); - puglSetBackend(app.view, puglVulkanBackend()); - puglSetViewHint(app.view, PUGL_RESIZABLE, app.opts.resizable); - puglSetEventFunc(app.view, onEvent); - const PuglStatus st = puglRealize(app.view); - if (st) { - puglFreeWorld(app.world); - puglFreeView(app.view); - return logError("Failed to create window (%s)\n", puglStrerror(st)); - } - - // Create Vulkan surface for window - PuglVulkanLoader* loader = puglNewVulkanLoader(app.world); - if (puglCreateSurface(puglGetInstanceProcAddrFunc(loader), - app.view, - vk->instance, - ALLOC_VK, - &vk->surface)) { - return logError("Failed to create surface\n"); - } - - // Set up Vulkan - VkResult vr = VK_SUCCESS; - if ((vr = enableDebugging(vk)) || // - (vr = selectPhysicalDevice(vk)) || // - (vr = openDevice(vk)) || // - (vr = configureSurface(vk)) || // - (vr = createSwapchain(vk, defaultWidth, defaultHeight)) || // - (vr = createSyncObjects(vk))) { - destroyWorld(&app); - return logError("Failed to set up graphics (%d)\n", vr); - } - - printf("Swapchain images: %u\n", app.vk.swapchain->nImages); - - PuglFpsPrinter fpsPrinter = {puglGetTime(app.world)}; - puglShow(app.view); - while (!app.quit) { - puglUpdate(app.world, -1.0); - - if (app.opts.continuous) { - puglPrintFps(app.world, &fpsPrinter, &app.framesDrawn); - } - } - - destroyWorld(&app); - return 0; -} diff --git a/dpf/dgl/src/pugl-upstream/examples/pugl_window_demo.c b/dpf/dgl/src/pugl-upstream/examples/pugl_window_demo.c deleted file mode 100644 index 1e38aa1..0000000 --- a/dpf/dgl/src/pugl-upstream/examples/pugl_window_demo.c +++ /dev/null @@ -1,254 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/* - A demonstration of using multiple top-level windows. -*/ - -#include "cube_view.h" -#include "demo_utils.h" -#include "test/test_utils.h" - -#include "pugl/gl.h" -#include "pugl/pugl.h" - -#include -#include -#include - -typedef struct { - PuglView* view; - double xAngle; - double yAngle; - double lastMouseX; - double lastMouseY; - double lastDrawTime; - float dist; - bool entered; -} CubeView; - -typedef struct { - PuglWorld* world; - CubeView cubes[2]; - int quit; - bool continuous; - bool verbose; -} PuglTestApp; - -static const double pad = 64.0; - -static void -onDisplay(PuglView* view) -{ - PuglWorld* world = puglGetWorld(view); - PuglTestApp* app = (PuglTestApp*)puglGetWorldHandle(world); - CubeView* cube = (CubeView*)puglGetHandle(view); - - const double thisTime = puglGetTime(app->world); - if (app->continuous) { - const double dTime = thisTime - cube->lastDrawTime; - - cube->xAngle = fmod(cube->xAngle + dTime * 100.0, 360.0); - cube->yAngle = fmod(cube->yAngle + dTime * 100.0, 360.0); - } - - displayCube( - view, cube->dist, (float)cube->xAngle, (float)cube->yAngle, cube->entered); - - cube->lastDrawTime = thisTime; -} - -static void -onKeyPress(PuglView* view, const PuglKeyEvent* event) -{ - PuglWorld* world = puglGetWorld(view); - PuglTestApp* app = (PuglTestApp*)puglGetWorldHandle(world); - PuglRect frame = puglGetFrame(view); - - if (event->key == 'q' || event->key == PUGL_KEY_ESCAPE) { - app->quit = 1; - } else if (event->state & PUGL_MOD_SHIFT) { - if (event->key == PUGL_KEY_UP) { - frame.height += 10; - } else if (event->key == PUGL_KEY_DOWN) { - frame.height -= 10; - } else if (event->key == PUGL_KEY_LEFT) { - frame.width -= 10; - } else if (event->key == PUGL_KEY_RIGHT) { - frame.width += 10; - } else { - return; - } - puglSetFrame(view, frame); - } else { - if (event->key == PUGL_KEY_UP) { - frame.y -= 10; - } else if (event->key == PUGL_KEY_DOWN) { - frame.y += 10; - } else if (event->key == PUGL_KEY_LEFT) { - frame.x -= 10; - } else if (event->key == PUGL_KEY_RIGHT) { - frame.x += 10; - } else { - return; - } - puglSetFrame(view, frame); - } -} - -static void -redisplayView(PuglTestApp* app, PuglView* view) -{ - if (!app->continuous) { - puglPostRedisplay(view); - } -} - -static PuglStatus -onEvent(PuglView* view, const PuglEvent* event) -{ - PuglWorld* world = puglGetWorld(view); - PuglTestApp* app = (PuglTestApp*)puglGetWorldHandle(world); - CubeView* cube = (CubeView*)puglGetHandle(view); - - const char* const prefix = cube == &app->cubes[0] ? "View 1: " : "View 2: "; - printEvent(event, prefix, app->verbose); - - switch (event->type) { - case PUGL_CONFIGURE: - reshapeCube((float)event->configure.width, (float)event->configure.height); - break; - case PUGL_UPDATE: - if (app->continuous) { - puglPostRedisplay(view); - } - break; - case PUGL_EXPOSE: - onDisplay(view); - break; - case PUGL_CLOSE: - app->quit = 1; - break; - case PUGL_KEY_PRESS: - onKeyPress(view, &event->key); - break; - case PUGL_MOTION: - cube->xAngle -= event->motion.x - cube->lastMouseX; - cube->yAngle += event->motion.y - cube->lastMouseY; - cube->lastMouseX = event->motion.x; - cube->lastMouseY = event->motion.y; - redisplayView(app, view); - break; - case PUGL_SCROLL: - cube->dist = fmaxf(10.0f, cube->dist + (float)event->scroll.dy); - redisplayView(app, view); - break; - case PUGL_POINTER_IN: - cube->entered = true; - redisplayView(app, view); - break; - case PUGL_POINTER_OUT: - cube->entered = false; - redisplayView(app, view); - break; - case PUGL_FOCUS_IN: - case PUGL_FOCUS_OUT: - redisplayView(app, view); - break; - default: - break; - } - - return PUGL_SUCCESS; -} - -int -main(int argc, char** argv) -{ - PuglTestApp app = {0}; - - const PuglTestOptions opts = puglParseTestOptions(&argc, &argv); - if (opts.help) { - puglPrintTestUsage(argv[0], ""); - return 1; - } - - app.continuous = opts.continuous; - app.verbose = opts.verbose; - - app.world = puglNewWorld(PUGL_PROGRAM, 0); - app.cubes[0].view = puglNewView(app.world); - app.cubes[1].view = puglNewView(app.world); - - puglSetWorldHandle(app.world, &app); - puglSetClassName(app.world, "Pugl Test"); - - PuglStatus st = PUGL_SUCCESS; - for (unsigned i = 0; i < 2; ++i) { - CubeView* cube = &app.cubes[i]; - PuglView* view = cube->view; - const PuglRect frame = { - pad + (128.0 + pad) * i, pad + (128.0 + pad) * i, 512.0, 512.0}; - - cube->dist = 10; - - puglSetWindowTitle(view, "Pugl Window Demo"); - puglSetFrame(view, frame); - puglSetDefaultSize(view, 512, 512); - puglSetMinSize(view, 128, 128); - puglSetMaxSize(view, 2048, 2048); - puglSetBackend(view, puglGlBackend()); - - puglSetViewHint(view, PUGL_USE_DEBUG_CONTEXT, opts.errorChecking); - puglSetViewHint(view, PUGL_RESIZABLE, opts.resizable); - puglSetViewHint(view, PUGL_SAMPLES, opts.samples); - puglSetViewHint(view, PUGL_DOUBLE_BUFFER, opts.doubleBuffer); - puglSetViewHint(view, PUGL_SWAP_INTERVAL, opts.sync); - puglSetViewHint(view, PUGL_IGNORE_KEY_REPEAT, opts.ignoreKeyRepeat); - puglSetHandle(view, cube); - puglSetEventFunc(view, onEvent); - - if (i == 1) { - puglSetTransientFor(app.cubes[1].view, - puglGetNativeWindow(app.cubes[0].view)); - } - - if ((st = puglRealize(view))) { - return logError("Failed to create window (%s)\n", puglStrerror(st)); - } - - puglShow(view); - } - - PuglFpsPrinter fpsPrinter = {puglGetTime(app.world)}; - unsigned framesDrawn = 0; - while (!app.quit) { - puglUpdate(app.world, app.continuous ? 0.0 : -1.0); - ++framesDrawn; - - if (app.continuous) { - puglPrintFps(app.world, &fpsPrinter, &framesDrawn); - } - } - - for (size_t i = 0; i < 2; ++i) { - puglFreeView(app.cubes[i].view); - } - - puglFreeWorld(app.world); - - return 0; -} diff --git a/dpf/dgl/src/pugl-upstream/examples/rects.h b/dpf/dgl/src/pugl-upstream/examples/rects.h deleted file mode 100644 index b99d9f0..0000000 --- a/dpf/dgl/src/pugl-upstream/examples/rects.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - Copyright 2019-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef EXAMPLES_RECTS_H -#define EXAMPLES_RECTS_H - -#include -#include - -typedef float vec2[2]; - -typedef struct { - float pos[2]; - float size[2]; - float fillColor[4]; -} Rect; - -static const vec2 rectVertices[] = { - {0.0f, 0.0f}, // TL - {1.0f, 0.0f}, // TR - {0.0f, 1.0f}, // BL - {1.0f, 1.0f} // BR -}; - -static const unsigned rectIndices[4] = {0, 1, 2, 3}; - -/// Make a new rectangle with the given index (each is slightly different) -static inline Rect -makeRect(const size_t index, const float frameWidth) -{ - static const float alpha = 0.3f; - const float minSize = frameWidth / 64.0f; - const float maxSize = frameWidth / 6.0f; - const float s = (sinf((float)index) / 2.0f + 0.5f); - const float c = (cosf((float)index) / 2.0f + 0.5f); - - const Rect rect = { - {0.0f, 0.0f}, // Position is set later during expose - {minSize + s * maxSize, minSize + c * maxSize}, - {0.0f, s / 2.0f + 0.25f, c / 2.0f + 0.25f, alpha}, - }; - - return rect; -} - -/// Move `rect` with the given index around in an arbitrary way that looks cool -static inline void -moveRect(Rect* const rect, - const size_t index, - const size_t numRects, - const float frameWidth, - const float frameHeight, - const double time) -{ - const float normal = (float)index / (float)numRects; - const float offset[2] = {normal * 128.0f, normal * 128.0f}; - - rect->pos[0] = (frameWidth - rect->size[0] + offset[0]) * - (sinf((float)time * rect->size[0] / 64.0f + normal) + 1.0f) / - 2.0f; - rect->pos[1] = (frameHeight - rect->size[1] + offset[1]) * - (cosf((float)time * rect->size[1] / 64.0f + normal) + 1.0f) / - 2.0f; -} - -#endif // EXAMPLES_RECTS_H diff --git a/dpf/dgl/src/pugl-upstream/examples/shader_utils.h b/dpf/dgl/src/pugl-upstream/examples/shader_utils.h deleted file mode 100644 index 2575f47..0000000 --- a/dpf/dgl/src/pugl-upstream/examples/shader_utils.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - Copyright 2019-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef EXAMPLES_SHADER_UTILS_H -#define EXAMPLES_SHADER_UTILS_H - -#include "glad/glad.h" - -#include -#include -#include - -typedef struct { - GLuint vertexShader; - GLuint fragmentShader; - GLuint program; -} Program; - -static GLuint -compileShader(const char* header, const char* source, const GLenum type) -{ - const GLchar* sources[] = {header, source}; - const GLint lengths[] = {(GLint)strlen(header), (GLint)strlen(source)}; - GLuint shader = glCreateShader(type); - glShaderSource(shader, 2, sources, lengths); - glCompileShader(shader); - - int status = 0; - glGetShaderiv(shader, GL_COMPILE_STATUS, &status); - if (status == GL_FALSE) { - GLint length = 0; - glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length); - - char* log = (char*)calloc(1, (size_t)length); - glGetShaderInfoLog(shader, length, &length, log); - fprintf(stderr, "error: Failed to compile shader (%s)\n", log); - free(log); - - return 0; - } - - return shader; -} - -static void -deleteProgram(Program program) -{ - glDeleteShader(program.vertexShader); - glDeleteShader(program.fragmentShader); - glDeleteProgram(program.program); -} - -static Program -compileProgram(const char* headerSource, - const char* vertexSource, - const char* fragmentSource) -{ - static const Program nullProgram = {0, 0, 0}; - - Program program = { - compileShader(headerSource, vertexSource, GL_VERTEX_SHADER), - compileShader(headerSource, fragmentSource, GL_FRAGMENT_SHADER), - glCreateProgram(), - }; - - if (!program.vertexShader || !program.fragmentShader || !program.program) { - deleteProgram(program); - return nullProgram; - } - - glAttachShader(program.program, program.vertexShader); - glAttachShader(program.program, program.fragmentShader); - glLinkProgram(program.program); - - GLint status = 0; - glGetProgramiv(program.program, GL_LINK_STATUS, &status); - if (status == GL_FALSE) { - GLint length = 0; - glGetProgramiv(program.program, GL_INFO_LOG_LENGTH, &length); - - char* log = (char*)calloc(1, (size_t)length); - glGetProgramInfoLog(program.program, length, &length, &log[0]); - fprintf(stderr, "error: Failed to link program (%s)\n", log); - free(log); - - deleteProgram(program); - return nullProgram; - } - - return program; -} - -#endif // EXAMPLES_SHADER_UTILS_H diff --git a/dpf/dgl/src/pugl-upstream/examples/shaders/header_330.glsl b/dpf/dgl/src/pugl-upstream/examples/shaders/header_330.glsl deleted file mode 100644 index 59d5f6f..0000000 --- a/dpf/dgl/src/pugl-upstream/examples/shaders/header_330.glsl +++ /dev/null @@ -1,4 +0,0 @@ -#version 330 core - -#define INTER(qualifiers) -#define UBO(qualifiers) layout(std140) diff --git a/dpf/dgl/src/pugl-upstream/examples/shaders/header_420.glsl b/dpf/dgl/src/pugl-upstream/examples/shaders/header_420.glsl deleted file mode 100644 index 2beaad0..0000000 --- a/dpf/dgl/src/pugl-upstream/examples/shaders/header_420.glsl +++ /dev/null @@ -1,4 +0,0 @@ -#version 420 core - -#define INTER(qualifiers) layout(qualifiers) -#define UBO(qualifiers) layout(std140, qualifiers) diff --git a/dpf/dgl/src/pugl-upstream/examples/shaders/meson.build b/dpf/dgl/src/pugl-upstream/examples/shaders/meson.build deleted file mode 100644 index e47be9d..0000000 --- a/dpf/dgl/src/pugl-upstream/examples/shaders/meson.build +++ /dev/null @@ -1,35 +0,0 @@ -shader_files = [ - 'header_330.glsl', - 'header_420.glsl', - 'rect.frag', - 'rect.vert', -] - -# Copy shader sources for GL examples -foreach shader_file : shader_files - configure_file(copy: true, input: shader_file, output: shader_file) -endforeach - -# Build SPV shader binaries for Vulkan examples -if vulkan_dep.found() - cat = find_program('../../scripts/cat.py') - glslang = find_program('glslangValidator') - - shaders = ['rect.vert', 'rect.frag'] - foreach shader : shaders - source = shader.split('.')[0] + '.vulkan.' + shader.split('.')[1] - shader_input = custom_target(source, - output: source, - input: ['header_420.glsl', shader], - command: [cat, '@INPUT@'], - build_by_default: true, - capture: true) - - mytarget = custom_target(shader, - output: shader + '.spv', - input: shader_input, - command: [glslang, '-V', '-o', '@OUTPUT@', '@INPUT@'], - build_by_default: true, - install: false) - endforeach -endif diff --git a/dpf/dgl/src/pugl-upstream/examples/shaders/rect.frag b/dpf/dgl/src/pugl-upstream/examples/shaders/rect.frag deleted file mode 100644 index 33bfbb2..0000000 --- a/dpf/dgl/src/pugl-upstream/examples/shaders/rect.frag +++ /dev/null @@ -1,33 +0,0 @@ -/* The fragment shader uses the UV coordinates to calculate whether it is in - the T, R, B, or L border. These are then mixed with the border color, and - their inverse is mixed with the fill color, to calculate the fragment color. - For example, if we are in the top border, then T=1, so the border mix factor - TRBL=1, and the fill mix factor (1-TRBL) is 0. - - The use of pixel units here is handy because the border width can be - specified precisely in pixels to draw sharp lines. The border width is just - hardcoded, but could be made a uniform or vertex attribute easily enough. */ - -INTER(location = 0) noperspective in vec2 f_uv; -INTER(location = 1) noperspective in vec2 f_size; -INTER(location = 2) noperspective in vec4 f_fillColor; - -layout(location = 0) out vec4 FragColor; - -void -main() -{ - const float borderWidth = 2.0; - - vec4 borderColor = f_fillColor + vec4(0.0, 0.4, 0.4, 0.0); - float t = step(borderWidth, f_uv[1]); - float r = step(borderWidth, f_size.x - f_uv[0]); - float b = step(borderWidth, f_size.y - f_uv[1]); - float l = step(borderWidth, f_uv[0]); - float fillMix = t * r * b * l; - float borderMix = 1.0 - fillMix; - vec4 fill = fillMix * f_fillColor; - vec4 border = borderMix * borderColor; - - FragColor = fill + border; -} diff --git a/dpf/dgl/src/pugl-upstream/examples/shaders/rect.vert b/dpf/dgl/src/pugl-upstream/examples/shaders/rect.vert deleted file mode 100644 index 2c7b5f1..0000000 --- a/dpf/dgl/src/pugl-upstream/examples/shaders/rect.vert +++ /dev/null @@ -1,36 +0,0 @@ -/* The vertex shader is trivial, but forwards scaled UV coordinates (in pixels) - to the fragment shader for drawing the border. */ - -UBO(binding = 0) uniform UniformBufferObject -{ - mat4 projection; -} -ubo; - -layout(location = 0) in vec2 v_position; -layout(location = 1) in vec2 v_origin; -layout(location = 2) in vec2 v_size; -layout(location = 3) in vec4 v_fillColor; - -INTER(location = 0) noperspective out vec2 f_uv; -INTER(location = 1) noperspective out vec2 f_size; -INTER(location = 2) noperspective out vec4 f_fillColor; - -void -main() -{ - // clang-format off - mat4 m = mat4(v_size[0], 0.0, 0.0, 0.0, - 0.0, v_size[1], 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - v_origin[0], v_origin[1], 0.0, 1.0); - // clang-format on - - mat4 MVP = ubo.projection * m; - - f_uv = v_position * v_size; - f_size = v_size; - f_fillColor = v_fillColor; - - gl_Position = MVP * vec4(v_position, 0.0, 1.0); -} diff --git a/dpf/dgl/src/pugl-upstream/examples/sybok.hpp b/dpf/dgl/src/pugl-upstream/examples/sybok.hpp deleted file mode 100644 index 7740824..0000000 --- a/dpf/dgl/src/pugl-upstream/examples/sybok.hpp +++ /dev/null @@ -1,2325 +0,0 @@ -/* - Copyright 2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/** - @file sybok.hpp - @brief A minimal C++ wrapper for the Vulkan API. - - This is a manually-written minimal wrapper for Vulkan. It makes working - with Vulkan a little easier in C++, but takes a different approach than - vulkan.hpp. In particular: - - - Works nicely with dynamic loading. Since the API itself is an object, it - is simple to ensure the dynamically loaded API (or a consistent API in - general) is used everywhere. Passing a dispatch parameter to every - function as in vulkan.hpp makes dynamic loading extremely painful (not to - mention ugly), and mistakes tend to become link time errors. This is, in - my opinion, a glaring design flaw, and the real reason why this wrapper - reluctantly exists. - - - Explicit separation of the initial API that does not require an instance - to load, from the rest of the API that does. - - - Opinionated use of scoped handles everywhere. - - - Remains close to the C API so that code can be easily ported. This means - that the pattern of return codes with output parameters is preserved, - except with smart handles that make leaks impossible. While less pretty, - this does not require exceptions. - - - No exceptions or RTTI required. - - - A safe scoped API for commands that encodes the semantics of the Vulkan - API. For example, it is statically impossible to call render scope - commands while not in a render scope. - - - A reasonable amount of relatively readable code. - - On the other hand, there are far fewer niceties, and the C API is used - directly as much as possible, particularly for structs (although they are - taken by const reference so they can be written inline). There is only - support for a minimal portable subset of Vulkan 1.1 with a few portable KHR - extensions. - - In short, if the above sounds appealing, or you want a minimal wrapper that - can be extended if necessary to suit your application, you might find this - useful. If you want a fully-featured wrapper for Vulkan and don't care - about linker dependencies, you probably won't. -*/ - -#ifndef SYBOK_HPP -#define SYBOK_HPP - -#ifdef VULKAN_CORE_H_ -# error "sybok.hpp must be included before or instead of vulkan headers" -#endif - -#ifdef __GNUC__ -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wswitch-enum" -#endif - -#define VK_NO_PROTOTYPES - -// On 64-bit platforms, all handles are "dispatchable" pointers -#if defined(__LP64__) || defined(_WIN64) || \ - (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || \ - defined(__ia64) || defined(_M_IA64) || defined(__aarch64__) || \ - defined(__powerpc64__) - -# define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) \ - typedef struct object##_T* object; // NOLINT(bugprone-macro-parentheses) - -// On 32-bit platforms, some "non-dispatchable" handles are 64 bit integers -#else - -/// Trivial wrapper class for a 64-bit integer handle for type safety -template -struct NonDispatchableHandle { - explicit operator uint64_t() const noexcept { return handle; } - explicit operator bool() const noexcept { return handle; } - - uint64_t handle; -}; - -# define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) \ - using object = NonDispatchableHandle; - -#endif - -#include // IWYU pragma: export - -#include -#include -#include -#include -#include -#include - -#if __cplusplus >= 201703L -# define SYBOK_NODISCARD [[nodiscard]] -#elif defined(__GNUC__) -# define SYBOK_NODISCARD [[gnu::warn_unused_result]] -#else -# define SYBOK_NODISCARD -#endif - -/// Helper macro to make array arguments format nicely -#define SK_COUNTED(count, ...) count, __VA_ARGS__ - -namespace sk { - -class CommandScope; -class RenderCommandScope; - -inline const char* -string(const VkResult result) -{ - switch (result) { - case VK_SUCCESS: - return "Success"; - case VK_NOT_READY: - return "Not Ready"; - case VK_TIMEOUT: - return "Timeout"; - case VK_EVENT_SET: - return "Event set"; - case VK_EVENT_RESET: - return "Event reset"; - case VK_INCOMPLETE: - return "Incomplete"; - case VK_ERROR_OUT_OF_HOST_MEMORY: - return "Out of host memory"; - case VK_ERROR_OUT_OF_DEVICE_MEMORY: - return "Out of device memory"; - case VK_ERROR_INITIALIZATION_FAILED: - return "Initialization failed"; - case VK_ERROR_DEVICE_LOST: - return "Device lost"; - case VK_ERROR_MEMORY_MAP_FAILED: - return "Memory map failed"; - case VK_ERROR_LAYER_NOT_PRESENT: - return "Layer not present"; - case VK_ERROR_EXTENSION_NOT_PRESENT: - return "Extension not present"; - case VK_ERROR_FEATURE_NOT_PRESENT: - return "Feature not present"; - case VK_ERROR_INCOMPATIBLE_DRIVER: - return "Incompatible driver"; - case VK_ERROR_TOO_MANY_OBJECTS: - return "Too many objects"; - case VK_ERROR_FORMAT_NOT_SUPPORTED: - return "Format not supported"; - case VK_ERROR_FRAGMENTED_POOL: - return "Fragmented pool"; - case VK_ERROR_OUT_OF_POOL_MEMORY: // Vulkan 1.1 - return "Out of pool memory"; - case VK_ERROR_INVALID_EXTERNAL_HANDLE: // Vulkan 1.1 - return "Invalid external handle"; - case VK_ERROR_SURFACE_LOST_KHR: // VK_KHR_surface - return "Surface lost"; - case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: // VK_KHR_surface - return "Native window in use"; - case VK_SUBOPTIMAL_KHR: // VK_KHR_swapchain - return "Suboptimal"; - case VK_ERROR_OUT_OF_DATE_KHR: // VK_KHR_swapchain - return "Out of date"; - case VK_ERROR_VALIDATION_FAILED_EXT: // VK_EXT_debug_report - return "Validation failed"; - default: - break; - } - - return "Unknown error"; -} - -inline const char* -string(const VkPresentModeKHR presentMode) -{ - switch (presentMode) { - case VK_PRESENT_MODE_IMMEDIATE_KHR: - return "Immediate"; - case VK_PRESENT_MODE_MAILBOX_KHR: - return "Mailbox"; - case VK_PRESENT_MODE_FIFO_KHR: - return "FIFO"; - case VK_PRESENT_MODE_FIFO_RELAXED_KHR: - return "Relaxed FIFO"; - default: - break; - } - - return "Unknown present mode"; -} - -inline const char* -string(const VkDebugReportFlagBitsEXT flag) -{ - switch (flag) { - case VK_DEBUG_REPORT_INFORMATION_BIT_EXT: - return "Information"; - case VK_DEBUG_REPORT_WARNING_BIT_EXT: - return "Warning"; - case VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT: - return "Performance Warning"; - case VK_DEBUG_REPORT_ERROR_BIT_EXT: - return "Error"; - case VK_DEBUG_REPORT_DEBUG_BIT_EXT: - return "Debug"; - default: - break; - } - - return "Unknown report"; -} - -template -class GlobalDeleter -{ -public: - using DestroyFunc = void (*)(T, const VkAllocationCallbacks*); - - GlobalDeleter() = default; - ~GlobalDeleter() = default; - - // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) - GlobalDeleter(DestroyFunc destroyFunc) noexcept - : _destroyFunc{destroyFunc} - {} - - GlobalDeleter(const GlobalDeleter&) = delete; - GlobalDeleter& operator=(const GlobalDeleter&) = delete; - - GlobalDeleter(GlobalDeleter&& other) noexcept - { - std::swap(_destroyFunc, other._destroyFunc); - } - - GlobalDeleter& operator=(GlobalDeleter&& other) noexcept - { - std::swap(_destroyFunc, other._destroyFunc); - return *this; - } - - void operator()(T handle) noexcept - { - if (_destroyFunc && handle) { - _destroyFunc(handle, nullptr); - } - } - -private: - DestroyFunc _destroyFunc{}; -}; - -template -class DependantDeleter -{ -public: - using DestroyFunc = void (*)(Parent, T, const VkAllocationCallbacks*); - - DependantDeleter() = default; - ~DependantDeleter() = default; - - DependantDeleter(Parent parent, DestroyFunc destroyFunc) noexcept - : _parent{parent} - , _destroyFunc{destroyFunc} - {} - - DependantDeleter(const DependantDeleter&) = delete; - DependantDeleter& operator=(const DependantDeleter&) = delete; - - DependantDeleter(DependantDeleter&& other) noexcept { swap(other); } - - DependantDeleter& operator=(DependantDeleter&& other) noexcept - { - swap(other); - return *this; - } - - void operator()(T handle) noexcept - { - if (_parent && _destroyFunc && handle) { - _destroyFunc(_parent, handle, nullptr); - } - } - -private: - void swap(DependantDeleter& other) noexcept - { - std::swap(_parent, other._parent); - std::swap(_destroyFunc, other._destroyFunc); - } - - Parent _parent{}; - DestroyFunc _destroyFunc{}; -}; - -template -class PoolDeleter -{ -public: - using FreeFunc = FreeFuncResult (*)(VkDevice, Pool, uint32_t, const T*); - - PoolDeleter() noexcept = default; - ~PoolDeleter() noexcept = default; - - PoolDeleter(VkDevice device, - Pool pool, - uint32_t count, - FreeFunc freeFunc) noexcept - : _device{device} - , _pool{pool} - , _count{count} - , _freeFunc{freeFunc} - {} - - PoolDeleter(const PoolDeleter&) = delete; - PoolDeleter& operator=(const PoolDeleter&) = delete; - - PoolDeleter(PoolDeleter&& other) noexcept { swap(other); } - - PoolDeleter& operator=(PoolDeleter&& other) noexcept - { - swap(other); - return *this; - } - - void operator()(T* handle) noexcept - { - if (_device && _pool && handle) { - _freeFunc(_device, _pool, _count, handle); - } - } - -private: - void swap(PoolDeleter& other) noexcept - { - std::swap(_device, other._device); - std::swap(_pool, other._pool); - std::swap(_count, other._count); - std::swap(_freeFunc, other._freeFunc); - } - - VkDevice _device{}; - Pool _pool{}; - uint32_t _count{}; - FreeFunc _freeFunc{}; -}; - -template -class UniqueDispatchableHandle -{ -public: - using Deleter = TDeleter; - using Handle = T; - - static_assert(std::is_pointer::value, ""); - - UniqueDispatchableHandle() = default; - - UniqueDispatchableHandle(Handle handle, Deleter deleter) noexcept - : _handle{handle} - , _deleter{std::move(deleter)} - {} - - ~UniqueDispatchableHandle() noexcept - { - if (_handle) { - _deleter(_handle); - } - } - - UniqueDispatchableHandle(const UniqueDispatchableHandle&) noexcept = delete; - UniqueDispatchableHandle& operator =( - const UniqueDispatchableHandle&) noexcept = delete; - - UniqueDispatchableHandle(UniqueDispatchableHandle&& other) noexcept - { - swap(other); - } - - UniqueDispatchableHandle& operator=(UniqueDispatchableHandle&& other) noexcept - { - swap(other); - return *this; - } - - const Handle& get() const noexcept { return _handle; } - - // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) - operator Handle() const noexcept { return _handle; } - -private: - void swap(UniqueDispatchableHandle& other) noexcept - { - std::swap(_handle, other._handle); - std::swap(_deleter, other._deleter); - } - - Handle _handle{}; - Deleter _deleter{}; -}; - -#if defined(__LP64__) || defined(_WIN64) || \ - (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || \ - defined(__ia64) || defined(_M_IA64) || defined(__aarch64__) || \ - defined(__powerpc64__) - -template -using UniqueNonDispatchableHandle = UniqueDispatchableHandle; - -#else - -template -class UniqueNonDispatchableHandle -{ -public: - using Deleter = TDeleter; - using Handle = T; - - UniqueNonDispatchableHandle() = default; - - UniqueNonDispatchableHandle(T handle, Deleter deleter) noexcept - : _handle{handle} - , _deleter{std::move(deleter)} - { - assert(handle); - } - - ~UniqueNonDispatchableHandle() noexcept - { - if (_handle) { - _deleter(_handle); - } - } - - UniqueNonDispatchableHandle(const UniqueNonDispatchableHandle&) noexcept = - delete; - UniqueNonDispatchableHandle& operator =( - const UniqueNonDispatchableHandle&) noexcept = delete; - - UniqueNonDispatchableHandle(UniqueNonDispatchableHandle&& other) noexcept - { - swap(other); - } - - UniqueNonDispatchableHandle& operator=( - UniqueNonDispatchableHandle&& other) noexcept - { - swap(other); - return *this; - } - - const Handle& get() const noexcept { return _handle; } - - operator Handle() const noexcept { return _handle; } - -private: - void swap(UniqueNonDispatchableHandle& other) noexcept - { - std::swap(_handle, other._handle); - std::swap(_deleter, other._deleter); - } - - T _handle{}; - Deleter _deleter{}; -}; - -#endif - -template -class UniqueArrayHandle -{ -public: - using T = typename Vector::value_type; - - UniqueArrayHandle() = default; - - UniqueArrayHandle(uint32_t size, Vector&& array, Deleter deleter) noexcept - : _array{std::move(array)} - , _deleter{std::move(deleter)} - , _size{size} - { - assert(!_array.empty()); - } - - ~UniqueArrayHandle() noexcept - { - if (!_array.empty()) { - _deleter(_array.data()); - } - } - - UniqueArrayHandle(const UniqueArrayHandle&) noexcept = delete; - UniqueArrayHandle& operator=(const UniqueArrayHandle&) noexcept = delete; - - UniqueArrayHandle(UniqueArrayHandle&& other) noexcept { swap(other); } - - UniqueArrayHandle& operator=(UniqueArrayHandle&& other) noexcept - { - swap(other); - return *this; - } - - const T& operator[](const size_t index) const noexcept - { - return _array[index]; - } - - T& operator[](const size_t index) noexcept { return _array[index]; } - - const T* get() const noexcept { return _array.data(); } - T* get() noexcept { return _array.data(); } - -private: - void swap(UniqueArrayHandle& other) noexcept - { - std::swap(_array, other._array); - std::swap(_deleter, other._deleter); - std::swap(_size, other._size); - } - - Vector _array{}; - Deleter _deleter{}; - uint32_t _size{}; -}; - -template -class OptionalParameter -{ -public: - using Handle = typename T::Handle; - - // NOLINTNEXTLINE(hicpp-explicit-conversions, google-explicit-constructor) - OptionalParameter(const T& value) noexcept - : _handle{value.get()} - {} - - OptionalParameter() noexcept = default; - ~OptionalParameter() noexcept = default; - - OptionalParameter(const OptionalParameter&) = delete; - OptionalParameter& operator=(const OptionalParameter&) = delete; - - OptionalParameter(OptionalParameter&&) = delete; - OptionalParameter& operator=(OptionalParameter&&) = delete; - - Handle get() const noexcept { return _handle; } - -private: - Handle _handle{}; -}; - -template -using GlobalObject = UniqueDispatchableHandle>; - -template -using InstanceChild = - UniqueNonDispatchableHandle>; - -template -using DispatchableDeviceChild = - UniqueDispatchableHandle>; - -template -using NonDispatchableDeviceChild = - UniqueNonDispatchableHandle>; - -template -using PoolChild = UniqueArrayHandle< - Vector, - PoolDeleter>; - -using Device = GlobalObject; -using Instance = GlobalObject; - -using PhysicalDevice = VkPhysicalDevice; // Weak handle, no destroy function -using Queue = VkQueue; // Weak handle, no destroy function - -using Buffer = NonDispatchableDeviceChild; -using BufferView = NonDispatchableDeviceChild; -using CommandBuffer = DispatchableDeviceChild; -using CommandPool = NonDispatchableDeviceChild; -using DescriptorPool = NonDispatchableDeviceChild; -using DescriptorSetLayout = NonDispatchableDeviceChild; -using DeviceMemory = NonDispatchableDeviceChild; -using Event = NonDispatchableDeviceChild; -using Fence = NonDispatchableDeviceChild; -using Framebuffer = NonDispatchableDeviceChild; -using Image = NonDispatchableDeviceChild; -using ImageView = NonDispatchableDeviceChild; -using Pipeline = NonDispatchableDeviceChild; -using PipelineCache = NonDispatchableDeviceChild; -using PipelineLayout = NonDispatchableDeviceChild; -using QueryPool = NonDispatchableDeviceChild; -using RenderPass = NonDispatchableDeviceChild; -using Sampler = NonDispatchableDeviceChild; -using Semaphore = NonDispatchableDeviceChild; -using ShaderModule = NonDispatchableDeviceChild; - -template -using CommandBuffers = PoolChild; - -template -using DescriptorSets = - PoolChild; - -// VK_KHR_swapchain -using SwapchainKHR = NonDispatchableDeviceChild; - -// VK_KHR_surface -using SurfaceKHR = InstanceChild; - -// VK_EXT_debug_report -using DebugReportCallbackEXT = InstanceChild; - -template -struct IndexSequence {}; - -template -struct IndexSequenceHelper - : public IndexSequenceHelper {}; - -template -struct IndexSequenceHelper<0U, Next...> { - using type = IndexSequence; -}; - -template -using makeIndexSequence = typename IndexSequenceHelper::type; - -template -std::array -make_handle_array_h(Parent parent, - DestroyFunc destroyFunc, - std::array handles, - IndexSequence) noexcept -{ - return {T{handles[Is], {parent, destroyFunc}}...}; -} - -template -std::array -make_handle_array(Parent parent, - DestroyFunc destroyFunc, - std::array handles) noexcept -{ - return make_handle_array_h( - parent, destroyFunc, handles, makeIndexSequence()); -} - -namespace detail { - -template -inline VkResult -wrapVectorAccessor(Vector& vector, Func func, Args... args) noexcept -{ - uint32_t count = 0u; - VkResult r = func(args..., &count, nullptr); - if (r > VK_INCOMPLETE) { - vector.clear(); - return r; - } - - vector = Vector(count); - if ((r = func(args..., &count, vector.data()))) { - vector.clear(); - return r; - } - - return VK_SUCCESS; -} - -} // namespace detail - -class VulkanApi; - -struct MappedMemory { - MappedMemory() noexcept = default; - - MappedMemory(const VulkanApi& api, - VkDevice device, - VkDeviceMemory memory, - void* data) noexcept - : _api{&api} - , _device{device} - , _memory{memory} - , _data{data} - {} - - MappedMemory(const MappedMemory&) = delete; - MappedMemory& operator=(const MappedMemory&) = delete; - - MappedMemory(MappedMemory&& mappedMemory) noexcept - : _api{mappedMemory._api} - , _device{mappedMemory._device} - , _memory{mappedMemory._memory} - , _data{mappedMemory._data} - { - mappedMemory._device = {}; - mappedMemory._memory = {}; - mappedMemory._data = {}; - } - - MappedMemory& operator=(MappedMemory&& mappedMemory) noexcept - { - std::swap(_api, mappedMemory._api); - std::swap(_device, mappedMemory._device); - std::swap(_memory, mappedMemory._memory); - std::swap(_data, mappedMemory._data); - return *this; - } - - ~MappedMemory() noexcept; - - const void* get() const noexcept { return _data; } - void* get() noexcept { return _data; } - -private: - const VulkanApi* _api{}; - VkDevice _device{}; - VkDeviceMemory _memory{}; - void* _data{}; -}; - -class VulkanInitApi -{ -public: - template - VkResult init(PFN_vkGetInstanceProcAddr pGetInstanceProcAddr, - NotFoundFunc notFound) noexcept - { -#define SK_INIT(name) \ - do { \ - if (!(name = PFN_##name(getInstanceProcAddr(NULL, #name)))) { \ - notFound(#name); \ - } \ - } while (0) - - vkGetInstanceProcAddr = pGetInstanceProcAddr; - SK_INIT(vkCreateInstance); - vkDestroyInstance = {}; // Loaded after we create an instance - SK_INIT(vkEnumerateInstanceExtensionProperties); - SK_INIT(vkEnumerateInstanceLayerProperties); - - if (!vkCreateInstance || !vkEnumerateInstanceExtensionProperties || - !vkEnumerateInstanceLayerProperties) { - return VK_ERROR_INITIALIZATION_FAILED; - } - - return VK_SUCCESS; -#undef SK_INIT - } - - VkResult init(PFN_vkGetInstanceProcAddr pGetInstanceProcAddr) noexcept - { - return init(pGetInstanceProcAddr, [](const char*) {}); - } - - PFN_vkVoidFunction getInstanceProcAddr(VkInstance instance, - const char* const name) const noexcept - { - return vkGetInstanceProcAddr(instance, name); - } - - VkResult createInstance(const VkInstanceCreateInfo& createInfo, - Instance& instance) noexcept - { - VkInstance h = {}; - if (const VkResult r = vkCreateInstance(&createInfo, nullptr, &h)) { - return r; - } - - if (!h) { - // Shouldn't actually happen, but this lets the compiler know that - return VK_ERROR_INITIALIZATION_FAILED; - } - - if (!vkDestroyInstance) { - vkDestroyInstance = PFN_vkDestroyInstance( - getInstanceProcAddr(instance, "vkDestroyInstance")); - } - - instance = {h, {vkDestroyInstance}}; - return VK_SUCCESS; - } - - template - VkResult enumerateInstanceExtensionProperties( - Vector& properties) const noexcept - { - return detail::wrapVectorAccessor( - properties, vkEnumerateInstanceExtensionProperties, nullptr); - } - - template - VkResult enumerateInstanceExtensionProperties( - const char* const layerName, - Vector& properties) const noexcept - { - return detail::wrapVectorAccessor( - properties, vkEnumerateInstanceExtensionProperties, layerName); - } - - template - VkResult enumerateInstanceLayerProperties(Vector& properties) const noexcept - { - return detail::wrapVectorAccessor( - properties, vkEnumerateInstanceLayerProperties); - } - -private: - PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr{}; - -#define SK_FUNC(name) \ - PFN_##name name {} - - SK_FUNC(vkCreateInstance); - SK_FUNC(vkDestroyInstance); - SK_FUNC(vkEnumerateInstanceExtensionProperties); - SK_FUNC(vkEnumerateInstanceLayerProperties); - -#undef SK_FUNC -}; - -class VulkanApi -{ -public: - template - VkResult init(const VulkanInitApi& initApi, - const Instance& instance, - NotFoundFunc notFound) noexcept - { - VkResult r = VK_SUCCESS; - - const auto notFoundWrapper = [&r, notFound](const char* name) { - r = VK_INCOMPLETE; - notFound(name); - }; - -#define SK_INIT(name) \ - do { \ - if (!(name = PFN_##name(initApi.getInstanceProcAddr(instance, #name)))) { \ - notFoundWrapper(#name); \ - } \ - } while (0) - - SK_INIT(vkAllocateCommandBuffers); - SK_INIT(vkAllocateDescriptorSets); - SK_INIT(vkAllocateMemory); - SK_INIT(vkBeginCommandBuffer); - SK_INIT(vkBindBufferMemory); - SK_INIT(vkBindImageMemory); - SK_INIT(vkCmdBeginQuery); - SK_INIT(vkCmdBeginRenderPass); - SK_INIT(vkCmdBindDescriptorSets); - SK_INIT(vkCmdBindIndexBuffer); - SK_INIT(vkCmdBindPipeline); - SK_INIT(vkCmdBindVertexBuffers); - SK_INIT(vkCmdBlitImage); - SK_INIT(vkCmdClearAttachments); - SK_INIT(vkCmdClearColorImage); - SK_INIT(vkCmdClearDepthStencilImage); - SK_INIT(vkCmdCopyBuffer); - SK_INIT(vkCmdCopyBufferToImage); - SK_INIT(vkCmdCopyImage); - SK_INIT(vkCmdCopyImageToBuffer); - SK_INIT(vkCmdCopyQueryPoolResults); - SK_INIT(vkCmdDispatch); - SK_INIT(vkCmdDispatchIndirect); - SK_INIT(vkCmdDraw); - SK_INIT(vkCmdDrawIndexed); - SK_INIT(vkCmdDrawIndexedIndirect); - SK_INIT(vkCmdDrawIndirect); - SK_INIT(vkCmdEndQuery); - SK_INIT(vkCmdEndRenderPass); - SK_INIT(vkCmdExecuteCommands); - SK_INIT(vkCmdFillBuffer); - SK_INIT(vkCmdNextSubpass); - SK_INIT(vkCmdPipelineBarrier); - SK_INIT(vkCmdPushConstants); - SK_INIT(vkCmdResetEvent); - SK_INIT(vkCmdResetQueryPool); - SK_INIT(vkCmdResolveImage); - SK_INIT(vkCmdSetBlendConstants); - SK_INIT(vkCmdSetDepthBias); - SK_INIT(vkCmdSetDepthBounds); - SK_INIT(vkCmdSetEvent); - SK_INIT(vkCmdSetLineWidth); - SK_INIT(vkCmdSetScissor); - SK_INIT(vkCmdSetStencilCompareMask); - SK_INIT(vkCmdSetStencilReference); - SK_INIT(vkCmdSetStencilWriteMask); - SK_INIT(vkCmdSetViewport); - SK_INIT(vkCmdUpdateBuffer); - SK_INIT(vkCmdWaitEvents); - SK_INIT(vkCmdWriteTimestamp); - SK_INIT(vkCreateBuffer); - SK_INIT(vkCreateBufferView); - SK_INIT(vkCreateCommandPool); - SK_INIT(vkCreateComputePipelines); - SK_INIT(vkCreateDescriptorPool); - SK_INIT(vkCreateDescriptorSetLayout); - SK_INIT(vkCreateDevice); - SK_INIT(vkCreateEvent); - SK_INIT(vkCreateFence); - SK_INIT(vkCreateFramebuffer); - SK_INIT(vkCreateGraphicsPipelines); - SK_INIT(vkCreateImage); - SK_INIT(vkCreateImageView); - SK_INIT(vkCreateInstance); - SK_INIT(vkCreatePipelineCache); - SK_INIT(vkCreatePipelineLayout); - SK_INIT(vkCreateQueryPool); - SK_INIT(vkCreateRenderPass); - SK_INIT(vkCreateSampler); - SK_INIT(vkCreateSemaphore); - SK_INIT(vkCreateShaderModule); - SK_INIT(vkDestroyBuffer); - SK_INIT(vkDestroyBufferView); - SK_INIT(vkDestroyCommandPool); - SK_INIT(vkDestroyDescriptorPool); - SK_INIT(vkDestroyDescriptorSetLayout); - SK_INIT(vkDestroyDevice); - SK_INIT(vkDestroyEvent); - SK_INIT(vkDestroyFence); - SK_INIT(vkDestroyFramebuffer); - SK_INIT(vkDestroyImage); - SK_INIT(vkDestroyImageView); - SK_INIT(vkDestroyPipeline); - SK_INIT(vkDestroyPipelineCache); - SK_INIT(vkDestroyPipelineLayout); - SK_INIT(vkDestroyQueryPool); - SK_INIT(vkDestroyRenderPass); - SK_INIT(vkDestroySampler); - SK_INIT(vkDestroySemaphore); - SK_INIT(vkDestroyShaderModule); - SK_INIT(vkDeviceWaitIdle); - SK_INIT(vkEndCommandBuffer); - SK_INIT(vkEnumerateDeviceExtensionProperties); - SK_INIT(vkEnumerateDeviceLayerProperties); - SK_INIT(vkEnumeratePhysicalDevices); - SK_INIT(vkFlushMappedMemoryRanges); - SK_INIT(vkFreeCommandBuffers); - SK_INIT(vkFreeDescriptorSets); - SK_INIT(vkFreeMemory); - SK_INIT(vkGetBufferMemoryRequirements); - SK_INIT(vkGetDeviceMemoryCommitment); - SK_INIT(vkGetDeviceProcAddr); - SK_INIT(vkGetDeviceQueue); - SK_INIT(vkGetEventStatus); - SK_INIT(vkGetFenceStatus); - SK_INIT(vkGetImageMemoryRequirements); - SK_INIT(vkGetImageSparseMemoryRequirements); - SK_INIT(vkGetImageSubresourceLayout); - SK_INIT(vkGetInstanceProcAddr); - SK_INIT(vkGetPhysicalDeviceFeatures); - SK_INIT(vkGetPhysicalDeviceFormatProperties); - SK_INIT(vkGetPhysicalDeviceImageFormatProperties); - SK_INIT(vkGetPhysicalDeviceMemoryProperties); - SK_INIT(vkGetPhysicalDeviceProperties); - SK_INIT(vkGetPhysicalDeviceQueueFamilyProperties); - SK_INIT(vkGetPhysicalDeviceSparseImageFormatProperties); - SK_INIT(vkGetPipelineCacheData); - SK_INIT(vkGetQueryPoolResults); - SK_INIT(vkGetRenderAreaGranularity); - SK_INIT(vkInvalidateMappedMemoryRanges); - SK_INIT(vkMapMemory); - SK_INIT(vkMergePipelineCaches); - SK_INIT(vkQueueBindSparse); - SK_INIT(vkQueueSubmit); - SK_INIT(vkQueueWaitIdle); - SK_INIT(vkResetCommandBuffer); - SK_INIT(vkResetCommandPool); - SK_INIT(vkResetDescriptorPool); - SK_INIT(vkResetEvent); - SK_INIT(vkResetFences); - SK_INIT(vkSetEvent); - SK_INIT(vkUnmapMemory); - SK_INIT(vkUpdateDescriptorSets); - SK_INIT(vkWaitForFences); - - // VK_EXT_debug_report - SK_INIT(vkCreateDebugReportCallbackEXT); - SK_INIT(vkDebugReportMessageEXT); - SK_INIT(vkDestroyDebugReportCallbackEXT); - - // VK_KHR_surface - SK_INIT(vkDestroySurfaceKHR); - SK_INIT(vkGetPhysicalDeviceSurfaceCapabilitiesKHR); - SK_INIT(vkGetPhysicalDeviceSurfaceFormatsKHR); - SK_INIT(vkGetPhysicalDeviceSurfacePresentModesKHR); - SK_INIT(vkGetPhysicalDeviceSurfaceSupportKHR); - - // VK_KHR_swapchain - SK_INIT(vkAcquireNextImageKHR); - SK_INIT(vkCreateSwapchainKHR); - SK_INIT(vkDestroySwapchainKHR); - SK_INIT(vkGetDeviceGroupPresentCapabilitiesKHR); - SK_INIT(vkGetDeviceGroupSurfacePresentModesKHR); - SK_INIT(vkGetPhysicalDevicePresentRectanglesKHR); - SK_INIT(vkGetSwapchainImagesKHR); - SK_INIT(vkQueuePresentKHR); - -#undef SK_INIT - - return r; - } - - VkResult init(const VulkanInitApi& initApi, const Instance& instance) noexcept - { - return init(initApi, instance, [](const char*) {}); - } - - template - VkResult allocateCommandBuffers( - const Device& device, - const VkCommandBufferAllocateInfo& allocateInfo, - CommandBuffers& commandBuffers) const noexcept - { - VkCommandBufferVector rawCommandBuffers = - VkCommandBufferVector(allocateInfo.commandBufferCount); - - if (const VkResult r = vkAllocateCommandBuffers( - device, &allocateInfo, rawCommandBuffers.data())) { - return r; - } - - commandBuffers = CommandBuffers{ - allocateInfo.commandBufferCount, - std::move(rawCommandBuffers), - PoolDeleter{ - device, - allocateInfo.commandPool, - allocateInfo.commandBufferCount, - vkFreeCommandBuffers}}; - return VK_SUCCESS; - } - - template - VkResult allocateDescriptorSets( - const Device& device, - const VkDescriptorSetAllocateInfo& allocateInfo, - DescriptorSets& descriptorSets) const noexcept - { - auto descriptorSetVector = - VkDescriptorSetVector(allocateInfo.descriptorSetCount); - - if (const VkResult r = vkAllocateDescriptorSets( - device, &allocateInfo, descriptorSetVector.data())) { - return r; - } - - descriptorSets = DescriptorSets{ - allocateInfo.descriptorSetCount, - std::move(descriptorSetVector), - PoolDeleter{ - device, - allocateInfo.descriptorPool, - allocateInfo.descriptorSetCount, - vkFreeDescriptorSets}}; - return VK_SUCCESS; - } - - VkResult bindBufferMemory(const Device& device, - const Buffer& buffer, - const DeviceMemory& memory, - VkDeviceSize memoryOffset) const noexcept - { - return vkBindBufferMemory - ? vkBindBufferMemory(device, buffer, memory, memoryOffset) - : VK_ERROR_FEATURE_NOT_PRESENT; - } - - VkResult createBuffer(const Device& device, - const VkBufferCreateInfo& createInfo, - Buffer& buffer) const noexcept - { - VkBuffer h = {}; - const VkResult r = vkCreateBuffer(device, &createInfo, nullptr, &h); - return wrapResult(r, h, {device, vkDestroyBuffer}, buffer); - } - - VkResult createBufferView(const Device& device, - const VkBufferViewCreateInfo& createInfo, - BufferView& bufferView) const noexcept - { - VkBufferView h = {}; - const VkResult r = vkCreateBufferView(device, &createInfo, nullptr, &h); - return wrapResult(r, h, {device, vkDestroyBufferView}, bufferView); - } - - VkResult createCommandPool(const Device& device, - const VkCommandPoolCreateInfo& createInfo, - CommandPool& commandPool) const noexcept - { - VkCommandPool h = {}; - const VkResult r = vkCreateCommandPool(device, &createInfo, nullptr, &h); - return wrapResult(r, h, {device, vkDestroyCommandPool}, commandPool); - } - - VkResult createDescriptorPool(const Device& device, - const VkDescriptorPoolCreateInfo& createInfo, - DescriptorPool& descriptorPool) const noexcept - { - VkDescriptorPool h = {}; - const VkResult r = vkCreateDescriptorPool(device, &createInfo, nullptr, &h); - - return wrapResult(r, h, {device, vkDestroyDescriptorPool}, descriptorPool); - } - - VkResult createDescriptorSetLayout( - const Device& device, - const VkDescriptorSetLayoutCreateInfo& createInfo, - DescriptorSetLayout& descriptorSetLayout) const noexcept - { - VkDescriptorSetLayout h = {}; - const VkResult r = - vkCreateDescriptorSetLayout(device, &createInfo, nullptr, &h); - - return wrapResult( - r, h, {device, vkDestroyDescriptorSetLayout}, descriptorSetLayout); - } - - VkResult createDevice(const PhysicalDevice& physicalDevice, - const VkDeviceCreateInfo& createInfo, - Device& result) const noexcept - { - VkDevice h = {}; - const VkResult r = vkCreateDevice(physicalDevice, &createInfo, nullptr, &h); - - return wrapResult(r, h, {vkDestroyDevice}, result); - } - - VkResult createEvent(const Device& device, - const VkEventCreateInfo& createInfo, - Event& event) const noexcept - { - VkEvent h = {}; - const VkResult r = vkCreateEvent(device, &createInfo, nullptr, &h); - - return wrapResult(r, h, {device, vkDestroyEvent}, event); - } - - VkResult createFence(const Device& device, - const VkFenceCreateInfo& createInfo, - Fence& fence) const noexcept - { - VkFence h = {}; - const VkResult r = vkCreateFence(device, &createInfo, nullptr, &h); - - return wrapResult(r, h, {device, vkDestroyFence}, fence); - } - - VkResult createFramebuffer(const Device& device, - const VkFramebufferCreateInfo& createInfo, - Framebuffer& framebuffer) const noexcept - { - VkFramebuffer h = {}; - const VkResult r = vkCreateFramebuffer(device, &createInfo, nullptr, &h); - - return wrapResult(r, h, {device, vkDestroyFramebuffer}, framebuffer); - } - - VkResult createImage(const Device& device, - const VkImageCreateInfo& createInfo, - Image& image) const noexcept - { - VkImage h = {}; - const VkResult r = vkCreateImage(device, &createInfo, nullptr, &h); - - return wrapResult(r, h, {device, vkDestroyImage}, image); - } - - VkResult createImageView(const Device& device, - const VkImageViewCreateInfo& createInfo, - ImageView& imageView) const noexcept - { - VkImageView h = {}; - const VkResult r = vkCreateImageView(device, &createInfo, nullptr, &h); - - return wrapResult(r, h, {device, vkDestroyImageView}, imageView); - } - - template - VkResult createGraphicsPipelines( - const Device& device, - const OptionalParameter& pipelineCache, - const std::array& createInfos, - std::array& pipelines) const noexcept - { - std::array pipelineHandles{}; - - if (const VkResult r = - vkCreateGraphicsPipelines(device, - pipelineCache.get(), - static_cast(createInfos.size()), - createInfos.data(), - nullptr, - pipelineHandles.data())) { - return r; - } - - pipelines = make_handle_array( - device.get(), vkDestroyPipeline, pipelineHandles); - return VK_SUCCESS; - } - - VkResult createPipelineCache(const Device& device, - const VkPipelineCacheCreateInfo& createInfo, - PipelineCache& pipelineCache) const noexcept - { - VkPipelineCache h = {}; - const VkResult r = vkCreatePipelineCache(device, &createInfo, nullptr, &h); - - return wrapResult(r, h, {device, vkDestroyPipelineCache}, pipelineCache); - } - - VkResult createPipelineLayout(const Device& device, - const VkPipelineLayoutCreateInfo& createInfo, - PipelineLayout& pipelineLayout) const noexcept - { - VkPipelineLayout h = {}; - const VkResult r = vkCreatePipelineLayout(device, &createInfo, nullptr, &h); - - return wrapResult(r, h, {device, vkDestroyPipelineLayout}, pipelineLayout); - } - - VkResult createQueryPool(const Device& device, - const VkQueryPoolCreateInfo& createInfo, - QueryPool& queryPool) const noexcept - { - VkQueryPool h = {}; - const VkResult r = vkCreateQueryPool(device, &createInfo, nullptr, &h); - - return wrapResult(r, h, {device, vkDestroyQueryPool}, queryPool); - } - - VkResult createRenderPass(const Device& device, - const VkRenderPassCreateInfo& createInfo, - RenderPass& renderPass) const noexcept - { - VkRenderPass h = {}; - const VkResult r = vkCreateRenderPass(device, &createInfo, nullptr, &h); - - return wrapResult(r, h, {device, vkDestroyRenderPass}, renderPass); - } - - VkResult createSampler(const Device& device, - const VkSamplerCreateInfo& createInfo, - Sampler& sampler) const noexcept - { - VkSampler h = {}; - const VkResult r = vkCreateSampler(device, &createInfo, nullptr, &h); - - return wrapResult(r, h, {device, vkDestroySampler}, sampler); - } - - VkResult createSemaphore(const Device& device, - const VkSemaphoreCreateInfo& createInfo, - Semaphore& semaphore) const noexcept - { - VkSemaphore h = {}; - const VkResult r = vkCreateSemaphore(device, &createInfo, nullptr, &h); - - return wrapResult(r, h, {device, vkDestroySemaphore}, semaphore); - } - - VkResult createShaderModule(const Device& device, - const VkShaderModuleCreateInfo& createInfo, - ShaderModule& shaderModule) const noexcept - { - VkShaderModule h = {}; - const VkResult r = vkCreateShaderModule(device, &createInfo, nullptr, &h); - - return wrapResult(r, h, {device, vkDestroyShaderModule}, shaderModule); - } - - VkResult deviceWaitIdle(const Device& device) const noexcept - { - return vkDeviceWaitIdle(device); - } - - template - VkResult enumerateDeviceExtensionProperties( - const PhysicalDevice& physicalDevice, - const char* const layerName, - Vector& properties) const noexcept - { - return detail::wrapVectorAccessor( - properties, - vkEnumerateDeviceExtensionProperties, - physicalDevice, - layerName); - } - - template - VkResult enumerateDeviceExtensionProperties( - const PhysicalDevice& physicalDevice, - Vector& properties) const noexcept - { - return detail::wrapVectorAccessor( - properties, - vkEnumerateDeviceExtensionProperties, - physicalDevice, - nullptr); - } - - template - VkResult enumeratePhysicalDevices(const Instance& instance, - Vector& physicalDevices) const noexcept - { - uint32_t count = 0u; - VkResult r = vkEnumeratePhysicalDevices(instance, &count, nullptr); - if (r > VK_INCOMPLETE) { - return r; - } - - physicalDevices = Vector(count); - if ((r = vkEnumeratePhysicalDevices( - instance, &count, physicalDevices.data()))) { - return r; - } - - return VK_SUCCESS; - } - - sk::Queue getDeviceQueue(const Device& device, - const uint32_t queueFamilyIndex, - const uint32_t queueIndex) const noexcept - { - VkQueue queue{}; - vkGetDeviceQueue(device, queueFamilyIndex, queueIndex, &queue); - return sk::Queue{queue}; - } - - VkPhysicalDeviceMemoryProperties getPhysicalDeviceMemoryProperties( - VkPhysicalDevice physicalDevice) const noexcept - { - VkPhysicalDeviceMemoryProperties properties{}; - vkGetPhysicalDeviceMemoryProperties(physicalDevice, &properties); - return properties; - } - - VkPhysicalDeviceProperties getPhysicalDeviceProperties( - const PhysicalDevice& physicalDevice) const noexcept - { - VkPhysicalDeviceProperties properties{}; - vkGetPhysicalDeviceProperties(physicalDevice, &properties); - return properties; - } - - template - VkResult getPhysicalDeviceQueueFamilyProperties( - const PhysicalDevice& physicalDevice, - Vector& queueFamilyProperties) const noexcept - { - uint32_t count = 0u; - vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &count, nullptr); - - queueFamilyProperties = Vector(count); - vkGetPhysicalDeviceQueueFamilyProperties( - physicalDevice, &count, queueFamilyProperties.data()); - - return VK_SUCCESS; - } - - VkMemoryRequirements getBufferMemoryRequirements( - const Device& device, - const Buffer& buffer) const noexcept - { - VkMemoryRequirements requirements; - vkGetBufferMemoryRequirements(device, buffer, &requirements); - return requirements; - } - - VkResult allocateMemory(const Device& device, - const VkMemoryAllocateInfo& info, - DeviceMemory& memory) const noexcept - { - VkDeviceMemory h = {}; - if (const VkResult r = vkAllocateMemory(device, &info, nullptr, &h)) { - return r; - } - - if (!h) { - return VK_ERROR_OUT_OF_DEVICE_MEMORY; - } - - memory = DeviceMemory{h, {device, vkFreeMemory}}; - return VK_SUCCESS; - } - - VkResult mapMemory(const Device& device, - const DeviceMemory& memory, - VkDeviceSize offset, - VkDeviceSize size, - VkMemoryMapFlags flags, - MappedMemory& mappedMemory) const noexcept - { - void* data = nullptr; - if (const VkResult r = - vkMapMemory(device, memory, offset, size, flags, &data)) { - return r; - } - - mappedMemory = MappedMemory{*this, device, memory, data}; - return VK_SUCCESS; - } - - VkResult queueSubmit(const Queue& queue, - uint32_t submitCount, - const VkSubmitInfo& submits, - const Fence& fence) const noexcept - { - return vkQueueSubmit(queue, submitCount, &submits, fence); - } - - VkResult queueSubmit(const Queue& queue, - const VkSubmitInfo& submit, - const Fence& fence) const noexcept - { - return vkQueueSubmit(queue, 1u, &submit, fence); - } - - template - void updateDescriptorSets( - const Device& device, - std::array descriptorWrites, - std::array descriptorCopies) - const noexcept - { - vkUpdateDescriptorSets(device, - static_cast(descriptorWrites.size()), - descriptorWrites.data(), - static_cast(descriptorCopies.size()), - descriptorCopies.data()); - } - - VkResult resetFence(const Device& device, const Fence& fence) const noexcept - { - VkFence h = fence; - return vkResetFences(device, 1u, &h); - } - - VkResult waitForFence(const Device& device, - const Fence& fence, - uint64_t timeout) const noexcept - { - VkFence h = fence; - return vkWaitForFences(device, 1u, &h, VK_TRUE, timeout); - } - - VkResult waitForFence(const Device& device, const Fence& fence) const noexcept - { - VkFence h = fence; - return vkWaitForFences(device, 1u, &h, VK_TRUE, UINT64_MAX); - } - - // Scoped command buffer interface - SYBOK_NODISCARD - CommandScope beginCommandBuffer( - VkCommandBuffer commandBuffer, - VkCommandBufferBeginInfo beginInfo) const noexcept; - - // VK_EXT_debug_report - - VkResult createDebugReportCallbackEXT( - const Instance& instance, - const VkDebugReportCallbackCreateInfoEXT& createInfo, - DebugReportCallbackEXT& callback) const noexcept - { - VkDebugReportCallbackEXT h = {}; - - if (const VkResult r = - vkCreateDebugReportCallbackEXT(instance, &createInfo, nullptr, &h)) { - return r; - } - - if (!h) { - return VK_ERROR_FEATURE_NOT_PRESENT; - } - - callback = {h, {instance, vkDestroyDebugReportCallbackEXT}}; - return VK_SUCCESS; - } - - // VK_KHR_surface - - VkResult getPhysicalDeviceSurfaceCapabilitiesKHR( - const PhysicalDevice& physicalDevice, - const SurfaceKHR& surface, - VkSurfaceCapabilitiesKHR& capabilities) const noexcept - { - return vkGetPhysicalDeviceSurfaceCapabilitiesKHR( - physicalDevice, surface, &capabilities); - } - - template - VkResult getPhysicalDeviceSurfaceFormatsKHR( - const PhysicalDevice& physicalDevice, - const SurfaceKHR& surface, - Vector& surfaceFormats) const noexcept - { - return detail::wrapVectorAccessor( - surfaceFormats, - vkGetPhysicalDeviceSurfaceFormatsKHR, - physicalDevice, - surface.get()); - } - - template - VkResult getPhysicalDeviceSurfacePresentModesKHR( - const PhysicalDevice& physicalDevice, - const SurfaceKHR& surface, - Vector& presentModes) const noexcept - { - return detail::wrapVectorAccessor( - presentModes, - vkGetPhysicalDeviceSurfacePresentModesKHR, - physicalDevice, - surface.get()); - } - - VkResult getPhysicalDeviceSurfaceSupportKHR( - const PhysicalDevice& physicalDevice, - uint32_t queueFamilyIndex, - const SurfaceKHR& surface, - bool& supported) const noexcept - { - VkBool32 s = {}; - - if (VkResult r = vkGetPhysicalDeviceSurfaceSupportKHR( - physicalDevice, queueFamilyIndex, surface, &s)) { - return r; - } - - supported = s; - return VK_SUCCESS; - } - - // VK_KHR_swapchain - - VkResult acquireNextImageKHR(const Device& device, - const SwapchainKHR& swapchain, - uint64_t timeout, - const Semaphore& semaphore, - const OptionalParameter& fence, - uint32_t* pImageIndex) const noexcept - { - return vkAcquireNextImageKHR( - device, swapchain, timeout, semaphore, fence.get(), pImageIndex); - } - - template - VkResult getSwapchainImagesKHR(const Device& device, - const SwapchainKHR& swapchain, - Vector& images) const noexcept - { - return detail::wrapVectorAccessor( - images, vkGetSwapchainImagesKHR, device.get(), swapchain.get()); - } - - VkResult createSwapchainKHR(const Device& device, - const VkSwapchainCreateInfoKHR& createInfo, - SwapchainKHR& swapchain) const noexcept - { - VkSwapchainKHR h = {}; - const VkResult r = vkCreateSwapchainKHR(device, &createInfo, nullptr, &h); - - if (r) { - return r; - } - - if (!h) { - return VK_ERROR_INCOMPATIBLE_DRIVER; - } - - swapchain = {h, {device, vkDestroySwapchainKHR}}; - return VK_SUCCESS; - } - - VkResult queuePresentKHR(const Queue& queue, - const VkPresentInfoKHR& presentInfo) const noexcept - { - return vkQueuePresentKHR(queue, &presentInfo); - } - -#define SK_FUNC(name) \ - PFN_##name name {} // NOLINT - - // Vulkan 1.0 Core - SK_FUNC(vkAllocateCommandBuffers); - SK_FUNC(vkAllocateDescriptorSets); - SK_FUNC(vkAllocateMemory); - SK_FUNC(vkBeginCommandBuffer); - SK_FUNC(vkBindBufferMemory); - SK_FUNC(vkBindImageMemory); - SK_FUNC(vkCmdBeginQuery); - SK_FUNC(vkCmdBeginRenderPass); - SK_FUNC(vkCmdBindDescriptorSets); - SK_FUNC(vkCmdBindIndexBuffer); - SK_FUNC(vkCmdBindPipeline); - SK_FUNC(vkCmdBindVertexBuffers); - SK_FUNC(vkCmdBlitImage); - SK_FUNC(vkCmdClearAttachments); - SK_FUNC(vkCmdClearColorImage); - SK_FUNC(vkCmdClearDepthStencilImage); - SK_FUNC(vkCmdCopyBuffer); - SK_FUNC(vkCmdCopyBufferToImage); - SK_FUNC(vkCmdCopyImage); - SK_FUNC(vkCmdCopyImageToBuffer); - SK_FUNC(vkCmdCopyQueryPoolResults); - SK_FUNC(vkCmdDispatch); - SK_FUNC(vkCmdDispatchIndirect); - SK_FUNC(vkCmdDraw); - SK_FUNC(vkCmdDrawIndexed); - SK_FUNC(vkCmdDrawIndexedIndirect); - SK_FUNC(vkCmdDrawIndirect); - SK_FUNC(vkCmdEndQuery); - SK_FUNC(vkCmdEndRenderPass); - SK_FUNC(vkCmdExecuteCommands); - SK_FUNC(vkCmdFillBuffer); - SK_FUNC(vkCmdNextSubpass); - SK_FUNC(vkCmdPipelineBarrier); - SK_FUNC(vkCmdPushConstants); - SK_FUNC(vkCmdResetEvent); - SK_FUNC(vkCmdResetQueryPool); - SK_FUNC(vkCmdResolveImage); - SK_FUNC(vkCmdSetBlendConstants); - SK_FUNC(vkCmdSetDepthBias); - SK_FUNC(vkCmdSetDepthBounds); - SK_FUNC(vkCmdSetEvent); - SK_FUNC(vkCmdSetLineWidth); - SK_FUNC(vkCmdSetScissor); - SK_FUNC(vkCmdSetStencilCompareMask); - SK_FUNC(vkCmdSetStencilReference); - SK_FUNC(vkCmdSetStencilWriteMask); - SK_FUNC(vkCmdSetViewport); - SK_FUNC(vkCmdUpdateBuffer); - SK_FUNC(vkCmdWaitEvents); - SK_FUNC(vkCmdWriteTimestamp); - SK_FUNC(vkCreateBuffer); - SK_FUNC(vkCreateBufferView); - SK_FUNC(vkCreateCommandPool); - SK_FUNC(vkCreateComputePipelines); - SK_FUNC(vkCreateDescriptorPool); - SK_FUNC(vkCreateDescriptorSetLayout); - SK_FUNC(vkCreateDevice); - SK_FUNC(vkCreateEvent); - SK_FUNC(vkCreateFence); - SK_FUNC(vkCreateFramebuffer); - SK_FUNC(vkCreateGraphicsPipelines); - SK_FUNC(vkCreateImage); - SK_FUNC(vkCreateImageView); - SK_FUNC(vkCreateInstance); - SK_FUNC(vkCreatePipelineCache); - SK_FUNC(vkCreatePipelineLayout); - SK_FUNC(vkCreateQueryPool); - SK_FUNC(vkCreateRenderPass); - SK_FUNC(vkCreateSampler); - SK_FUNC(vkCreateSemaphore); - SK_FUNC(vkCreateShaderModule); - SK_FUNC(vkDestroyBuffer); - SK_FUNC(vkDestroyBufferView); - SK_FUNC(vkDestroyCommandPool); - SK_FUNC(vkDestroyDescriptorPool); - SK_FUNC(vkDestroyDescriptorSetLayout); - SK_FUNC(vkDestroyDevice); - SK_FUNC(vkDestroyEvent); - SK_FUNC(vkDestroyFence); - SK_FUNC(vkDestroyFramebuffer); - SK_FUNC(vkDestroyImage); - SK_FUNC(vkDestroyImageView); - SK_FUNC(vkDestroyPipeline); - SK_FUNC(vkDestroyPipelineCache); - SK_FUNC(vkDestroyPipelineLayout); - SK_FUNC(vkDestroyQueryPool); - SK_FUNC(vkDestroyRenderPass); - SK_FUNC(vkDestroySampler); - SK_FUNC(vkDestroySemaphore); - SK_FUNC(vkDestroyShaderModule); - SK_FUNC(vkDeviceWaitIdle); - SK_FUNC(vkEndCommandBuffer); - SK_FUNC(vkEnumerateDeviceExtensionProperties); - SK_FUNC(vkEnumerateDeviceLayerProperties); - SK_FUNC(vkEnumeratePhysicalDevices); - SK_FUNC(vkFlushMappedMemoryRanges); - SK_FUNC(vkFreeCommandBuffers); - SK_FUNC(vkFreeDescriptorSets); - SK_FUNC(vkFreeMemory); - SK_FUNC(vkGetBufferMemoryRequirements); - SK_FUNC(vkGetDeviceMemoryCommitment); - SK_FUNC(vkGetDeviceProcAddr); - SK_FUNC(vkGetDeviceQueue); - SK_FUNC(vkGetEventStatus); - SK_FUNC(vkGetFenceStatus); - SK_FUNC(vkGetImageMemoryRequirements); - SK_FUNC(vkGetImageSparseMemoryRequirements); - SK_FUNC(vkGetImageSubresourceLayout); - SK_FUNC(vkGetInstanceProcAddr); - SK_FUNC(vkGetPhysicalDeviceFeatures); - SK_FUNC(vkGetPhysicalDeviceFormatProperties); - SK_FUNC(vkGetPhysicalDeviceImageFormatProperties); - SK_FUNC(vkGetPhysicalDeviceMemoryProperties); - SK_FUNC(vkGetPhysicalDeviceProperties); - SK_FUNC(vkGetPhysicalDeviceQueueFamilyProperties); - SK_FUNC(vkGetPhysicalDeviceSparseImageFormatProperties); - SK_FUNC(vkGetPipelineCacheData); - SK_FUNC(vkGetQueryPoolResults); - SK_FUNC(vkGetRenderAreaGranularity); - SK_FUNC(vkInvalidateMappedMemoryRanges); - SK_FUNC(vkMapMemory); - SK_FUNC(vkMergePipelineCaches); - SK_FUNC(vkQueueBindSparse); - SK_FUNC(vkQueueSubmit); - SK_FUNC(vkQueueWaitIdle); - SK_FUNC(vkResetCommandBuffer); - SK_FUNC(vkResetCommandPool); - SK_FUNC(vkResetDescriptorPool); - SK_FUNC(vkResetEvent); - SK_FUNC(vkResetFences); - SK_FUNC(vkSetEvent); - SK_FUNC(vkUnmapMemory); - SK_FUNC(vkUpdateDescriptorSets); - SK_FUNC(vkWaitForFences); - - // VK_EXT_debug_report - SK_FUNC(vkCreateDebugReportCallbackEXT); - SK_FUNC(vkDebugReportMessageEXT); - SK_FUNC(vkDestroyDebugReportCallbackEXT); - - // VK_KHR_surface - SK_FUNC(vkDestroySurfaceKHR); - SK_FUNC(vkGetPhysicalDeviceSurfaceCapabilitiesKHR); - SK_FUNC(vkGetPhysicalDeviceSurfaceFormatsKHR); - SK_FUNC(vkGetPhysicalDeviceSurfacePresentModesKHR); - SK_FUNC(vkGetPhysicalDeviceSurfaceSupportKHR); - - // VK_KHR_swapchain - SK_FUNC(vkAcquireNextImageKHR); - SK_FUNC(vkCreateSwapchainKHR); - SK_FUNC(vkDestroySwapchainKHR); - SK_FUNC(vkGetDeviceGroupPresentCapabilitiesKHR); - SK_FUNC(vkGetDeviceGroupSurfacePresentModesKHR); - SK_FUNC(vkGetPhysicalDevicePresentRectanglesKHR); - SK_FUNC(vkGetSwapchainImagesKHR); - SK_FUNC(vkQueuePresentKHR); - -#undef SK_FUNC - -private: - template - static inline VkResult wrapResult(const VkResult r, - const typename T::Handle handle, - typename T::Deleter&& deleter, - T& result) noexcept - { - if (r) { - return r; - } - - if (!handle) { - return VK_ERROR_INITIALIZATION_FAILED; - } - - result = T{handle, std::move(deleter)}; - return VK_SUCCESS; - } -}; - -/// Scope for commands that work both inside and outside a render pass -class CommonCommandScope -{ -public: - CommonCommandScope(const VulkanApi& api, - VkCommandBuffer commandBuffer, - VkResult result) noexcept - : _api{api} - , _commandBuffer{commandBuffer} - , _result{result} - {} - - CommonCommandScope(const CommonCommandScope&) noexcept = delete; - CommonCommandScope& operator=(const CommonCommandScope&) noexcept = delete; - - CommonCommandScope(CommonCommandScope&& scope) noexcept - : _api{scope._api} - , _commandBuffer{scope._commandBuffer} - , _result{scope._result} - { - scope._commandBuffer = {}; - } - - CommonCommandScope& operator=(CommonCommandScope&&) = delete; - - ~CommonCommandScope() noexcept = default; - - explicit operator bool() const noexcept { return _result == VK_SUCCESS; } - - VkResult error() const noexcept { return _result; } - - void bindPipeline(VkPipelineBindPoint pipelineBindPoint, - VkPipeline pipeline) const noexcept - { - _api.vkCmdBindPipeline(_commandBuffer, pipelineBindPoint, pipeline); - } - - void setViewport(uint32_t firstViewport, - uint32_t viewportCount, - const VkViewport* pViewports) const noexcept - { - _api.vkCmdSetViewport( - _commandBuffer, firstViewport, viewportCount, pViewports); - } - - void setScissor(uint32_t firstScissor, - uint32_t scissorCount, - const VkRect2D* pScissors) const noexcept - { - _api.vkCmdSetScissor(_commandBuffer, firstScissor, scissorCount, pScissors); - } - - void setLineWidth(float lineWidth) const noexcept - { - _api.vkCmdSetLineWidth(_commandBuffer, lineWidth); - } - - void setDepthBias(float depthBiasConstantFactor, - float depthBiasClamp, - float depthBiasSlopeFactor) const noexcept - { - _api.vkCmdSetDepthBias(_commandBuffer, - depthBiasConstantFactor, - depthBiasClamp, - depthBiasSlopeFactor); - } - - void setBlendConstants(const float blendConstants[4]) const noexcept - { - _api.vkCmdSetBlendConstants(_commandBuffer, blendConstants); - } - - void setDepthBounds(float minDepthBounds, float maxDepthBounds) const noexcept - { - _api.vkCmdSetDepthBounds(_commandBuffer, minDepthBounds, maxDepthBounds); - } - - void setStencilCompareMask(VkStencilFaceFlags faceMask, - uint32_t compareMask) const noexcept - { - _api.vkCmdSetStencilCompareMask(_commandBuffer, faceMask, compareMask); - } - - void setStencilWriteMask(VkStencilFaceFlags faceMask, - uint32_t writeMask) const noexcept - { - _api.vkCmdSetStencilWriteMask(_commandBuffer, faceMask, writeMask); - } - - void setStencilReference(VkStencilFaceFlags faceMask, - uint32_t reference) const noexcept - { - _api.vkCmdSetStencilReference(_commandBuffer, faceMask, reference); - } - - void bindDescriptorSets(VkPipelineBindPoint pipelineBindPoint, - VkPipelineLayout layout, - uint32_t firstSet, - uint32_t descriptorSetCount, - const VkDescriptorSet* pDescriptorSets, - uint32_t dynamicOffsetCount, - const uint32_t* pDynamicOffsets) const noexcept - { - _api.vkCmdBindDescriptorSets(_commandBuffer, - pipelineBindPoint, - layout, - firstSet, - descriptorSetCount, - pDescriptorSets, - dynamicOffsetCount, - pDynamicOffsets); - } - - void bindIndexBuffer(VkBuffer buffer, - VkDeviceSize offset, - VkIndexType indexType) const noexcept - { - _api.vkCmdBindIndexBuffer(_commandBuffer, buffer, offset, indexType); - } - - void bindVertexBuffers(uint32_t firstBinding, - uint32_t bindingCount, - const VkBuffer* pBuffers, - const VkDeviceSize* pOffsets) const noexcept - { - _api.vkCmdBindVertexBuffers( - _commandBuffer, firstBinding, bindingCount, pBuffers, pOffsets); - } - - void waitEvents( - uint32_t eventCount, - const VkEvent* pEvents, - VkPipelineStageFlags srcStageMask, - VkPipelineStageFlags dstStageMask, - uint32_t memoryBarrierCount, - const VkMemoryBarrier* pMemoryBarriers, - uint32_t bufferMemoryBarrierCount, - const VkBufferMemoryBarrier* pBufferMemoryBarriers, - uint32_t imageMemoryBarrierCount, - const VkImageMemoryBarrier* pImageMemoryBarriers) const noexcept - { - _api.vkCmdWaitEvents(_commandBuffer, - eventCount, - pEvents, - srcStageMask, - dstStageMask, - memoryBarrierCount, - pMemoryBarriers, - bufferMemoryBarrierCount, - pBufferMemoryBarriers, - imageMemoryBarrierCount, - pImageMemoryBarriers); - } - - void pipelineBarrier( - VkPipelineStageFlags srcStageMask, - VkPipelineStageFlags dstStageMask, - VkDependencyFlags dependencyFlags, - uint32_t memoryBarrierCount, - const VkMemoryBarrier* pMemoryBarriers, - uint32_t bufferMemoryBarrierCount, - const VkBufferMemoryBarrier* pBufferMemoryBarriers, - uint32_t imageMemoryBarrierCount, - const VkImageMemoryBarrier* pImageMemoryBarriers) const noexcept - { - _api.vkCmdPipelineBarrier(_commandBuffer, - srcStageMask, - dstStageMask, - dependencyFlags, - memoryBarrierCount, - pMemoryBarriers, - bufferMemoryBarrierCount, - pBufferMemoryBarriers, - imageMemoryBarrierCount, - pImageMemoryBarriers); - } - - void beginQuery(VkQueryPool queryPool, - uint32_t query, - VkQueryControlFlags flags) const noexcept - { - _api.vkCmdBeginQuery(_commandBuffer, queryPool, query, flags); - } - - void endQuery(VkQueryPool queryPool, uint32_t query) const noexcept - { - _api.vkCmdEndQuery(_commandBuffer, queryPool, query); - } - - void writeTimestamp(VkPipelineStageFlagBits pipelineStage, - VkQueryPool queryPool, - uint32_t query) const noexcept - { - _api.vkCmdWriteTimestamp(_commandBuffer, pipelineStage, queryPool, query); - } - - void pushConstants(VkPipelineLayout layout, - VkShaderStageFlags stageFlags, - uint32_t offset, - uint32_t size, - const void* pValues) const noexcept - { - _api.vkCmdPushConstants( - _commandBuffer, layout, stageFlags, offset, size, pValues); - } - - void executeCommands(uint32_t commandBufferCount, - const VkCommandBuffer* pCommandBuffers) const noexcept - { - _api.vkCmdExecuteCommands( - _commandBuffer, commandBufferCount, pCommandBuffers); - } - -protected: - const VulkanApi& _api; - VkCommandBuffer _commandBuffer; - VkResult _result; -}; - -// Top level command scope outside a render pass -class CommandScope : public CommonCommandScope -{ -public: - CommandScope(const VulkanApi& api, - VkCommandBuffer commandBuffer, - VkResult result) noexcept - : CommonCommandScope{api, commandBuffer, result} - {} - - CommandScope(const CommandScope&) = delete; - CommandScope& operator=(const CommandScope&) = delete; - - CommandScope(CommandScope&& scope) noexcept - : CommonCommandScope{std::forward(scope)} - {} - - CommandScope& operator=(CommandScope&&) = delete; - - ~CommandScope() noexcept - { - assert(!_commandBuffer); // Buffer must be finished with end() - } - - VkResult end() noexcept - { - if (_commandBuffer) { - VkResult r = _api.vkEndCommandBuffer(_commandBuffer); - _commandBuffer = {}; - return r; - } - - return VK_NOT_READY; - } - - void dispatch(uint32_t groupCountX, - uint32_t groupCountY, - uint32_t groupCountZ) const noexcept - { - _api.vkCmdDispatch(_commandBuffer, groupCountX, groupCountY, groupCountZ); - } - - void dispatchIndirect(VkBuffer buffer, VkDeviceSize offset) const noexcept - { - _api.vkCmdDispatchIndirect(_commandBuffer, buffer, offset); - } - - void copyBuffer(VkBuffer srcBuffer, - VkBuffer dstBuffer, - uint32_t regionCount, - const VkBufferCopy* pRegions) const noexcept - { - _api.vkCmdCopyBuffer( - _commandBuffer, srcBuffer, dstBuffer, regionCount, pRegions); - } - - void copyImage(VkImage srcImage, - VkImageLayout srcImageLayout, - VkImage dstImage, - VkImageLayout dstImageLayout, - uint32_t regionCount, - const VkImageCopy* pRegions) const noexcept - { - _api.vkCmdCopyImage(_commandBuffer, - srcImage, - srcImageLayout, - dstImage, - dstImageLayout, - regionCount, - pRegions); - } - - void blitImage(VkImage srcImage, - VkImageLayout srcImageLayout, - VkImage dstImage, - VkImageLayout dstImageLayout, - uint32_t regionCount, - const VkImageBlit* pRegions, - VkFilter filter) const noexcept - { - _api.vkCmdBlitImage(_commandBuffer, - srcImage, - srcImageLayout, - dstImage, - dstImageLayout, - regionCount, - pRegions, - filter); - } - - void copyBufferToImage(VkBuffer srcBuffer, - VkImage dstImage, - VkImageLayout dstImageLayout, - uint32_t regionCount, - const VkBufferImageCopy* pRegions) const noexcept - { - _api.vkCmdCopyBufferToImage(_commandBuffer, - srcBuffer, - dstImage, - dstImageLayout, - regionCount, - pRegions); - } - - void copyImageToBuffer(VkImage srcImage, - VkImageLayout srcImageLayout, - VkBuffer dstBuffer, - uint32_t regionCount, - const VkBufferImageCopy* pRegions) const noexcept - { - _api.vkCmdCopyImageToBuffer(_commandBuffer, - srcImage, - srcImageLayout, - dstBuffer, - regionCount, - pRegions); - } - - void updateBuffer(VkBuffer dstBuffer, - VkDeviceSize dstOffset, - VkDeviceSize dataSize, - const void* pData) const noexcept - { - _api.vkCmdUpdateBuffer( - _commandBuffer, dstBuffer, dstOffset, dataSize, pData); - } - - void fillBuffer(VkBuffer dstBuffer, - VkDeviceSize dstOffset, - VkDeviceSize size, - uint32_t data) const noexcept - { - _api.vkCmdFillBuffer(_commandBuffer, dstBuffer, dstOffset, size, data); - } - - void clearColorImage(VkImage image, - VkImageLayout imageLayout, - const VkClearColorValue& color, - uint32_t rangeCount, - const VkImageSubresourceRange* pRanges) const noexcept - { - _api.vkCmdClearColorImage( - _commandBuffer, image, imageLayout, &color, rangeCount, pRanges); - } - - void clearDepthStencilImage( - VkImage image, - VkImageLayout imageLayout, - const VkClearDepthStencilValue& depthStencil, - uint32_t rangeCount, - const VkImageSubresourceRange* pRanges) const noexcept - { - _api.vkCmdClearDepthStencilImage( - _commandBuffer, image, imageLayout, &depthStencil, rangeCount, pRanges); - } - - void resolveImage(VkImage srcImage, - VkImageLayout srcImageLayout, - VkImage dstImage, - VkImageLayout dstImageLayout, - uint32_t regionCount, - const VkImageResolve* pRegions) const noexcept - { - _api.vkCmdResolveImage(_commandBuffer, - srcImage, - srcImageLayout, - dstImage, - dstImageLayout, - regionCount, - pRegions); - } - - void setEvent(VkEvent event, VkPipelineStageFlags stageMask) const noexcept - { - _api.vkCmdSetEvent(_commandBuffer, event, stageMask); - } - - void resetEvent(VkEvent event, VkPipelineStageFlags stageMask) const noexcept - { - _api.vkCmdResetEvent(_commandBuffer, event, stageMask); - } - - void resetQueryPool(VkQueryPool queryPool, - uint32_t firstQuery, - uint32_t queryCount) const noexcept - { - _api.vkCmdResetQueryPool(_commandBuffer, queryPool, firstQuery, queryCount); - } - - void copyQueryPoolResults(VkQueryPool queryPool, - uint32_t firstQuery, - uint32_t queryCount, - VkBuffer dstBuffer, - VkDeviceSize dstOffset, - VkDeviceSize stride, - VkQueryResultFlags flags) const noexcept - { - _api.vkCmdCopyQueryPoolResults(_commandBuffer, - queryPool, - firstQuery, - queryCount, - dstBuffer, - dstOffset, - stride, - flags); - } - - SYBOK_NODISCARD - RenderCommandScope beginRenderPass( - const VkRenderPassBeginInfo& renderPassBegin, - VkSubpassContents contents) const noexcept; -}; - -class RenderCommandScope : public CommonCommandScope -{ -public: - RenderCommandScope(const VulkanApi& api, - VkCommandBuffer commandBuffer) noexcept - : CommonCommandScope{api, commandBuffer, VK_SUCCESS} - {} - - RenderCommandScope(const RenderCommandScope&) = delete; - RenderCommandScope& operator=(const RenderCommandScope&) = delete; - - RenderCommandScope(RenderCommandScope&& scope) noexcept - : CommonCommandScope{std::forward(scope)} - {} - - RenderCommandScope& operator=(RenderCommandScope&&) = delete; - - ~RenderCommandScope() noexcept { _api.vkCmdEndRenderPass(_commandBuffer); } - - void draw(uint32_t vertexCount, - uint32_t instanceCount, - uint32_t firstVertex, - uint32_t firstInstance) const noexcept - { - _api.vkCmdDraw( - _commandBuffer, vertexCount, instanceCount, firstVertex, firstInstance); - } - - void drawIndexed(uint32_t indexCount, - uint32_t instanceCount, - uint32_t firstIndex, - int32_t vertexOffset, - uint32_t firstInstance) const noexcept - { - _api.vkCmdDrawIndexed(_commandBuffer, - indexCount, - instanceCount, - firstIndex, - vertexOffset, - firstInstance); - } - - void drawIndirect(VkBuffer buffer, - VkDeviceSize offset, - uint32_t drawCount, - uint32_t stride) const noexcept - { - _api.vkCmdDrawIndirect(_commandBuffer, buffer, offset, drawCount, stride); - } - - void drawIndexedIndirect(VkBuffer buffer, - VkDeviceSize offset, - uint32_t drawCount, - uint32_t stride) const noexcept - { - _api.vkCmdDrawIndexedIndirect( - _commandBuffer, buffer, offset, drawCount, stride); - } - - void clearAttachments(uint32_t attachmentCount, - const VkClearAttachment& attachments, - uint32_t rectCount, - const VkClearRect* pRects) const noexcept - { - _api.vkCmdClearAttachments( - _commandBuffer, attachmentCount, &attachments, rectCount, pRects); - } - - void nextSubpass(VkSubpassContents contents) const noexcept - { - _api.vkCmdNextSubpass(_commandBuffer, contents); - } -}; - -inline CommandScope -VulkanApi::beginCommandBuffer( - VkCommandBuffer commandBuffer, - const VkCommandBufferBeginInfo beginInfo) const noexcept -{ - if (const VkResult r = vkBeginCommandBuffer(commandBuffer, &beginInfo)) { - return {*this, nullptr, r}; - } - - return {*this, commandBuffer, VK_SUCCESS}; -} - -inline RenderCommandScope -CommandScope::beginRenderPass(const VkRenderPassBeginInfo& renderPassBegin, - VkSubpassContents contents) const noexcept -{ - _api.vkCmdBeginRenderPass(_commandBuffer, &renderPassBegin, contents); - - return {_api, _commandBuffer}; -} - -inline MappedMemory::~MappedMemory() noexcept -{ - if (_api && _memory) { - _api->vkUnmapMemory(_device, _memory); - } -} - -} // namespace sk - -#ifdef __GNUC__ -# pragma GCC diagnostic pop -#endif - -#endif // SYBOK_HPP diff --git a/dpf/dgl/src/pugl-upstream/include/.clang-tidy b/dpf/dgl/src/pugl-upstream/include/.clang-tidy index b6d941c..3421cc2 100644 --- a/dpf/dgl/src/pugl-upstream/include/.clang-tidy +++ b/dpf/dgl/src/pugl-upstream/include/.clang-tidy @@ -2,7 +2,7 @@ Checks: > *, -*-magic-numbers, -*-uppercase-literal-suffix, - -altera-struct-pack-align, + -altera*, -clang-diagnostic-unused-function, -clang-diagnostic-unused-macros, -llvmlibc-*, diff --git a/dpf/dgl/src/pugl-upstream/include/meson.build b/dpf/dgl/src/pugl-upstream/include/meson.build index 2e1f7d8..f381df6 100644 --- a/dpf/dgl/src/pugl-upstream/include/meson.build +++ b/dpf/dgl/src/pugl-upstream/include/meson.build @@ -1,3 +1,6 @@ +# Copyright 2021 David Robillard +# SPDX-License-Identifier: CC0-1.0 OR ISC + c_headers = [ 'pugl/pugl.h', diff --git a/dpf/dgl/src/pugl-upstream/include/pugl/cairo.h b/dpf/dgl/src/pugl-upstream/include/pugl/cairo.h index 48e868e..302bfe0 100644 --- a/dpf/dgl/src/pugl-upstream/include/pugl/cairo.h +++ b/dpf/dgl/src/pugl-upstream/include/pugl/cairo.h @@ -1,18 +1,5 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ +// Copyright 2012-2020 David Robillard +// SPDX-License-Identifier: ISC #ifndef PUGL_CAIRO_H #define PUGL_CAIRO_H diff --git a/dpf/dgl/src/pugl-upstream/include/pugl/gl.h b/dpf/dgl/src/pugl-upstream/include/pugl/gl.h index 51c4a7d..c9726ae 100644 --- a/dpf/dgl/src/pugl-upstream/include/pugl/gl.h +++ b/dpf/dgl/src/pugl-upstream/include/pugl/gl.h @@ -1,18 +1,5 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ +// Copyright 2012-2020 David Robillard +// SPDX-License-Identifier: ISC #ifndef PUGL_GL_H #define PUGL_GL_H diff --git a/dpf/dgl/src/pugl-upstream/include/pugl/pugl.h b/dpf/dgl/src/pugl-upstream/include/pugl/pugl.h index f0bd91b..7724241 100644 --- a/dpf/dgl/src/pugl-upstream/include/pugl/pugl.h +++ b/dpf/dgl/src/pugl-upstream/include/pugl/pugl.h @@ -1,26 +1,16 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ +// Copyright 2012-2022 David Robillard +// SPDX-License-Identifier: ISC #ifndef PUGL_PUGL_H #define PUGL_PUGL_H -#include #include #include +#ifndef __cplusplus +# include +#endif + #ifndef PUGL_API # if defined(_WIN32) && !defined(PUGL_STATIC) && defined(PUGL_INTERNAL) # define PUGL_API __declspec(dllexport) @@ -53,13 +43,8 @@ PUGL_API \ PUGL_CONST_FUNC -#ifdef __cplusplus -# define PUGL_BEGIN_DECLS extern "C" { -# define PUGL_END_DECLS } -#else -# define PUGL_BEGIN_DECLS -# define PUGL_END_DECLS -#endif +#define PUGL_BEGIN_DECLS +#define PUGL_END_DECLS PUGL_BEGIN_DECLS @@ -70,16 +55,40 @@ PUGL_BEGIN_DECLS */ /** - A rectangle. + A pixel coordinate within/of a view. + + This is relative to the top left corner of the view's parent, or to the top + left corner of the view itself, depending on the context. - This is used to describe things like view position and size. Pugl generally - uses coordinates where the top left corner is 0,0. + There are platform-imposed limits on window positions. For portability, + applications should keep coordinates between -16000 and 16000. Note that + negative frame coordinates are possible, for example with multiple screens. +*/ +typedef int16_t PuglCoord; + +/** + A pixel span (width or height) within/of a view. + + Due to platform limits, the span of a view in either dimension should be + between 1 and 10000. +*/ +typedef uint16_t PuglSpan; + +/** + A rectangle in a view or on the screen. + + This type is used to describe two things: the position and size of a view + (for configuring), or a rectangle within a view (for exposing). + + The coordinate (0, 0) represents the top-left pixel of the parent window (or + display if there isn't one), or the top-left pixel of the view, + respectively. */ typedef struct { - double x; - double y; - double width; - double height; + PuglCoord x; + PuglCoord y; + PuglSpan width; + PuglSpan height; } PuglRect; /** @@ -192,6 +201,8 @@ typedef enum { PUGL_TIMER, ///< Timer triggered, a #PuglTimerEvent PUGL_LOOP_ENTER, ///< Recursive loop entered, a #PuglLoopEnterEvent PUGL_LOOP_LEAVE, ///< Recursive loop left, a #PuglLoopLeaveEvent + PUGL_DATA_OFFER, ///< Data offered from clipboard, a #PuglDataOfferEvent + PUGL_DATA, ///< Data available from clipboard, a #PuglDataEvent } PuglEventType; /// Common flags for all event types @@ -269,10 +280,10 @@ typedef PuglAnyEvent PuglDestroyEvent; typedef struct { PuglEventType type; ///< #PUGL_CONFIGURE PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values - double x; ///< New parent-relative X coordinate - double y; ///< New parent-relative Y coordinate - double width; ///< New width - double height; ///< New height + PuglCoord x; ///< Parent-relative X coordinate of view + PuglCoord y; ///< Parent-relative Y coordinate of view + PuglSpan width; ///< Width of view + PuglSpan height; ///< Height of view } PuglConfigureEvent; /** @@ -315,10 +326,10 @@ typedef PuglAnyEvent PuglUpdateEvent; typedef struct { PuglEventType type; ///< #PUGL_EXPOSE PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values - double x; ///< View-relative X coordinate - double y; ///< View-relative Y coordinate - double width; ///< Width of exposed region - double height; ///< Height of exposed region + PuglCoord x; ///< View-relative top-left X coordinate of region + PuglCoord y; ///< View-relative top-left Y coordinate of region + PuglSpan width; ///< Width of exposed region + PuglSpan height; ///< Height of exposed region } PuglExposeEvent; /** @@ -419,6 +430,21 @@ typedef struct { /** Button press or release event. + + Button numbers start from 0, and are ordered: primary, secondary, middle. + So, on a typical right-handed mouse, the button numbers are: + + Left: 0 + Right: 1 + Middle (often a wheel): 2 + + Higher button numbers are reported in the same order they are represented on + the system. There is no universal standard here, but buttons 3 and 4 are + typically a pair of buttons or a rocker, which are usually bound to "back" + and "forward" operations. + + Note that these numbers may differ from those used on the underlying + platform, since they are manipulated to provide a consistent portable API. */ typedef struct { PuglEventType type; ///< #PUGL_BUTTON_PRESS or #PUGL_BUTTON_RELEASE @@ -429,7 +455,7 @@ typedef struct { double xRoot; ///< Root-relative X coordinate double yRoot; ///< Root-relative Y coordinate PuglMods state; ///< Bitwise OR of #PuglMod flags - uint32_t button; ///< Button number starting from 1 + uint32_t button; ///< Button number starting from 0 } PuglButtonEvent; /** @@ -499,6 +525,34 @@ typedef struct { uintptr_t id; ///< Timer ID } PuglTimerEvent; +/** + Clipboard data offer event. + + This event is sent when a clipboard has data present, possibly with several + datatypes. While handling this event, the types can be investigated with + puglGetClipboardType() to decide whether to accept the offer with + puglAcceptOffer(). +*/ +typedef struct { + PuglEventType type; ///< #PUGL_DATA_OFFER + PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values + double time; ///< Time in seconds +} PuglDataOfferEvent; + +/** + Clipboard data event. + + This event is sent after accepting a data offer when the data has been + retrieved and converted. While handling this event, the data can be + accessed with puglGetClipboard(). +*/ +typedef struct { + PuglEventType type; ///< #PUGL_DATA + PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values + double time; ///< Time in seconds + uint32_t typeIndex; ///< Index of datatype +} PuglDataEvent; + /** Recursive loop enter event. @@ -556,6 +610,8 @@ typedef union { PuglFocusEvent focus; ///< #PUGL_FOCUS_IN, #PUGL_FOCUS_OUT PuglClientEvent client; ///< #PUGL_CLIENT PuglTimerEvent timer; ///< #PUGL_TIMER + PuglDataOfferEvent offer; ///< #PUGL_DATA_OFFER + PuglDataEvent data; ///< #PUGL_DATA } PuglEvent; /** @@ -580,7 +636,8 @@ typedef enum { PUGL_REALIZE_FAILED, ///< System view realization failed PUGL_SET_FORMAT_FAILED, ///< Failed to set pixel format PUGL_CREATE_CONTEXT_FAILED, ///< Failed to create drawing context - PUGL_UNSUPPORTED_TYPE, ///< Unsupported data type + PUGL_UNSUPPORTED, ///< Unsupported operation + PUGL_NO_MEMORY, ///< Failed to allocate memory } PuglStatus; /// Return a string describing a status code @@ -626,7 +683,7 @@ typedef enum { /** Set up support for threads if necessary. - - X11: Calls XInitThreads() which is required for some drivers. + X11: Calls XInitThreads() which is required for some drivers. */ PUGL_WORLD_THREADS = 1u << 0u } PuglWorldFlag; @@ -693,6 +750,11 @@ PUGL_API PuglStatus puglSetClassName(PuglWorld* world, const char* name); +/// Get the class name of the application, or null +PUGL_API +const char* +puglGetClassName(const PuglWorld* world); + /** Return the time in seconds. @@ -792,10 +854,11 @@ typedef enum { PUGL_RESIZABLE, ///< True if view should be resizable PUGL_IGNORE_KEY_REPEAT, ///< True if key repeat events are ignored PUGL_REFRESH_RATE, ///< Refresh rate in Hz - - PUGL_NUM_VIEW_HINTS } PuglViewHint; +/// The number of #PuglViewHint values +#define PUGL_NUM_VIEW_HINTS ((unsigned)PUGL_REFRESH_RATE + 1u) + /// A special view hint value typedef enum { PUGL_DONT_CARE = -1, ///< Use best available value @@ -803,6 +866,46 @@ typedef enum { PUGL_TRUE = 1 ///< Explicitly true } PuglViewHintValue; +/** + A hint for configuring/constraining the size of a view. + + The system will attempt to make the view's window adhere to these, but they + are suggestions, not hard constraints. Applications should handle any view + size gracefully. +*/ +typedef enum { + PUGL_DEFAULT_SIZE, ///< Default size + PUGL_MIN_SIZE, ///< Minimum size + PUGL_MAX_SIZE, ///< Maximum size + + /** + Fixed aspect ratio. + + If set, the view's size should be constrained to this aspect ratio. + Mutually exclusive with #PUGL_MIN_ASPECT and #PUGL_MAX_ASPECT. + */ + PUGL_FIXED_ASPECT, + + /** + Minimum aspect ratio. + + If set, the view's size should be constrained to an aspect ratio no lower + than this. Mutually exclusive with #PUGL_FIXED_ASPECT. + */ + PUGL_MIN_ASPECT, + + /** + Maximum aspect ratio. + + If set, the view's size should be constrained to an aspect ratio no higher + than this. Mutually exclusive with #PUGL_FIXED_ASPECT. + */ + PUGL_MAX_ASPECT +} PuglSizeHint; + +/// The number of #PuglSizeHint values +#define PUGL_NUM_SIZE_HINTS ((unsigned)PUGL_MAX_ASPECT + 1u) + /// A function called when an event occurs typedef PuglStatus (*PuglEventFunc)(PuglView* view, const PuglEvent* event); @@ -872,6 +975,10 @@ PUGL_API PuglStatus puglSetBackend(PuglView* view, const PuglBackend* backend); +/// Return the graphics backend used by a view +const PuglBackend* +puglGetBackend(const PuglView* view); + /// Set the function to call when an event occurs PUGL_API PuglStatus @@ -897,6 +1004,22 @@ PUGL_API int puglGetViewHint(const PuglView* view, PuglViewHint hint); +/** + Return the scale factor of the view. + + This factor describe how large UI elements (especially text) should be + compared to "normal". For example, 2.0 means the UI should be drawn twice + as large. + + "Normal" is loosely defined, but means a good size on a "standard DPI" + display (around 96 DPI). In other words, the scale 1.0 should have text + that is reasonably sized on a 96 DPI display, and the scale 2.0 should have + text twice that large. +*/ +PUGL_API +double +puglGetScaleFactor(const PuglView* view); + /** @} @defgroup frame Frame @@ -926,64 +1049,43 @@ PuglStatus puglSetFrame(PuglView* view, PuglRect frame); /** - Set the default size of the view. + Set the current position of the view. - This should be called before puglResize() to set the default size of the - view, which will be the initial size of the window if this is a top level - view. - - @return #PUGL_UNKNOWN_ERROR on failure, but always succeeds if the view is - not yet realized. -*/ -PUGL_API -PuglStatus -puglSetDefaultSize(PuglView* view, int width, int height); - -/** - Set the minimum size of the view. - - If an initial minimum size is known, this should be called before - puglRealize() to avoid stutter, though it can be called afterwards as well. - - @return #PUGL_UNKNOWN_ERROR on failure, but always succeeds if the view is - not yet realized. + @return #PUGL_UNKNOWN_ERROR on failure, in which case the view frame is + unchanged. */ PUGL_API PuglStatus -puglSetMinSize(PuglView* view, int width, int height); +puglSetPosition(PuglView* view, int x, int y); /** - Set the maximum size of the view. - - If an initial maximum size is known, this should be called before - puglRealize() to avoid stutter, though it can be called afterwards as well. + Set the current size of the view. - @return #PUGL_UNKNOWN_ERROR on failure, but always succeeds if the view is - not yet realized. + @return #PUGL_UNKNOWN_ERROR on failure, in which case the view frame is + unchanged. */ PUGL_API PuglStatus -puglSetMaxSize(PuglView* view, int width, int height); +puglSetSize(PuglView* view, unsigned width, unsigned height); /** - Set the view aspect ratio range. + Set a size hint for the view. - The x and y values here represent a ratio of width to height. To set a - fixed aspect ratio, set the minimum and maximum values to the same ratio. + This can be used to set the default, minimum, and maximum size of a view, + as well as the supported range of aspect ratios. - Note that setting different minimum and maximum constraints does not - currenty work on MacOS (the minimum is used), so only setting a fixed aspect - ratio works properly across all platforms. - - If an initial aspect ratio is known, this should be called before - puglRealize() to avoid stutter, though it can be called afterwards as well. + This should be called before puglRealize() so the initial window for the + view can be configured correctly. @return #PUGL_UNKNOWN_ERROR on failure, but always succeeds if the view is not yet realized. */ PUGL_API PuglStatus -puglSetAspectRatio(PuglView* view, int minX, int minY, int maxX, int maxY); +puglSetSizeHint(PuglView* view, + PuglSizeHint hint, + PuglSpan width, + PuglSpan height); /** @} @@ -1003,6 +1105,11 @@ PUGL_API PuglStatus puglSetWindowTitle(PuglView* view, const char* title); +/// Return the title of the window, or null +PUGL_API +const char* +puglGetWindowTitle(const PuglView* view); + /** Set the parent window for embedding a view in an existing window. @@ -1012,6 +1119,11 @@ PUGL_API PuglStatus puglSetParentWindow(PuglView* view, PuglNativeView parent); +/// Return the parent window this view is embedded in, or null +PUGL_API +PuglNativeView +puglGetParentWindow(const PuglView* view); + /** Set the transient parent of the window. @@ -1024,13 +1136,23 @@ puglSetParentWindow(PuglView* view, PuglNativeView parent); */ PUGL_API PuglStatus -puglSetTransientFor(PuglView* view, PuglNativeView parent); +puglSetTransientParent(PuglView* view, PuglNativeView parent); + +/** + Return the transient parent of the window. + + @return The native handle to the window this view is a transient child of, + or null. +*/ +PUGL_API +PuglNativeView +puglGetTransientParent(const PuglView* view); /** Realize a view by creating a corresponding system view or window. After this call, the (initially invisible) underlying system view exists and - can be accessed with puglGetNativeWindow(). There is currently no + can be accessed with puglGetNativeView(). There is currently no corresponding unrealize function, the system view will be destroyed along with the view when puglFreeView() is called. @@ -1067,7 +1189,7 @@ puglGetVisible(const PuglView* view); /// Return the native window handle PUGL_API PuglNativeView -puglGetNativeWindow(PuglView* view); +puglGetNativeView(PuglView* view); /** @} @@ -1139,7 +1261,17 @@ typedef enum { PUGL_CURSOR_ANTI_DIAGONAL, ///< Bottom-left to top-right arrow for diagonal resize } PuglCursor; -/// Grab the keyboard input focus +/// The number of #PuglCursor values +#define PUGL_NUM_CURSORS ((unsigned)PUGL_CURSOR_ANTI_DIAGONAL + 1u) + +/** + Grab the keyboard input focus. + + Note that this will fail if the view is not mapped and so should not, for + example, be called immediately after puglShow(). + + @return #PUGL_SUCCESS if the focus was successfully grabbed, or an error. +*/ PUGL_API PuglStatus puglGrabFocus(PuglView* view); @@ -1149,6 +1281,59 @@ PUGL_API bool puglHasFocus(const PuglView* view); +/** + Request data from the general copy/paste clipboard. + + A #PUGL_DATA_OFFER event will be sent if data is available. +*/ +PUGL_API +PuglStatus +puglPaste(PuglView* view); + +/** + Return the number of types available for the data in a clipboard. + + Returns zero if the clipboard is empty. +*/ +PUGL_API +uint32_t +puglGetNumClipboardTypes(const PuglView* view); + +/** + Return the identifier of a type available in a clipboard. + + This is usually a MIME type, but may also be another platform-specific type + identifier. Applications must ignore any type they do not recognize. + + Returns null if `typeIndex` is out of bounds according to + puglGetNumClipboardTypes(). +*/ +PUGL_API +const char* +puglGetClipboardType(const PuglView* view, uint32_t typeIndex); + +/** + Accept data offered from a clipboard. + + To accept data, this must be called while handling a #PUGL_DATA_OFFER event. + Doing so will request the data from the source as the specified type. When + the data is available, a #PUGL_DATA event will be sent to the view which can + then retrieve the data with puglGetClipboard(). + + @param view The view. + + @param offer The data offer event. + + @param typeIndex The index of the type that the view will accept. This is + the `typeIndex` argument to the call of puglGetClipboardType() that returned + the accepted type. +*/ +PUGL_API +PuglStatus +puglAcceptOffer(PuglView* view, + const PuglDataOfferEvent* offer, + uint32_t typeIndex); + /** Set the clipboard contents. @@ -1174,13 +1359,13 @@ puglSetClipboard(PuglView* view, puglSetClipboard() or copied from another application. @param view The view. - @param[out] type Set to the MIME type of the data. + @param typeIndex Index of the data type to get the item as. @param[out] len Set to the length of the data in bytes. @return The clipboard contents, or null. */ PUGL_API const void* -puglGetClipboard(PuglView* view, const char** type, size_t* len); +puglGetClipboard(PuglView* view, uint32_t typeIndex, size_t* len); /** Set the mouse cursor. @@ -1263,8 +1448,8 @@ puglStopTimer(PuglView* view, uintptr_t id); puglPostRedisplayRect(), but will always send a message to the X server, even when called in an event handler. - @return #PUGL_UNSUPPORTED_TYPE if sending events of this type is not - supported, #PUGL_UNKNOWN_ERROR if sending the event failed. + @return #PUGL_UNSUPPORTED if sending events of this type is not supported, + #PUGL_UNKNOWN_ERROR if sending the event failed. */ PUGL_API PuglStatus @@ -1348,6 +1533,7 @@ typedef PuglLoopLeaveEvent PuglEventLoopLeave; Windows: This is a `HWND`. */ +PUGL_DEPRECATED_BY("PuglNativeView") typedef uintptr_t PuglNativeWindow; /** @@ -1408,8 +1594,8 @@ puglInitWindowSize(PuglView* view, int width, int height) { PuglRect frame = puglGetFrame(view); - frame.width = width; - frame.height = height; + frame.width = (PuglSpan)width; + frame.height = (PuglSpan)height; puglSetFrame(view, frame); } @@ -1421,7 +1607,7 @@ static inline PUGL_DEPRECATED_BY("puglSetMinSize") void puglInitWindowMinSize(PuglView* view, int width, int height) { - puglSetMinSize(view, width, height); + puglSetSizeHint(view, PUGL_MIN_SIZE, (PuglSpan)width, (PuglSpan)height); } /** @@ -1431,8 +1617,8 @@ puglInitWindowMinSize(PuglView* view, int width, int height) fixed aspect ratio, set the minimum and maximum values to the same ratio. Note that setting different minimum and maximum constraints does not - currenty work on MacOS (the minimum is used), so only setting a fixed aspect - ratio works properly across all platforms. + currently work on MacOS (the minimum is used), so only setting a fixed + aspect ratio works properly across all platforms. */ static inline PUGL_DEPRECATED_BY("puglSetAspectRatio") void @@ -1442,7 +1628,8 @@ puglInitWindowAspectRatio(PuglView* view, int maxX, int maxY) { - puglSetAspectRatio(view, minX, minY, maxX, maxY); + puglSetSizeHint(view, PUGL_MIN_ASPECT, (PuglSpan)minX, (PuglSpan)minY); + puglSetSizeHint(view, PUGL_MAX_ASPECT, (PuglSpan)maxX, (PuglSpan)maxY); } /** @@ -1451,11 +1638,23 @@ puglInitWindowAspectRatio(PuglView* view, On X11, parent must be a Window. On OSX, parent must be an NSView*. */ -static inline PUGL_DEPRECATED_BY("puglSetTransientFor") +static inline PUGL_DEPRECATED_BY("puglSetTransientParent") void puglInitTransientFor(PuglView* view, uintptr_t parent) { - puglSetTransientFor(view, (PuglNativeWindow)parent); + puglSetTransientParent(view, (PuglNativeWindow)parent); +} + +/** + Set transient parent before creating a window. + + @deprecated Use puglSetTransientParent(). +*/ +static inline PUGL_DEPRECATED_BY("puglSetTransientParent") +PuglStatus +puglSetTransientFor(PuglView* view, uintptr_t parent) +{ + return puglSetTransientParent(view, (PuglNativeWindow)parent); } /** @@ -1594,10 +1793,12 @@ puglProcessEvents(PuglView* view); @deprecated Use puglUpdate(). */ -PUGL_API -PUGL_DEPRECATED_BY("puglUpdate") +static inline PUGL_DEPRECATED_BY("puglUpdate") PuglStatus -puglPollEvents(PuglWorld* world, double timeout); +puglPollEvents(PuglWorld* world, double timeout) +{ + return puglUpdate(world, timeout); +} /** Dispatch any pending events to views. @@ -1609,20 +1810,115 @@ puglPollEvents(PuglWorld* world, double timeout); @deprecated Use puglUpdate(). */ -PUGL_API -PUGL_DEPRECATED_BY("puglUpdate") +static inline PUGL_DEPRECATED_BY("puglUpdate") PuglStatus -puglDispatchEvents(PuglWorld* world); +puglDispatchEvents(PuglWorld* world) +{ + return puglUpdate(world, 0.0); +} -PUGL_API -PUGL_DEPRECATED_BY("puglShow") +static inline PUGL_DEPRECATED_BY("puglShow") PuglStatus -puglShowWindow(PuglView* view); +puglShowWindow(PuglView* view) +{ + return puglShow(view); +} -PUGL_API -PUGL_DEPRECATED_BY("puglHide") +static inline PUGL_DEPRECATED_BY("puglHide") +PuglStatus +puglHideWindow(PuglView* view) +{ + return puglHide(view); +} + +/** + Set the default size of the view. + + This should be called before puglRealize() to set the default size of the + view, which will be the initial size of the window if this is a top level + view. + + @return #PUGL_UNKNOWN_ERROR on failure, but always succeeds if the view is + not yet realized. +*/ +static inline PUGL_DEPRECATED_BY("puglSetSizeHint") +PuglStatus +puglSetDefaultSize(PuglView* view, int width, int height) +{ + return puglSetSizeHint( + view, PUGL_DEFAULT_SIZE, (PuglSpan)width, (PuglSpan)height); +} + +/** + Set the minimum size of the view. + + If an initial minimum size is known, this should be called before + puglRealize() to avoid stutter, though it can be called afterwards as well. + + @return #PUGL_UNKNOWN_ERROR on failure, but always succeeds if the view is + not yet realized. +*/ +static inline PUGL_DEPRECATED_BY("puglSetSizeHint") +PuglStatus +puglSetMinSize(PuglView* view, int width, int height) +{ + return puglSetSizeHint( + view, PUGL_MIN_SIZE, (PuglSpan)width, (PuglSpan)height); +} + +/** + Set the maximum size of the view. + + If an initial maximum size is known, this should be called before + puglRealize() to avoid stutter, though it can be called afterwards as well. + + @return #PUGL_UNKNOWN_ERROR on failure, but always succeeds if the view is + not yet realized. +*/ +static inline PUGL_DEPRECATED_BY("puglSetSizeHint") PuglStatus -puglHideWindow(PuglView* view); +puglSetMaxSize(PuglView* view, int width, int height) +{ + return puglSetSizeHint( + view, PUGL_MAX_SIZE, (PuglSpan)width, (PuglSpan)height); +} + +/** + Set the view aspect ratio range. + + The x and y values here represent a ratio of width to height. To set a + fixed aspect ratio, set the minimum and maximum values to the same ratio. + + Note that setting different minimum and maximum constraints does not + currently work on MacOS (the minimum is used), so only setting a fixed + aspect ratio works properly across all platforms. + + If an initial aspect ratio is known, this should be called before + puglRealize() to avoid stutter, though it can be called afterwards as well. + + @return #PUGL_UNKNOWN_ERROR on failure, but always succeeds if the view is + not yet realized. +*/ +static inline PUGL_DEPRECATED_BY("puglSetSizeHint") +PuglStatus +puglSetAspectRatio(PuglView* view, int minX, int minY, int maxX, int maxY) +{ + const PuglStatus st0 = + puglSetSizeHint(view, PUGL_MIN_ASPECT, (PuglSpan)minX, (PuglSpan)minY); + + const PuglStatus st1 = + puglSetSizeHint(view, PUGL_MAX_ASPECT, (PuglSpan)maxX, (PuglSpan)maxY); + + return st0 ? st0 : st1; +} + +/// Return the native window handle +static inline PUGL_DEPRECATED_BY("puglGetNativeView") +PuglNativeView +puglGetNativeWindow(PuglView* view) +{ + return puglGetNativeView(view); +} #endif // PUGL_DISABLE_DEPRECATED diff --git a/dpf/dgl/src/pugl-upstream/include/pugl/stub.h b/dpf/dgl/src/pugl-upstream/include/pugl/stub.h index d1a699a..f98d78e 100644 --- a/dpf/dgl/src/pugl-upstream/include/pugl/stub.h +++ b/dpf/dgl/src/pugl-upstream/include/pugl/stub.h @@ -1,18 +1,5 @@ -/* - Copyright 2019-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ +// Copyright 2019-2020 David Robillard +// SPDX-License-Identifier: ISC #ifndef PUGL_STUB_H #define PUGL_STUB_H diff --git a/dpf/dgl/src/pugl-upstream/include/pugl/vulkan.h b/dpf/dgl/src/pugl-upstream/include/pugl/vulkan.h index f12ad97..978f468 100644 --- a/dpf/dgl/src/pugl-upstream/include/pugl/vulkan.h +++ b/dpf/dgl/src/pugl-upstream/include/pugl/vulkan.h @@ -1,18 +1,5 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ +// Copyright 2012-2020 David Robillard +// SPDX-License-Identifier: ISC /* Note that this header includes Vulkan headers, so if you are writing a diff --git a/dpf/dgl/src/pugl-upstream/meson.build b/dpf/dgl/src/pugl-upstream/meson.build deleted file mode 100644 index ae4c03c..0000000 --- a/dpf/dgl/src/pugl-upstream/meson.build +++ /dev/null @@ -1,377 +0,0 @@ -project('pugl', ['c'], - version: '0.3.0', - license: 'ISC', - meson_version: '>= 0.49.2', - default_options: [ - 'c_std=c99', - 'cpp_std=c++11', - 'default_library=shared' - ]) - -pugl_src_root = meson.current_source_dir() -major_version = meson.project_version().split('.')[0] -version_suffix = '-@0@'.format(major_version) -versioned_name = 'pugl' + version_suffix - -# Load build tools -pkg = import('pkgconfig') -cc = meson.get_compiler('c') - -# Enable C++ support if we're building the examples -if get_option('examples') or get_option('tests') - add_languages(['cpp']) - cpp = meson.get_compiler('cpp') -endif - -# Enable Objective C support if we're building for MacOS -if host_machine.system() == 'darwin' - add_languages(['objc']) - objcc = meson.get_compiler('objc') -endif - -# Set ultra strict warnings for developers, if requested -# These are for the implementation, tests and examples add more suppressions -if get_option('strict') - subdir('meson') - - c_warnings = all_c_warnings - if cc.get_id() == 'clang' - c_warnings += [ - '-Wno-bad-function-cast', - '-Wno-documentation', # Cairo - '-Wno-documentation-unknown-command', # Cairo - '-Wno-padded', - '-Wno-reserved-id-macro', - '-Wno-switch-default', - '-Wno-switch-enum', - ] - elif cc.get_id() == 'gcc' - c_warnings += [ - '-Wno-bad-function-cast', - '-Wno-float-equal', - '-Wno-padded', - '-Wno-suggest-attribute=const', - '-Wno-suggest-attribute=malloc', - '-Wno-suggest-attribute=pure', - '-Wno-switch-default', - '-Wno-switch-enum', - '-Wno-unsuffixed-float-constants', - ] - elif cc.get_id() == 'msvc' - c_warnings += [ - '/wd4028', # formal parameter different from declaration - '/wd4061', # enumerator in switch is not explicitly handled - '/wd4191', # unsafe conversion from type to type - '/wd4514', # unreferenced inline function has been removed - '/wd4706', # assignment within conditional expression - '/wd4710', # function not inlined - '/wd4711', # function selected for automatic inline expansion - '/wd4800', # implicit conversion from int to bool - '/wd4820', # padding added after construct - '/wd4996', # function or variable may be unsafe - '/wd5045', # will insert Spectre mitigation for memory load - ] - endif - - add_project_arguments(cc.get_supported_arguments(c_warnings), - language: ['c', 'objc']) - - # Objective C warnings - if is_variable('objcc') - objc_warnings = all_objc_warnings - - objc_warnings += [ - '-Wno-deprecated-declarations', - '-Wno-direct-ivar-access', - '-Wno-pedantic', - ] - - add_project_arguments(objcc.get_supported_arguments(objc_warnings), - language: ['objc']) - endif -endif - -# Disable deprecated API which is not used by tests or examples -add_project_arguments(['-DPUGL_DISABLE_DEPRECATED'], - language: ['c', 'cpp', 'objc']) - -# System libraries -m_dep = cc.find_library('m', required: false) -dl_dep = cc.find_library('dl', required: false) -thread_dep = dependency('threads') - -# Cairo (optional backend) -cairo_dep = dependency('cairo', - required: get_option('cairo')) - -# OpenGL (optional backend) -opengl_dep = dependency('GL', - required: get_option('opengl')) - -# Vulkan (optional backend) -vulkan_dep = dependency('vulkan', - required: get_option('vulkan')) - -core_args = [] - -# MacOS -if host_machine.system() == 'darwin' - cocoa_dep = dependency('Cocoa', required: false, modules: 'foundation') - corevideo_dep = dependency('CoreVideo', required: false) - - platform = 'mac' - platform_sources = files('src/mac.m') - core_deps = [cocoa_dep, corevideo_dep] - extension = '.m' - - add_project_arguments(['-DGL_SILENCE_DEPRECATION'], - language: ['c', 'objc']) - - add_project_link_arguments(['-Wl,-framework,Cocoa'], - language: ['c', 'objc']) - -# Windows -elif host_machine.system() == 'windows' - if cc.get_id() == 'msvc' - msvc_args = [ - '/TP', - '/experimental:external', - '/external:W0', - '/external:anglebrackets', - ] - - add_project_arguments(msvc_args, language: ['c', 'cpp']) - endif - - win_args = [ - '-DWIN32_LEAN_AND_MEAN', - '-D_CRT_SECURE_NO_WARNINGS', - ] - - add_project_arguments(win_args, language: ['c', 'cpp']) - - platform = 'win' - platform_sources = files('src/win.c') - core_deps = [] - extension = '.c' - -else # X11 - x11_dep = cc.find_library('X11') - - xcursor_dep = cc.find_library('Xcursor', required: false) - if xcursor_dep.found() - core_args += ['-DHAVE_XCURSOR'] - endif - - xrandr_dep = cc.find_library('Xrandr', required: false) - if xrandr_dep.found() - core_args += ['-DHAVE_XRANDR'] - endif - - xext_dep = cc.find_library('Xext', required: false) - if xext_dep.found() - xsync_fragment = '''#include - #include - int main(void) { XSyncQueryExtension(0, 0, 0); return 0; }''' - if cc.compiles(xsync_fragment, name: 'Xsync') - core_args += ['-DHAVE_XSYNC'] - endif - endif - - platform = 'x11' - platform_sources = files('src/x11.c') - core_deps = [x11_dep, xcursor_dep, xrandr_dep, xext_dep] - extension = '.c' -endif - -# Build core library - -core_deps += [m_dep] -core_name = 'pugl_@0@@1@'.format(platform, version_suffix) - -# Determine library type and set up defines for building them -library_args = ['-DPUGL_INTERNAL'] -if get_option('default_library') == 'both' - if host_machine.system() == 'windows' - error('default_library=both is not supported on Windows') - endif - - library_type = 'both_libraries' -elif get_option('default_library') == 'shared' - library_type = 'shared_library' -else - library_type = 'static_library' - add_project_arguments(['-DPUGL_STATIC'], language: ['c', 'cpp', 'objc']) -endif - -# Build core library -libpugl = build_target( - core_name, - files('src/implementation.c') + platform_sources, - version: meson.project_version(), - include_directories: include_directories(['include']), - c_args: library_args + core_args, - dependencies: core_deps, - gnu_symbol_visibility: 'hidden', - install: true, - target_type: library_type) - -pugl_dep = declare_dependency(link_with: libpugl, dependencies: core_deps) - -# Build pkg-config file -pkg.generate(libpugl, - name: 'Pugl', - filebase: versioned_name, - subdirs: [versioned_name], - version: meson.project_version(), - description: 'Pugl GUI library core') - -# Build stub backend - -name = 'pugl_' + platform + '_stub' + version_suffix -sources = files('src/' + platform + '_stub' + extension) - -stub_backend = build_target( - name, sources, - version: meson.project_version(), - include_directories: include_directories(['include']), - c_args: library_args, - dependencies: [pugl_dep], - gnu_symbol_visibility: 'hidden', - install: true, - target_type: library_type) - -stub_backend_dep = declare_dependency(link_with: stub_backend) - -pkg.generate(stub_backend, - name: 'Pugl Stub', - filebase: 'pugl-stub-@0@'.format(major_version), - subdirs: [versioned_name], - version: meson.project_version(), - description: 'Native window pugl graphics backend') - -# Build GL backend -if opengl_dep.found() - name = 'pugl_' + platform + '_gl' + version_suffix - sources = files('src/' + platform + '_gl' + extension) - - gl_backend = build_target( - name, sources, - version: meson.project_version(), - include_directories: include_directories(['include']), - c_args: library_args, - dependencies: [pugl_dep, opengl_dep], - gnu_symbol_visibility: 'hidden', - install: true, - target_type: library_type) - - gl_backend_dep = declare_dependency(link_with: gl_backend, - dependencies: [pugl_dep, opengl_dep]) - - pkg.generate(gl_backend, - name: 'Pugl OpenGL', - filebase: 'pugl-gl-@0@'.format(major_version), - subdirs: [versioned_name], - version: meson.project_version(), - description: 'Pugl GUI library with OpenGL backend') -endif - -# Build Cairo backend -if cairo_dep.found() - name = 'pugl_' + platform + '_cairo' + version_suffix - sources = files('src/' + platform + '_cairo' + extension) - - cairo_backend = build_target( - name, sources, - version: meson.project_version(), - include_directories: include_directories(['include']), - c_args: library_args, - dependencies: [pugl_dep, cairo_dep], - gnu_symbol_visibility: 'hidden', - install: true, - target_type: library_type) - - cairo_backend_dep = declare_dependency( - link_with: cairo_backend, - dependencies: [pugl_dep, cairo_dep]) - - pkg.generate(cairo_backend, - name: 'Pugl Cairo', - filebase: 'pugl-cairo-@0@'.format(major_version), - subdirs: [versioned_name], - version: meson.project_version(), - description: 'Pugl GUI library with Cairo backend') -endif - -# Build Vulkan backend -if vulkan_dep.found() - name = 'pugl_' + platform + '_vulkan' + version_suffix - sources = files('src/' + platform + '_vulkan' + extension) - - vulkan_deps = [pugl_dep, vulkan_dep, dl_dep] - vulkan_c_args = library_args - vulkan_link_args = [] - if platform == 'mac' - metal_dep = dependency('Metal', modules: 'foundation') - quartzcore_dep = dependency('QuartzCore', modules: 'foundation') - - vulkan_deps += [metal_dep, quartzcore_dep] - endif - - vulkan_backend = build_target( - name, sources, - version: meson.project_version(), - include_directories: include_directories(['include']), - c_args: library_args, - dependencies: vulkan_deps, - gnu_symbol_visibility: 'hidden', - install: true, - target_type: library_type) - - vulkan_backend_dep = declare_dependency( - link_with: vulkan_backend, - dependencies: [pugl_dep, vulkan_dep, thread_dep]) - - pkg.generate(vulkan_backend, - name: 'Pugl Vulkan', - filebase: 'pugl-vulkan-@0@'.format(major_version), - subdirs: [versioned_name], - version: meson.project_version(), - description: 'Pugl GUI library with Vulkan backend') -endif - -# Process all headers first so they are available for building documentation -subdir('include') -subdir('bindings/cpp') - -if not get_option('docs').disabled() - subdir('doc') -else - build_docs = false -endif - -if get_option('examples') - subdir('examples') -endif - -if get_option('tests') - subdir('test') -endif - -if meson.version().version_compare('>=0.53.0') - summary('Platform', platform) - summary('Cairo backend', cairo_dep.found(), bool_yn: true) - summary('OpenGL backend', opengl_dep.found(), bool_yn: true) - summary('Vulkan backend', vulkan_dep.found(), bool_yn: true) - summary('Tests', get_option('tests'), bool_yn: true) - summary('Examples', get_option('examples'), bool_yn: true) - summary('Documentation', build_docs, bool_yn: true) - - summary('Install prefix', get_option('prefix')) - summary('Headers', get_option('prefix') / get_option('includedir')) - summary('Libraries', get_option('prefix') / get_option('libdir')) - - if get_option('examples') - summary('Executables', get_option('prefix') / get_option('bindir')) - endif -endif diff --git a/dpf/dgl/src/pugl-upstream/meson/meson.build b/dpf/dgl/src/pugl-upstream/meson/meson.build deleted file mode 100644 index 20e0522..0000000 --- a/dpf/dgl/src/pugl-upstream/meson/meson.build +++ /dev/null @@ -1,196 +0,0 @@ -# General code to enable approximately all warnings. -# -# This is trivial for clang and MSVC, but GCC does not have such an option, and -# has several esoteric warnings, so we need to enable everything we want -# explicitly. We enable everything that does not require a value argument, -# except for warnings that are only relevant for very old languages (earlier -# than C99 or C++11) or non-standard extensions. -# -# Omitted common warnings: -# -# Wabi= -# Waggregate-return -# Walloc-size-larger-than=BYTES -# Walloca-larger-than=BYTES -# Wframe-larger-than=BYTES -# Wlarger-than=BYTES -# Wstack-usage=BYTES -# Wsystem-headers -# Wtraditional -# Wtraditional-conversion -# Wtrampolines -# Wvla-larger-than=BYTES -# -# Omitted C warnings: -# -# Wc90-c99-compat -# Wdeclaration-after-statement -# Wtraditional -# Wtraditional-conversion -# -# Omitted C++ warnings: -# -# Wnamespaces -# Wtemplates - -gcc_common_warnings = [ - '-Walloc-zero', - '-Walloca', - '-Wanalyzer-too-complex', - '-Warith-conversion', - '-Warray-bounds=2', - '-Wattribute-alias=2', - '-Wcast-align=strict', - '-Wcast-qual', - '-Wconversion', - '-Wdate-time', - '-Wdisabled-optimization', - '-Wdouble-promotion', - '-Wduplicated-branches', - '-Wduplicated-cond', - '-Wfloat-equal', - '-Wformat-overflow=2', - '-Wformat-signedness', - '-Wformat-truncation=2', - '-Wformat=2', - '-Wimplicit-fallthrough=2', - '-Winit-self', - '-Winline', - '-Winvalid-pch', - '-Wlogical-op', - '-Wmissing-declarations', - '-Wmissing-include-dirs', - '-Wmultichar', - '-Wnormalized=nfc', - '-Wnull-dereference', - '-Wpacked', - '-Wpadded', - '-Wredundant-decls', - '-Wscalar-storage-order', - '-Wshadow', - '-Wshift-overflow=2', - '-Wsizeof-array-argument', - '-Wstack-protector', - '-Wstrict-aliasing=3', - '-Wstrict-overflow=5', - '-Wstringop-overflow=3', - '-Wsuggest-attribute=cold', - '-Wsuggest-attribute=const', - '-Wsuggest-attribute=format', - '-Wsuggest-attribute=malloc', - '-Wsuggest-attribute=noreturn', - '-Wsuggest-attribute=pure', - '-Wswitch-default', - '-Wswitch-enum', - '-Wsync-nand', - '-Wundef', - '-Wunused-const-variable=2', - '-Wunused-macros', - '-Wvarargs', - '-Wvector-operation-performance', - '-Wvla', - '-Wwrite-strings', -] - -gcc_c_warnings = [ - '-Wbad-function-cast', - '-Wc++-compat', - '-Wc99-c11-compat', - '-Wdesignated-init', - '-Wdiscarded-array-qualifiers', - '-Wdiscarded-qualifiers', - '-Wincompatible-pointer-types', - '-Wjump-misses-init', - '-Wmissing-prototypes', - '-Wnested-externs', - '-Wold-style-definition', - '-Wstrict-prototypes', - '-Wunsuffixed-float-constants', -] - -# Set all_c_warnings for the current C compiler -if is_variable('cc') - if cc.get_id() == 'clang' - all_c_warnings = ['-Weverything'] - elif cc.get_id() == 'gcc' - all_c_warnings = gcc_common_warnings + [ - '-Wbad-function-cast', - '-Wc++-compat', - '-Wc99-c11-compat', - '-Wdesignated-init', - '-Wdiscarded-array-qualifiers', - '-Wdiscarded-qualifiers', - '-Wincompatible-pointer-types', - '-Wjump-misses-init', - '-Wmissing-prototypes', - '-Wnested-externs', - '-Wold-style-definition', - '-Wstrict-prototypes', - '-Wunsuffixed-float-constants', - ] - elif cc.get_id() == 'msvc' - all_c_warnings = ['/Wall'] - else - all_c_warnings = [] - endif -endif - -# Set all_cpp_warnings for the current C++ compiler -if is_variable('cpp') - if cpp.get_id() == 'clang' - all_cpp_warnings = [ - '-Weverything', - '-Wno-c++98-compat', - '-Wno-c++98-compat-pedantic' - ] - elif cpp.get_id() == 'gcc' - all_cpp_warnings = gcc_common_warnings + [ - '-Wabi-tag', - '-Waligned-new=all', - '-Wcatch-value=3', - '-Wcomma-subscript', - '-Wconditionally-supported', - '-Wctor-dtor-privacy', - '-Wdeprecated-copy-dtor', - '-Weffc++', - '-Wextra-semi', - '-Wmismatched-tags', - '-Wmultiple-inheritance', - '-Wnoexcept', - '-Wnoexcept-type', - '-Wnon-virtual-dtor', - '-Wold-style-cast', - '-Woverloaded-virtual', - '-Wplacement-new=2', - '-Wredundant-tags', - '-Wregister', - '-Wsign-promo', - '-Wstrict-null-sentinel', - '-Wsuggest-final-methods', - '-Wsuggest-final-types', - '-Wsuggest-override', - '-Wuseless-cast', - '-Wvirtual-inheritance', - '-Wvolatile', - '-Wzero-as-null-pointer-constant', - ] - elif cpp.get_id() == 'msvc' - all_cpp_warnings = ['/Wall'] - else - all_cpp_warnings = [] - endif -endif - -# Set all_objc_warnings for the current Objective C compiler -if is_variable('objcc') - all_objc_warnings = [] - if objcc.get_id() == 'clang' - all_objc_warnings = ['-Weverything'] - elif objc.get_id() == 'gcc' - all_objc_warnings = gcc_common_warnings + [ - '-Wno-direct-ivar-access', - ] - else - all_objc_warnings = [] - endif -endif diff --git a/dpf/dgl/src/pugl-upstream/meson_options.txt b/dpf/dgl/src/pugl-upstream/meson_options.txt deleted file mode 100644 index dd6ea8c..0000000 --- a/dpf/dgl/src/pugl-upstream/meson_options.txt +++ /dev/null @@ -1,20 +0,0 @@ -option('cairo', type: 'feature', value: 'auto', - description : 'Enable support for the Cairo graphics API') - -option('examples', type: 'boolean', value: true, - description: 'Build example programs') - -option('docs', type: 'feature', value: 'auto', - description: 'Build documentation') - -option('opengl', type: 'feature', value: 'auto', - description : 'Enable support for the OpenGL graphics API') - -option('strict', type: 'boolean', value: false, - description: 'Enable ultra-strict warnings') - -option('tests', type: 'boolean', value: true, - description: 'Build tests') - -option('vulkan', type: 'feature', value: 'auto', - description : 'Enable support for the Vulkan graphics API') diff --git a/dpf/dgl/src/pugl-upstream/resources/Info.plist.in b/dpf/dgl/src/pugl-upstream/resources/Info.plist.in deleted file mode 100644 index a08dbd0..0000000 --- a/dpf/dgl/src/pugl-upstream/resources/Info.plist.in +++ /dev/null @@ -1,20 +0,0 @@ - - - - - CFBundleIdentifier - net.drobilla.pugl.@NAME@ - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1.0 - MinimumOSVersion - 10.6 - CFBundleDisplayName - @NAME@ - CFBundleName - @NAME@ - NSHighResolutionCapable - - - diff --git a/dpf/dgl/src/pugl-upstream/resources/pugl.ipe b/dpf/dgl/src/pugl-upstream/resources/pugl.ipe deleted file mode 100644 index 238c09c..0000000 --- a/dpf/dgl/src/pugl-upstream/resources/pugl.ipe +++ /dev/null @@ -1,293 +0,0 @@ - - - - - - - -0 0 m --1 0.333 l --1 -0.333 l -h - - - - -0 0 m --1 0.333 l --1 -0.333 l -h - - - - -0 0 m --1 0.333 l --0.8 0 l --1 -0.333 l -h - - - - -0 0 m --1 0.333 l --0.8 0 l --1 -0.333 l -h - - - - -0.6 0 0 0.6 0 0 e -0.4 0 0 0.4 0 0 e - - - - -0.6 0 0 0.6 0 0 e - - - - - -0.5 0 0 0.5 0 0 e - - -0.6 0 0 0.6 0 0 e -0.4 0 0 0.4 0 0 e - - - - - --0.6 -0.6 m -0.6 -0.6 l -0.6 0.6 l --0.6 0.6 l -h --0.4 -0.4 m -0.4 -0.4 l -0.4 0.4 l --0.4 0.4 l -h - - - - --0.6 -0.6 m -0.6 -0.6 l -0.6 0.6 l --0.6 0.6 l -h - - - - - --0.5 -0.5 m -0.5 -0.5 l -0.5 0.5 l --0.5 0.5 l -h - - --0.6 -0.6 m -0.6 -0.6 l -0.6 0.6 l --0.6 0.6 l -h --0.4 -0.4 m -0.4 -0.4 l -0.4 0.4 l --0.4 0.4 l -h - - - - - - --0.43 -0.57 m -0.57 0.43 l -0.43 0.57 l --0.57 -0.43 l -h - - --0.43 0.57 m -0.57 -0.43 l -0.43 -0.57 l --0.57 0.43 l -h - - - - - -0 0 m --1 0.333 l --1 -0.333 l -h - - - - -0 0 m --1 0.333 l --0.8 0 l --1 -0.333 l -h - - - - -0 0 m --1 0.333 l --0.8 0 l --1 -0.333 l -h - - - - --1 0.333 m -0 0 l --1 -0.333 l - - - - -0 0 m --1 0.333 l --1 -0.333 l -h --1 0 m --2 0.333 l --2 -0.333 l -h - - - - -0 0 m --1 0.333 l --1 -0.333 l -h --1 0 m --2 0.333 l --2 -0.333 l -h - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -128 704 m -128 640 l -448 640 l -448 704 l -h - - -128 704 m -128 384 l -448 384 l -448 704 l -h - - -176 592 m -176 432 l -400 432 l -400 592 l -h - - -176 592 m -176 560 l -400 560 l -400 592 l -h - - -416 544 m -416 544 l -416 544 l -416 544 l -h - - - diff --git a/dpf/dgl/src/pugl-upstream/resources/pugl.png b/dpf/dgl/src/pugl-upstream/resources/pugl.png deleted file mode 100644 index 46416600a6ab5de6fc78e154cd3c9c7f58adbdd4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2641 zcmd^=e@s(X6vt0nYdb}R0Sed(3mb|8Zq^m0M9VLWb*We+9n=Z-#TJx;4r3V#ebFUO zfwD~JL{ceOYfi-YTK5C-1hFC8rX_SZm>pec z%i;K54dlnW<~^%0c~eh5+~8MV;WubHTHkg*V1HeEz(wjdVD@G*@L&gkV)5qzxMLq2 z02zRZSy*l}Tz`41RQ^^IiXzh7zTZH%>v~aU*cqhcZFKg*Lh5im_Gv$w?KpiH(m9!thJ&t;U zNWuB4p=az$Eu1yE0MoQiu!rZP`v&NN-*Y=eGCHA2Bb7)G%wg>$aay^)Edu5LaSJUGHeKtRMOp-MdigY~ zmj1b8!px2~w#yD=*5unEyRk%|tx5loRze!_)Ml{)9PqJ>KU`FlWjFLlQq3+|MXXS` zm@eIhNdR55Mq<%<)kQUt$ASe|XdsLpcUaCnSEpAsK3D_(#lz;k{-vwwPKTQ{n&oXfDm}hG)jLX5 z)B8o;>~21db~ujrgnHuj8}pL4S8mbEf767|&f8lCFmqmLkKg!c}hYzJ68N!fO}jpVS2A~ftVpLfXsW@%Hmub zG_ZTDm6}I{%n*~lGFPjs#w&h)_wedNcSU&M8xqr#dF*jTxp_IdP`MQ0rP1N14=(G= z27;*4Pvuhk@JNpcWln3S(x}{|(P$F7KC4eMe3Fjv45?R)=3MX-Y*h{lMiAAcvj=l> n(~$^10ibJQ9?kVGhIhpn&cwv~1Z9k1J%cTwoRG^wu}A*_5pqBs diff --git a/dpf/dgl/src/pugl-upstream/resources/pugl.svg b/dpf/dgl/src/pugl-upstream/resources/pugl.svg deleted file mode 100644 index 93189f4..0000000 --- a/dpf/dgl/src/pugl-upstream/resources/pugl.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/dpf/dgl/src/pugl-upstream/scripts/cat.py b/dpf/dgl/src/pugl-upstream/scripts/cat.py deleted file mode 100755 index 5f628b6..0000000 --- a/dpf/dgl/src/pugl-upstream/scripts/cat.py +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env python - -import sys - -for filename in sys.argv[1:]: - with open(filename, 'r') as f: - sys.stdout.write(f.read()) diff --git a/dpf/dgl/src/pugl-upstream/scripts/dox_to_sphinx.py b/dpf/dgl/src/pugl-upstream/scripts/dox_to_sphinx.py deleted file mode 100755 index b88a484..0000000 --- a/dpf/dgl/src/pugl-upstream/scripts/dox_to_sphinx.py +++ /dev/null @@ -1,652 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright 2020 David Robillard -# -# Permission to use, copy, modify, and/or distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -""" -Write Sphinx markup from Doxygen XML. - -Takes a path to a directory of XML generated by Doxygen, and emits a directory -with a reStructuredText file for every documented symbol. -""" - -import argparse -import os -import sys -import textwrap -import xml.etree.ElementTree - -__author__ = "David Robillard" -__date__ = "2020-11-18" -__email__ = "d@drobilla.net" -__license__ = "ISC" -__version__ = __date__.replace("-", ".") - - -def load_index(index_path): - """ - Load the index from XML. - - :returns: A dictionary from ID to skeleton records with basic information - for every documented entity. Some records have an ``xml_filename`` key - with the filename of a definition file. These files will be loaded later - to flesh out the records in the index. - """ - - root = xml.etree.ElementTree.parse(index_path).getroot() - index = {} - - for compound in root: - compound_id = compound.get("refid") - compound_kind = compound.get("kind") - compound_name = compound.find("name").text - if compound_kind in ["dir", "file", "page"]: - continue - - # Add record for compound (compounds appear only once in the index) - assert compound_id not in index - index[compound_id] = { - "kind": compound_kind, - "name": compound_name, - "xml_filename": compound_id + ".xml", - "children": [], - } - - name_prefix = ( - ("%s::" % compound_name) if compound_kind == "namespace" else "" - ) - - for child in compound.findall("member"): - if child.get("refid") in index: - assert compound_kind == "group" - continue - - # Everything has a kind and a name - child_record = { - "kind": child.get("kind"), - "name": name_prefix + child.find("name").text, - } - - if child.get("kind") == "enum": - # Enums are not compounds, but we want to resolve the parent of - # their values so they are not written as top level documents - child_record["children"] = [] - - if child.get("kind") == "enumvalue": - # Remove namespace prefix - child_record["name"] = child.find("name").text - - index[child.get("refid")] = child_record - - return index - - -def resolve_index(index, root): - """ - Walk a definition document and extend the index for linking. - - This does two things: sets the "parent" and "children" fields of all - applicable records, and sets the "strong" field of enums so that the - correct Sphinx role can be used when referring to them. - """ - - def add_child(index, parent_id, child_id): - parent = index[parent_id] - child = index[child_id] - - if child["kind"] == "enumvalue": - assert parent["kind"] == "enum" - assert "parent" not in child or child["parent"] == parent_id - child["parent"] = parent_id - - else: - if parent["kind"] in ["class", "struct", "union"]: - assert "parent" not in child or child["parent"] == parent_id - child["parent"] = parent_id - - if child_id not in parent["children"]: - parent["children"] += [child_id] - - compound = root.find("compounddef") - compound_kind = compound.get("kind") - - if compound_kind == "group": - for subgroup in compound.findall("innergroup"): - add_child(index, compound.get("id"), subgroup.get("refid")) - - for klass in compound.findall("innerclass"): - add_child(index, compound.get("id"), klass.get("refid")) - - for section in compound.findall("sectiondef"): - if section.get("kind").startswith("private"): - for member in section.findall("memberdef"): - if member.get("id") in index: - del index[member.get("id")] - else: - for member in section.findall("memberdef"): - member_id = member.get("id") - add_child(index, compound.get("id"), member_id) - - if member.get("kind") == "enum": - index[member_id]["strong"] = member.get("strong") == "yes" - for value in member.findall("enumvalue"): - add_child(index, member_id, value.get("id")) - - -def sphinx_role(record, lang): - """ - Return the Sphinx role used for a record. - - This is used for the description directive like ".. c:function::", and - links like ":c:func:`foo`. - """ - - kind = record["kind"] - - if kind in ["class", "function", "namespace", "struct", "union"]: - return lang + ":" + kind - - if kind == "define": - return "c:macro" - - if kind == "enum": - return lang + (":enum-class" if record["strong"] else ":enum") - - if kind == "typedef": - return lang + ":type" - - if kind == "enumvalue": - return lang + ":enumerator" - - if kind == "variable": - return lang + (":member" if "parent" in record else ":var") - - raise RuntimeError("No known role for kind '%s'" % kind) - - -def child_identifier(lang, parent_name, child_name): - """ - Return the identifier for an enum value or struct member. - - Sphinx, for some reason, uses a different syntax for this in C and C++. - """ - - separator = "::" if lang == "cpp" else "." - - return "%s%s%s" % (parent_name, separator, child_name) - - -def link_markup(index, lang, refid): - """Return a Sphinx link for a Doxygen reference.""" - - record = index[refid] - kind, name = record["kind"], record["name"] - role = sphinx_role(record, lang) - - if kind in ["class", "enum", "struct", "typedef", "union"]: - return ":%s:`%s`" % (role, name) - - if kind == "function": - return ":%s:func:`%s`" % (lang, name) - - if kind == "enumvalue": - parent_name = index[record["parent"]]["name"] - return ":%s:`%s`" % (role, child_identifier(lang, parent_name, name)) - - if kind == "variable": - if "parent" not in record: - return ":%s:var:`%s`" % (lang, name) - - parent_name = index[record["parent"]]["name"] - return ":%s:`%s`" % (role, child_identifier(lang, parent_name, name)) - - raise RuntimeError("Unknown link target kind: %s" % kind) - - -def indent(markup, depth): - """ - Indent markup to a depth level. - - Like textwrap.indent() but takes an integer and works in reST indentation - levels for clarity." - """ - - return textwrap.indent(markup, " " * depth) - - -def heading(text, level): - """ - Return a ReST heading at a given level. - - Follows the style in the Python documentation guide, see - . - """ - - assert 1 <= level <= 6 - - chars = ("#", "*", "=", "-", "^", '"') - line = chars[level] * len(text) - - return "%s%s\n%s\n\n" % (line + "\n" if level < 3 else "", text, line) - - -def dox_to_rst(index, lang, node): - """ - Convert documentation commands (docCmdGroup) to Sphinx markup. - - This is used to convert the content of descriptions in the documentation. - It recursively parses all children tags and raises a RuntimeError if any - unknown tag is encountered. - """ - - def field_value(markup): - """Return a value for a field as a single line or indented block.""" - if "\n" in markup.strip(): - return "\n" + indent(markup, 1) - - return " " + markup.strip() - - if node.tag == "lsquo": - return "‘" - - if node.tag == "rsquo": - return "’" - - if node.tag == "computeroutput": - assert len(node) == 0 - return "``%s``" % node.text - - if node.tag == "itemizedlist": - markup = "" - for item in node.findall("listitem"): - assert len(item) == 1 - markup += "\n- %s" % dox_to_rst(index, lang, item[0]) - - return markup - - if node.tag == "para": - markup = node.text if node.text is not None else "" - for child in node: - markup += dox_to_rst(index, lang, child) - markup += child.tail if child.tail is not None else "" - - return markup.strip() + "\n\n" - - if node.tag == "parameterlist": - markup = "" - for item in node.findall("parameteritem"): - name = item.find("parameternamelist/parametername") - description = item.find("parameterdescription") - assert len(description) == 1 - markup += "\n\n:param %s:%s" % ( - name.text, - field_value(dox_to_rst(index, lang, description[0])), - ) - - return markup + "\n" - - if node.tag == "programlisting": - return "\n.. code-block:: %s\n\n%s" % ( - lang, - indent(plain_text(node), 1), - ) - - if node.tag == "ref": - refid = node.get("refid") - if refid not in index: - sys.stderr.write("warning: Unresolved link: %s\n" % refid) - return node.text - - assert len(node) == 0 - assert len(link_markup(index, lang, refid)) > 0 - return link_markup(index, lang, refid) - - if node.tag == "simplesect": - assert len(node) == 1 - - if node.get("kind") == "return": - return "\n:returns:" + field_value( - dox_to_rst(index, lang, node[0]) - ) - - if node.get("kind") == "see": - return dox_to_rst(index, lang, node[0]) - - raise RuntimeError("Unknown simplesect kind: %s" % node.get("kind")) - - if node.tag == "ulink": - return "`%s <%s>`_" % (node.text, node.get("url")) - - raise RuntimeError("Unknown documentation command: %s" % node.tag) - - -def description_markup(index, lang, node): - """Return the markup for a brief or detailed description.""" - - assert node.tag == "briefdescription" or node.tag == "detaileddescription" - assert not (node.tag == "briefdescription" and len(node) > 1) - assert len(node.text.strip()) == 0 - - return "".join([dox_to_rst(index, lang, child) for child in node]).strip() - - -def set_descriptions(index, lang, definition, record): - """Set a record's brief/detailed descriptions from the XML definition.""" - - for tag in ["briefdescription", "detaileddescription"]: - node = definition.find(tag) - if node is not None: - record[tag] = description_markup(index, lang, node) - - -def set_template_params(node, record): - """Set a record's template_params from the XML definition.""" - - template_param_list = node.find("templateparamlist") - if template_param_list is not None: - params = [] - for param in template_param_list.findall("param"): - if param.find("declname") is not None: - # Value parameter - type_text = plain_text(param.find("type")) - name_text = plain_text(param.find("declname")) - - params += ["%s %s" % (type_text, name_text)] - else: - # Type parameter - params += ["%s" % (plain_text(param.find("type")))] - - record["template_params"] = "%s" % ", ".join(params) - - -def plain_text(node): - """ - Return the plain text of a node with all tags ignored. - - This is needed where Doxygen may include refs but Sphinx needs plain text - because it parses things itself to generate links. - """ - - if node.tag == "sp": - markup = " " - elif node.text is not None: - markup = node.text - else: - markup = "" - - for child in node: - markup += plain_text(child) - markup += child.tail if child.tail is not None else "" - - return markup - - -def local_name(name): - """Return a name with all namespace prefixes stripped.""" - - return name[name.rindex("::") + 2 :] if "::" in name else name - - -def read_definition_doc(index, lang, root): - """Walk a definition document and update described records in the index.""" - - # Set descriptions for the compound itself - compound = root.find("compounddef") - compound_record = index[compound.get("id")] - set_descriptions(index, lang, compound, compound_record) - set_template_params(compound, compound_record) - - if compound.find("title") is not None: - compound_record["title"] = compound.find("title").text.strip() - - # Set documentation for all children - for section in compound.findall("sectiondef"): - if section.get("kind").startswith("private"): - continue - - for member in section.findall("memberdef"): - kind = member.get("kind") - record = index[member.get("id")] - set_descriptions(index, lang, member, record) - set_template_params(member, record) - - if compound.get("kind") in ["class", "struct", "union"]: - assert kind in ["function", "typedef", "variable"] - record["type"] = plain_text(member.find("type")) - - if kind == "enum": - for value in member.findall("enumvalue"): - set_descriptions( - index, lang, value, index[value.get("id")] - ) - - elif kind == "function": - record["prototype"] = "%s %s%s" % ( - plain_text(member.find("type")), - member.find("name").text, - member.find("argsstring").text, - ) - - elif kind == "typedef": - name = local_name(record["name"]) - args_text = member.find("argsstring").text - target_text = plain_text(member.find("type")) - if args_text is not None: # Function pointer - assert target_text[-2:] == "(*" and args_text[0] == ")" - record["type"] = target_text + args_text - record["definition"] = target_text + name + args_text - else: # Normal named typedef - assert target_text is not None - record["type"] = target_text - if member.find("definition").text.startswith("using"): - record["definition"] = "%s = %s" % ( - name, - target_text, - ) - else: - record["definition"] = "%s %s" % ( - target_text, - name, - ) - - elif kind == "variable": - record["definition"] = member.find("definition").text - - -def declaration_string(record): - """ - Return the string that describes a declaration. - - This is what follows the directive, and is in C/C++ syntax, except without - keywords like "typedef" and "using" as expected by Sphinx. For example, - "struct ThingImpl Thing" or "void run(int value)". - """ - - kind = record["kind"] - result = "" - - if "template_params" in record: - result = "template <%s> " % record["template_params"] - - if kind == "function": - result += record["prototype"] - elif kind == "typedef": - result += record["definition"] - elif kind == "variable": - if "parent" in record: - result += "%s %s" % (record["type"], local_name(record["name"])) - else: - result += record["definition"] - elif "type" in record: - result += "%s %s" % (record["type"], local_name(record["name"])) - else: - result += local_name(record["name"]) - - return result - - -def document_markup(index, lang, record): - """Return the complete document that describes some documented entity.""" - - kind = record["kind"] - role = sphinx_role(record, lang) - name = record["name"] - markup = "" - - if name != local_name(name): - markup += ".. cpp:namespace:: %s\n\n" % name[0 : name.rindex("::")] - - # Write top-level directive - markup += ".. %s:: %s\n" % (role, declaration_string(record)) - - # Write main description blurb - markup += "\n" + indent(record["briefdescription"] + "\n", 1) - if len(record["detaileddescription"]) > 0: - markup += "\n" + indent(record["detaileddescription"], 1) + "\n" - - assert ( - kind in ["class", "enum", "namespace", "struct", "union"] - or "children" not in record - ) - - # Sphinx C++ namespaces work by setting a scope, they have no content - child_indent = 0 if kind == "namespace" else 1 - - # Write inline children if applicable - markup += "\n" if "children" in record else "" - for child_id in record.get("children", []): - child_record = index[child_id] - child_role = sphinx_role(child_record, lang) - - child_header = ".. %s:: %s\n\n" % ( - child_role, - declaration_string(child_record), - ) - - markup += "\n" - markup += indent(child_header, child_indent) - markup += indent(child_record["briefdescription"], child_indent + 1) - markup += indent(child_record["detaileddescription"], child_indent + 1) - - return markup - - -def symbol_filename(name): - """Adapt the name of a symbol to be suitable for use as a filename.""" - - return name.replace("::", "__") - - -def emit_groups(index, lang, output_dir, force): - """Write a description file for every group documented in the index.""" - - for record in index.values(): - if record["kind"] != "group": - continue - - name = record["name"] - filename = os.path.join(output_dir, "%s.rst" % name) - if not force and os.path.exists(filename): - raise FileExistsError("File already exists: '%s'" % filename) - - with open(filename, "w") as rst: - rst.write(heading(record["title"], 1)) - - # Get all child group and symbol names - child_groups = {} - child_symbols = {} - for child_id in record["children"]: - child = index[child_id] - if child["kind"] == "group": - child_groups[child["name"]] = child - else: - child_symbols[child["name"]] = child - - # Emit description (document body) - if len(record["briefdescription"]) > 0: - rst.write(record["briefdescription"] + "\n\n") - if len(record["detaileddescription"]) > 0: - rst.write(record["detaileddescription"] + "\n\n") - - if len(child_groups) > 0: - # Emit TOC for child groups - rst.write(".. toctree::\n\n") - for name, group in child_groups.items(): - rst.write(indent(group["name"], 1) + "\n") - - # Emit symbols in sorted order - for name, symbol in child_symbols.items(): - rst.write("\n") - rst.write(document_markup(index, lang, symbol)) - rst.write("\n") - - -def run(index_xml_path, output_dir, language, force): - """Write a directory of Sphinx files from a Doxygen XML directory.""" - - # Build skeleton index from index.xml - xml_dir = os.path.dirname(index_xml_path) - index = load_index(index_xml_path) - - # Load all definition documents - definition_docs = [] - for record in index.values(): - if "xml_filename" in record: - xml_path = os.path.join(xml_dir, record["xml_filename"]) - definition_docs += [xml.etree.ElementTree.parse(xml_path)] - - # Do an initial pass of the definition documents to resolve the index - for root in definition_docs: - resolve_index(index, root) - - # Finally read the documentation from definition documents - for root in definition_docs: - read_definition_doc(index, language, root) - - # Create output directory - try: - os.makedirs(output_dir) - except OSError: - pass - - # Emit output files - emit_groups(index, language, output_dir, force) - - -if __name__ == "__main__": - ap = argparse.ArgumentParser( - usage="%(prog)s [OPTION]... XML_DIR OUTPUT_DIR", - description=__doc__, - formatter_class=argparse.RawDescriptionHelpFormatter, - ) - - ap.add_argument( - "-f", - "--force", - action="store_true", - help="overwrite files", - ) - - ap.add_argument( - "-l", - "--language", - default="c", - choices=["c", "cpp"], - help="language domain for output", - ) - - ap.add_argument("index_xml_path", help="path index.xml from Doxygen") - ap.add_argument("output_dir", help="output directory") - - run(**vars(ap.parse_args(sys.argv[1:]))) diff --git a/dpf/dgl/src/pugl-upstream/src/.clang-tidy b/dpf/dgl/src/pugl-upstream/src/.clang-tidy index f4378ba..981e098 100644 --- a/dpf/dgl/src/pugl-upstream/src/.clang-tidy +++ b/dpf/dgl/src/pugl-upstream/src/.clang-tidy @@ -2,15 +2,13 @@ Checks: > *, -*-uppercase-literal-suffix, -*magic-numbers, - -altera-struct-pack-align, - -bugprone-reserved-identifier, - -cert-dcl37-c, - -cert-dcl51-cpp, - -cert-flp30-c, + -altera*, + -bugprone-easily-swappable-parameters, -hicpp-multiway-paths-covered, -hicpp-signed-bitwise, -llvm-header-guard, -llvmlibc-*, + -performance-no-int-to-ptr, -readability-function-cognitive-complexity, FormatStyle: file HeaderFilterRegex: 'pugl/.*' diff --git a/dpf/dgl/src/pugl-upstream/src/attributes.h b/dpf/dgl/src/pugl-upstream/src/attributes.h new file mode 100644 index 0000000..578dd2c --- /dev/null +++ b/dpf/dgl/src/pugl-upstream/src/attributes.h @@ -0,0 +1,23 @@ +// Copyright 2012-2022 David Robillard +// SPDX-License-Identifier: ISC + +#ifndef PUGL_SRC_ATTRIBUTES_H +#define PUGL_SRC_ATTRIBUTES_H + +// Unused parameter macro to suppresses warnings and make it impossible to use +#if defined(__cplusplus) +# define PUGL_UNUSED(name) +#elif defined(__GNUC__) || defined(__clang__) +# define PUGL_UNUSED(name) name##_unused __attribute__((__unused__)) +#else +# define PUGL_UNUSED(name) name +#endif + +// Unused result macro to warn when an important return status is ignored +#ifndef _MSC_VER +# define PUGL_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +#else +# define PUGL_WARN_UNUSED_RESULT +#endif + +#endif // PUGL_SRC_ATTRIBUTES_H diff --git a/dpf/dgl/src/pugl-upstream/src/common.c b/dpf/dgl/src/pugl-upstream/src/common.c new file mode 100644 index 0000000..7758b70 --- /dev/null +++ b/dpf/dgl/src/pugl-upstream/src/common.c @@ -0,0 +1,273 @@ +// Copyright 2012-2022 David Robillard +// SPDX-License-Identifier: ISC + +// Common implementations of public API functions in the core library + +#include "internal.h" + +#include "platform.h" +#include "types.h" + +#include "pugl/pugl.h" + +#include +#include +#include + +const char* +puglStrerror(const PuglStatus status) +{ + // clang-format off + switch (status) { + case PUGL_SUCCESS: return "Success"; + case PUGL_FAILURE: return "Non-fatal failure"; + case PUGL_UNKNOWN_ERROR: return "Unknown system error"; + case PUGL_BAD_BACKEND: return "Invalid or missing backend"; + case PUGL_BAD_CONFIGURATION: return "Invalid view configuration"; + case PUGL_BAD_PARAMETER: return "Invalid parameter"; + case PUGL_BACKEND_FAILED: return "Backend initialisation failed"; + case PUGL_REGISTRATION_FAILED: return "Class registration failed"; + case PUGL_REALIZE_FAILED: return "View creation failed"; + case PUGL_SET_FORMAT_FAILED: return "Failed to set pixel format"; + case PUGL_CREATE_CONTEXT_FAILED: return "Failed to create drawing context"; + case PUGL_UNSUPPORTED: return "Unsupported operation"; + case PUGL_NO_MEMORY: return "Failed to allocate memory"; + } + // clang-format on + + return "Unknown error"; +} + +PuglWorld* +puglNewWorld(PuglWorldType type, PuglWorldFlags flags) +{ + PuglWorld* world = (PuglWorld*)calloc(1, sizeof(PuglWorld)); + if (!world || !(world->impl = puglInitWorldInternals(type, flags))) { + free(world); + return NULL; + } + + world->startTime = puglGetTime(world); + +#ifdef __EMSCRIPTEN__ + puglSetString(&world->className, "canvas"); +#else + puglSetString(&world->className, "Pugl"); +#endif + + return world; +} + +void +puglFreeWorld(PuglWorld* const world) +{ + puglFreeWorldInternals(world); + free(world->className); + free(world->views); + free(world); +} + +void +puglSetWorldHandle(PuglWorld* world, PuglWorldHandle handle) +{ + world->handle = handle; +} + +PuglWorldHandle +puglGetWorldHandle(PuglWorld* world) +{ + return world->handle; +} + +PuglStatus +puglSetClassName(PuglWorld* const world, const char* const name) +{ + puglSetString(&world->className, name); + return PUGL_SUCCESS; +} + +const char* +puglGetClassName(const PuglWorld* world) +{ + return world->className; +} + +static void +puglSetDefaultHints(PuglHints hints) +{ + hints[PUGL_USE_COMPAT_PROFILE] = PUGL_TRUE; + hints[PUGL_CONTEXT_VERSION_MAJOR] = 2; + hints[PUGL_CONTEXT_VERSION_MINOR] = 0; + hints[PUGL_RED_BITS] = 8; + hints[PUGL_GREEN_BITS] = 8; + hints[PUGL_BLUE_BITS] = 8; + hints[PUGL_ALPHA_BITS] = 8; + hints[PUGL_DEPTH_BITS] = 0; + hints[PUGL_STENCIL_BITS] = 0; + hints[PUGL_SAMPLES] = 0; + hints[PUGL_DOUBLE_BUFFER] = PUGL_TRUE; + hints[PUGL_SWAP_INTERVAL] = PUGL_DONT_CARE; + hints[PUGL_RESIZABLE] = PUGL_FALSE; + hints[PUGL_IGNORE_KEY_REPEAT] = PUGL_FALSE; + hints[PUGL_REFRESH_RATE] = PUGL_DONT_CARE; +} + +PuglView* +puglNewView(PuglWorld* const world) +{ + PuglView* view = (PuglView*)calloc(1, sizeof(PuglView)); + if (!view || !(view->impl = puglInitViewInternals(world))) { + free(view); + return NULL; + } + + view->world = world; + view->sizeHints[PUGL_MIN_SIZE].width = 1; + view->sizeHints[PUGL_MIN_SIZE].height = 1; + + puglSetDefaultHints(view->hints); + + // Add to world view list + ++world->numViews; + world->views = + (PuglView**)realloc(world->views, world->numViews * sizeof(PuglView*)); + + world->views[world->numViews - 1] = view; + + return view; +} + +void +puglFreeView(PuglView* view) +{ + if (view->eventFunc && view->backend) { + puglDispatchSimpleEvent(view, PUGL_DESTROY); + } + + // Remove from world view list + PuglWorld* world = view->world; + for (size_t i = 0; i < world->numViews; ++i) { + if (world->views[i] == view) { + if (i == world->numViews - 1) { + world->views[i] = NULL; + } else { + memmove(world->views + i, + world->views + i + 1, + sizeof(PuglView*) * (world->numViews - i - 1)); + world->views[world->numViews - 1] = NULL; + } + --world->numViews; + } + } + + free(view->title); + puglFreeViewInternals(view); + free(view); +} + +PuglWorld* +puglGetWorld(PuglView* view) +{ + return view->world; +} + +void +puglSetHandle(PuglView* view, PuglHandle handle) +{ + view->handle = handle; +} + +PuglHandle +puglGetHandle(PuglView* view) +{ + return view->handle; +} + +PuglStatus +puglSetBackend(PuglView* view, const PuglBackend* backend) +{ + view->backend = backend; + return PUGL_SUCCESS; +} + +const PuglBackend* +puglGetBackend(const PuglView* view) +{ + return view->backend; +} + +PuglStatus +puglSetEventFunc(PuglView* view, PuglEventFunc eventFunc) +{ + view->eventFunc = eventFunc; + return PUGL_SUCCESS; +} + +PuglStatus +puglSetViewHint(PuglView* view, PuglViewHint hint, int value) +{ + if (value == PUGL_DONT_CARE) { + switch (hint) { + case PUGL_USE_COMPAT_PROFILE: + case PUGL_USE_DEBUG_CONTEXT: + case PUGL_CONTEXT_VERSION_MAJOR: + case PUGL_CONTEXT_VERSION_MINOR: + case PUGL_SWAP_INTERVAL: + return PUGL_BAD_PARAMETER; + default: + break; + } + } + + view->hints[hint] = value; + return PUGL_SUCCESS; +} + +int +puglGetViewHint(const PuglView* view, PuglViewHint hint) +{ + return view->hints[hint]; +} + +PuglRect +puglGetFrame(const PuglView* view) +{ + return view->frame; +} + +const char* +puglGetWindowTitle(const PuglView* const view) +{ + return view->title; +} + +PuglStatus +puglSetParentWindow(PuglView* view, PuglNativeView parent) +{ + view->parent = parent; + return PUGL_SUCCESS; +} + +PuglNativeView +puglGetParentWindow(const PuglView* const view) +{ + return view->parent; +} + +PuglNativeView +puglGetTransientParent(const PuglView* const view) +{ + return view->transientParent; +} + +bool +puglGetVisible(const PuglView* view) +{ + return view->visible; +} + +void* +puglGetContext(PuglView* view) +{ + return view->backend->getContext(view); +} diff --git a/dpf/dgl/src/pugl-upstream/src/implementation.c b/dpf/dgl/src/pugl-upstream/src/implementation.c deleted file mode 100644 index 5ef3ce9..0000000 --- a/dpf/dgl/src/pugl-upstream/src/implementation.c +++ /dev/null @@ -1,468 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#include "implementation.h" - -#include "types.h" - -#include "pugl/pugl.h" - -#include -#include -#include -#include - -const char* -puglStrerror(const PuglStatus status) -{ - // clang-format off - switch (status) { - case PUGL_SUCCESS: return "Success"; - case PUGL_FAILURE: return "Non-fatal failure"; - case PUGL_UNKNOWN_ERROR: return "Unknown system error"; - case PUGL_BAD_BACKEND: return "Invalid or missing backend"; - case PUGL_BAD_CONFIGURATION: return "Invalid view configuration"; - case PUGL_BAD_PARAMETER: return "Invalid parameter"; - case PUGL_BACKEND_FAILED: return "Backend initialisation failed"; - case PUGL_REGISTRATION_FAILED: return "Class registration failed"; - case PUGL_REALIZE_FAILED: return "View creation failed"; - case PUGL_SET_FORMAT_FAILED: return "Failed to set pixel format"; - case PUGL_CREATE_CONTEXT_FAILED: return "Failed to create drawing context"; - case PUGL_UNSUPPORTED_TYPE: return "Unsupported data type"; - } - // clang-format on - - return "Unknown error"; -} - -void -puglSetString(char** dest, const char* string) -{ - if (*dest != string) { - const size_t len = strlen(string); - - *dest = (char*)realloc(*dest, len + 1); - strncpy(*dest, string, len + 1); - } -} - -void -puglSetBlob(PuglBlob* const dest, const void* const data, const size_t len) -{ - if (data) { - dest->len = len; - dest->data = realloc(dest->data, len + 1); - memcpy(dest->data, data, len); - ((char*)dest->data)[len] = 0; - } else { - dest->len = 0; - dest->data = NULL; - } -} - -static void -puglSetDefaultHints(PuglHints hints) -{ - hints[PUGL_USE_COMPAT_PROFILE] = PUGL_TRUE; - hints[PUGL_CONTEXT_VERSION_MAJOR] = 2; - hints[PUGL_CONTEXT_VERSION_MINOR] = 0; - hints[PUGL_RED_BITS] = 8; - hints[PUGL_GREEN_BITS] = 8; - hints[PUGL_BLUE_BITS] = 8; - hints[PUGL_ALPHA_BITS] = 8; - hints[PUGL_DEPTH_BITS] = 0; - hints[PUGL_STENCIL_BITS] = 0; - hints[PUGL_SAMPLES] = 0; - hints[PUGL_DOUBLE_BUFFER] = PUGL_TRUE; - hints[PUGL_SWAP_INTERVAL] = PUGL_DONT_CARE; - hints[PUGL_RESIZABLE] = PUGL_FALSE; - hints[PUGL_IGNORE_KEY_REPEAT] = PUGL_FALSE; - hints[PUGL_REFRESH_RATE] = PUGL_DONT_CARE; -} - -PuglWorld* -puglNewWorld(PuglWorldType type, PuglWorldFlags flags) -{ - PuglWorld* world = (PuglWorld*)calloc(1, sizeof(PuglWorld)); - if (!world || !(world->impl = puglInitWorldInternals(type, flags))) { - free(world); - return NULL; - } - - world->startTime = puglGetTime(world); - - puglSetString(&world->className, "Pugl"); - - return world; -} - -void -puglFreeWorld(PuglWorld* const world) -{ - puglFreeWorldInternals(world); - free(world->className); - free(world->views); - free(world); -} - -void -puglSetWorldHandle(PuglWorld* world, PuglWorldHandle handle) -{ - world->handle = handle; -} - -PuglWorldHandle -puglGetWorldHandle(PuglWorld* world) -{ - return world->handle; -} - -PuglStatus -puglSetClassName(PuglWorld* const world, const char* const name) -{ - puglSetString(&world->className, name); - return PUGL_SUCCESS; -} - -PuglView* -puglNewView(PuglWorld* const world) -{ - PuglView* view = (PuglView*)calloc(1, sizeof(PuglView)); - if (!view || !(view->impl = puglInitViewInternals())) { - free(view); - return NULL; - } - - view->world = world; - view->minWidth = 1; - view->minHeight = 1; - - puglSetDefaultHints(view->hints); - - // Add to world view list - ++world->numViews; - world->views = - (PuglView**)realloc(world->views, world->numViews * sizeof(PuglView*)); - - world->views[world->numViews - 1] = view; - - return view; -} - -void -puglFreeView(PuglView* view) -{ - if (view->eventFunc && view->backend) { - puglDispatchSimpleEvent(view, PUGL_DESTROY); - } - - // Remove from world view list - PuglWorld* world = view->world; - for (size_t i = 0; i < world->numViews; ++i) { - if (world->views[i] == view) { - if (i == world->numViews - 1) { - world->views[i] = NULL; - } else { - memmove(world->views + i, - world->views + i + 1, - sizeof(PuglView*) * (world->numViews - i - 1)); - world->views[world->numViews - 1] = NULL; - } - --world->numViews; - } - } - - free(view->title); - free(view->clipboard.data); - puglFreeViewInternals(view); - free(view); -} - -PuglWorld* -puglGetWorld(PuglView* view) -{ - return view->world; -} - -PuglStatus -puglSetViewHint(PuglView* view, PuglViewHint hint, int value) -{ - if (value == PUGL_DONT_CARE) { - switch (hint) { - case PUGL_USE_COMPAT_PROFILE: - case PUGL_USE_DEBUG_CONTEXT: - case PUGL_CONTEXT_VERSION_MAJOR: - case PUGL_CONTEXT_VERSION_MINOR: - case PUGL_SWAP_INTERVAL: - return PUGL_BAD_PARAMETER; - default: - break; - } - } - - if (hint < PUGL_NUM_VIEW_HINTS) { - view->hints[hint] = value; - return PUGL_SUCCESS; - } - - return PUGL_BAD_PARAMETER; -} - -int -puglGetViewHint(const PuglView* view, PuglViewHint hint) -{ - return (hint < PUGL_NUM_VIEW_HINTS) ? view->hints[hint] : PUGL_DONT_CARE; -} - -PuglStatus -puglSetParentWindow(PuglView* view, PuglNativeView parent) -{ - view->parent = parent; - return PUGL_SUCCESS; -} - -PuglStatus -puglSetBackend(PuglView* view, const PuglBackend* backend) -{ - view->backend = backend; - return PUGL_SUCCESS; -} - -void -puglSetHandle(PuglView* view, PuglHandle handle) -{ - view->handle = handle; -} - -PuglHandle -puglGetHandle(PuglView* view) -{ - return view->handle; -} - -bool -puglGetVisible(const PuglView* view) -{ - return view->visible; -} - -PuglRect -puglGetFrame(const PuglView* view) -{ - return view->frame; -} - -void* -puglGetContext(PuglView* view) -{ - return view->backend->getContext(view); -} - -#ifndef PUGL_DISABLE_DEPRECATED - -PuglStatus -puglPollEvents(PuglWorld* world, double timeout) -{ - return puglUpdate(world, timeout); -} - -PuglStatus -puglDispatchEvents(PuglWorld* world) -{ - return puglUpdate(world, 0.0); -} - -PuglStatus -puglShowWindow(PuglView* view) -{ - return puglShow(view); -} - -PuglStatus -puglHideWindow(PuglView* view) -{ - return puglHide(view); -} - -#endif - -PuglStatus -puglSetEventFunc(PuglView* view, PuglEventFunc eventFunc) -{ - view->eventFunc = eventFunc; - return PUGL_SUCCESS; -} - -/// Return the code point for buf, or the replacement character on error -uint32_t -puglDecodeUTF8(const uint8_t* buf) -{ -#define FAIL_IF(cond) \ - do { \ - if (cond) \ - return 0xFFFD; \ - } while (0) - - // http://en.wikipedia.org/wiki/UTF-8 - - if (buf[0] < 0x80) { - return buf[0]; - } - - if (buf[0] < 0xC2) { - return 0xFFFD; - } - - if (buf[0] < 0xE0) { - FAIL_IF((buf[1] & 0xC0u) != 0x80); - return ((uint32_t)buf[0] << 6u) + buf[1] - 0x3080u; - } - - if (buf[0] < 0xF0) { - FAIL_IF((buf[1] & 0xC0u) != 0x80); - FAIL_IF(buf[0] == 0xE0 && buf[1] < 0xA0); - FAIL_IF((buf[2] & 0xC0u) != 0x80); - return ((uint32_t)buf[0] << 12u) + // - ((uint32_t)buf[1] << 6u) + // - ((uint32_t)buf[2] - 0xE2080u); - } - - if (buf[0] < 0xF5) { - FAIL_IF((buf[1] & 0xC0u) != 0x80); - FAIL_IF(buf[0] == 0xF0 && buf[1] < 0x90); - FAIL_IF(buf[0] == 0xF4 && buf[1] >= 0x90); - FAIL_IF((buf[2] & 0xC0u) != 0x80u); - FAIL_IF((buf[3] & 0xC0u) != 0x80u); - return (((uint32_t)buf[0] << 18u) + // - ((uint32_t)buf[1] << 12u) + // - ((uint32_t)buf[2] << 6u) + // - ((uint32_t)buf[3] - 0x3C82080u)); - } - - return 0xFFFD; -} - -static inline bool -puglMustConfigure(PuglView* view, const PuglConfigureEvent* configure) -{ - return memcmp(configure, &view->lastConfigure, sizeof(PuglConfigureEvent)); -} - -void -puglDispatchSimpleEvent(PuglView* view, const PuglEventType type) -{ - assert(type == PUGL_CREATE || type == PUGL_DESTROY || type == PUGL_MAP || - type == PUGL_UNMAP || type == PUGL_UPDATE || type == PUGL_CLOSE || - type == PUGL_LOOP_ENTER || type == PUGL_LOOP_LEAVE); - - const PuglEvent event = {{type, 0}}; - puglDispatchEvent(view, &event); -} - -void -puglConfigure(PuglView* view, const PuglEvent* event) -{ - assert(event->type == PUGL_CONFIGURE); - - view->frame.x = event->configure.x; - view->frame.y = event->configure.y; - view->frame.width = event->configure.width; - view->frame.height = event->configure.height; - - if (puglMustConfigure(view, &event->configure)) { - view->eventFunc(view, event); - view->lastConfigure = event->configure; - } -} - -void -puglExpose(PuglView* view, const PuglEvent* event) -{ - if (event->expose.width > 0.0 && event->expose.height > 0.0) { - view->eventFunc(view, event); - } -} - -void -puglDispatchEvent(PuglView* view, const PuglEvent* event) -{ - switch (event->type) { - case PUGL_NOTHING: - break; - case PUGL_CREATE: - case PUGL_DESTROY: - view->backend->enter(view, NULL); - view->eventFunc(view, event); - view->backend->leave(view, NULL); - break; - case PUGL_CONFIGURE: - if (puglMustConfigure(view, &event->configure)) { - view->backend->enter(view, NULL); - puglConfigure(view, event); - view->backend->leave(view, NULL); - } - break; - case PUGL_MAP: - if (!view->visible) { - view->visible = true; - view->eventFunc(view, event); - } - break; - case PUGL_UNMAP: - if (view->visible) { - view->visible = false; - view->eventFunc(view, event); - } - break; - case PUGL_EXPOSE: - view->backend->enter(view, &event->expose); - puglExpose(view, event); - view->backend->leave(view, &event->expose); - break; - default: - view->eventFunc(view, event); - } -} - -const void* -puglGetInternalClipboard(const PuglView* const view, - const char** const type, - size_t* const len) -{ - if (len) { - *len = view->clipboard.len; - } - - if (type) { - *type = "text/plain"; - } - - return view->clipboard.data; -} - -PuglStatus -puglSetInternalClipboard(PuglView* const view, - const char* const type, - const void* const data, - const size_t len) -{ - if (type && !!strcmp(type, "text/plain")) { - return PUGL_UNSUPPORTED_TYPE; - } - - puglSetBlob(&view->clipboard, data, len); - return PUGL_SUCCESS; -} diff --git a/dpf/dgl/src/pugl-upstream/src/implementation.h b/dpf/dgl/src/pugl-upstream/src/implementation.h deleted file mode 100644 index 936322d..0000000 --- a/dpf/dgl/src/pugl-upstream/src/implementation.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef PUGL_IMPLEMENTATION_H -#define PUGL_IMPLEMENTATION_H - -#include "types.h" - -#include "pugl/pugl.h" - -#include -#include - -PUGL_BEGIN_DECLS - -/// Set `blob` to `data` with length `len`, reallocating if necessary -void -puglSetBlob(PuglBlob* dest, const void* data, size_t len); - -/// Reallocate and set `*dest` to `string` -void -puglSetString(char** dest, const char* string); - -/// Allocate and initialise world internals (implemented once per platform) -PuglWorldInternals* -puglInitWorldInternals(PuglWorldType type, PuglWorldFlags flags); - -/// Destroy and free world internals (implemented once per platform) -void -puglFreeWorldInternals(PuglWorld* world); - -/// Allocate and initialise view internals (implemented once per platform) -PuglInternals* -puglInitViewInternals(void); - -/// Destroy and free view internals (implemented once per platform) -void -puglFreeViewInternals(PuglView* view); - -/// Return the Unicode code point for `buf` or the replacement character -uint32_t -puglDecodeUTF8(const uint8_t* buf); - -/// Dispatch an event with a simple `type` to `view` -void -puglDispatchSimpleEvent(PuglView* view, PuglEventType type); - -/// Process configure event while already in the graphics context -void -puglConfigure(PuglView* view, const PuglEvent* event); - -/// Process expose event while already in the graphics context -void -puglExpose(PuglView* view, const PuglEvent* event); - -/// Dispatch `event` to `view`, entering graphics context if necessary -void -puglDispatchEvent(PuglView* view, const PuglEvent* event); - -/// Set internal (stored in view) clipboard contents -const void* -puglGetInternalClipboard(const PuglView* view, const char** type, size_t* len); - -/// Set internal (stored in view) clipboard contents -PuglStatus -puglSetInternalClipboard(PuglView* view, - const char* type, - const void* data, - size_t len); - -PUGL_END_DECLS - -#endif // PUGL_IMPLEMENTATION_H diff --git a/dpf/dgl/src/pugl-upstream/src/internal.c b/dpf/dgl/src/pugl-upstream/src/internal.c new file mode 100644 index 0000000..69f220e --- /dev/null +++ b/dpf/dgl/src/pugl-upstream/src/internal.c @@ -0,0 +1,190 @@ +// Copyright 2012-2022 David Robillard +// SPDX-License-Identifier: ISC + +#include "internal.h" + +#include "types.h" + +#include "pugl/pugl.h" + +#include +#include +#include +#include + +PuglStatus +puglSetBlob(PuglBlob* const dest, const void* const data, const size_t len) +{ + if (data) { + void* const newData = realloc(dest->data, len + 1); + if (!newData) { + free(dest->data); + dest->len = 0; + return PUGL_NO_MEMORY; + } + + memcpy(newData, data, len); + ((char*)newData)[len] = 0; + + dest->len = len; + dest->data = newData; + } else { + dest->len = 0; + dest->data = NULL; + } + + return PUGL_SUCCESS; +} + +void +puglSetString(char** dest, const char* string) +{ + if (*dest != string) { + const size_t len = strlen(string); + + *dest = (char*)realloc(*dest, len + 1); + strncpy(*dest, string, len + 1); + } +} + +uint32_t +puglDecodeUTF8(const uint8_t* buf) +{ +#define FAIL_IF(cond) \ + do { \ + if (cond) \ + return 0xFFFD; \ + } while (0) + + // http://en.wikipedia.org/wiki/UTF-8 + + if (buf[0] < 0x80) { + return buf[0]; + } + + if (buf[0] < 0xC2) { + return 0xFFFD; + } + + if (buf[0] < 0xE0) { + FAIL_IF((buf[1] & 0xC0u) != 0x80); + return ((uint32_t)buf[0] << 6u) + buf[1] - 0x3080u; + } + + if (buf[0] < 0xF0) { + FAIL_IF((buf[1] & 0xC0u) != 0x80); + FAIL_IF(buf[0] == 0xE0 && buf[1] < 0xA0); + FAIL_IF((buf[2] & 0xC0u) != 0x80); + return ((uint32_t)buf[0] << 12u) + // + ((uint32_t)buf[1] << 6u) + // + ((uint32_t)buf[2] - 0xE2080u); + } + + if (buf[0] < 0xF5) { + FAIL_IF((buf[1] & 0xC0u) != 0x80); + FAIL_IF(buf[0] == 0xF0 && buf[1] < 0x90); + FAIL_IF(buf[0] == 0xF4 && buf[1] >= 0x90); + FAIL_IF((buf[2] & 0xC0u) != 0x80u); + FAIL_IF((buf[3] & 0xC0u) != 0x80u); + return (((uint32_t)buf[0] << 18u) + // + ((uint32_t)buf[1] << 12u) + // + ((uint32_t)buf[2] << 6u) + // + ((uint32_t)buf[3] - 0x3C82080u)); + } + + return 0xFFFD; +} + +PuglStatus +puglDispatchSimpleEvent(PuglView* view, const PuglEventType type) +{ + assert(type == PUGL_CREATE || type == PUGL_DESTROY || type == PUGL_MAP || + type == PUGL_UNMAP || type == PUGL_UPDATE || type == PUGL_CLOSE || + type == PUGL_LOOP_ENTER || type == PUGL_LOOP_LEAVE); + + const PuglEvent event = {{type, 0}}; + return puglDispatchEvent(view, &event); +} + +static inline bool +puglMustConfigure(PuglView* view, const PuglConfigureEvent* configure) +{ + return !!memcmp(configure, &view->lastConfigure, sizeof(PuglConfigureEvent)); +} + +PuglStatus +puglConfigure(PuglView* view, const PuglEvent* event) +{ + PuglStatus st = PUGL_SUCCESS; + + assert(event->type == PUGL_CONFIGURE); + + view->frame.x = event->configure.x; + view->frame.y = event->configure.y; + view->frame.width = event->configure.width; + view->frame.height = event->configure.height; + + if (puglMustConfigure(view, &event->configure)) { + st = view->eventFunc(view, event); + view->lastConfigure = event->configure; + } + + return st; +} + +PuglStatus +puglExpose(PuglView* view, const PuglEvent* event) +{ + return (event->expose.width > 0.0 && event->expose.height > 0.0) + ? view->eventFunc(view, event) + : PUGL_SUCCESS; +} + +PuglStatus +puglDispatchEvent(PuglView* view, const PuglEvent* event) +{ + PuglStatus st0 = PUGL_SUCCESS; + PuglStatus st1 = PUGL_SUCCESS; + + switch (event->type) { + case PUGL_NOTHING: + break; + case PUGL_CREATE: + case PUGL_DESTROY: + if (!(st0 = view->backend->enter(view, NULL))) { + st0 = view->eventFunc(view, event); + st1 = view->backend->leave(view, NULL); + } + break; + case PUGL_CONFIGURE: + if (puglMustConfigure(view, &event->configure)) { + if (!(st0 = view->backend->enter(view, NULL))) { + st0 = puglConfigure(view, event); + st1 = view->backend->leave(view, NULL); + } + } + break; + case PUGL_MAP: + if (!view->visible) { + view->visible = true; + st0 = view->eventFunc(view, event); + } + break; + case PUGL_UNMAP: + if (view->visible) { + view->visible = false; + st0 = view->eventFunc(view, event); + } + break; + case PUGL_EXPOSE: + if (!(st0 = view->backend->enter(view, &event->expose))) { + st0 = puglExpose(view, event); + st1 = view->backend->leave(view, &event->expose); + } + break; + default: + st0 = view->eventFunc(view, event); + } + + return st0 ? st0 : st1; +} diff --git a/dpf/dgl/src/pugl-upstream/src/internal.h b/dpf/dgl/src/pugl-upstream/src/internal.h new file mode 100644 index 0000000..e3e7924 --- /dev/null +++ b/dpf/dgl/src/pugl-upstream/src/internal.h @@ -0,0 +1,51 @@ +// Copyright 2012-2022 David Robillard +// SPDX-License-Identifier: ISC + +// Internal utilities available to platform implementations + +#ifndef PUGL_INTERNAL_H +#define PUGL_INTERNAL_H + +#include "attributes.h" +#include "types.h" + +#include "pugl/pugl.h" + +#include +#include + +PUGL_BEGIN_DECLS + +/// Set `blob` to `data` with length `len`, reallocating if necessary +PuglStatus +puglSetBlob(PuglBlob* dest, const void* data, size_t len); + +/// Reallocate and set `*dest` to `string` +void +puglSetString(char** dest, const char* string); + +/// Return the Unicode code point for `buf` or the replacement character +uint32_t +puglDecodeUTF8(const uint8_t* buf); + +/// Dispatch an event with a simple `type` to `view` +PuglStatus +puglDispatchSimpleEvent(PuglView* view, PuglEventType type); + +/// Process configure event while already in the graphics context +PUGL_WARN_UNUSED_RESULT +PuglStatus +puglConfigure(PuglView* view, const PuglEvent* event); + +/// Process expose event while already in the graphics context +PUGL_WARN_UNUSED_RESULT +PuglStatus +puglExpose(PuglView* view, const PuglEvent* event); + +/// Dispatch `event` to `view`, entering graphics context if necessary +PuglStatus +puglDispatchEvent(PuglView* view, const PuglEvent* event); + +PUGL_END_DECLS + +#endif // PUGL_INTERNAL_H diff --git a/dpf/dgl/src/pugl-upstream/src/mac.h b/dpf/dgl/src/pugl-upstream/src/mac.h index 35e6e0d..10e37c5 100644 --- a/dpf/dgl/src/pugl-upstream/src/mac.h +++ b/dpf/dgl/src/pugl-upstream/src/mac.h @@ -1,22 +1,9 @@ -/* - Copyright 2012-2020 David Robillard - Copyright 2017 Hanspeter Portner - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef PUGL_DETAIL_MAC_H -#define PUGL_DETAIL_MAC_H +// Copyright 2012-2020 David Robillard +// Copyright 2017 Hanspeter Portner +// SPDX-License-Identifier: ISC + +#ifndef PUGL_SRC_MAC_H +#define PUGL_SRC_MAC_H #include "pugl/pugl.h" @@ -52,4 +39,4 @@ struct PuglInternalsImpl { bool mouseTracked; }; -#endif // PUGL_DETAIL_MAC_H +#endif // PUGL_SRC_MAC_H diff --git a/dpf/dgl/src/pugl-upstream/src/mac.m b/dpf/dgl/src/pugl-upstream/src/mac.m index de3ab2e..39eff67 100644 --- a/dpf/dgl/src/pugl-upstream/src/mac.m +++ b/dpf/dgl/src/pugl-upstream/src/mac.m @@ -1,25 +1,13 @@ -/* - Copyright 2012-2020 David Robillard - Copyright 2017 Hanspeter Portner - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ +// Copyright 2012-2022 David Robillard +// Copyright 2017 Hanspeter Portner +// SPDX-License-Identifier: ISC #define GL_SILENCE_DEPRECATION 1 #include "mac.h" -#include "implementation.h" +#include "internal.h" +#include "platform.h" #include "pugl/pugl.h" @@ -38,6 +26,70 @@ typedef NSUInteger NSEventSubtype; typedef NSUInteger NSWindowStyleMask; #endif +typedef struct { + const char* uti; + const char* mimeType; +} Datatype; + +#define NUM_DATATYPES 16 + +static const Datatype datatypes[NUM_DATATYPES + 1] = { + {"com.apple.pasteboard.promised-file-url", "text/uri-list"}, + {"org.7-zip.7-zip-archive", "application/x-7z-compressed"}, + {"org.gnu.gnu-zip-tar-archive", "application/tar+gzip"}, + {"public.7z-archive", "application/x-7z-compressed"}, + {"public.cpio-archive", "application/x-cpio"}, + {"public.deb-archive", "application/vnd.debian.binary-package"}, + {"public.file-url", "text/uri-list"}, + {"public.html", "text/html"}, + {"public.png", "image/png"}, + {"public.rar-archive", "application/x-rar-compressed"}, + {"public.rpm-archive", "application/x-rpm"}, + {"public.rtf", "text/rtf"}, + {"public.url", "text/uri-list"}, + {"public.utf8-plain-text", "text/plain"}, + {"public.utf8-tab-separated-values-text", "text/tab-separated-values"}, + {"public.xz-archive", "application/x-xz"}, + {NULL, NULL}, +}; + +static NSString* +mimeTypeForUti(const NSString* const uti) +{ + const char* const utiString = [uti UTF8String]; + + // First try internal map to override types the system won't convert sensibly + for (const Datatype* datatype = datatypes; datatype->uti; ++datatype) { + if (!strcmp(utiString, datatype->uti)) { + return [NSString stringWithUTF8String:datatype->mimeType]; + } + } + + // Try to get the MIME type from the system + return (NSString*)CFBridgingRelease(UTTypeCopyPreferredTagWithClass( + (__bridge CFStringRef)uti, kUTTagClassMIMEType)); +} + +static NSString* +utiForMimeType(const NSString* const mimeType) +{ + const char* const mimeTypeString = [mimeType UTF8String]; + + // First try internal map to override types the system won't convert sensibly + for (const Datatype* datatype = datatypes; datatype->mimeType; ++datatype) { + if (!strcmp(mimeTypeString, datatype->mimeType)) { + return [NSString stringWithUTF8String:datatype->uti]; + } + } + + // Try to get the UTI from the system + CFStringRef uti = UTTypeCreatePreferredIdentifierForTag( + kUTTagClassMIMEType, (__bridge CFStringRef)mimeType, NULL); + + return (uti && UTTypeIsDynamic(uti)) ? (NSString*)CFBridgingRelease(uti) + : NULL; +} + static NSRect rectToScreen(NSScreen* screen, NSRect rect) { @@ -48,10 +100,12 @@ rectToScreen(NSScreen* screen, NSRect rect) } static NSScreen* -viewScreen(PuglView* view) +viewScreen(const PuglView* view) { return view->impl->window ? [view->impl->window screen] - : [NSScreen mainScreen]; + : [view->impl->wrapperView window] + ? [[view->impl->wrapperView window] screen] + : [NSScreen mainScreen]; } static NSRect @@ -110,10 +164,12 @@ updateViewRect(PuglView* view) const NSRect contentPx = nsRectFromPoints(view, contentPt); const double screenHeight = screenFramePx.size.height; - view->frame.x = contentPx.origin.x; - view->frame.y = screenHeight - contentPx.origin.y - contentPx.size.height; - view->frame.width = contentPx.size.width; - view->frame.height = contentPx.size.height; + view->frame.x = (PuglCoord)contentPx.origin.x; + view->frame.y = + (PuglCoord)(screenHeight - contentPx.origin.y - contentPx.size.height); + + view->frame.width = (PuglSpan)contentPx.size.width; + view->frame.height = (PuglSpan)contentPx.size.height; } } @@ -188,6 +244,10 @@ updateViewRect(PuglView* view) NSTrackingArea* trackingArea; NSMutableAttributedString* markedText; NSMutableDictionary* userTimers; + id dragSource; + NSDragOperation dragOperation; + size_t dragTypeIndex; + NSString* droppedUriList; bool reshaped; } @@ -220,10 +280,10 @@ updateViewRect(PuglView* view) const PuglExposeEvent ev = { PUGL_EXPOSE, 0, - rect.origin.x * scaleFactor, - rect.origin.y * scaleFactor, - rect.size.width * scaleFactor, - rect.size.height * scaleFactor, + (PuglCoord)(rect.origin.x * scaleFactor), + (PuglCoord)(rect.origin.y * scaleFactor), + (PuglSpan)(rect.size.width * scaleFactor), + (PuglSpan)(rect.size.height * scaleFactor), }; PuglEvent exposeEvent; @@ -233,12 +293,11 @@ updateViewRect(PuglView* view) - (NSSize)intrinsicContentSize { - if (puglview->defaultWidth || puglview->defaultHeight) { - return sizePoints( - puglview, puglview->defaultWidth, puglview->defaultHeight); - } + const PuglViewSize defaultSize = puglview->sizeHints[PUGL_DEFAULT_SIZE]; - return NSMakeSize(NSViewNoInstrinsicMetric, NSViewNoInstrinsicMetric); + return (defaultSize.width && defaultSize.height) + ? sizePoints(puglview, defaultSize.width, defaultSize.height) + : NSMakeSize(NSViewNoInstrinsicMetric, NSViewNoInstrinsicMetric); } - (BOOL)isFlipped @@ -448,7 +507,7 @@ handleCrossing(PuglWrapperView* view, NSEvent* event, const PuglEventType type) rloc.x, [[NSScreen mainScreen] frame].size.height - rloc.y, getModifiers(event), - (uint32_t)[event buttonNumber] + 1, + (uint32_t)[event buttonNumber], }; PuglEvent pressEvent; @@ -469,7 +528,7 @@ handleCrossing(PuglWrapperView* view, NSEvent* event, const PuglEventType type) rloc.x, [[NSScreen mainScreen] frame].size.height - rloc.y, getModifiers(event), - (uint32_t)[event buttonNumber] + 1, + (uint32_t)[event buttonNumber], }; PuglEvent releaseEvent; @@ -856,6 +915,8 @@ puglInitWorldInternals(PuglWorldType type, PuglWorldFlags PUGL_UNUSED(flags)) if (type == PUGL_PROGRAM) { impl->autoreleasePool = [NSAutoreleasePool new]; + + [impl->app setActivationPolicy:NSApplicationActivationPolicyRegular]; } return impl; @@ -878,7 +939,7 @@ puglGetNativeWorld(PuglWorld* world) } PuglInternals* -puglInitViewInternals(void) +puglInitViewInternals(PuglWorld* PUGL_UNUSED(world)) { PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals)); @@ -888,26 +949,74 @@ puglInitViewInternals(void) } static NSLayoutConstraint* -puglConstraint(id item, NSLayoutAttribute attribute, float constant) +puglConstraint(const id item, + const NSLayoutAttribute attribute, + const NSLayoutRelation relation, + const float constant) +{ + return [NSLayoutConstraint constraintWithItem:item + attribute:attribute + relatedBy:relation + toItem:nil + attribute:NSLayoutAttributeNotAnAttribute + multiplier:1.0 + constant:(CGFloat)constant]; +} + +static PuglStatus +updateSizeHint(PuglView* const view, const PuglSizeHint hint) +{ + const PuglSpan width = view->sizeHints[hint].width; + const PuglSpan height = view->sizeHints[hint].height; + if (!width || !height) { + return PUGL_FAILURE; + } + + switch (hint) { + case PUGL_DEFAULT_SIZE: + break; + + case PUGL_MIN_SIZE: + [view->impl->window setContentMinSize:sizePoints(view, width, height)]; + break; + + case PUGL_MAX_SIZE: + [view->impl->window setContentMaxSize:sizePoints(view, width, height)]; + break; + + case PUGL_FIXED_ASPECT: + [view->impl->window setContentAspectRatio:sizePoints(view, width, height)]; + break; + + case PUGL_MIN_ASPECT: + case PUGL_MAX_ASPECT: + break; + } + + return PUGL_SUCCESS; +} + +static void +updateSizeHints(PuglView* const view) { - return - [NSLayoutConstraint constraintWithItem:item - attribute:attribute - relatedBy:NSLayoutRelationGreaterThanOrEqual - toItem:nil - attribute:NSLayoutAttributeNotAnAttribute - multiplier:1.0 - constant:(CGFloat)constant]; + for (unsigned i = 0u; i < PUGL_NUM_SIZE_HINTS; ++i) { + updateSizeHint(view, (PuglSizeHint)i); + } } PuglStatus puglRealize(PuglView* view) { PuglInternals* impl = view->impl; + if (impl->wrapperView) { return PUGL_FAILURE; } + if (!view->backend || !view->backend->configure) { + return PUGL_BAD_BACKEND; + } + const NSScreen* const screen = [NSScreen mainScreen]; const double scaleFactor = [screen backingScaleFactor]; @@ -946,17 +1055,21 @@ puglRealize(PuglView* view) } if (view->frame.width == 0.0 && view->frame.height == 0.0) { - if (view->defaultWidth == 0.0 && view->defaultHeight == 0.0) { + const PuglViewSize defaultSize = view->sizeHints[PUGL_DEFAULT_SIZE]; + if (!defaultSize.width || !defaultSize.height) { return PUGL_BAD_CONFIGURATION; } const double screenWidthPx = [screen frame].size.width * scaleFactor; const double screenHeightPx = [screen frame].size.height * scaleFactor; - view->frame.width = view->defaultWidth; - view->frame.height = view->defaultHeight; - view->frame.x = screenWidthPx / 2.0 - view->frame.width / 2.0; - view->frame.y = screenHeightPx / 2.0 - view->frame.height / 2.0; + view->frame.width = defaultSize.width; + view->frame.height = defaultSize.height; + + if (view->impl->window) { + view->frame.x = (PuglCoord)((screenWidthPx - view->frame.width) / 2.0); + view->frame.y = (PuglCoord)((screenHeightPx - view->frame.height) / 2.0); + } } const NSRect framePx = rectToNsRect(view->frame); @@ -972,12 +1085,33 @@ puglRealize(PuglView* view) impl->wrapperView->markedText = [[NSMutableAttributedString alloc] init]; [impl->wrapperView setAutoresizesSubviews:YES]; [impl->wrapperView initWithFrame:framePt]; - [impl->wrapperView addConstraint:puglConstraint(impl->wrapperView, - NSLayoutAttributeWidth, - view->minWidth)]; - [impl->wrapperView addConstraint:puglConstraint(impl->wrapperView, - NSLayoutAttributeHeight, - view->minHeight)]; + + [impl->wrapperView + addConstraint:puglConstraint(impl->wrapperView, + NSLayoutAttributeWidth, + NSLayoutRelationGreaterThanOrEqual, + view->sizeHints[PUGL_MIN_SIZE].width)]; + + [impl->wrapperView + addConstraint:puglConstraint(impl->wrapperView, + NSLayoutAttributeHeight, + NSLayoutRelationGreaterThanOrEqual, + view->sizeHints[PUGL_MIN_SIZE].height)]; + + if (view->sizeHints[PUGL_MAX_SIZE].width && + view->sizeHints[PUGL_MAX_SIZE].height) { + [impl->wrapperView + addConstraint:puglConstraint(impl->wrapperView, + NSLayoutAttributeWidth, + NSLayoutRelationLessThanOrEqual, + view->sizeHints[PUGL_MAX_SIZE].width)]; + + [impl->wrapperView + addConstraint:puglConstraint(impl->wrapperView, + NSLayoutAttributeHeight, + NSLayoutRelationLessThanOrEqual, + view->sizeHints[PUGL_MAX_SIZE].height)]; + } // Create draw view to be rendered to PuglStatus st = PUGL_SUCCESS; @@ -1019,26 +1153,19 @@ puglRealize(PuglView* view) [window setTitle:titleString]; } - if (view->minWidth || view->minHeight) { - [window - setContentMinSize:sizePoints(view, view->minWidth, view->minHeight)]; - } - impl->window = window; - ((NSWindow*)window).delegate = [[PuglWindowDelegate alloc] initWithPuglWindow:window]; - if (view->minAspectX && view->minAspectY) { - [window setContentAspectRatio:sizePoints(view, - view->minAspectX, - view->minAspectY)]; - } + impl->window = window; + updateSizeHints(view); puglSetFrame(view, view->frame); [window setContentView:impl->wrapperView]; + [view->world->impl->app activateIgnoringOtherApps:YES]; [window makeFirstResponder:impl->wrapperView]; - [window setIsVisible:NO]; + [window makeKeyAndOrderFront:window]; + [impl->window setIsVisible:NO]; } [impl->wrapperView updateTrackingAreas]; @@ -1064,11 +1191,6 @@ puglShow(PuglView* view) updateViewRect(view); } - if (! view->transientParent) { - [view->impl->window makeKeyAndOrderFront:view->impl->window]; - [view->world->impl->app activateIgnoringOtherApps:YES]; - } - return PUGL_SUCCESS; } @@ -1196,7 +1318,7 @@ puglSendEvent(PuglView* view, const PuglEvent* event) return PUGL_SUCCESS; } - return PUGL_UNSUPPORTED_TYPE; + return PUGL_UNSUPPORTED; } #ifndef PUGL_DISABLE_DEPRECATED @@ -1224,8 +1346,8 @@ puglUpdate(PuglWorld* world, const double timeout) [world->impl->app sendEvent:ev]; if (timeout < 0) { - // Now that we've waited and got an event, set the date to now to - // avoid looping forever + // Now that we've waited and got an event, set the date to now to avoid + // looping forever date = [NSDate date]; } } @@ -1277,7 +1399,7 @@ puglPostRedisplayRect(PuglView* view, const PuglRect rect) } PuglNativeView -puglGetNativeWindow(PuglView* view) +puglGetNativeView(PuglView* view) { return (PuglNativeView)view->impl->wrapperView; } @@ -1299,93 +1421,118 @@ puglSetWindowTitle(PuglView* view, const char* title) return PUGL_SUCCESS; } +double +puglGetScaleFactor(const PuglView* const view) +{ + return [viewScreen(view) backingScaleFactor]; +} + PuglStatus puglSetFrame(PuglView* view, const PuglRect frame) { - PuglInternals* const impl = view->impl; + PuglInternals* const impl = view->impl; + const NSRect framePx = rectToNsRect(frame); + const NSRect framePt = nsRectToPoints(view, framePx); - // Update view frame to exactly the requested frame in Pugl coordinates + // Update view frame to exactly the requested frame view->frame = frame; - const NSRect framePx = rectToNsRect(frame); - const NSRect framePt = nsRectToPoints(view, framePx); if (impl->window) { - // Resize window to fit new content rect const NSRect screenPt = rectToScreen(viewScreen(view), framePt); - const NSRect winFrame = [impl->window frameRectForContentRect:screenPt]; + // Move and resize window to fit new content rect + const NSRect winFrame = [impl->window frameRectForContentRect:screenPt]; [impl->window setFrame:winFrame display:NO]; - } - // Resize views - const NSRect sizePx = NSMakeRect(0, 0, frame.width, frame.height); - const NSRect sizePt = [impl->drawView convertRectFromBacking:sizePx]; + // Resize views + const NSRect sizePx = NSMakeRect(0, 0, frame.width, frame.height); + const NSRect sizePt = [impl->drawView convertRectFromBacking:sizePx]; + [impl->wrapperView setFrame:sizePt]; + [impl->drawView setFrame:sizePt]; + } else { + // Resize view + const NSRect sizePx = NSMakeRect(0, 0, frame.width, frame.height); + const NSRect sizePt = [impl->drawView convertRectFromBacking:sizePx]; - [impl->wrapperView setFrame:(impl->window ? sizePt : framePt)]; - [impl->drawView setFrame:sizePt]; + [impl->wrapperView setFrame:framePt]; + [impl->drawView setFrame:sizePt]; + } return PUGL_SUCCESS; } PuglStatus -puglSetDefaultSize(PuglView* const view, const int width, const int height) +puglSetPosition(PuglView* const view, const int x, const int y) { - view->defaultWidth = width; - view->defaultHeight = height; - return PUGL_SUCCESS; -} + if (x > INT16_MAX || y > INT16_MAX) { + return PUGL_BAD_PARAMETER; + } -PuglStatus -puglSetMinSize(PuglView* const view, const int width, const int height) -{ - view->minWidth = width; - view->minHeight = height; + const PuglRect frame = { + (PuglCoord)x, (PuglCoord)y, view->frame.height, view->frame.height}; - if (view->impl->window && (view->minWidth || view->minHeight)) { - [view->impl->window - setContentMinSize:sizePoints(view, view->minWidth, view->minHeight)]; + PuglInternals* const impl = view->impl; + if (impl->window) { + return puglSetFrame(view, frame); } + const NSRect framePx = rectToNsRect(frame); + const NSRect framePt = nsRectToPoints(view, framePx); + [impl->wrapperView setFrameOrigin:framePt.origin]; + + const NSRect drawPx = NSMakeRect(0, 0, frame.width, frame.height); + const NSRect drawPt = [impl->drawView convertRectFromBacking:drawPx]; + [impl->drawView setFrameOrigin:drawPt.origin]; + + view->frame = frame; return PUGL_SUCCESS; } PuglStatus -puglSetMaxSize(PuglView* const view, const int width, const int height) +puglSetSize(PuglView* const view, const unsigned width, const unsigned height) { - view->maxWidth = width; - view->maxHeight = height; + if (width > INT16_MAX || height > INT16_MAX) { + return PUGL_BAD_PARAMETER; + } + + const PuglRect frame = { + view->frame.x, view->frame.y, (PuglSpan)width, (PuglSpan)height}; - if (view->impl->window && (view->maxWidth || view->maxHeight)) { - [view->impl->window - setContentMaxSize:sizePoints(view, view->maxWidth, view->maxHeight)]; + PuglInternals* const impl = view->impl; + if (impl->window) { + return puglSetFrame(view, frame); } + const NSRect framePx = rectToNsRect(frame); + const NSRect framePt = nsRectToPoints(view, framePx); + [impl->wrapperView setFrameSize:framePt.size]; + + const NSRect drawPx = NSMakeRect(0, 0, frame.width, frame.height); + const NSRect drawPt = [impl->drawView convertRectFromBacking:drawPx]; + [impl->drawView setFrameSize:drawPt.size]; + + view->frame = frame; return PUGL_SUCCESS; } PuglStatus -puglSetAspectRatio(PuglView* const view, - const int minX, - const int minY, - const int maxX, - const int maxY) -{ - view->minAspectX = minX; - view->minAspectY = minY; - view->maxAspectX = maxX; - view->maxAspectY = maxY; - - if (view->impl->window && view->minAspectX && view->minAspectY) { - [view->impl->window setContentAspectRatio:sizePoints(view, - view->minAspectX, - view->minAspectY)]; +puglSetSizeHint(PuglView* const view, + const PuglSizeHint hint, + const PuglSpan width, + const PuglSpan height) +{ + if ((unsigned)hint >= PUGL_NUM_SIZE_HINTS) { + return PUGL_BAD_PARAMETER; } - return PUGL_SUCCESS; + view->sizeHints[hint].width = width; + view->sizeHints[hint].height = height; + + return view->impl->window ? updateSizeHint(view, hint) : PUGL_SUCCESS; } PuglStatus -puglSetTransientFor(PuglView* view, PuglNativeView parent) +puglSetTransientParent(PuglView* view, PuglNativeView parent) { view->transientParent = parent; @@ -1400,21 +1547,106 @@ puglSetTransientFor(PuglView* view, PuglNativeView parent) return PUGL_FAILURE; } +PuglStatus +puglPaste(PuglView* const view) +{ + const PuglDataOfferEvent offer = { + PUGL_DATA_OFFER, + 0, + mach_absolute_time() / 1e9, + }; + + PuglEvent offerEvent; + offerEvent.offer = offer; + puglDispatchEvent(view, &offerEvent); + return PUGL_SUCCESS; +} + +uint32_t +puglGetNumClipboardTypes(const PuglView* PUGL_UNUSED(view)) +{ + NSPasteboard* const pasteboard = [NSPasteboard generalPasteboard]; + + return pasteboard ? (uint32_t)[[pasteboard types] count] : 0; +} + +const char* +puglGetClipboardType(const PuglView* PUGL_UNUSED(view), + const uint32_t typeIndex) +{ + NSPasteboard* const pasteboard = [NSPasteboard generalPasteboard]; + if (!pasteboard) { + return NULL; + } + + const NSArray* const types = [pasteboard types]; + if (typeIndex >= [types count]) { + return NULL; + } + + NSString* const uti = [types objectAtIndex:typeIndex]; + NSString* const mimeType = mimeTypeForUti(uti); + + // FIXME: lifetime? + return mimeType ? [mimeType UTF8String] : [uti UTF8String]; +} + +PuglStatus +puglAcceptOffer(PuglView* const view, + const PuglDataOfferEvent* const PUGL_UNUSED(offer), + const uint32_t typeIndex) +{ + PuglWrapperView* const wrapper = view->impl->wrapperView; + NSPasteboard* const pasteboard = [NSPasteboard generalPasteboard]; + if (!pasteboard) { + return PUGL_BAD_PARAMETER; + } + + const NSArray* const types = [pasteboard types]; + if (typeIndex >= [types count]) { + return PUGL_BAD_PARAMETER; + } + + wrapper->dragOperation = NSDragOperationCopy; + wrapper->dragTypeIndex = typeIndex; + + const PuglDataEvent data = { + PUGL_DATA, 0u, mach_absolute_time() / 1e9, (uint32_t)typeIndex}; + + PuglEvent dataEvent; + dataEvent.data = data; + puglDispatchEvent(view, &dataEvent); + return PUGL_SUCCESS; +} + const void* -puglGetClipboard(PuglView* const view, - const char** const type, - size_t* const len) +puglGetClipboard(PuglView* const view, + const uint32_t typeIndex, + size_t* const len) { + *len = 0; + NSPasteboard* const pasteboard = [NSPasteboard generalPasteboard]; + if (!pasteboard) { + return NULL; + } - if ([[pasteboard types] containsObject:NSStringPboardType]) { - const NSString* str = [pasteboard stringForType:NSStringPboardType]; - const char* utf8 = [str UTF8String]; + const NSArray* const types = [pasteboard types]; + if (typeIndex >= [types count]) { + return NULL; + } - puglSetBlob(&view->clipboard, utf8, strlen(utf8) + 1); + NSString* const uti = [types objectAtIndex:typeIndex]; + if ([uti isEqualToString:@"public.file-url"] || + [uti isEqualToString:@"com.apple.pasteboard.promised-file-url"]) { + *len = [view->impl->wrapperView->droppedUriList length]; + return [view->impl->wrapperView->droppedUriList UTF8String]; } - return puglGetInternalClipboard(view, type, len); + const NSData* const data = [pasteboard dataForType:uti]; + + *len = [data length]; + return [data bytes]; } static NSCursor* @@ -1447,7 +1679,7 @@ puglGetNsCursor(const PuglCursor cursor) if (cursorSelector && [NSCursor respondsToSelector:cursorSelector]) { - id object = [NSCursor performSelector:cursorSelector]; + const id object = [NSCursor performSelector:cursorSelector]; if ([object isKindOfClass:[NSCursor class]]) return (NSCursor*)object; } @@ -1474,28 +1706,21 @@ puglSetCursor(PuglView* view, PuglCursor cursor) } PuglStatus -puglSetClipboard(PuglView* const view, +puglSetClipboard(PuglView* PUGL_UNUSED(view), const char* const type, const void* const data, const size_t len) { NSPasteboard* const pasteboard = [NSPasteboard generalPasteboard]; - const char* const str = (const char*)data; - - PuglStatus st = puglSetInternalClipboard(view, type, data, len); - if (st) { - return st; - } - - NSString* nsString = [NSString stringWithUTF8String:str]; - if (nsString) { - [pasteboard declareTypes:[NSArray arrayWithObjects:NSStringPboardType, nil] - owner:nil]; + NSString* const mimeType = [NSString stringWithUTF8String:type]; + NSString* const uti = utiForMimeType(mimeType); + NSData* const blob = [NSData dataWithBytes:data length:len]; - [pasteboard setString:nsString forType:NSStringPboardType]; + [pasteboard declareTypes:[NSArray arrayWithObjects:uti, nil] owner:nil]; + if ([pasteboard setData:blob forType:uti]) { return PUGL_SUCCESS; } - return PUGL_UNKNOWN_ERROR; + return PUGL_FAILURE; } diff --git a/dpf/dgl/src/pugl-upstream/src/mac_cairo.m b/dpf/dgl/src/pugl-upstream/src/mac_cairo.m index a2888ab..66af5ba 100644 --- a/dpf/dgl/src/pugl-upstream/src/mac_cairo.m +++ b/dpf/dgl/src/pugl-upstream/src/mac_cairo.m @@ -1,20 +1,7 @@ -/* - Copyright 2019-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#include "implementation.h" +// Copyright 2019-2022 David Robillard +// SPDX-License-Identifier: ISC + +#include "internal.h" #include "mac.h" #include "stub.h" @@ -77,7 +64,7 @@ puglMacCairoCreate(PuglView* view) return PUGL_SUCCESS; } -static PuglStatus +static void puglMacCairoDestroy(PuglView* view) { PuglCairoView* const drawView = (PuglCairoView*)view->impl->drawView; @@ -86,7 +73,6 @@ puglMacCairoDestroy(PuglView* view) [drawView release]; view->impl->drawView = nil; - return PUGL_SUCCESS; } static PuglStatus @@ -100,10 +86,14 @@ puglMacCairoEnter(PuglView* view, const PuglExposeEvent* expose) assert(!drawView->surface); assert(!drawView->cr); - const double scale = 1.0 / [[NSScreen mainScreen] backingScaleFactor]; - CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort]; - const CGSize sizePx = {view->frame.width, view->frame.height}; - const CGSize sizePt = CGContextConvertSizeToUserSpace(context, sizePx); + const double scale = 1.0 / [[NSScreen mainScreen] backingScaleFactor]; + CGContextRef context = + (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort]; + + const CGSize sizePx = {(CGFloat)view->frame.width, + (CGFloat)view->frame.height}; + + const CGSize sizePt = CGContextConvertSizeToUserSpace(context, sizePx); // Convert coordinates to standard Cairo space CGContextTranslateCTM(context, 0.0, -sizePt.height); diff --git a/dpf/dgl/src/pugl-upstream/src/mac_gl.m b/dpf/dgl/src/pugl-upstream/src/mac_gl.m index 3e74afe..ddd9fde 100644 --- a/dpf/dgl/src/pugl-upstream/src/mac_gl.m +++ b/dpf/dgl/src/pugl-upstream/src/mac_gl.m @@ -1,20 +1,7 @@ -/* - Copyright 2019-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#include "implementation.h" +// Copyright 2019-2022 David Robillard +// SPDX-License-Identifier: ISC + +#include "internal.h" #include "mac.h" #include "stub.h" @@ -133,7 +120,7 @@ puglMacGlCreate(PuglView* view) return PUGL_SUCCESS; } -static PuglStatus +static void puglMacGlDestroy(PuglView* view) { PuglOpenGLView* const drawView = (PuglOpenGLView*)view->impl->drawView; @@ -142,13 +129,15 @@ puglMacGlDestroy(PuglView* view) [drawView release]; view->impl->drawView = nil; - return PUGL_SUCCESS; } static PuglStatus puglMacGlEnter(PuglView* view, const PuglExposeEvent* PUGL_UNUSED(expose)) { PuglOpenGLView* const drawView = (PuglOpenGLView*)view->impl->drawView; + if (!drawView) { + return PUGL_FAILURE; + } [[drawView openGLContext] makeCurrentContext]; return PUGL_SUCCESS; diff --git a/dpf/dgl/src/pugl-upstream/src/mac_stub.m b/dpf/dgl/src/pugl-upstream/src/mac_stub.m index ac7bfcc..ceffa6e 100644 --- a/dpf/dgl/src/pugl-upstream/src/mac_stub.m +++ b/dpf/dgl/src/pugl-upstream/src/mac_stub.m @@ -1,20 +1,7 @@ -/* - Copyright 2019-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#include "implementation.h" +// Copyright 2019-2022 David Robillard +// SPDX-License-Identifier: ISC + +#include "internal.h" #include "mac.h" #include "stub.h" @@ -66,7 +53,7 @@ puglMacStubCreate(PuglView* view) return PUGL_SUCCESS; } -static PuglStatus +static void puglMacStubDestroy(PuglView* view) { PuglStubView* const drawView = (PuglStubView*)view->impl->drawView; @@ -75,7 +62,6 @@ puglMacStubDestroy(PuglView* view) [drawView release]; view->impl->drawView = nil; - return PUGL_SUCCESS; } const PuglBackend* diff --git a/dpf/dgl/src/pugl-upstream/src/mac_vulkan.m b/dpf/dgl/src/pugl-upstream/src/mac_vulkan.m index 22fff10..2362db1 100644 --- a/dpf/dgl/src/pugl-upstream/src/mac_vulkan.m +++ b/dpf/dgl/src/pugl-upstream/src/mac_vulkan.m @@ -1,22 +1,9 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ +// Copyright 2012-2022 David Robillard +// SPDX-License-Identifier: ISC #define VK_NO_PROTOTYPES 1 -#include "implementation.h" +#include "internal.h" #include "mac.h" #include "stub.h" #include "types.h" @@ -102,7 +89,7 @@ puglMacVulkanCreate(PuglView* view) return PUGL_SUCCESS; } -static PuglStatus +static void puglMacVulkanDestroy(PuglView* view) { PuglVulkanView* const drawView = (PuglVulkanView*)view->impl->drawView; @@ -111,7 +98,6 @@ puglMacVulkanDestroy(PuglView* view) [drawView release]; view->impl->drawView = nil; - return PUGL_SUCCESS; } struct PuglVulkanLoaderImpl { diff --git a/dpf/dgl/src/pugl-upstream/src/platform.h b/dpf/dgl/src/pugl-upstream/src/platform.h new file mode 100644 index 0000000..ec16197 --- /dev/null +++ b/dpf/dgl/src/pugl-upstream/src/platform.h @@ -0,0 +1,33 @@ +// Copyright 2012-2022 David Robillard +// SPDX-License-Identifier: ISC + +// The API that a platform implementation must define + +#ifndef PUGL_PLATFORM_H +#define PUGL_PLATFORM_H + +#include "types.h" + +#include "pugl/pugl.h" + +PUGL_BEGIN_DECLS + +/// Allocate and initialise world internals (implemented once per platform) +PuglWorldInternals* +puglInitWorldInternals(PuglWorldType type, PuglWorldFlags flags); + +/// Destroy and free world internals (implemented once per platform) +void +puglFreeWorldInternals(PuglWorld* world); + +/// Allocate and initialise view internals (implemented once per platform) +PuglInternals* +puglInitViewInternals(PuglWorld* world); + +/// Destroy and free view internals (implemented once per platform) +void +puglFreeViewInternals(PuglView* view); + +PUGL_END_DECLS + +#endif // PUGL_PLATFORM_H diff --git a/dpf/dgl/src/pugl-upstream/src/stub.h b/dpf/dgl/src/pugl-upstream/src/stub.h index 4ade84c..699bbb9 100644 --- a/dpf/dgl/src/pugl-upstream/src/stub.h +++ b/dpf/dgl/src/pugl-upstream/src/stub.h @@ -1,21 +1,8 @@ -/* - Copyright 2012-2021 David Robillard +// Copyright 2012-2022 David Robillard +// SPDX-License-Identifier: ISC - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef PUGL_DETAIL_STUB_H -#define PUGL_DETAIL_STUB_H +#ifndef PUGL_SRC_STUB_H +#define PUGL_SRC_STUB_H #include "pugl/pugl.h" @@ -37,11 +24,10 @@ puglStubCreate(PuglView* const view) return PUGL_SUCCESS; } -static inline PuglStatus +static inline void puglStubDestroy(PuglView* const view) { (void)view; - return PUGL_SUCCESS; } static inline PuglStatus @@ -69,4 +55,4 @@ puglStubGetContext(PuglView* const view) PUGL_END_DECLS -#endif // PUGL_DETAIL_STUB_H +#endif // PUGL_SRC_STUB_H diff --git a/dpf/dgl/src/pugl-upstream/src/types.h b/dpf/dgl/src/pugl-upstream/src/types.h index 1f82486..dc2e29f 100644 --- a/dpf/dgl/src/pugl-upstream/src/types.h +++ b/dpf/dgl/src/pugl-upstream/src/types.h @@ -1,21 +1,10 @@ -/* - Copyright 2012-2020 David Robillard +// Copyright 2012-2022 David Robillard +// SPDX-License-Identifier: ISC - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. +#ifndef PUGL_SRC_TYPES_H +#define PUGL_SRC_TYPES_H - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef PUGL_DETAIL_TYPES_H -#define PUGL_DETAIL_TYPES_H +#include "attributes.h" #include "pugl/pugl.h" @@ -23,15 +12,6 @@ #include #include -// Unused parameter macro to suppresses warnings and make it impossible to use -#if defined(__cplusplus) -# define PUGL_UNUSED(name) -#elif defined(__GNUC__) || defined(__clang__) -# define PUGL_UNUSED(name) name##_unused __attribute__((__unused__)) -#else -# define PUGL_UNUSED(name) name -#endif - /// Platform-specific world internals typedef struct PuglWorldInternalsImpl PuglWorldInternals; @@ -41,6 +21,12 @@ typedef struct PuglInternalsImpl PuglInternals; /// View hints typedef int PuglHints[PUGL_NUM_VIEW_HINTS]; +/// View size (both X and Y coordinates) +typedef struct { + PuglSpan width; + PuglSpan height; +} PuglViewSize; + /// Blob of arbitrary data typedef struct { void* data; ///< Dynamically allocated data @@ -55,22 +41,12 @@ struct PuglViewImpl { PuglHandle handle; PuglEventFunc eventFunc; char* title; - PuglBlob clipboard; PuglNativeView parent; uintptr_t transientParent; PuglRect frame; PuglConfigureEvent lastConfigure; PuglHints hints; - int defaultWidth; - int defaultHeight; - int minWidth; - int minHeight; - int maxWidth; - int maxHeight; - int minAspectX; - int minAspectY; - int maxAspectX; - int maxAspectY; + PuglViewSize sizeHints[PUGL_NUM_SIZE_HINTS]; bool visible; }; @@ -90,22 +66,26 @@ typedef void PuglSurface; /// Graphics backend interface struct PuglBackendImpl { /// Get visual information from display and setup view as necessary + PUGL_WARN_UNUSED_RESULT PuglStatus (*configure)(PuglView*); /// Create surface and drawing context + PUGL_WARN_UNUSED_RESULT PuglStatus (*create)(PuglView*); /// Destroy surface and drawing context - PuglStatus (*destroy)(PuglView*); + void (*destroy)(PuglView*); /// Enter drawing context, for drawing if expose is non-null + PUGL_WARN_UNUSED_RESULT PuglStatus (*enter)(PuglView*, const PuglExposeEvent*); /// Leave drawing context, after drawing if expose is non-null + PUGL_WARN_UNUSED_RESULT PuglStatus (*leave)(PuglView*, const PuglExposeEvent*); /// Return the puglGetContext() handle for the application, if any void* (*getContext)(PuglView*); }; -#endif // PUGL_DETAIL_TYPES_H +#endif // PUGL_SRC_TYPES_H diff --git a/dpf/dgl/src/pugl-upstream/src/wasm.c b/dpf/dgl/src/pugl-upstream/src/wasm.c new file mode 100644 index 0000000..b7d81da --- /dev/null +++ b/dpf/dgl/src/pugl-upstream/src/wasm.c @@ -0,0 +1,734 @@ +// Copyright 2012-2022 David Robillard +// Copyright 2021-2022 Filipe Coelho +// SPDX-License-Identifier: ISC + +#include "wasm.h" + +#include "internal.h" + +#include + +#include + +#ifdef __cplusplus +# define PUGL_INIT_STRUCT \ + {} +#else +# define PUGL_INIT_STRUCT \ + { \ + 0 \ + } +#endif + +PuglWorldInternals* +puglInitWorldInternals(const PuglWorldType type, const PuglWorldFlags flags) +{ + printf("DONE: %s %d\n", __func__, __LINE__); + + PuglWorldInternals* impl = + (PuglWorldInternals*)calloc(1, sizeof(PuglWorldInternals)); + + impl->scaleFactor = emscripten_get_device_pixel_ratio(); + + return impl; +} + +void* +puglGetNativeWorld(PuglWorld*) +{ + printf("DONE: %s %d\n", __func__, __LINE__); + return NULL; +} + +PuglInternals* +puglInitViewInternals(PuglWorld* const world) +{ + printf("DONE: %s %d\n", __func__, __LINE__); + PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals)); + + return impl; +} + +static PuglStatus +puglDispatchEventWithContext(PuglView* const view, const PuglEvent* event) +{ + PuglStatus st0 = PUGL_SUCCESS; + PuglStatus st1 = PUGL_SUCCESS; + + if (!(st0 = view->backend->enter(view, NULL))) { + st0 = view->eventFunc(view, event); + st1 = view->backend->leave(view, NULL); + } + + return st0 ? st0 : st1; +} + +static PuglKey +keyCodeToSpecial(const unsigned long code, const unsigned long location) +{ + switch (code) { + case 0x08: return PUGL_KEY_BACKSPACE; + case 0x1B: return PUGL_KEY_ESCAPE; + case 0x2E: return PUGL_KEY_DELETE; + case 0x70: return PUGL_KEY_F1; + case 0x71: return PUGL_KEY_F2; + case 0x72: return PUGL_KEY_F3; + case 0x73: return PUGL_KEY_F4; + case 0x74: return PUGL_KEY_F5; + case 0x75: return PUGL_KEY_F6; + case 0x76: return PUGL_KEY_F7; + case 0x77: return PUGL_KEY_F8; + case 0x78: return PUGL_KEY_F9; + case 0x79: return PUGL_KEY_F10; + case 0x7A: return PUGL_KEY_F11; + case 0x7B: return PUGL_KEY_F12; + case 0x25: return PUGL_KEY_LEFT; + case 0x26: return PUGL_KEY_UP; + case 0x27: return PUGL_KEY_RIGHT; + case 0x28: return PUGL_KEY_DOWN; + case 0x21: return PUGL_KEY_PAGE_UP; + case 0x22: return PUGL_KEY_PAGE_DOWN; + case 0x24: return PUGL_KEY_HOME; + case 0x23: return PUGL_KEY_END; + case 0x2D: return PUGL_KEY_INSERT; + case 0x10: return location == DOM_KEY_LOCATION_RIGHT ? PUGL_KEY_SHIFT_R : PUGL_KEY_SHIFT_L; + case 0x11: return location == DOM_KEY_LOCATION_RIGHT ? PUGL_KEY_CTRL_R : PUGL_KEY_CTRL_L; + case 0x12: return location == DOM_KEY_LOCATION_RIGHT ? PUGL_KEY_ALT_R : PUGL_KEY_ALT_L; + case 0xE0: return location == DOM_KEY_LOCATION_RIGHT ? PUGL_KEY_SUPER_R : PUGL_KEY_SUPER_L; + case 0x5D: return PUGL_KEY_MENU; + case 0x14: return PUGL_KEY_CAPS_LOCK; + case 0x91: return PUGL_KEY_SCROLL_LOCK; + case 0x90: return PUGL_KEY_NUM_LOCK; + case 0x2C: return PUGL_KEY_PRINT_SCREEN; + case 0x13: return PUGL_KEY_PAUSE; + case '\r': return (PuglKey)'\r'; + default: break; + } + + return (PuglKey)0; +} + +static PuglMods +translateModifiers(const EM_BOOL ctrlKey, + const EM_BOOL shiftKey, + const EM_BOOL altKey, + const EM_BOOL metaKey) +{ + return (ctrlKey ? PUGL_MOD_CTRL : 0u) | + (shiftKey ? PUGL_MOD_SHIFT : 0u) | + (altKey ? PUGL_MOD_ALT : 0u) | + (metaKey ? PUGL_MOD_SUPER : 0u); +} + +static bool +decodeCharacterString(const unsigned long keyCode, + const EM_UTF8 key[EM_HTML5_SHORT_STRING_LEN_BYTES], + char str[8]) +{ + if (key[1] == 0) + { + str[0] = key[0]; + return true; + } + + return false; +} + +static EM_BOOL +puglKeyCallback(const int eventType, const EmscriptenKeyboardEvent* const keyEvent, void* const userData) +{ + PuglView* const view = (PuglView*)userData; + + if (!view->visible) { + return EM_FALSE; + } + + if (keyEvent->repeat && view->hints[PUGL_IGNORE_KEY_REPEAT]) + return EM_TRUE; + + PuglStatus st0 = PUGL_SUCCESS; + PuglStatus st1 = PUGL_SUCCESS; + + const uint state = translateModifiers(keyEvent->ctrlKey, + keyEvent->shiftKey, + keyEvent->altKey, + keyEvent->metaKey); + + const PuglKey special = keyCodeToSpecial(keyEvent->keyCode, keyEvent->location); + + uint key = keyEvent->keyCode; + if (key >= 'A' && key <= 'Z' && !keyEvent->shiftKey) + key += 'a' - 'A'; + + PuglEvent event = {{PUGL_NOTHING, 0}}; + event.key.type = eventType == EMSCRIPTEN_EVENT_KEYDOWN ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE; + event.key.time = keyEvent->timestamp / 1000; + // event.key.x = xevent.xkey.x; + // event.key.y = xevent.xkey.y; + // event.key.xRoot = xevent.xkey.x_root; + // event.key.yRoot = xevent.xkey.y_root; + event.key.key = special ? special : key; + event.key.keycode = keyEvent->keyCode; + event.key.state = state; + st0 = puglDispatchEventWithContext(view, &event); + + d_debug("key event \n" + "\tdown: %d\n" + "\trepeat: %d\n" + "\tlocation: %d\n" + "\tstate: 0x%x\n" + "\tkey[]: '%s'\n" + "\tcode[]: '%s'\n" + "\tlocale[]: '%s'\n" + "\tkeyCode: 0x%lx:'%c' [deprecated, use key]\n" + "\twhich: 0x%lx:'%c' [deprecated, use key, same as keycode?]\n" + "\tspecial: 0x%x", + eventType == EMSCRIPTEN_EVENT_KEYDOWN, + keyEvent->repeat, + keyEvent->location, + state, + keyEvent->key, + keyEvent->code, + keyEvent->locale, + keyEvent->keyCode, keyEvent->keyCode >= ' ' && keyEvent->keyCode <= '~' ? keyEvent->keyCode : 0, + keyEvent->which, keyEvent->which >= ' ' && keyEvent->which <= '~' ? keyEvent->which : 0, + special); + + if (event.type == PUGL_KEY_PRESS && !special && !(keyEvent->ctrlKey|keyEvent->altKey|keyEvent->metaKey)) { + char str[8] = PUGL_INIT_STRUCT; + + if (decodeCharacterString(keyEvent->keyCode, keyEvent->key, str)) { + d_debug("resulting string is '%s'", str); + + event.text.type = PUGL_TEXT; + event.text.character = event.key.key; + memcpy(event.text.string, str, sizeof(event.text.string)); + st1 = puglDispatchEventWithContext(view, &event); + } + } + + return (st0 ? st0 : st1) == PUGL_SUCCESS ? EM_TRUE : EM_FALSE; +} + +static EM_BOOL +puglMouseCallback(const int eventType, const EmscriptenMouseEvent* const mouseEvent, void* const userData) +{ + PuglView* const view = (PuglView*)userData; + + if (!view->visible) { + return EM_FALSE; + } + + PuglEvent event = {{PUGL_NOTHING, 0}}; + + const double time = mouseEvent->timestamp / 1000; + const PuglMods state = translateModifiers(mouseEvent->ctrlKey, + mouseEvent->shiftKey, + mouseEvent->altKey, + mouseEvent->metaKey); + + const double scaleFactor = view->world->impl->scaleFactor; + + switch (eventType) { + case EMSCRIPTEN_EVENT_MOUSEDOWN: + case EMSCRIPTEN_EVENT_MOUSEUP: + event.button.type = eventType == EMSCRIPTEN_EVENT_MOUSEDOWN ? PUGL_BUTTON_PRESS : PUGL_BUTTON_RELEASE; + event.button.time = time; + event.button.x = mouseEvent->targetX * scaleFactor; + event.button.y = mouseEvent->targetY * scaleFactor; + event.button.xRoot = mouseEvent->screenX * scaleFactor; + event.button.yRoot = mouseEvent->screenY * scaleFactor; + event.button.state = state; + switch (mouseEvent->button) { + case 1: + event.button.button = 2; + break; + case 2: + event.button.button = 1; + break; + default: + event.button.button = mouseEvent->button; + break; + } + break; + case EMSCRIPTEN_EVENT_MOUSEMOVE: + event.motion.type = PUGL_MOTION; + event.motion.time = time; + if (view->impl->lastX == mouseEvent->targetX && view->impl->lastY == mouseEvent->targetY) { + // adjust local values for delta + const double movementX = mouseEvent->movementX * scaleFactor; + const double movementY = mouseEvent->movementY * scaleFactor; + view->impl->lockedX += movementX; + view->impl->lockedY += movementY; + view->impl->lockedRootX += movementX; + view->impl->lockedRootY += movementY; + // now set x, y, xRoot and yRoot + event.motion.x = view->impl->lockedX; + event.motion.y = view->impl->lockedY; + event.motion.xRoot = view->impl->lockedRootX; + event.motion.yRoot = view->impl->lockedRootY; + } else { + // cache unmodified value first, for pointer lock detection + view->impl->lastX = mouseEvent->targetX; + view->impl->lastY = mouseEvent->targetY; + // now set x, y, xRoot and yRoot + view->impl->lockedX = event.motion.x = mouseEvent->targetX * scaleFactor; + view->impl->lockedY = event.motion.y = mouseEvent->targetY * scaleFactor; + view->impl->lockedRootX = event.motion.xRoot = mouseEvent->screenX * scaleFactor; + view->impl->lockedRootY = event.motion.yRoot = mouseEvent->screenY * scaleFactor; + } + event.motion.state = state; + break; + case EMSCRIPTEN_EVENT_MOUSEENTER: + case EMSCRIPTEN_EVENT_MOUSELEAVE: + event.crossing.type = eventType == EMSCRIPTEN_EVENT_MOUSEENTER ? PUGL_POINTER_IN : PUGL_POINTER_OUT; + event.crossing.time = time; + event.crossing.x = mouseEvent->targetX * scaleFactor; + event.crossing.y = mouseEvent->targetY * scaleFactor; + event.crossing.xRoot = mouseEvent->screenX * scaleFactor; + event.crossing.yRoot = mouseEvent->screenY * scaleFactor; + event.crossing.state = state; + event.crossing.mode = PUGL_CROSSING_NORMAL; + break; + } + + if (event.type == PUGL_NOTHING) + return EM_FALSE; + + puglDispatchEventWithContext(view, &event); + + // note: we must always return false, otherwise canvas never gets keyboard input + return EM_FALSE; +} + +static EM_BOOL +puglFocusCallback(const int eventType, const EmscriptenFocusEvent* /*const focusEvent*/, void* const userData) +{ + PuglView* const view = (PuglView*)userData; + + if (!view->visible) { + return EM_FALSE; + } + + PuglEvent event = {{eventType == EMSCRIPTEN_EVENT_FOCUSIN ? PUGL_FOCUS_IN : PUGL_FOCUS_OUT, 0}}; + event.focus.mode = PUGL_CROSSING_NORMAL; + + puglDispatchEventWithContext(view, &event); + + // note: we must always return false, otherwise canvas never gets proper focus + return EM_FALSE; +} + +static EM_BOOL +puglPointerLockChangeCallback(const int eventType, const EmscriptenPointerlockChangeEvent* event, void* const userData) +{ + PuglView* const view = (PuglView*)userData; + + printf("puglPointerLockChangeCallback %d\n", event->isActive); + view->impl->pointerLocked = event->isActive; + return EM_TRUE; +} + +static EM_BOOL +puglWheelCallback(const int eventType, const EmscriptenWheelEvent* const wheelEvent, void* const userData) +{ + PuglView* const view = (PuglView*)userData; + + if (!view->visible) { + return EM_FALSE; + } + + const double scaleFactor = view->world->impl->scaleFactor; + + PuglEvent event = {{PUGL_SCROLL, 0}}; + event.scroll.time = wheelEvent->mouse.timestamp / 1000; + event.scroll.x = wheelEvent->mouse.targetX; + event.scroll.y = wheelEvent->mouse.targetY; + event.scroll.xRoot = wheelEvent->mouse.screenX; + event.scroll.yRoot = wheelEvent->mouse.screenY; + event.scroll.state = translateModifiers(wheelEvent->mouse.ctrlKey, + wheelEvent->mouse.shiftKey, + wheelEvent->mouse.altKey, + wheelEvent->mouse.metaKey); + event.scroll.direction = PUGL_SCROLL_SMOOTH; + // FIXME handle wheelEvent->deltaMode + event.scroll.dx = wheelEvent->deltaX * 0.01 * scaleFactor; + event.scroll.dy = -wheelEvent->deltaY * 0.01 * scaleFactor; + + return puglDispatchEventWithContext(view, &event) == PUGL_SUCCESS ? EM_TRUE : EM_FALSE; +} + +static EM_BOOL +puglUiCallback(const int eventType, const EmscriptenUiEvent* const uiEvent, void* const userData) +{ + PuglView* const view = (PuglView*)userData; + + // FIXME + const int width = EM_ASM_INT({ return canvas.parentElement.clientWidth; }); + const int height = EM_ASM_INT({ return canvas.parentElement.clientHeight; }); + + if (!width || !height) + return EM_FALSE; + + const double scaleFactor = view->world->impl->scaleFactor = emscripten_get_device_pixel_ratio(); + + emscripten_set_canvas_element_size(view->world->className, width * scaleFactor, height * scaleFactor); + + PuglEvent event = {{PUGL_CONFIGURE, 0}}; + event.configure.x = view->frame.x; + event.configure.y = view->frame.y; + event.configure.width = width * scaleFactor; + event.configure.height = height * scaleFactor; + puglDispatchEvent(view, &event); + return EM_TRUE; +} + +PuglStatus +puglRealize(PuglView* const view) +{ + printf("TODO: %s %d\n", __func__, __LINE__); + PuglStatus st = PUGL_SUCCESS; + + // Ensure that we do not have a parent + if (view->parent) { + printf("TODO: %s %d\n", __func__, __LINE__); + return PUGL_FAILURE; + } + + if (!view->backend || !view->backend->configure) { + printf("TODO: %s %d\n", __func__, __LINE__); + return PUGL_BAD_BACKEND; + } + + const char* const className = view->world->className; + d_stdout("className is %s", className); + + // Set the size to the default if it has not already been set + if (view->frame.width <= 0.0 && view->frame.height <= 0.0) { + PuglViewSize defaultSize = view->sizeHints[PUGL_DEFAULT_SIZE]; + if (!defaultSize.width || !defaultSize.height) { + return PUGL_BAD_CONFIGURATION; + } + + view->frame.width = defaultSize.width; + view->frame.height = defaultSize.height; + } + + // Configure and create the backend + if ((st = view->backend->configure(view)) || (st = view->backend->create(view))) { + view->backend->destroy(view); + return st; + } + + if (view->title) { + puglSetWindowTitle(view, view->title); + } + + puglDispatchSimpleEvent(view, PUGL_CREATE); + + PuglEvent event = {{PUGL_CONFIGURE, 0}}; + event.configure.x = view->frame.x; + event.configure.y = view->frame.y; + event.configure.width = view->frame.width; + event.configure.height = view->frame.height; + puglDispatchEvent(view, &event); + + emscripten_set_canvas_element_size(className, view->frame.width, view->frame.height); +// emscripten_set_keypress_callback(className, view, false, puglKeyCallback); + emscripten_set_keydown_callback(className, view, false, puglKeyCallback); + emscripten_set_keyup_callback(className, view, false, puglKeyCallback); + emscripten_set_mousedown_callback(className, view, false, puglMouseCallback); + emscripten_set_mouseup_callback(className, view, false, puglMouseCallback); + emscripten_set_mousemove_callback(className, view, false, puglMouseCallback); + emscripten_set_mouseenter_callback(className, view, false, puglMouseCallback); + emscripten_set_mouseleave_callback(className, view, false, puglMouseCallback); + emscripten_set_focusin_callback(className, view, false, puglFocusCallback); + emscripten_set_focusout_callback(className, view, false, puglFocusCallback); + emscripten_set_pointerlockchange_callback(className, view, false, puglPointerLockChangeCallback); + emscripten_set_wheel_callback(className, view, false, puglWheelCallback); + emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, view, false, puglUiCallback); + view->impl->pointerLocked = true; + + printf("TODO: %s %d\n", __func__, __LINE__); + return PUGL_SUCCESS; +} + +PuglStatus +puglShow(PuglView* const view) +{ + printf("TODO: %s %d\n", __func__, __LINE__); + view->visible = true; + return puglPostRedisplay(view); +} + +PuglStatus +puglHide(PuglView* const view) +{ + printf("TODO: %s %d\n", __func__, __LINE__); + view->visible = false; + return PUGL_FAILURE; +} + +void +puglFreeViewInternals(PuglView* const view) +{ + printf("DONE: %s %d\n", __func__, __LINE__); + if (view && view->impl) { + if (view->backend) { + view->backend->destroy(view); + } + free(view->impl->timers); + free(view->impl); + } +} + +void +puglFreeWorldInternals(PuglWorld* const world) +{ + printf("DONE: %s %d\n", __func__, __LINE__); + free(world->impl); +} + +PuglStatus +puglGrabFocus(PuglView*) +{ + return PUGL_FAILURE; +} + +PuglStatus +puglAcceptOffer(PuglView* const view, + const PuglDataOfferEvent* const offer, + const uint32_t typeIndex) +{ + printf("TODO: %s %d\n", __func__, __LINE__); + return PUGL_FAILURE; +} + +PuglStatus +puglPaste(PuglView* const view) +{ + printf("TODO: %s %d\n", __func__, __LINE__); + return PUGL_FAILURE; +} + +uint32_t +puglGetNumClipboardTypes(const PuglView* const view) +{ + printf("TODO: %s %d\n", __func__, __LINE__); + return 0; +} + +const char* +puglGetClipboardType(const PuglView* const view, const uint32_t typeIndex) +{ + printf("TODO: %s %d\n", __func__, __LINE__); + return NULL; +} + +double +puglGetScaleFactor(const PuglView* const view) +{ + printf("DONE: %s %d\n", __func__, __LINE__); + return view->world->impl->scaleFactor; +} + +double +puglGetTime(const PuglWorld*) +{ +// d_stdout("DONE %s %d", __func__, __LINE__); + return emscripten_get_now() / 1000; +} + +PuglStatus +puglUpdate(PuglWorld* const world, const double timeout) +{ +// printf("TODO: %s %d\n", __func__, __LINE__); + + for (size_t i = 0; i < world->numViews; ++i) { + PuglView* const view = world->views[i]; + + if (view->visible) { + puglDispatchSimpleEvent(view, PUGL_UPDATE); + } + + if (!view->impl->needsRepaint) { + continue; + } + + view->impl->needsRepaint = false; + + PuglEvent event = {{PUGL_EXPOSE, 0}}; + event.expose.x = view->frame.x; + event.expose.y = view->frame.y; + event.expose.width = view->frame.width; + event.expose.height = view->frame.height; + puglDispatchEvent(view, &event); + + static bool p = true; + if (p) { + p = false; + d_stdout("drawing at %d %d %u %u", (int)view->frame.x, (int)view->frame.y, + (uint)view->frame.width, (uint)view->frame.height); + } + } + + return PUGL_SUCCESS; +} + +PuglStatus +puglPostRedisplay(PuglView* const view) +{ +// printf("TODO: %s %d\n", __func__, __LINE__); + view->impl->needsRepaint = true; + return PUGL_SUCCESS; +} + +PuglStatus +puglPostRedisplayRect(PuglView* const view, const PuglRect rect) +{ +// printf("TODO: %s %d\n", __func__, __LINE__); + view->impl->needsRepaint = true; + return PUGL_FAILURE; +} + +PuglNativeView +puglGetNativeView(PuglView* const view) +{ + printf("TODO: %s %d\n", __func__, __LINE__); + return 0; +} + +PuglStatus +puglSetWindowTitle(PuglView* const view, const char* const title) +{ + printf("DONE: %s %d\n", __func__, __LINE__); + puglSetString(&view->title, title); + emscripten_set_window_title(title); + return PUGL_SUCCESS; +} + +PuglStatus +puglSetSizeHint(PuglView* const view, + const PuglSizeHint hint, + const PuglSpan width, + const PuglSpan height) +{ + printf("DONE: %s %d\n", __func__, __LINE__); + view->sizeHints[hint].width = width; + view->sizeHints[hint].height = height; + return PUGL_SUCCESS; +} + +static EM_BOOL +puglTimerLoopCallback(double timeout, void* const arg) +{ + PuglTimer* const timer = (PuglTimer*)arg; + PuglInternals* const impl = timer->view->impl; + + // only handle active timers + for (uint32_t i=0; inumTimers; ++i) + { + if (impl->timers[i].id == timer->id) + { + PuglEvent event = {{PUGL_TIMER, 0}}; + event.timer.id = timer->id; + puglDispatchEventWithContext(timer->view, &event); + return EM_TRUE; + } + } + + return EM_FALSE; + + // unused + (void)timeout; +} + +PuglStatus +puglStartTimer(PuglView* const view, const uintptr_t id, const double timeout) +{ + printf("DONE: %s %d\n", __func__, __LINE__); + PuglInternals* const impl = view->impl; + const uint32_t timerIndex = impl->numTimers++; + + if (impl->timers == NULL) + impl->timers = (PuglTimer*)malloc(sizeof(PuglTimer)); + else + impl->timers = (PuglTimer*)realloc(impl->timers, sizeof(PuglTimer) * timerIndex); + + PuglTimer* const timer = &impl->timers[timerIndex]; + timer->view = view; + timer->id = id; + + emscripten_set_timeout_loop(puglTimerLoopCallback, timeout * 1000, timer); + return PUGL_SUCCESS; +} + +PuglStatus +puglStopTimer(PuglView* const view, const uintptr_t id) +{ + printf("DONE: %s %d\n", __func__, __LINE__); + PuglInternals* const impl = view->impl; + + if (impl->timers == NULL || impl->numTimers == 0) + return PUGL_FAILURE; + + for (uint32_t i=0; inumTimers; ++i) + { + if (impl->timers[i].id == id) + { + memmove(impl->timers + i, impl->timers + (i + 1), sizeof(PuglTimer) * (impl->numTimers - 1)); + --impl->numTimers; + return PUGL_SUCCESS; + } + } + + return PUGL_FAILURE; +} + +const void* +puglGetClipboard(PuglView* const view, + const uint32_t typeIndex, + size_t* const len) +{ + printf("TODO: %s %d\n", __func__, __LINE__); + return NULL; +} + +PuglStatus +puglSetClipboard(PuglView* const view, + const char* const type, + const void* const data, + const size_t len) +{ + printf("TODO: %s %d\n", __func__, __LINE__); + return PUGL_FAILURE; +} + +PuglStatus +puglSetCursor(PuglView* const view, const PuglCursor cursor) +{ + printf("TODO: %s %d\n", __func__, __LINE__); + return PUGL_FAILURE; +} + +PuglStatus +puglSetTransientParent(PuglView* const view, const PuglNativeView parent) +{ + printf("TODO: %s %d\n", __func__, __LINE__); + view->transientParent = parent; + return PUGL_FAILURE; +} + +PuglStatus +puglSetPosition(PuglView* const view, const int x, const int y) +{ + printf("TODO: %s %d\n", __func__, __LINE__); + + if (x > INT16_MAX || y > INT16_MAX) { + return PUGL_BAD_PARAMETER; + } + + view->frame.x = (PuglCoord)x; + view->frame.y = (PuglCoord)y; + return PUGL_FAILURE; +} diff --git a/dpf/dgl/src/pugl-upstream/src/wasm.h b/dpf/dgl/src/pugl-upstream/src/wasm.h new file mode 100644 index 0000000..850f62b --- /dev/null +++ b/dpf/dgl/src/pugl-upstream/src/wasm.h @@ -0,0 +1,33 @@ +// Copyright 2012-2022 David Robillard +// Copyright 2021-2022 Filipe Coelho +// SPDX-License-Identifier: ISC + +#ifndef PUGL_SRC_WASM_H +#define PUGL_SRC_WASM_H + +// #include "attributes.h" +#include "types.h" + +#include "pugl/pugl.h" + +struct PuglTimer { + PuglView* view; + uintptr_t id; +}; + +struct PuglWorldInternalsImpl { + double scaleFactor; +}; + +struct PuglInternalsImpl { + PuglSurface* surface; + bool needsRepaint; + bool pointerLocked; + uint32_t numTimers; + long lastX, lastY; + double lockedX, lockedY; + double lockedRootX, lockedRootY; + struct PuglTimer* timers; +}; + +#endif // PUGL_SRC_WASM_H diff --git a/dpf/dgl/src/pugl-upstream/src/wasm_gl.c b/dpf/dgl/src/pugl-upstream/src/wasm_gl.c new file mode 100644 index 0000000..3b3b9ec --- /dev/null +++ b/dpf/dgl/src/pugl-upstream/src/wasm_gl.c @@ -0,0 +1,255 @@ +// Copyright 2012-2022 David Robillard +// Copyright 2021-2022 Filipe Coelho +// SPDX-License-Identifier: ISC + +// #include "attributes.h" +#include "stub.h" +// #include "types.h" +#include "wasm.h" + +// #include "pugl/gl.h" +#include "pugl/pugl.h" + +#include +#include + +#include + +typedef struct { + EGLDisplay display; + EGLConfig config; + EGLContext context; + EGLSurface surface; +} PuglWasmGlSurface; + +static EGLint +puglWasmGlHintValue(const int value) +{ + return value == PUGL_DONT_CARE ? EGL_DONT_CARE : value; +} + +static int +puglWasmGlGetAttrib(const EGLDisplay display, + const EGLConfig config, + const EGLint attrib) +{ + EGLint value = 0; + eglGetConfigAttrib(display, config, attrib, &value); + return value; +} + +static PuglStatus +puglWasmGlConfigure(PuglView* view) +{ + PuglInternals* const impl = view->impl; +// const int screen = impl->screen; +// Display* const display = view->world->impl->display; + + printf("TODO: %s %d | start\n", __func__, __LINE__); + + const EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + + if (display == EGL_NO_DISPLAY) { + printf("eglGetDisplay Failed\n"); + return PUGL_CREATE_CONTEXT_FAILED; + } + + int major, minor; + if (eglInitialize(display, &major, &minor) != EGL_TRUE) { + printf("eglInitialize Failed\n"); + return PUGL_CREATE_CONTEXT_FAILED; + } + + EGLConfig config; + int numConfigs; + + if (eglGetConfigs(display, &config, 1, &numConfigs) != EGL_TRUE || numConfigs != 1) { + printf("eglGetConfigs Failed\n"); + eglTerminate(display); + return PUGL_CREATE_CONTEXT_FAILED; + } + + // clang-format off + const EGLint attrs[] = { +// GLX_X_RENDERABLE, True, +// GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, +// GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, +// GLX_RENDER_TYPE, GLX_RGBA_BIT, + +// GLX_DOUBLEBUFFER, puglX11GlHintValue(view->hints[PUGL_DOUBLE_BUFFER]), + + EGL_SAMPLES, puglWasmGlHintValue(view->hints[PUGL_SAMPLES]), + EGL_RED_SIZE, puglWasmGlHintValue(view->hints[PUGL_RED_BITS]), + EGL_GREEN_SIZE, puglWasmGlHintValue(view->hints[PUGL_GREEN_BITS]), + EGL_BLUE_SIZE, puglWasmGlHintValue(view->hints[PUGL_BLUE_BITS]), + EGL_ALPHA_SIZE, puglWasmGlHintValue(view->hints[PUGL_ALPHA_BITS]), + EGL_DEPTH_SIZE, puglWasmGlHintValue(view->hints[PUGL_DEPTH_BITS]), + EGL_STENCIL_SIZE, puglWasmGlHintValue(view->hints[PUGL_STENCIL_BITS]), + EGL_NONE + }; + // clang-format on + + if (eglChooseConfig(display, attrs, &config, 1, &numConfigs) != EGL_TRUE || numConfigs != 1) { + printf("eglChooseConfig Failed\n"); + eglTerminate(display); + return PUGL_CREATE_CONTEXT_FAILED; + } + + PuglWasmGlSurface* const surface = + (PuglWasmGlSurface*)calloc(1, sizeof(PuglWasmGlSurface)); + impl->surface = surface; + + surface->display = display; + surface->config = config; + surface->context = EGL_NO_SURFACE; + surface->surface = EGL_NO_CONTEXT; + + view->hints[PUGL_RED_BITS] = + puglWasmGlGetAttrib(display, config, EGL_RED_SIZE); + view->hints[PUGL_GREEN_BITS] = + puglWasmGlGetAttrib(display, config, EGL_GREEN_SIZE); + view->hints[PUGL_BLUE_BITS] = + puglWasmGlGetAttrib(display, config, EGL_BLUE_SIZE); + view->hints[PUGL_ALPHA_BITS] = + puglWasmGlGetAttrib(display, config, EGL_ALPHA_SIZE); + view->hints[PUGL_DEPTH_BITS] = + puglWasmGlGetAttrib(display, config, EGL_DEPTH_SIZE); + view->hints[PUGL_STENCIL_BITS] = + puglWasmGlGetAttrib(display, config, EGL_STENCIL_SIZE); + view->hints[PUGL_SAMPLES] = + puglWasmGlGetAttrib(display, config, EGL_SAMPLES); + + // always enabled for EGL + view->hints[PUGL_DOUBLE_BUFFER] = 1; + + printf("TODO: %s %d | ok\n", __func__, __LINE__); + + return PUGL_SUCCESS; +} + +PUGL_WARN_UNUSED_RESULT +static PuglStatus +puglWasmGlEnter(PuglView* view, const PuglExposeEvent* PUGL_UNUSED(expose)) +{ +// printf("DONE: %s %d\n", __func__, __LINE__); + PuglWasmGlSurface* const surface = (PuglWasmGlSurface*)view->impl->surface; + if (!surface || !surface->context || !surface->surface) { + return PUGL_FAILURE; + } + + // TESTING: is it faster if we never unset context? + return PUGL_SUCCESS; + + return eglMakeCurrent(surface->display, surface->surface, surface->surface, surface->context) ? PUGL_SUCCESS : PUGL_FAILURE; +} + +PUGL_WARN_UNUSED_RESULT +static PuglStatus +puglWasmGlLeave(PuglView* view, const PuglExposeEvent* expose) +{ +// printf("DONE: %s %d\n", __func__, __LINE__); + PuglWasmGlSurface* const surface = (PuglWasmGlSurface*)view->impl->surface; + + if (expose) { // note: swap buffers always enabled for EGL + eglSwapBuffers(surface->display, surface->surface); + } + + // TESTING: is it faster if we never unset context? + return PUGL_SUCCESS; + + return eglMakeCurrent(surface->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT) ? PUGL_SUCCESS : PUGL_FAILURE; +} + +static PuglStatus +puglWasmGlCreate(PuglView* view) +{ + printf("TODO: %s %d | start\n", __func__, __LINE__); + PuglWasmGlSurface* const surface = (PuglWasmGlSurface*)view->impl->surface; + const EGLDisplay display = surface->display; + const EGLConfig config = surface->config; + + const EGLint attrs[] = { + EGL_CONTEXT_CLIENT_VERSION, + view->hints[PUGL_CONTEXT_VERSION_MAJOR], + + EGL_CONTEXT_MAJOR_VERSION, + view->hints[PUGL_CONTEXT_VERSION_MAJOR], + + /* + EGL_CONTEXT_MINOR_VERSION, + view->hints[PUGL_CONTEXT_VERSION_MINOR], + + EGL_CONTEXT_OPENGL_DEBUG, + (view->hints[PUGL_USE_DEBUG_CONTEXT] ? EGL_TRUE : EGL_FALSE), + + EGL_CONTEXT_OPENGL_PROFILE_MASK, + (view->hints[PUGL_USE_COMPAT_PROFILE] + ? EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT + : EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT), + */ + + EGL_NONE + }; + + surface->context = eglCreateContext(display, config, EGL_NO_CONTEXT, attrs); + + if (surface->context == EGL_NO_CONTEXT) { + printf("eglCreateContext Failed\n"); + return PUGL_CREATE_CONTEXT_FAILED; + } + +#if 0 + eglMakeCurrent(surface->display, surface->surface, surface->surface, surface->context); + + printf("GL_VENDOR=%s\n", glGetString(GL_VENDOR)); + printf("GL_RENDERER=%s\n", glGetString(GL_RENDERER)); + printf("GL_VERSION=%s\n", glGetString(GL_VERSION)); + + eglMakeCurrent(surface->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); +#endif + + surface->surface = eglCreateWindowSurface(display, config, 0, NULL); + + if (surface->surface == EGL_NO_SURFACE) { + printf("eglCreateWindowSurface Failed\n"); + return PUGL_CREATE_CONTEXT_FAILED; + } + + printf("TODO: %s %d | ok\n", __func__, __LINE__); + + // TESTING: is it faster if we never unset context? + eglMakeCurrent(surface->display, surface->surface, surface->surface, surface->context); + + return PUGL_SUCCESS; +} + +static void +puglWasmGlDestroy(PuglView* view) +{ + printf("DONE: %s %d\n", __func__, __LINE__); + PuglWasmGlSurface* surface = (PuglWasmGlSurface*)view->impl->surface; + if (surface) { + const EGLDisplay display = surface->display; + if (surface->surface != EGL_NO_SURFACE) + eglDestroySurface(display, surface->surface); + if (surface->context != EGL_NO_CONTEXT) + eglDestroyContext(display, surface->context); + eglTerminate(display); + free(surface); + view->impl->surface = NULL; + } +} + +const PuglBackend* +puglGlBackend(void) +{ + printf("DONE: %s %d\n", __func__, __LINE__); + static const PuglBackend backend = {puglWasmGlConfigure, + puglWasmGlCreate, + puglWasmGlDestroy, + puglWasmGlEnter, + puglWasmGlLeave, + puglStubGetContext}; + + return &backend; +} diff --git a/dpf/dgl/src/pugl-upstream/src/wasm_stub.c b/dpf/dgl/src/pugl-upstream/src/wasm_stub.c new file mode 100644 index 0000000..8cf2f49 --- /dev/null +++ b/dpf/dgl/src/pugl-upstream/src/wasm_stub.c @@ -0,0 +1,26 @@ +// Copyright 2012-2022 David Robillard +// Copyright 2021-2022 Filipe Coelho +// SPDX-License-Identifier: ISC + +#include "pugl/stub.h" + +#include "stub.h" +// #include "types.h" +// #include "wasm.h" + +#include "pugl/pugl.h" + +const PuglBackend* +puglStubBackend(void) +{ + static const PuglBackend backend = { + puglStubConfigure, + puglStubCreate, + puglStubDestroy, + puglStubEnter, + puglStubLeave, + puglStubGetContext, + }; + + return &backend; +} diff --git a/dpf/dgl/src/pugl-upstream/src/win.c b/dpf/dgl/src/pugl-upstream/src/win.c index cae7263..13d042c 100644 --- a/dpf/dgl/src/pugl-upstream/src/win.c +++ b/dpf/dgl/src/pugl-upstream/src/win.c @@ -1,22 +1,10 @@ -/* - Copyright 2012-2021 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ +// Copyright 2012-2022 David Robillard +// SPDX-License-Identifier: ISC #include "win.h" -#include "implementation.h" +#include "internal.h" +#include "platform.h" #include "pugl/pugl.h" @@ -48,6 +36,8 @@ #define PUGL_USER_TIMER_MIN 9470 typedef BOOL(WINAPI* PFN_SetProcessDPIAware)(void); +typedef HRESULT(WINAPI* PFN_GetProcessDpiAwareness)(HANDLE, DWORD*); +typedef HRESULT(WINAPI* PFN_GetScaleFactorForMonitor)(HMONITOR, DWORD*); LRESULT CALLBACK wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); @@ -72,7 +62,7 @@ puglWideCharToUtf8(const wchar_t* const wstr, size_t* len) if (n > 0) { char* result = (char*)calloc((size_t)n, sizeof(char)); WideCharToMultiByte(CP_UTF8, 0, wstr, -1, result, n, NULL, NULL); - *len = (size_t)n; + *len = (size_t)n - 1; return result; } @@ -82,27 +72,35 @@ puglWideCharToUtf8(const wchar_t* const wstr, size_t* len) static bool puglRegisterWindowClass(const char* name) { + HMODULE module = NULL; + if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | + GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + (LPCTSTR)puglRegisterWindowClass, + &module)) { + module = GetModuleHandle(NULL); + } + WNDCLASSEX wc = {0}; - if (GetClassInfoEx(GetModuleHandle(NULL), name, &wc)) { + if (GetClassInfoEx(module, name, &wc)) { return true; // Already registered } wc.cbSize = sizeof(wc); wc.style = CS_OWNDC; wc.lpfnWndProc = wndProc; - wc.hInstance = GetModuleHandle(NULL); + wc.hInstance = module; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); wc.lpszClassName = name; - return RegisterClassEx(&wc); + return !!RegisterClassEx(&wc); } static unsigned puglWinGetWindowFlags(const PuglView* const view) { - const bool resizable = view->hints[PUGL_RESIZABLE]; + const bool resizable = !!view->hints[PUGL_RESIZABLE]; const unsigned sizeFlags = resizable ? (WS_SIZEBOX | WS_MAXIMIZEBOX) : 0u; return (WS_CLIPCHILDREN | WS_CLIPSIBLINGS | @@ -117,6 +115,35 @@ puglWinGetWindowExFlags(const PuglView* const view) return WS_EX_NOINHERITLAYOUT | (view->parent ? 0u : WS_EX_APPWINDOW); } +static double +puglWinGetViewScaleFactor(HWND hwnd) +{ + const HMODULE shcore = LoadLibrary("Shcore.dll"); + if (!shcore) { + return 1.0; + } + + const PFN_GetProcessDpiAwareness GetProcessDpiAwareness = + (PFN_GetProcessDpiAwareness)GetProcAddress(shcore, + "GetProcessDpiAwareness"); + + const PFN_GetScaleFactorForMonitor GetScaleFactorForMonitor = + (PFN_GetScaleFactorForMonitor)GetProcAddress(shcore, + "GetScaleFactorForMonitor"); + + DWORD dpiAware = 0; + DWORD scaleFactor = 100; + if (GetProcessDpiAwareness && GetScaleFactorForMonitor && + !GetProcessDpiAwareness(NULL, &dpiAware) && dpiAware) { + GetScaleFactorForMonitor( + MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY), + &scaleFactor); + } + + FreeLibrary(shcore); + return (double)scaleFactor / 100.0; +} + PuglWorldInternals* puglInitWorldInternals(PuglWorldType type, PuglWorldFlags PUGL_UNUSED(flags)) { @@ -153,7 +180,7 @@ puglGetNativeWorld(PuglWorld* PUGL_UNUSED(world)) } PuglInternals* -puglInitViewInternals(void) +puglInitViewInternals(PuglWorld* PUGL_UNUSED(world)) { return (PuglInternals*)calloc(1, sizeof(PuglInternals)); } @@ -195,7 +222,8 @@ puglRealize(PuglView* view) } // Get refresh rate for resize draw timer - DEVMODEA devMode = {0}; + DEVMODEA devMode; + memset(&devMode, 0, sizeof(devMode)); EnumDisplaySettingsA(NULL, ENUM_CURRENT_SETTINGS, &devMode); view->hints[PUGL_REFRESH_RATE] = (int)devMode.dmDisplayFrequency; @@ -218,7 +246,8 @@ puglRealize(PuglView* view) puglSetWindowTitle(view, view->title); } - view->impl->cursor = LoadCursor(NULL, IDC_ARROW); + view->impl->scaleFactor = puglWinGetViewScaleFactor(view->impl->hwnd); + view->impl->cursor = LoadCursor(NULL, IDC_ARROW); puglSetFrame(view, view->frame); SetWindowLongPtr(impl->hwnd, GWLP_USERDATA, (LONG_PTR)view); @@ -389,7 +418,9 @@ puglDecodeUTF16(const wchar_t* buf, const int len) if (c0 >= 0xD800u && c0 < 0xDC00u) { if (len < 2) { return 0xFFFD; // Surrogate, but length is only 1 - } else if (c1 >= 0xDC00u && c1 <= 0xDFFFu) { + } + + if (c1 >= 0xDC00u && c1 <= 0xDFFFu) { return ((c0 & 0x03FFu) << 10u) + (c1 & 0x03FFu) + 0x10000u; } @@ -484,19 +515,14 @@ handleConfigure(PuglView* view, PuglEvent* event) const LONG width = rect.right - rect.left; const LONG height = rect.bottom - rect.top; - view->frame.x = rect.left; - view->frame.y = rect.top; + view->frame.x = (PuglCoord)rect.left; + view->frame.y = (PuglCoord)rect.top; event->configure.type = PUGL_CONFIGURE; - event->configure.x = view->frame.x; - event->configure.y = view->frame.y; - event->configure.width = width; - event->configure.height = height; - - if (view->frame.width != width || view->frame.height != height) { - view->frame.width = width; - view->frame.height = height; - } + event->configure.x = (PuglCoord)view->frame.x; + event->configure.y = (PuglCoord)view->frame.y; + event->configure.width = (PuglSpan)width; + event->configure.height = (PuglSpan)height; return rect; } @@ -529,8 +555,11 @@ constrainAspect(const PuglView* const view, RECT* const size, const WPARAM wParam) { - const float minA = (float)view->minAspectX / (float)view->minAspectY; - const float maxA = (float)view->maxAspectX / (float)view->maxAspectY; + const PuglViewSize minAspect = view->sizeHints[PUGL_MIN_ASPECT]; + const PuglViewSize maxAspect = view->sizeHints[PUGL_MAX_ASPECT]; + + const float minA = (float)minAspect.width / (float)minAspect.height; + const float maxA = (float)maxAspect.width / (float)maxAspect.height; const float w = (float)(size->right - size->left); const float h = (float)(size->bottom - size->top); const float a = w / h; @@ -608,8 +637,14 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam) InvalidateRect(view->impl->hwnd, NULL, false); } break; + case WM_DISPLAYCHANGE: + view->impl->scaleFactor = puglWinGetViewScaleFactor(view->impl->hwnd); + break; + case WM_WINDOWPOSCHANGED: + handleConfigure(view, &event); + break; case WM_SIZING: - if (view->minAspectX) { + if (view->sizeHints[PUGL_MIN_ASPECT].width) { constrainAspect(view, (RECT*)lParam, wParam); return TRUE; } @@ -631,20 +666,21 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam) break; case WM_GETMINMAXINFO: mmi = (MINMAXINFO*)lParam; - mmi->ptMinTrackSize.x = view->minWidth; - mmi->ptMinTrackSize.y = view->minHeight; - if (view->maxWidth > 0 && view->maxHeight > 0) { - mmi->ptMaxTrackSize.x = view->maxWidth; - mmi->ptMaxTrackSize.y = view->maxHeight; + mmi->ptMinTrackSize.x = view->sizeHints[PUGL_MIN_SIZE].width; + mmi->ptMinTrackSize.y = view->sizeHints[PUGL_MIN_SIZE].height; + if (view->sizeHints[PUGL_MAX_SIZE].width && + view->sizeHints[PUGL_MAX_SIZE].height) { + mmi->ptMaxTrackSize.x = view->sizeHints[PUGL_MAX_SIZE].width; + mmi->ptMaxTrackSize.y = view->sizeHints[PUGL_MAX_SIZE].height; } break; case WM_PAINT: GetUpdateRect(view->impl->hwnd, &rect, false); event.expose.type = PUGL_EXPOSE; - event.expose.x = rect.left; - event.expose.y = rect.top; - event.expose.width = rect.right - rect.left; - event.expose.height = rect.bottom - rect.top; + event.expose.x = (PuglCoord)rect.left; + event.expose.y = (PuglCoord)rect.top; + event.expose.width = (PuglSpan)(rect.right - rect.left); + event.expose.height = (PuglSpan)(rect.bottom - rect.top); break; case WM_ERASEBKGND: return true; @@ -680,22 +716,36 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam) view->impl->mouseTracked = false; break; case WM_LBUTTONDOWN: - initMouseEvent(&event, view, 1, true, lParam); + initMouseEvent(&event, view, 0, true, lParam); break; case WM_MBUTTONDOWN: initMouseEvent(&event, view, 2, true, lParam); break; case WM_RBUTTONDOWN: - initMouseEvent(&event, view, 3, true, lParam); + initMouseEvent(&event, view, 1, true, lParam); + break; + case WM_XBUTTONDOWN: + if (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) { + initMouseEvent(&event, view, 3, true, lParam); + } else { + initMouseEvent(&event, view, 4, true, lParam); + } break; case WM_LBUTTONUP: - initMouseEvent(&event, view, 1, false, lParam); + initMouseEvent(&event, view, 0, false, lParam); break; case WM_MBUTTONUP: initMouseEvent(&event, view, 2, false, lParam); break; case WM_RBUTTONUP: - initMouseEvent(&event, view, 3, false, lParam); + initMouseEvent(&event, view, 1, false, lParam); + break; + case WM_XBUTTONUP: + if (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) { + initMouseEvent(&event, view, 3, false, lParam); + } else { + initMouseEvent(&event, view, 4, false, lParam); + } break; case WM_MOUSEWHEEL: initScrollEvent(&event, view, lParam); @@ -806,7 +856,7 @@ puglSendEvent(PuglView* view, const PuglEvent* event) return PUGL_SUCCESS; } - return PUGL_UNSUPPORTED_TYPE; + return PUGL_UNSUPPORTED; } #ifndef PUGL_DISABLE_DEPRECATED @@ -952,7 +1002,7 @@ puglPostRedisplayRect(PuglView* view, const PuglRect rect) } PuglNativeView -puglGetNativeWindow(PuglView* view) +puglGetNativeView(PuglView* view) { return (PuglNativeView)view->impl->hwnd; } @@ -973,17 +1023,40 @@ puglSetWindowTitle(PuglView* view, const char* title) return PUGL_SUCCESS; } +static RECT +adjustedWindowRect(PuglView* const view, + const long x, + const long y, + const long width, + const long height) +{ + const unsigned flags = puglWinGetWindowFlags(view); + const unsigned exFlags = puglWinGetWindowExFlags(view); + + RECT rect = {(long)x, (long)y, (long)x + (long)width, (long)y + (long)height}; + AdjustWindowRectEx(&rect, flags, FALSE, exFlags); + return rect; +} + +double +puglGetScaleFactor(const PuglView* const view) +{ + if (view->impl->scaleFactor) { + return view->impl->scaleFactor; + } + return puglWinGetViewScaleFactor(view->parent + ? (HWND)view->parent + : view->transientParent + ? (HWND)view->transientParent + : NULL); +} + PuglStatus puglSetFrame(PuglView* view, const PuglRect frame) { if (view->impl->hwnd) { - RECT rect = {(long)frame.x, - (long)frame.y, - (long)frame.x + (long)frame.width, - (long)frame.y + (long)frame.height}; - - AdjustWindowRectEx( - &rect, puglWinGetWindowFlags(view), FALSE, puglWinGetWindowExFlags(view)); + const RECT rect = + adjustedWindowRect(view, frame.x, frame.y, frame.width, frame.height); if (!SetWindowPos(view->impl->hwnd, HWND_TOP, @@ -1001,45 +1074,78 @@ puglSetFrame(PuglView* view, const PuglRect frame) } PuglStatus -puglSetDefaultSize(PuglView* const view, const int width, const int height) +puglSetPosition(PuglView* const view, const int x, const int y) { - view->defaultWidth = width; - view->defaultHeight = height; - return PUGL_SUCCESS; -} + if (x > INT16_MAX || y > INT16_MAX) { + return PUGL_BAD_PARAMETER; + } -PuglStatus -puglSetMinSize(PuglView* const view, const int width, const int height) -{ - view->minWidth = width; - view->minHeight = height; + if (view->impl->hwnd) { + const RECT rect = + adjustedWindowRect(view, x, y, view->frame.width, view->frame.height); + + if (!SetWindowPos(view->impl->hwnd, + HWND_TOP, + rect.left, + rect.top, + 0, + 0, + SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | + SWP_NOSIZE)) { + return PUGL_UNKNOWN_ERROR; + } + } + + view->frame.x = (PuglCoord)x; + view->frame.y = (PuglCoord)y; return PUGL_SUCCESS; } PuglStatus -puglSetMaxSize(PuglView* const view, const int width, const int height) +puglSetSize(PuglView* const view, const unsigned width, const unsigned height) { - view->maxWidth = width; - view->maxHeight = height; + if (width > INT16_MAX || height > INT16_MAX) { + return PUGL_BAD_PARAMETER; + } + + if (view->impl->hwnd) { + const RECT rect = adjustedWindowRect( + view, view->frame.x, view->frame.y, (long)width, (long)height); + + if (!SetWindowPos(view->impl->hwnd, + HWND_TOP, + 0, + 0, + rect.right - rect.left, + rect.bottom - rect.top, + SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | + SWP_NOMOVE)) { + return PUGL_UNKNOWN_ERROR; + } + } + + view->frame.width = (PuglSpan)width; + view->frame.height = (PuglSpan)height; return PUGL_SUCCESS; } PuglStatus -puglSetAspectRatio(PuglView* const view, - const int minX, - const int minY, - const int maxX, - const int maxY) +puglSetSizeHint(PuglView* const view, + const PuglSizeHint hint, + const PuglSpan width, + const PuglSpan height) { - view->minAspectX = minX; - view->minAspectY = minY; - view->maxAspectX = maxX; - view->maxAspectY = maxY; + if ((unsigned)hint >= PUGL_NUM_SIZE_HINTS) { + return PUGL_BAD_PARAMETER; + } + + view->sizeHints[hint].width = width; + view->sizeHints[hint].height = height; return PUGL_SUCCESS; } PuglStatus -puglSetTransientFor(PuglView* view, PuglNativeView parent) +puglSetTransientParent(PuglView* view, PuglNativeView parent) { if (view->parent) { return PUGL_FAILURE; @@ -1055,14 +1161,51 @@ puglSetTransientFor(PuglView* view, PuglNativeView parent) return PUGL_SUCCESS; } +uint32_t +puglGetNumClipboardTypes(const PuglView* const PUGL_UNUSED(view)) +{ + return IsClipboardFormatAvailable(CF_UNICODETEXT) ? 1u : 0u; +} + +const char* +puglGetClipboardType(const PuglView* const PUGL_UNUSED(view), + const uint32_t typeIndex) +{ + return (typeIndex == 0 && IsClipboardFormatAvailable(CF_UNICODETEXT)) + ? "text/plain" + : NULL; +} + +PuglStatus +puglAcceptOffer(PuglView* const view, + const PuglDataOfferEvent* const PUGL_UNUSED(offer), + const uint32_t typeIndex) +{ + if (typeIndex != 0) { + return PUGL_UNSUPPORTED; + } + + const PuglDataEvent data = { + PUGL_DATA, + 0, + GetMessageTime() / 1e3, + 0, + }; + + PuglEvent dataEvent; + dataEvent.data = data; + puglDispatchEvent(view, &dataEvent); + return PUGL_SUCCESS; +} + const void* -puglGetClipboard(PuglView* const view, - const char** const type, - size_t* const len) +puglGetClipboard(PuglView* const view, + const uint32_t typeIndex, + size_t* const len) { PuglInternals* const impl = view->impl; - if (!IsClipboardFormatAvailable(CF_UNICODETEXT) || + if (typeIndex > 0u || !IsClipboardFormatAvailable(CF_UNICODETEXT) || !OpenClipboard(impl->hwnd)) { return NULL; } @@ -1074,12 +1217,15 @@ puglGetClipboard(PuglView* const view, return NULL; } - free(view->clipboard.data); - view->clipboard.data = puglWideCharToUtf8(wstr, &view->clipboard.len); + free(view->impl->clipboard.data); + view->impl->clipboard.data = + puglWideCharToUtf8(wstr, &view->impl->clipboard.len); + GlobalUnlock(mem); CloseClipboard(); - return puglGetInternalClipboard(view, type, len); + *len = view->impl->clipboard.len; + return view->impl->clipboard.data; } PuglStatus @@ -1090,10 +1236,16 @@ puglSetClipboard(PuglView* const view, { PuglInternals* const impl = view->impl; - PuglStatus st = puglSetInternalClipboard(view, type, data, len); + PuglStatus st = puglSetBlob(&view->impl->clipboard, data, len); if (st) { return st; - } else if (!OpenClipboard(impl->hwnd)) { + } + + if (!!strcmp(type, "text/plain")) { + return PUGL_UNSUPPORTED; + } + + if (!OpenClipboard(impl->hwnd)) { return PUGL_UNKNOWN_ERROR; } @@ -1124,6 +1276,21 @@ puglSetClipboard(PuglView* const view, return PUGL_SUCCESS; } +PuglStatus +puglPaste(PuglView* const view) +{ + const PuglDataOfferEvent offer = { + PUGL_DATA_OFFER, + 0, + GetMessageTime() / 1e3, + }; + + PuglEvent offerEvent; + offerEvent.offer = offer; + puglDispatchEvent(view, &offerEvent); + return PUGL_SUCCESS; +} + static const char* const cursor_ids[] = { IDC_ARROW, // ARROW IDC_IBEAM, // CARET @@ -1199,7 +1366,8 @@ puglWinCreateWindow(PuglView* const view, const unsigned winExFlags = puglWinGetWindowExFlags(view); if (view->frame.width <= 0.0 && view->frame.height <= 0.0) { - if (view->defaultWidth <= 0.0 && view->defaultHeight <= 0.0) { + const PuglViewSize defaultSize = view->sizeHints[PUGL_DEFAULT_SIZE]; + if (!defaultSize.width || !defaultSize.height) { return PUGL_BAD_CONFIGURATION; } @@ -1209,10 +1377,13 @@ puglWinCreateWindow(PuglView* const view, const int screenWidth = desktopRect.right - desktopRect.left; const int screenHeight = desktopRect.bottom - desktopRect.top; - view->frame.width = view->defaultWidth; - view->frame.height = view->defaultHeight; - view->frame.x = screenWidth / 2.0 - view->frame.width / 2.0; - view->frame.y = screenHeight / 2.0 - view->frame.height / 2.0; + view->frame.width = defaultSize.width; + view->frame.height = defaultSize.height; + + if (!view->parent) { + view->frame.x = (PuglCoord)((screenWidth - view->frame.width) / 2); + view->frame.y = (PuglCoord)((screenHeight - view->frame.height) / 2); + } } // The meaning of "parent" depends on the window type (WS_CHILD) @@ -1239,7 +1410,9 @@ puglWinCreateWindow(PuglView* const view, NULL, NULL))) { return PUGL_REALIZE_FAILED; - } else if (!(*hdc = GetDC(*hwnd))) { + } + + if (!(*hdc = GetDC(*hwnd))) { DestroyWindow(*hwnd); *hwnd = NULL; return PUGL_REALIZE_FAILED; diff --git a/dpf/dgl/src/pugl-upstream/src/win.h b/dpf/dgl/src/pugl-upstream/src/win.h index fcd92df..4a89e11 100644 --- a/dpf/dgl/src/pugl-upstream/src/win.h +++ b/dpf/dgl/src/pugl-upstream/src/win.h @@ -1,23 +1,10 @@ -/* - Copyright 2012-2021 David Robillard +// Copyright 2012-2022 David Robillard +// SPDX-License-Identifier: ISC - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. +#ifndef PUGL_SRC_WIN_H +#define PUGL_SRC_WIN_H - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef PUGL_DETAIL_WIN_H -#define PUGL_DETAIL_WIN_H - -#include "implementation.h" +#include "internal.h" #include "pugl/pugl.h" @@ -37,7 +24,9 @@ struct PuglInternalsImpl { HWND hwnd; HCURSOR cursor; HDC hdc; + PuglBlob clipboard; PuglSurface* surface; + double scaleFactor; bool flashing; bool mouseTracked; }; @@ -46,23 +35,24 @@ PUGL_API PuglWinPFD puglWinGetPixelFormatDescriptor(const PuglHints hints); +PUGL_WARN_UNUSED_RESULT PUGL_API PuglStatus -puglWinCreateWindow(PuglView* const view, - const char* const title, - HWND* const hwnd, - HDC* const hdc); +puglWinCreateWindow(PuglView* view, const char* title, HWND* hwnd, HDC* hdc); +PUGL_WARN_UNUSED_RESULT PUGL_API PuglStatus puglWinConfigure(PuglView* view); +PUGL_WARN_UNUSED_RESULT PUGL_API PuglStatus puglWinEnter(PuglView* view, const PuglExposeEvent* expose); +PUGL_WARN_UNUSED_RESULT PUGL_API PuglStatus puglWinLeave(PuglView* view, const PuglExposeEvent* expose); -#endif // PUGL_DETAIL_WIN_H +#endif // PUGL_SRC_WIN_H diff --git a/dpf/dgl/src/pugl-upstream/src/win_cairo.c b/dpf/dgl/src/pugl-upstream/src/win_cairo.c index abb06f5..ddc9554 100644 --- a/dpf/dgl/src/pugl-upstream/src/win_cairo.c +++ b/dpf/dgl/src/pugl-upstream/src/win_cairo.c @@ -1,18 +1,5 @@ -/* - Copyright 2012-2021 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ +// Copyright 2012-2022 David Robillard +// SPDX-License-Identifier: ISC #include "stub.h" #include "types.h" @@ -102,7 +89,7 @@ puglWinCairoOpen(PuglView* view) return PUGL_SUCCESS; } -static PuglStatus +static void puglWinCairoDestroy(PuglView* view) { PuglInternals* const impl = view->impl; @@ -112,8 +99,6 @@ puglWinCairoDestroy(PuglView* view) puglWinCairoDestroyDrawContext(view); free(surface); impl->surface = NULL; - - return PUGL_SUCCESS; } static PuglStatus diff --git a/dpf/dgl/src/pugl-upstream/src/win_gl.c b/dpf/dgl/src/pugl-upstream/src/win_gl.c index 529493f..a755020 100644 --- a/dpf/dgl/src/pugl-upstream/src/win_gl.c +++ b/dpf/dgl/src/pugl-upstream/src/win_gl.c @@ -1,18 +1,5 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ +// Copyright 2012-2022 David Robillard +// SPDX-License-Identifier: ISC #include "stub.h" #include "types.h" @@ -224,7 +211,9 @@ puglWinGlCreate(PuglView* view) // Create real window with desired pixel format if ((st = puglWinCreateWindow(view, "Pugl", &impl->hwnd, &impl->hdc))) { return st; - } else if (!SetPixelFormat(impl->hdc, impl->pfId, &impl->pfd)) { + } + + if (!SetPixelFormat(impl->hdc, impl->pfId, &impl->pfd)) { ReleaseDC(impl->hwnd, impl->hdc); DestroyWindow(impl->hwnd); impl->hwnd = NULL; @@ -237,7 +226,9 @@ puglWinGlCreate(PuglView* view) !(surface->hglrc = surface->procs.wglCreateContextAttribs( impl->hdc, 0, contextAttribs))) { return PUGL_CREATE_CONTEXT_FAILED; - } else if (!(surface->hglrc = wglCreateContext(impl->hdc))) { + } + + if (!(surface->hglrc = wglCreateContext(impl->hdc))) { return PUGL_CREATE_CONTEXT_FAILED; } @@ -251,7 +242,7 @@ puglWinGlCreate(PuglView* view) return PUGL_SUCCESS; } -static PuglStatus +static void puglWinGlDestroy(PuglView* view) { PuglWinGlSurface* surface = (PuglWinGlSurface*)view->impl->surface; @@ -261,14 +252,15 @@ puglWinGlDestroy(PuglView* view) free(surface); view->impl->surface = NULL; } - - return PUGL_SUCCESS; } static PuglStatus puglWinGlEnter(PuglView* view, const PuglExposeEvent* expose) { PuglWinGlSurface* surface = (PuglWinGlSurface*)view->impl->surface; + if (!surface || !surface->hglrc) { + return PUGL_FAILURE; + } wglMakeCurrent(view->impl->hdc, surface->hglrc); diff --git a/dpf/dgl/src/pugl-upstream/src/win_stub.c b/dpf/dgl/src/pugl-upstream/src/win_stub.c index 5ba4eb4..e98357c 100644 --- a/dpf/dgl/src/pugl-upstream/src/win_stub.c +++ b/dpf/dgl/src/pugl-upstream/src/win_stub.c @@ -1,18 +1,5 @@ -/* - Copyright 2012-2021 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ +// Copyright 2012-2021 David Robillard +// SPDX-License-Identifier: ISC #include "stub.h" #include "types.h" diff --git a/dpf/dgl/src/pugl-upstream/src/win_vulkan.c b/dpf/dgl/src/pugl-upstream/src/win_vulkan.c index e2d9bb4..fa686ed 100644 --- a/dpf/dgl/src/pugl-upstream/src/win_vulkan.c +++ b/dpf/dgl/src/pugl-upstream/src/win_vulkan.c @@ -1,18 +1,5 @@ -/* - Copyright 2012-2021 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ +// Copyright 2012-2021 David Robillard +// SPDX-License-Identifier: ISC #define VK_NO_PROTOTYPES 1 diff --git a/dpf/dgl/src/pugl-upstream/src/x11.c b/dpf/dgl/src/pugl-upstream/src/x11.c index 5478db7..25f7912 100644 --- a/dpf/dgl/src/pugl-upstream/src/x11.c +++ b/dpf/dgl/src/pugl-upstream/src/x11.c @@ -1,28 +1,13 @@ -/* - Copyright 2012-2021 David Robillard - Copyright 2013 Robin Gareus - Copyright 2011-2012 Ben Loftis, Harrison Consoles - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef _POSIX_C_SOURCE -# define _POSIX_C_SOURCE 199309L -#endif +// Copyright 2012-2022 David Robillard +// Copyright 2013 Robin Gareus +// Copyright 2011-2012 Ben Loftis, Harrison Consoles +// SPDX-License-Identifier: ISC #include "x11.h" -#include "implementation.h" +#include "attributes.h" +#include "internal.h" +#include "platform.h" #include "types.h" #include "pugl/pugl.h" @@ -30,6 +15,7 @@ #include #include #include +#include #include #include @@ -44,11 +30,9 @@ #ifdef HAVE_XCURSOR # include -# include #endif #include -#include #include #include @@ -82,32 +66,20 @@ enum WmClientStateMessageAction { WM_STATE_TOGGLE }; +#define NUM_CURSORS ((unsigned)PUGL_CURSOR_ANTI_DIAGONAL + 1u) + #ifdef HAVE_XCURSOR -static const char* cursor_names_x11[] = { - "left_ptr", // ARROW - "xterm", // CARET +static const char* const cursor_names[NUM_CURSORS] = { + "default", // ARROW + "text", // CARET "crosshair", // CROSSHAIR - "hand2", // HAND - "forbidden", // NO + "pointer", // HAND + "not-allowed", // NO "sb_h_double_arrow", // LEFT_RIGHT "sb_v_double_arrow", // UP_DOWN "size_fdiag", // DIAGONAL - "size_bdiag", // ANTI_DIAGONAL -}; - -/* -static const char* cursor_names_xdg[] = { - "default", // ARROW - "text", // CARET - "crosshair", // CROSSHAIR - "pointer", // HAND - "not-allowed", // NO - "ew-resize", // LEFT_RIGHT - "ns-resize", // UP_DOWN - "nwse-resize", // DIAGONAL - "nesw-resize", // ANTI_DIAGONAL + "size_bdiag" // ANTI_DIAGONAL }; -*/ #endif static bool @@ -140,6 +112,33 @@ initXSync(PuglWorldInternals* const impl) return false; } +static double +puglX11GetDisplayScaleFactor(Display* const display) +{ + double dpi = 96.0; + const char* const rms = XResourceManagerString(display); + if (rms) { + XrmDatabase db = XrmGetStringDatabase(rms); + if (db) { + XrmValue value = {0u, NULL}; + char* type = NULL; + if (XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value)) { + if (!type || !strcmp(type, "String")) { + char* end = NULL; + const double xftDpi = strtod(value.addr, &end); + if (xftDpi > 0.0 && xftDpi < HUGE_VAL) { + dpi = xftDpi; + } + } + } + + XrmDestroyDatabase(db); + } + } + + return dpi / 96.0; +} + PuglWorldInternals* puglInitWorldInternals(const PuglWorldType type, const PuglWorldFlags flags) { @@ -155,7 +154,8 @@ puglInitWorldInternals(const PuglWorldType type, const PuglWorldFlags flags) PuglWorldInternals* impl = (PuglWorldInternals*)calloc(1, sizeof(PuglWorldInternals)); - impl->display = display; + impl->display = display; + impl->scaleFactor = puglX11GetDisplayScaleFactor(display); // Intern the various atoms we will need impl->atoms.CLIPBOARD = XInternAtom(display, "CLIPBOARD", 0); @@ -170,6 +170,9 @@ puglInitWorldInternals(const PuglWorldType type, const PuglWorldFlags flags) impl->atoms.NET_WM_STATE_HIDDEN = XInternAtom(display, "_NET_WM_STATE_HIDDEN", 0); + impl->atoms.TARGETS = XInternAtom(display, "TARGETS", 0); + impl->atoms.text_uri_list = XInternAtom(display, "text/uri-list", 0); + // Open input method XSetLocaleModifiers(""); if (!(impl->xim = XOpenIM(display, NULL, NULL, NULL))) { @@ -177,6 +180,7 @@ puglInitWorldInternals(const PuglWorldType type, const PuglWorldFlags flags) impl->xim = XOpenIM(display, NULL, NULL, NULL); } + XrmInitialize(); initXSync(impl); XFlush(display); @@ -190,12 +194,15 @@ puglGetNativeWorld(PuglWorld* const world) } PuglInternals* -puglInitViewInternals(void) +puglInitViewInternals(PuglWorld* const world) { PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals)); + impl->clipboard.selection = world->impl->atoms.CLIPBOARD; + impl->clipboard.property = XA_PRIMARY; + #ifdef HAVE_XCURSOR - impl->cursorName = cursor_names_x11[0]; + impl->cursorName = cursor_names[PUGL_CURSOR_ARROW]; #endif return impl; @@ -258,30 +265,45 @@ updateSizeHints(const PuglView* const view) sizeHints.max_width = (int)view->frame.width; sizeHints.max_height = (int)view->frame.height; } else { - if (view->defaultWidth || view->defaultHeight) { + const PuglViewSize defaultSize = view->sizeHints[PUGL_DEFAULT_SIZE]; + if (defaultSize.width && defaultSize.height) { sizeHints.flags |= PBaseSize; - sizeHints.base_width = view->defaultWidth; - sizeHints.base_height = view->defaultHeight; + sizeHints.base_width = defaultSize.width; + sizeHints.base_height = defaultSize.height; } - if (view->minWidth || view->minHeight) { + const PuglViewSize minSize = view->sizeHints[PUGL_MIN_SIZE]; + if (minSize.width && minSize.height) { sizeHints.flags |= PMinSize; - sizeHints.min_width = view->minWidth; - sizeHints.min_height = view->minHeight; + sizeHints.min_width = minSize.width; + sizeHints.min_height = minSize.height; } - if (view->maxWidth || view->maxHeight) { + const PuglViewSize maxSize = view->sizeHints[PUGL_MAX_SIZE]; + if (maxSize.width && maxSize.height) { sizeHints.flags |= PMaxSize; - sizeHints.max_width = view->maxWidth; - sizeHints.max_height = view->maxHeight; + sizeHints.max_width = maxSize.width; + sizeHints.max_height = maxSize.height; } - if (view->minAspectX) { + const PuglViewSize minAspect = view->sizeHints[PUGL_MIN_ASPECT]; + const PuglViewSize maxAspect = view->sizeHints[PUGL_MAX_ASPECT]; + if (minAspect.width && minAspect.height && maxAspect.width && + maxAspect.height) { sizeHints.flags |= PAspect; - sizeHints.min_aspect.x = view->minAspectX; - sizeHints.min_aspect.y = view->minAspectY; - sizeHints.max_aspect.x = view->maxAspectX; - sizeHints.max_aspect.y = view->maxAspectY; + sizeHints.min_aspect.x = minAspect.width; + sizeHints.min_aspect.y = minAspect.height; + sizeHints.max_aspect.x = maxAspect.width; + sizeHints.max_aspect.y = maxAspect.height; + } + + const PuglViewSize fixedAspect = view->sizeHints[PUGL_FIXED_ASPECT]; + if (fixedAspect.width && fixedAspect.height) { + sizeHints.flags |= PAspect; + sizeHints.min_aspect.x = fixedAspect.width; + sizeHints.min_aspect.y = fixedAspect.height; + sizeHints.max_aspect.x = fixedAspect.width; + sizeHints.max_aspect.y = fixedAspect.height; } } @@ -296,15 +318,31 @@ defineCursorName(PuglView* const view, const char* const name) PuglInternals* const impl = view->impl; PuglWorld* const world = view->world; Display* const display = world->impl->display; - const Cursor cur = XcursorLibraryLoadCursor(display, name); - if (cur) { - XDefineCursor(display, impl->win, cur); - XFreeCursor(display, cur); - return PUGL_SUCCESS; + // Load cursor theme + char* const theme = XcursorGetTheme(display); + if (!theme) { + return PUGL_FAILURE; } - return PUGL_FAILURE; + // Get the default size and cursor image from it + const int size = XcursorGetDefaultSize(display); + XcursorImage* const image = XcursorLibraryLoadImage(name, theme, size); + if (!image) { + return PUGL_BAD_PARAMETER; + } + + // Load a cursor from the image + const Cursor cur = XcursorImageLoadCursor(display, image); + XcursorImageDestroy(image); + if (!cur) { + return PUGL_UNKNOWN_ERROR; + } + + // Set the view's cursor to the new loaded one + XDefineCursor(display, impl->win, cur); + XFreeCursor(display, cur); + return PUGL_SUCCESS; } #endif @@ -332,26 +370,26 @@ puglRealize(PuglView* const view) // Set the size to the default if it has not already been set if (view->frame.width <= 0.0 && view->frame.height <= 0.0) { - if (view->defaultWidth <= 0.0 || view->defaultHeight <= 0.0) { + const PuglViewSize defaultSize = view->sizeHints[PUGL_DEFAULT_SIZE]; + if (!defaultSize.width || !defaultSize.height) { return PUGL_BAD_CONFIGURATION; } - view->frame.width = view->defaultWidth; - view->frame.height = view->defaultHeight; + view->frame.width = defaultSize.width; + view->frame.height = defaultSize.height; } // Center top-level windows if a position has not been set - if (!view->parent && view->frame.x <= 0.0 && view->frame.y <= 0.0) { + if (!view->parent && !view->frame.x && !view->frame.y) { const int screenWidth = DisplayWidth(display, screen); const int screenHeight = DisplayHeight(display, screen); - view->frame.x = screenWidth / 2.0 - view->frame.width / 2.0; - view->frame.y = screenHeight / 2.0 - view->frame.height / 2.0; + view->frame.x = (PuglCoord)((screenWidth - view->frame.width) / 2); + view->frame.y = (PuglCoord)((screenHeight - view->frame.height) / 2); } // Configure the backend to get the visual info - impl->display = display; - impl->screen = screen; + impl->screen = screen; if ((st = view->backend->configure(view)) || !impl->vi) { view->backend->destroy(view); return st ? st : PUGL_BACKEND_FAILED; @@ -377,10 +415,10 @@ puglRealize(PuglView* const view) // Create the window impl->win = XCreateWindow(display, parent, - (int)view->frame.x, - (int)view->frame.y, - (unsigned)view->frame.width, - (unsigned)view->frame.height, + view->frame.x, + view->frame.y, + view->frame.width, + view->frame.height, 0, impl->vi->depth, InputOutput, @@ -423,17 +461,27 @@ puglRealize(PuglView* const view) } // Create input context - impl->xic = XCreateIC(world->impl->xim, - XNInputStyle, - XIMPreeditNothing | XIMStatusNothing, - XNClientWindow, - impl->win, - XNFocusWindow, - impl->win, - (XIM)0); + if (world->impl->xim) { + impl->xic = XCreateIC(world->impl->xim, + XNInputStyle, + XIMPreeditNothing | XIMStatusNothing, + XNClientWindow, + impl->win, + XNFocusWindow, + impl->win, + (XIM)0); + } puglDispatchSimpleEvent(view, PUGL_CREATE); + /* Flush before returning for two reasons: so that hints are available to the + view's parent via the X server during embedding, and so that the X server + has a chance to create the window (and make its actual position and size + known) before any children are created. Potential bugs aside, this + increases the chances that an application will be cleanly configured once + on startup with the correct position and size. */ + XFlush(display); + return PUGL_SUCCESS; } @@ -443,7 +491,7 @@ puglShow(PuglView* const view) PuglStatus st = view->impl->win ? PUGL_SUCCESS : puglRealize(view); if (!st) { - XMapRaised(view->impl->display, view->impl->win); + XMapRaised(view->world->impl->display, view->impl->win); st = puglPostRedisplay(view); } @@ -453,22 +501,41 @@ puglShow(PuglView* const view) PuglStatus puglHide(PuglView* const view) { - XUnmapWindow(view->impl->display, view->impl->win); + XUnmapWindow(view->world->impl->display, view->impl->win); return PUGL_SUCCESS; } +static void +clearX11Clipboard(PuglX11Clipboard* const board) +{ + for (unsigned long i = 0; i < board->numFormats; ++i) { + free(board->formatStrings[i]); + board->formatStrings[i] = NULL; + } + + board->source = None; + board->numFormats = 0; + board->acceptedFormatIndex = UINT32_MAX; + board->acceptedFormat = None; + board->data.len = 0; +} + void puglFreeViewInternals(PuglView* const view) { if (view && view->impl) { + clearX11Clipboard(&view->impl->clipboard); + free(view->impl->clipboard.data.data); + free(view->impl->clipboard.formats); + free(view->impl->clipboard.formatStrings); if (view->impl->xic) { XDestroyIC(view->impl->xic); } if (view->backend) { view->backend->destroy(view); } - if (view->impl->display) { - XDestroyWindow(view->impl->display, view->impl->win); + if (view->world->impl->display && view->impl->win) { + XDestroyWindow(view->world->impl->display, view->impl->win); } XFree(view->impl->vi); free(view->impl); @@ -566,7 +633,7 @@ translateKey(PuglView* const view, XEvent* const xevent, PuglEvent* const event) event->key.key = ((special || ufound <= 0) ? special : puglDecodeUTF8((const uint8_t*)ustr)); - if (xevent->type == KeyPress && !filter && !special) { + if (xevent->type == KeyPress && !filter && !special && view->impl->xic) { // Lookup shifted key for possible text event xevent->xkey.state = state; @@ -604,7 +671,7 @@ getAtomProperty(PuglView* const view, int actualFormat = 0; unsigned long bytesAfter = 0; - return (XGetWindowProperty(view->impl->display, + return (XGetWindowProperty(view->world->impl->display, window, property, 0, @@ -620,8 +687,66 @@ getAtomProperty(PuglView* const view, : PUGL_FAILURE; } +static PuglX11Clipboard* +getX11SelectionClipboard(PuglView* const view, const Atom selection) +{ + return (selection == view->world->impl->atoms.CLIPBOARD) + ? &view->impl->clipboard + : NULL; +} + +static void +setClipboardFormats(PuglView* const view, + PuglX11Clipboard* const board, + const unsigned long numFormats, + const Atom* const formats) +{ + Atom* const newFormats = + (Atom*)realloc(board->formats, numFormats * sizeof(Atom)); + if (!newFormats) { + return; + } + + for (unsigned long i = 0; i < board->numFormats; ++i) { + free(board->formatStrings[i]); + board->formatStrings[i] = NULL; + } + + board->formats = newFormats; + board->numFormats = 0; + + board->formatStrings = + (char**)realloc(board->formatStrings, numFormats * sizeof(char*)); + + for (unsigned long i = 0; i < numFormats; ++i) { + if (formats[i]) { + char* const name = XGetAtomName(view->world->impl->display, formats[i]); + const char* type = NULL; + + if (strchr(name, '/')) { // MIME type (hopefully) + type = name; + } else if (!strcmp(name, "UTF8_STRING")) { // Plain text + type = "text/plain"; + } + + if (type) { + const size_t typeLen = strlen(type); + char* const formatString = (char*)calloc(typeLen + 1, 1); + + memcpy(formatString, type, typeLen + 1); + + board->formats[board->numFormats] = formats[i]; + board->formatStrings[board->numFormats] = formatString; + ++board->numFormats; + } + + XFree(name); + } + } +} + static PuglEvent -translateClientMessage(PuglView* const view, const XClientMessageEvent message) +translateClientMessage(PuglView* const view, XClientMessageEvent message) { const PuglX11Atoms* const atoms = &view->world->impl->atoms; PuglEvent event = {{PUGL_NOTHING, 0}}; @@ -645,8 +770,7 @@ translatePropertyNotify(PuglView* const view, XPropertyEvent message) { const PuglX11Atoms* const atoms = &view->world->impl->atoms; - PuglEvent event = {{PUGL_NOTHING, 0}}; - bool hidden = false; + PuglEvent event = {{PUGL_NOTHING, 0}}; if (message.atom == atoms->NET_WM_STATE) { unsigned long numHints = 0; Atom* hints = NULL; @@ -655,6 +779,7 @@ translatePropertyNotify(PuglView* const view, XPropertyEvent message) return event; } + bool hidden = false; for (unsigned long i = 0; i < numHints; ++i) { if (hints[i] == atoms->NET_WM_STATE_HIDDEN) { hidden = true; @@ -687,11 +812,9 @@ translateEvent(PuglView* const view, XEvent xevent) event = translatePropertyNotify(view, xevent.xproperty); break; case VisibilityNotify: - if (xevent.xvisibility.state == VisibilityFullyObscured) { - event.type = PUGL_UNMAP; - } else { - event.type = PUGL_MAP; - } + event.type = (xevent.xvisibility.state == VisibilityFullyObscured) + ? PUGL_UNMAP + : PUGL_MAP; break; case MapNotify: event.type = PUGL_MAP; @@ -701,17 +824,17 @@ translateEvent(PuglView* const view, XEvent xevent) break; case ConfigureNotify: event.type = PUGL_CONFIGURE; - event.configure.x = xevent.xconfigure.x; - event.configure.y = xevent.xconfigure.y; - event.configure.width = xevent.xconfigure.width; - event.configure.height = xevent.xconfigure.height; + event.configure.x = (PuglCoord)xevent.xconfigure.x; + event.configure.y = (PuglCoord)xevent.xconfigure.y; + event.configure.width = (PuglSpan)xevent.xconfigure.width; + event.configure.height = (PuglSpan)xevent.xconfigure.height; break; case Expose: event.type = PUGL_EXPOSE; - event.expose.x = xevent.xexpose.x; - event.expose.y = xevent.xexpose.y; - event.expose.width = xevent.xexpose.width; - event.expose.height = xevent.xexpose.height; + event.expose.x = (PuglCoord)xevent.xexpose.x; + event.expose.y = (PuglCoord)xevent.xexpose.y; + event.expose.width = (PuglSpan)xevent.xexpose.width; + event.expose.height = (PuglSpan)xevent.xexpose.height; break; case MotionNotify: event.type = PUGL_MOTION; @@ -765,7 +888,14 @@ translateEvent(PuglView* const view, XEvent xevent) event.button.xRoot = xevent.xbutton.x_root; event.button.yRoot = xevent.xbutton.y_root; event.button.state = translateModifiers(xevent.xbutton.state); - event.button.button = xevent.xbutton.button; + event.button.button = xevent.xbutton.button - 1; + if (event.button.button == 1) { + event.button.button = 2; + } else if (event.button.button == 2) { + event.button.button = 1; + } else if (event.button.button >= 7) { + event.button.button -= 4; + } } break; case KeyPress: @@ -819,9 +949,19 @@ translateEvent(PuglView* const view, XEvent xevent) PuglStatus puglGrabFocus(PuglView* const view) { - PuglInternals* const impl = view->impl; + PuglInternals* const impl = view->impl; + Display* const display = view->world->impl->display; + XWindowAttributes attrs = PUGL_INIT_STRUCT; - XSetInputFocus(impl->display, impl->win, RevertToNone, CurrentTime); + if (!impl->win || !XGetWindowAttributes(display, impl->win, &attrs)) { + return PUGL_UNKNOWN_ERROR; + } + + if (attrs.map_state != IsViewable) { + return PUGL_FAILURE; + } + + XSetInputFocus(display, impl->win, RevertToNone, CurrentTime); return PUGL_SUCCESS; } @@ -830,16 +970,17 @@ puglHasFocus(const PuglView* const view) { int revertTo = 0; Window focusedWindow = 0; - XGetInputFocus(view->impl->display, &focusedWindow, &revertTo); + XGetInputFocus(view->world->impl->display, &focusedWindow, &revertTo); return focusedWindow == view->impl->win; } PuglStatus puglRequestAttention(PuglView* const view) { - PuglInternals* const impl = view->impl; - const PuglX11Atoms* const atoms = &view->world->impl->atoms; - XEvent event = {0}; + PuglInternals* const impl = view->impl; + Display* const display = view->world->impl->display; + const PuglX11Atoms* const atoms = &view->world->impl->atoms; + XEvent event = PUGL_INIT_STRUCT; event.type = ClientMessage; event.xclient.window = impl->win; @@ -851,14 +992,15 @@ puglRequestAttention(PuglView* const view) event.xclient.data.l[3] = 1; event.xclient.data.l[4] = 0; - const Window root = RootWindow(impl->display, impl->screen); - XSendEvent(impl->display, - root, - False, - SubstructureNotifyMask | SubstructureRedirectMask, - &event); + const Window root = RootWindow(display, impl->screen); - return PUGL_SUCCESS; + return XSendEvent(display, + root, + False, + SubstructureNotifyMask | SubstructureRedirectMask, + &event) + ? PUGL_SUCCESS + : PUGL_UNKNOWN_ERROR; } PuglStatus @@ -939,7 +1081,7 @@ puglStopTimer(PuglView* const view, const uintptr_t id) static XEvent eventToX(PuglView* const view, const PuglEvent* const event) { - XEvent xev = {0}; + XEvent xev = PUGL_INIT_STRUCT; xev.xany.send_event = True; switch (event->type) { @@ -951,7 +1093,7 @@ eventToX(PuglView* const view, const PuglEvent* const event) xev.xexpose.type = Expose; xev.xexpose.serial = 0; - xev.xexpose.display = view->impl->display; + xev.xexpose.display = view->world->impl->display; xev.xexpose.window = view->impl->win; xev.xexpose.x = (int)x; xev.xexpose.y = (int)y; @@ -964,7 +1106,7 @@ eventToX(PuglView* const view, const PuglEvent* const event) xev.xclient.type = ClientMessage; xev.xclient.serial = 0; xev.xclient.send_event = True; - xev.xclient.display = view->impl->display; + xev.xclient.display = view->world->impl->display; xev.xclient.window = view->impl->win; xev.xclient.message_type = view->world->impl->atoms.PUGL_CLIENT_MSG; xev.xclient.format = 32; @@ -985,14 +1127,13 @@ puglSendEvent(PuglView* const view, const PuglEvent* const event) XEvent xev = eventToX(view, event); if (xev.type) { - if (XSendEvent(view->impl->display, view->impl->win, False, 0, &xev)) { - return PUGL_SUCCESS; - } - - return PUGL_UNKNOWN_ERROR; + return XSendEvent( + view->world->impl->display, view->impl->win, False, 0, &xev) + ? PUGL_SUCCESS + : PUGL_UNKNOWN_ERROR; } - return PUGL_UNSUPPORTED_TYPE; + return PUGL_UNSUPPORTED; } #ifndef PUGL_DISABLE_DEPRECATED @@ -1000,7 +1141,7 @@ PuglStatus puglWaitForEvent(PuglView* const view) { XEvent xevent; - XPeekEvent(view->impl->display, &xevent); + XPeekEvent(view->world->impl->display, &xevent); return PUGL_SUCCESS; } #endif @@ -1011,85 +1152,164 @@ mergeExposeEvents(PuglExposeEvent* const dst, const PuglExposeEvent* const src) if (!dst->type) { *dst = *src; } else { - const double max_x = MAX(dst->x + dst->width, src->x + src->width); - const double max_y = MAX(dst->y + dst->height, src->y + src->height); + const int dst_r = dst->x + dst->width; + const int src_r = src->x + src->width; + const int max_x = MAX(dst_r, src_r); + const int dst_b = dst->y + dst->height; + const int src_b = src->y + src->height; + const int max_y = MAX(dst_b, src_b); + + dst->x = (PuglCoord)MIN(dst->x, src->x); + dst->y = (PuglCoord)MIN(dst->y, src->y); + dst->width = (PuglSpan)(max_x - dst->x); + dst->height = (PuglSpan)(max_y - dst->y); + } +} - dst->x = MIN(dst->x, src->x); - dst->y = MIN(dst->y, src->y); - dst->width = max_x - dst->x; - dst->height = max_y - dst->y; +static PuglStatus +retrieveSelection(const PuglWorld* const world, + PuglView* const view, + const Atom property, + const Atom type, + PuglBlob* const result) +{ + uint8_t* value = NULL; + Atom actualType = 0u; + int actualFormat = 0; + unsigned long actualNumItems = 0u; + unsigned long bytesAfter = 0u; + + if (XGetWindowProperty(world->impl->display, + view->impl->win, + property, + 0, + 0x1FFFFFFF, + False, + type, + &actualType, + &actualFormat, + &actualNumItems, + &bytesAfter, + &value) != Success) { + return PUGL_FAILURE; + } + + if (value && actualFormat == 8 && bytesAfter == 0) { + puglSetBlob(result, value, actualNumItems); } + + XFree(value); + return PUGL_SUCCESS; } static void -handleSelectionNotify(const PuglWorld* const world, PuglView* const view) +handleSelectionNotify(const PuglWorld* const world, + PuglView* const view, + const XSelectionEvent* const event) { - uint8_t* str = NULL; - Atom type = 0; - int fmt = 0; - unsigned long len = 0; - unsigned long left = 0; - - XGetWindowProperty(world->impl->display, - view->impl->win, - XA_PRIMARY, - 0, - 0x1FFFFFFF, - False, - AnyPropertyType, - &type, - &fmt, - &len, - &left, - &str); - - if (str && fmt == 8 && type == world->impl->atoms.UTF8_STRING && left == 0) { - puglSetBlob(&view->clipboard, str, len); - } - - XFree(str); + const PuglX11Atoms* const atoms = &world->impl->atoms; + + Display* const display = view->world->impl->display; + const Atom selection = event->selection; + PuglX11Clipboard* const board = getX11SelectionClipboard(view, selection); + PuglEvent puglEvent = {{PUGL_NOTHING, 0}}; + + if (event->target == atoms->TARGETS) { + // Notification of available datatypes + unsigned long numFormats = 0; + Atom* formats = NULL; + if (!getAtomProperty( + view, event->requestor, event->property, &numFormats, &formats)) { + setClipboardFormats(view, board, numFormats, formats); + + const PuglDataOfferEvent offer = { + PUGL_DATA_OFFER, 0, (double)event->time / 1e3}; + + puglEvent.offer = offer; + board->acceptedFormatIndex = UINT32_MAX; + board->acceptedFormat = None; + + XFree(formats); + } + + } else if (event->selection == atoms->CLIPBOARD && + event->property == XA_PRIMARY && + board->acceptedFormatIndex < board->numFormats) { + // Notification of data from the clipboard + if (!retrieveSelection( + world, view, event->property, event->target, &board->data)) { + board->source = XGetSelectionOwner(display, board->selection); + + const PuglDataEvent data = { + PUGL_DATA, 0u, (double)event->time / 1e3, board->acceptedFormatIndex}; + + puglEvent.data = data; + } + } + + puglDispatchEvent(view, &puglEvent); } -static void +static PuglStatus handleSelectionRequest(const PuglWorld* const world, PuglView* const view, const XSelectionRequestEvent* const request) { + Display* const display = world->impl->display; + const PuglX11Atoms* const atoms = &world->impl->atoms; + + PuglX11Clipboard* const board = + getX11SelectionClipboard(view, request->selection); + + if (!board) { + return PUGL_UNKNOWN_ERROR; + } + + if (request->target == atoms->TARGETS) { + XChangeProperty(world->impl->display, + request->requestor, + request->property, + XA_ATOM, + 32, + PropModeReplace, + (const uint8_t*)board->formats, + (int)board->numFormats); + } else { + XChangeProperty(world->impl->display, + request->requestor, + request->property, + request->target, + 8, + PropModeReplace, + (const uint8_t*)board->data.data, + (int)board->data.len); + } + XSelectionEvent note = {SelectionNotify, request->serial, False, - world->impl->display, + display, request->requestor, request->selection, request->target, - None, + request->property, request->time}; - const char* type = NULL; - size_t len = 0; - const void* data = puglGetInternalClipboard(view, &type, &len); - if (data && request->selection == world->impl->atoms.CLIPBOARD && - request->target == world->impl->atoms.UTF8_STRING) { - note.property = request->property; - XChangeProperty(world->impl->display, - note.requestor, - note.property, - note.target, - 8, - PropModeReplace, - (const uint8_t*)data, - (int)len); - } else { - note.property = None; - } - - XSendEvent(world->impl->display, note.requestor, True, 0, (XEvent*)¬e); + return XSendEvent( + world->impl->display, note.requestor, True, 0, (XEvent*)¬e) + ? PUGL_SUCCESS + : PUGL_UNKNOWN_ERROR; } /// Flush pending configure and expose events for all views -static void +PUGL_WARN_UNUSED_RESULT +static PuglStatus flushExposures(PuglWorld* const world) { + PuglStatus st0 = PUGL_SUCCESS; + PuglStatus st1 = PUGL_SUCCESS; + PuglStatus st2 = PUGL_SUCCESS; + for (size_t i = 0; i < world->numViews; ++i) { PuglView* const view = world->views[i]; @@ -1106,20 +1326,23 @@ flushExposures(PuglWorld* const world) view->impl->pendingExpose.type = PUGL_NOTHING; if (expose.type) { - view->backend->enter(view, &expose.expose); + if (!(st0 = view->backend->enter(view, &expose.expose))) { + if (configure.type) { + st0 = puglConfigure(view, &configure); + } - if (configure.type) { - puglConfigure(view, &configure); + st1 = puglExpose(view, &expose); + st2 = view->backend->leave(view, &expose.expose); } - - puglExpose(view, &expose); - view->backend->leave(view, &expose.expose); } else if (configure.type) { - view->backend->enter(view, NULL); - puglConfigure(view, &configure); - view->backend->leave(view, NULL); + if (!(st0 = view->backend->enter(view, NULL))) { + st0 = puglConfigure(view, &configure); + st1 = view->backend->leave(view, NULL); + } } } + + return st0 ? st0 : st1 ? st1 : st2; } static bool @@ -1148,10 +1371,28 @@ handleTimerEvent(PuglWorld* const world, const XEvent xevent) return false; } +static PuglStatus +dispatchCurrentConfiguration(PuglView* const view) +{ + // Get initial window position and size + XWindowAttributes attrs; + XGetWindowAttributes(view->world->impl->display, view->impl->win, &attrs); + + // Build an initial configure event in case the WM doesn't send one + PuglEvent configureEvent = {{PUGL_CONFIGURE, 0}}; + configureEvent.configure.x = (PuglCoord)attrs.x; + configureEvent.configure.y = (PuglCoord)attrs.y; + configureEvent.configure.width = (PuglSpan)attrs.width; + configureEvent.configure.height = (PuglSpan)attrs.height; + + return puglDispatchEvent(view, &configureEvent); +} + static PuglStatus dispatchX11Events(PuglWorld* const world) { - const PuglX11Atoms* const atoms = &world->impl->atoms; + PuglStatus st0 = PUGL_SUCCESS; + PuglStatus st1 = PUGL_SUCCESS; // Flush output to the server once at the start Display* display = world->impl->display; @@ -1166,7 +1407,7 @@ dispatchX11Events(PuglWorld* const world) continue; } - PuglView* view = findView(world, xevent.xany.window); + PuglView* const view = findView(world, xevent.xany.window); if (!view) { continue; } @@ -1180,17 +1421,14 @@ dispatchX11Events(PuglWorld* const world) next.xkey.keycode == xevent.xkey.keycode) { continue; } - } else if (xevent.type == FocusIn) { - XSetICFocus(impl->xic); - } else if (xevent.type == FocusOut) { - XUnsetICFocus(impl->xic); } else if (xevent.type == SelectionClear) { - puglSetBlob(&view->clipboard, NULL, 0); - } else if (xevent.type == SelectionNotify && - xevent.xselection.selection == atoms->CLIPBOARD && - xevent.xselection.target == atoms->UTF8_STRING && - xevent.xselection.property == XA_PRIMARY) { - handleSelectionNotify(world, view); + PuglX11Clipboard* const board = + getX11SelectionClipboard(view, xevent.xselectionclear.selection); + if (board) { + clearX11Clipboard(board); + } + } else if (xevent.type == SelectionNotify) { + handleSelectionNotify(world, view, &xevent.xselection); } else if (xevent.type == SelectionRequest) { handleSelectionRequest(world, view, &xevent.xselectionrequest); } @@ -1198,34 +1436,40 @@ dispatchX11Events(PuglWorld* const world) // Translate X11 event to Pugl event const PuglEvent event = translateEvent(view, xevent); - if (event.type == PUGL_EXPOSE) { - // Expand expose event to be dispatched after loop - mergeExposeEvents(&view->impl->pendingExpose.expose, &event.expose); - } else if (event.type == PUGL_CONFIGURE) { + switch (event.type) { + case PUGL_CONFIGURE: // Update configure event to be dispatched after loop view->impl->pendingConfigure = event; - } else if (event.type == PUGL_MAP) { - // Get initial window position and size - XWindowAttributes attrs; - XGetWindowAttributes(view->impl->display, view->impl->win, &attrs); - - // Build an initial configure event in case the WM doesn't send one - PuglEvent configureEvent = {{PUGL_CONFIGURE, 0}}; - configureEvent.configure.x = (double)attrs.x; - configureEvent.configure.y = (double)attrs.y; - configureEvent.configure.width = (double)attrs.width; - configureEvent.configure.height = (double)attrs.height; - + break; + case PUGL_MAP: // Dispatch an initial configure (if necessary), then the map event - puglDispatchEvent(view, &configureEvent); - puglDispatchEvent(view, &event); - } else { + st0 = dispatchCurrentConfiguration(view); + st1 = puglDispatchEvent(view, &event); + break; + case PUGL_EXPOSE: + // Expand expose event to be dispatched after loop + mergeExposeEvents(&view->impl->pendingExpose.expose, &event.expose); + break; + case PUGL_FOCUS_IN: + // Set the input context focus + if (view->impl->xic) { + XSetICFocus(view->impl->xic); + } + break; + case PUGL_FOCUS_OUT: + // Unset the input context focus + if (view->impl->xic) { + XUnsetICFocus(view->impl->xic); + } + break; + default: // Dispatch event to application immediately - puglDispatchEvent(view, &event); + st0 = puglDispatchEvent(view, &event); + break; } } - return PUGL_SUCCESS; + return st0 ? st0 : st1; } #ifndef PUGL_DISABLE_DEPRECATED @@ -1240,32 +1484,33 @@ PuglStatus puglUpdate(PuglWorld* const world, const double timeout) { const double startTime = puglGetTime(world); - PuglStatus st = PUGL_SUCCESS; + PuglStatus st0 = PUGL_SUCCESS; + PuglStatus st1 = PUGL_SUCCESS; world->impl->dispatchingEvents = true; if (timeout < 0.0) { - st = pollX11Socket(world, timeout); - st = st ? st : dispatchX11Events(world); + st0 = pollX11Socket(world, timeout); + st0 = st0 ? st0 : dispatchX11Events(world); } else if (timeout <= 0.001) { - st = dispatchX11Events(world); + st0 = dispatchX11Events(world); } else { const double endTime = startTime + timeout - 0.001; double t = startTime; - while (!st && t < endTime) { - if (!(st = pollX11Socket(world, endTime - t))) { - st = dispatchX11Events(world); + while (!st0 && t < endTime) { + if (!(st0 = pollX11Socket(world, endTime - t))) { + st0 = dispatchX11Events(world); } t = puglGetTime(world); } } - flushExposures(world); + st1 = flushExposures(world); world->impl->dispatchingEvents = false; - return st; + return st0 ? st0 : st1; } double @@ -1305,7 +1550,7 @@ puglPostRedisplayRect(PuglView* const view, const PuglRect rect) } PuglNativeView -puglGetNativeWindow(PuglView* const view) +puglGetNativeView(PuglView* const view) { return (PuglNativeView)view->impl->win; } @@ -1333,16 +1578,22 @@ puglSetWindowTitle(PuglView* const view, const char* const title) return PUGL_SUCCESS; } +double +puglGetScaleFactor(const PuglView* const view) +{ + return view->world->impl->scaleFactor; +} + PuglStatus puglSetFrame(PuglView* const view, const PuglRect frame) { if (view->impl->win) { if (!XMoveResizeWindow(view->world->impl->display, view->impl->win, - (int)frame.x, - (int)frame.y, - (unsigned)frame.width, - (unsigned)frame.height)) { + frame.x, + frame.y, + frame.width, + frame.height)) { return PUGL_UNKNOWN_ERROR; } } @@ -1352,45 +1603,57 @@ puglSetFrame(PuglView* const view, const PuglRect frame) } PuglStatus -puglSetDefaultSize(PuglView* const view, const int width, const int height) +puglSetPosition(PuglView* const view, const int x, const int y) { - view->defaultWidth = width; - view->defaultHeight = height; - return updateSizeHints(view); -} + Display* const display = view->world->impl->display; + const Window win = view->impl->win; -PuglStatus -puglSetMinSize(PuglView* const view, const int width, const int height) -{ - view->minWidth = width; - view->minHeight = height; - return updateSizeHints(view); + if (x > INT16_MAX || y > INT16_MAX) { + return PUGL_BAD_PARAMETER; + } + + if (win && !XMoveWindow(display, win, x, y)) { + return PUGL_UNKNOWN_ERROR; + } + + view->frame.x = (PuglCoord)x; + view->frame.y = (PuglCoord)y; + return PUGL_SUCCESS; } PuglStatus -puglSetMaxSize(PuglView* const view, const int width, const int height) +puglSetSize(PuglView* const view, const unsigned width, const unsigned height) { - view->maxWidth = width; - view->maxHeight = height; - return updateSizeHints(view); + Display* const display = view->world->impl->display; + const Window win = view->impl->win; + + if (width > INT16_MAX || height > INT16_MAX) { + return PUGL_BAD_PARAMETER; + } + + if (win) { + return XResizeWindow(display, win, width, height) ? PUGL_SUCCESS + : PUGL_UNKNOWN_ERROR; + } + + view->frame.width = (PuglSpan)width; + view->frame.height = (PuglSpan)height; + return PUGL_SUCCESS; } PuglStatus -puglSetAspectRatio(PuglView* const view, - const int minX, - const int minY, - const int maxX, - const int maxY) +puglSetSizeHint(PuglView* const view, + const PuglSizeHint hint, + const PuglSpan width, + const PuglSpan height) { - view->minAspectX = minX; - view->minAspectY = minY; - view->maxAspectX = maxX; - view->maxAspectY = maxY; + view->sizeHints[hint].width = width; + view->sizeHints[hint].height = height; return updateSizeHints(view); } PuglStatus -puglSetTransientFor(PuglView* const view, const PuglNativeView parent) +puglSetTransientParent(PuglView* const view, const PuglNativeView parent) { Display* display = view->world->impl->display; @@ -1405,33 +1668,82 @@ puglSetTransientFor(PuglView* const view, const PuglNativeView parent) } const void* -puglGetClipboard(PuglView* const view, - const char** const type, - size_t* const len) +puglGetClipboard(PuglView* const view, + const uint32_t typeIndex, + size_t* const len) { - PuglInternals* const impl = view->impl; - const PuglX11Atoms* const atoms = &view->world->impl->atoms; + Display* const display = view->world->impl->display; + PuglX11Clipboard* const board = &view->impl->clipboard; - const Window owner = XGetSelectionOwner(impl->display, atoms->CLIPBOARD); - if (owner != None && owner != impl->win) { - // Clear internal selection - puglSetBlob(&view->clipboard, NULL, 0); - - // Request selection from the owner - XConvertSelection(impl->display, - atoms->CLIPBOARD, - atoms->UTF8_STRING, - XA_PRIMARY, - impl->win, - CurrentTime); - - // Run event loop until data is received, within limits - for (int i=500; !view->clipboard.data && --i >= 0;) { - puglUpdate(view->world, -1.0); - } + if (typeIndex != board->acceptedFormatIndex) { + return NULL; } - return puglGetInternalClipboard(view, type, len); + const Window owner = XGetSelectionOwner(display, board->selection); + if (!owner || owner != board->source) { + *len = 0; + return NULL; + } + + *len = board->data.len; + return board->data.data; +} + +PuglStatus +puglAcceptOffer(PuglView* const view, + const PuglDataOfferEvent* const offer, + const uint32_t typeIndex) +{ + (void)offer; + + PuglInternals* const impl = view->impl; + Display* const display = view->world->impl->display; + PuglX11Clipboard* const board = &view->impl->clipboard; + + board->acceptedFormatIndex = typeIndex; + board->acceptedFormat = board->formats[typeIndex]; + + // Request the data in the specified type from the general clipboard + XConvertSelection(display, + board->selection, + board->acceptedFormat, + board->property, + impl->win, + CurrentTime); + + return PUGL_SUCCESS; +} + +PuglStatus +puglPaste(PuglView* const view) +{ + Display* const display = view->world->impl->display; + const PuglX11Atoms* atoms = &view->world->impl->atoms; + const PuglX11Clipboard* board = &view->impl->clipboard; + + // Request a SelectionNotify for TARGETS (available datatypes) + XConvertSelection(display, + board->selection, + atoms->TARGETS, + board->property, + view->impl->win, + CurrentTime); + + return PUGL_SUCCESS; +} + +uint32_t +puglGetNumClipboardTypes(const PuglView* const view) +{ + return (uint32_t)view->impl->clipboard.numFormats; +} + +const char* +puglGetClipboardType(const PuglView* const view, const uint32_t typeIndex) +{ + const PuglX11Clipboard* const board = &view->impl->clipboard; + + return typeIndex < board->numFormats ? board->formatStrings[typeIndex] : NULL; } PuglStatus @@ -1440,12 +1752,18 @@ puglSetClipboard(PuglView* const view, const void* const data, const size_t len) { - PuglInternals* const impl = view->impl; - const PuglX11Atoms* const atoms = &view->world->impl->atoms; + PuglInternals* const impl = view->impl; + Display* const display = view->world->impl->display; + PuglX11Clipboard* const board = &view->impl->clipboard; + const PuglStatus st = puglSetBlob(&board->data, data, len); - PuglStatus st = puglSetInternalClipboard(view, type, data, len); if (!st) { - XSetSelectionOwner(impl->display, atoms->CLIPBOARD, impl->win, CurrentTime); + const Atom format = {XInternAtom(display, type, 0)}; + + setClipboardFormats(view, board, 1, &format); + XSetSelectionOwner(display, board->selection, impl->win, CurrentTime); + + board->source = impl->win; } return st; @@ -1457,17 +1775,17 @@ puglSetCursor(PuglView* const view, const PuglCursor cursor) #ifdef HAVE_XCURSOR PuglInternals* const impl = view->impl; const unsigned index = (unsigned)cursor; - const unsigned count = sizeof(cursor_names_x11) / sizeof(cursor_names_x11[0]); + const unsigned count = sizeof(cursor_names) / sizeof(cursor_names[0]); if (index >= count) { return PUGL_BAD_PARAMETER; } - const char* name = cursor_names_x11[index]; + const char* const name = cursor_names[index]; if (!impl->win || impl->cursorName == name) { return PUGL_SUCCESS; } - impl->cursorName = cursor_names_x11[index]; + impl->cursorName = cursor_names[index]; return defineCursorName(view, impl->cursorName); #else @@ -1482,12 +1800,15 @@ puglSetCursor(PuglView* const view, const PuglCursor cursor) PuglStatus puglX11Configure(PuglView* view) { - PuglInternals* const impl = view->impl; - XVisualInfo pat = PUGL_INIT_STRUCT; - int n = 0; + PuglInternals* const impl = view->impl; + Display* const display = view->world->impl->display; + XVisualInfo pat = PUGL_INIT_STRUCT; + int n = 0; pat.screen = impl->screen; - impl->vi = XGetVisualInfo(impl->display, VisualScreenMask, &pat, &n); + if (!(impl->vi = XGetVisualInfo(display, VisualScreenMask, &pat, &n))) { + return PUGL_BAD_CONFIGURATION; + } view->hints[PUGL_RED_BITS] = impl->vi->bits_per_rgb; view->hints[PUGL_GREEN_BITS] = impl->vi->bits_per_rgb; diff --git a/dpf/dgl/src/pugl-upstream/src/x11.h b/dpf/dgl/src/pugl-upstream/src/x11.h index 8c7985f..27cfb73 100644 --- a/dpf/dgl/src/pugl-upstream/src/x11.h +++ b/dpf/dgl/src/pugl-upstream/src/x11.h @@ -1,22 +1,10 @@ -/* - Copyright 2012-2021 David Robillard +// Copyright 2012-2022 David Robillard +// SPDX-License-Identifier: ISC - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef PUGL_DETAIL_X11_H -#define PUGL_DETAIL_X11_H +#ifndef PUGL_SRC_X11_H +#define PUGL_SRC_X11_H +#include "attributes.h" #include "types.h" #include "pugl/pugl.h" @@ -39,6 +27,8 @@ typedef struct { Atom NET_WM_STATE; Atom NET_WM_STATE_DEMANDS_ATTENTION; Atom NET_WM_STATE_HIDDEN; + Atom TARGETS; + Atom text_uri_list; } PuglX11Atoms; typedef struct { @@ -47,10 +37,23 @@ typedef struct { uintptr_t id; } PuglTimer; +typedef struct { + Atom selection; + Atom property; + Window source; + Atom* formats; + char** formatStrings; + unsigned long numFormats; + uint32_t acceptedFormatIndex; + Atom acceptedFormat; + PuglBlob data; +} PuglX11Clipboard; + struct PuglWorldInternalsImpl { Display* display; PuglX11Atoms atoms; XIM xim; + double scaleFactor; PuglTimer* timers; size_t numTimers; XID serverTimeCounter; @@ -60,21 +63,20 @@ struct PuglWorldInternalsImpl { }; struct PuglInternalsImpl { - Display* display; - XVisualInfo* vi; - Window win; - XIC xic; - PuglSurface* surface; - PuglEvent pendingConfigure; - PuglEvent pendingExpose; - int screen; -#ifdef HAVE_XCURSOR - const char* cursorName; -#endif + XVisualInfo* vi; + Window win; + XIC xic; + PuglSurface* surface; + PuglEvent pendingConfigure; + PuglEvent pendingExpose; + PuglX11Clipboard clipboard; + int screen; + const char* cursorName; }; +PUGL_WARN_UNUSED_RESULT PUGL_API PuglStatus puglX11Configure(PuglView* view); -#endif // PUGL_DETAIL_X11_H +#endif // PUGL_SRC_X11_H diff --git a/dpf/dgl/src/pugl-upstream/src/x11_cairo.c b/dpf/dgl/src/pugl-upstream/src/x11_cairo.c index 6bb1254..74de735 100644 --- a/dpf/dgl/src/pugl-upstream/src/x11_cairo.c +++ b/dpf/dgl/src/pugl-upstream/src/x11_cairo.c @@ -1,18 +1,5 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ +// Copyright 2012-2022 David Robillard +// SPDX-License-Identifier: ISC #include "types.h" #include "x11.h" @@ -49,7 +36,7 @@ puglX11CairoOpen(PuglView* view) PuglInternals* const impl = view->impl; PuglX11CairoSurface* const surface = (PuglX11CairoSurface*)impl->surface; - surface->back = cairo_xlib_surface_create(impl->display, + surface->back = cairo_xlib_surface_create(view->world->impl->display, impl->win, impl->vi->visual, (int)view->frame.width, @@ -80,7 +67,7 @@ puglX11CairoCreate(PuglView* view) return PUGL_SUCCESS; } -static PuglStatus +static void puglX11CairoDestroy(PuglView* view) { PuglInternals* const impl = view->impl; @@ -88,8 +75,6 @@ puglX11CairoDestroy(PuglView* view) puglX11CairoClose(view); free(surface); - - return PUGL_SUCCESS; } static PuglStatus diff --git a/dpf/dgl/src/pugl-upstream/src/x11_gl.c b/dpf/dgl/src/pugl-upstream/src/x11_gl.c index ac2659b..2e15092 100644 --- a/dpf/dgl/src/pugl-upstream/src/x11_gl.c +++ b/dpf/dgl/src/pugl-upstream/src/x11_gl.c @@ -1,19 +1,7 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ +// Copyright 2012-2022 David Robillard +// SPDX-License-Identifier: ISC +#include "attributes.h" #include "stub.h" #include "types.h" #include "x11.h" @@ -28,6 +16,7 @@ #include #include #include +#include typedef struct { GLXFBConfig fb_config; @@ -55,7 +44,7 @@ puglX11GlConfigure(PuglView* view) { PuglInternals* const impl = view->impl; const int screen = impl->screen; - Display* const display = impl->display; + Display* const display = view->world->impl->display; PuglX11GlSurface* const surface = (PuglX11GlSurface*)calloc(1, sizeof(PuglX11GlSurface)); @@ -63,9 +52,6 @@ puglX11GlConfigure(PuglView* view) // clang-format off const int attrs[] = { -#ifdef DGL_USE_RGBA - GLX_RGBA, -#endif GLX_X_RENDERABLE, True, GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, @@ -89,7 +75,7 @@ puglX11GlConfigure(PuglView* view) } surface->fb_config = fbc[0]; - impl->vi = glXGetVisualFromFBConfig(impl->display, fbc[0]); + impl->vi = glXGetVisualFromFBConfig(display, fbc[0]); view->hints[PUGL_RED_BITS] = puglX11GlGetAttrib(display, fbc[0], GLX_RED_SIZE); @@ -112,24 +98,31 @@ puglX11GlConfigure(PuglView* view) return PUGL_SUCCESS; } +PUGL_WARN_UNUSED_RESULT static PuglStatus puglX11GlEnter(PuglView* view, const PuglExposeEvent* PUGL_UNUSED(expose)) { PuglX11GlSurface* surface = (PuglX11GlSurface*)view->impl->surface; - glXMakeCurrent(view->impl->display, view->impl->win, surface->ctx); - return PUGL_SUCCESS; + Display* const display = view->world->impl->display; + if (!surface || !surface->ctx) { + return PUGL_FAILURE; + } + + return glXMakeCurrent(display, view->impl->win, surface->ctx) ? PUGL_SUCCESS + : PUGL_FAILURE; } +PUGL_WARN_UNUSED_RESULT static PuglStatus puglX11GlLeave(PuglView* view, const PuglExposeEvent* expose) { + Display* const display = view->world->impl->display; + if (expose && view->hints[PUGL_DOUBLE_BUFFER]) { - glXSwapBuffers(view->impl->display, view->impl->win); + glXSwapBuffers(display, view->impl->win); } - glXMakeCurrent(view->impl->display, None, NULL); - - return PUGL_SUCCESS; + return glXMakeCurrent(display, None, NULL) ? PUGL_SUCCESS : PUGL_FAILURE; } static PuglStatus @@ -137,8 +130,9 @@ puglX11GlCreate(PuglView* view) { PuglInternals* const impl = view->impl; PuglX11GlSurface* const surface = (PuglX11GlSurface*)impl->surface; - Display* const display = impl->display; + Display* const display = view->world->impl->display; GLXFBConfig fb_config = surface->fb_config; + PuglStatus st = PUGL_SUCCESS; const int ctx_attrs[] = { GLX_CONTEXT_MAJOR_VERSION_ARB, @@ -156,15 +150,19 @@ puglX11GlCreate(PuglView* view) : GLX_CONTEXT_CORE_PROFILE_BIT_ARB), 0}; - PFNGLXCREATECONTEXTATTRIBSARBPROC create_context = - (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress( - (const uint8_t*)"glXCreateContextAttribsARB"); + const char* const extensions = + glXQueryExtensionsString(display, view->impl->screen); - PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT = - (PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddress( - (const uint8_t*)"glXSwapIntervalEXT"); + // Try to create a modern context + if (!!strstr(extensions, "GLX_ARB_create_context")) { + PFNGLXCREATECONTEXTATTRIBSARBPROC create_context = + (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress( + (const uint8_t*)"glXCreateContextAttribsARB"); - surface->ctx = create_context(display, fb_config, 0, True, ctx_attrs); + surface->ctx = create_context(display, fb_config, 0, True, ctx_attrs); + } + + // If that failed, fall back to the legacy API if (!surface->ctx) { surface->ctx = glXCreateNewContext(display, fb_config, GLX_RGBA_TYPE, 0, True); @@ -174,36 +172,50 @@ puglX11GlCreate(PuglView* view) return PUGL_CREATE_CONTEXT_FAILED; } - const int swapInterval = view->hints[PUGL_SWAP_INTERVAL]; - if (glXSwapIntervalEXT && swapInterval != PUGL_DONT_CARE) { - puglX11GlEnter(view, NULL); - glXSwapIntervalEXT(display, impl->win, swapInterval); - puglX11GlLeave(view, NULL); + // Set up the swap interval + if (!!strstr(extensions, "GLX_EXT_swap_control")) { + PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT = + (PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddress( + (const uint8_t*)"glXSwapIntervalEXT"); + + // Note that some drivers (NVidia) require the context to be entered here + if ((st = puglX11GlEnter(view, NULL))) { + return st; + } + + // Set the swap interval if the user requested a specific value + if (view->hints[PUGL_SWAP_INTERVAL] != PUGL_DONT_CARE) { + glXSwapIntervalEXT(display, impl->win, view->hints[PUGL_SWAP_INTERVAL]); + } + + // Get the actual current swap interval + glXQueryDrawable(display, + impl->win, + GLX_SWAP_INTERVAL_EXT, + (unsigned int*)&view->hints[PUGL_SWAP_INTERVAL]); + + if ((st = puglX11GlLeave(view, NULL))) { + return st; + } } - glXGetConfig(impl->display, - impl->vi, - GLX_DOUBLEBUFFER, - &view->hints[PUGL_DOUBLE_BUFFER]); - - glXQueryDrawable(display, - impl->win, - GLX_SWAP_INTERVAL_EXT, - (unsigned int*)&view->hints[PUGL_SWAP_INTERVAL]); - - return PUGL_SUCCESS; + return !glXGetConfig(display, + impl->vi, + GLX_DOUBLEBUFFER, + &view->hints[PUGL_DOUBLE_BUFFER]) + ? PUGL_SUCCESS + : PUGL_UNKNOWN_ERROR; } -static PuglStatus +static void puglX11GlDestroy(PuglView* view) { PuglX11GlSurface* surface = (PuglX11GlSurface*)view->impl->surface; if (surface) { - glXDestroyContext(view->impl->display, surface->ctx); + glXDestroyContext(view->world->impl->display, surface->ctx); free(surface); view->impl->surface = NULL; } - return PUGL_SUCCESS; } PuglGlFunc diff --git a/dpf/dgl/src/pugl-upstream/src/x11_stub.c b/dpf/dgl/src/pugl-upstream/src/x11_stub.c index 856f90c..844b4db 100644 --- a/dpf/dgl/src/pugl-upstream/src/x11_stub.c +++ b/dpf/dgl/src/pugl-upstream/src/x11_stub.c @@ -1,18 +1,5 @@ -/* - Copyright 2012-2021 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ +// Copyright 2012-2021 David Robillard +// SPDX-License-Identifier: ISC #include "pugl/stub.h" diff --git a/dpf/dgl/src/pugl-upstream/src/x11_vulkan.c b/dpf/dgl/src/pugl-upstream/src/x11_vulkan.c index 857c41b..72ff701 100644 --- a/dpf/dgl/src/pugl-upstream/src/x11_vulkan.c +++ b/dpf/dgl/src/pugl-upstream/src/x11_vulkan.c @@ -1,21 +1,9 @@ -/* - Copyright 2012-2021 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ +// Copyright 2012-2022 David Robillard +// SPDX-License-Identifier: ISC #define VK_NO_PROTOTYPES 1 +#include "attributes.h" #include "stub.h" #include "types.h" #include "x11.h" diff --git a/dpf/dgl/src/pugl-upstream/test/.clang-tidy b/dpf/dgl/src/pugl-upstream/test/.clang-tidy deleted file mode 100644 index f3a1adc..0000000 --- a/dpf/dgl/src/pugl-upstream/test/.clang-tidy +++ /dev/null @@ -1,18 +0,0 @@ -Checks: > - *, - -*-magic-numbers, - -*-uppercase-literal-suffix, - -altera-struct-pack-align, - -bugprone-reserved-identifier, - -bugprone-suspicious-include, - -cert-dcl37-c, - -cert-dcl51-cpp, - -google-runtime-references, - -hicpp-multiway-paths-covered, - -hicpp-signed-bitwise, - -llvm-header-guard, - -llvmlibc-*, - -modernize-use-trailing-return-type, - -readability-function-cognitive-complexity, -FormatStyle: file -HeaderFilterRegex: 'pugl/.*|test/.*' diff --git a/dpf/dgl/src/pugl-upstream/test/meson.build b/dpf/dgl/src/pugl-upstream/test/meson.build deleted file mode 100644 index a50b6c7..0000000 --- a/dpf/dgl/src/pugl-upstream/test/meson.build +++ /dev/null @@ -1,167 +0,0 @@ -# Suppress some additional C warnings in tests -test_c_args = [] -if get_option('strict') - if cc.get_id() == 'clang' - test_c_args += [ - '-Wno-float-equal', - ] - elif cc.get_id() == 'gcc' - test_c_args += [ - '-Wno-float-equal', - ] - endif - - test_c_args = cc.get_supported_arguments(test_c_args) -endif - -# Suppress some additional C++ warnings in tests -test_cpp_args = [] -if get_option('strict') and is_variable('cpp') - if cpp.get_id() == 'clang' - test_cpp_args += [ - '-Wno-documentation', # Cairo - '-Wno-documentation-unknown-command', # Cairo - '-Wno-old-style-cast', - '-Wno-padded', - ] - elif cpp.get_id() == 'gcc' - test_cpp_args += [ - '-Wno-padded', - ] - endif - - test_cpp_args = cpp.get_supported_arguments(test_cpp_args) -endif - -basic_tests = [ - 'local_copy_paste', - 'realize', - 'redisplay', - 'remote_copy_paste', - 'show_hide', - 'size', - 'strerror', - 'stub', - 'stub_hints', - 'timer', - 'update', - 'view', - 'world', -] - -cairo_tests = [ - 'cairo' -] - -gl_tests = [ - 'gl', - 'gl_hints' -] - -vulkan_tests = [ - 'vulkan' -] - -includes = [ - '.', - '../include', -] - -foreach test : basic_tests - test(test, - executable('test_' + test, 'test_@0@.c'.format(test), - c_args: test_c_args, - include_directories: include_directories(includes), - dependencies: [pugl_dep, stub_backend_dep])) -endforeach - -if opengl_dep.found() - foreach test : gl_tests - test(test, - executable('test_' + test, 'test_@0@.c'.format(test), - c_args: test_c_args, - include_directories: include_directories(includes), - dependencies: [pugl_dep, gl_backend_dep])) - endforeach -endif - -if cairo_dep.found() - foreach test : cairo_tests - test(test, - executable('test_' + test, 'test_@0@.c'.format(test), - c_args: test_c_args, - include_directories: include_directories(includes), - dependencies: [pugl_dep, cairo_backend_dep])) - endforeach -endif - -if vulkan_dep.found() - foreach test : vulkan_tests - test(test, - executable('test_' + test, 'test_@0@.c'.format(test), - c_args: test_c_args, - cpp_args: test_cpp_args, - include_directories: include_directories(includes), - dependencies: [pugl_dep, vulkan_backend_dep])) - endforeach -endif - -unified_args = [] -unified_deps = [core_deps] -if cairo_dep.found() - unified_args += ['-DWITH_CAIRO'] - unified_deps += [cairo_dep] -endif - -if opengl_dep.found() - unified_args += ['-DWITH_OPENGL'] - unified_deps += [opengl_dep] -endif - -if vulkan_dep.found() - unified_args += ['-DWITH_VULKAN'] - unified_deps += [vulkan_deps] -endif - -if host_machine.system() == 'darwin' - add_languages(['objcpp']) - - objcpp = meson.get_compiler('objcpp') - unified_args += objcpp.get_supported_arguments( - c_warnings + test_cpp_args + objc_warnings) - - executable('inline_objcpp', 'test_inline_objcpp.mm', - include_directories: include_directories(includes), - dependencies: unified_deps, - objcpp_args: unified_args) - -elif is_variable('cpp') - unified_args = [] - - if cpp.get_id() == 'clang' - unified_args += [ - '-Wno-old-style-cast', - '-Wno-reserved-id-macro', - '-Wno-switch-default', - '-Wno-switch-enum', - '-Wno-unused-macros', # Mac - ] - elif cpp.get_id() == 'gcc' - unified_args += [ - '-Wno-conditionally-supported', - '-Wno-old-style-cast', - '-Wno-switch-default', - '-Wno-switch-enum', - '-Wno-useless-cast', - ] - elif cpp.get_id() == 'msvc' - unified_args += [ - '/wd4464' # relative include path contains '..' - ] - endif - - executable('inline_cpp', 'test_inline_cpp.cpp', - include_directories: include_directories(includes), - dependencies: unified_deps, - cpp_args: test_cpp_args + unified_args) -endif diff --git a/dpf/dgl/src/pugl-upstream/test/test_build.c b/dpf/dgl/src/pugl-upstream/test/test_build.c deleted file mode 100644 index 957e0bd..0000000 --- a/dpf/dgl/src/pugl-upstream/test/test_build.c +++ /dev/null @@ -1,32 +0,0 @@ -/* - Copyright 2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/* - Tests that C headers compile without any warnings. -*/ - -#define PUGL_DISABLE_DEPRECATED - -#include "pugl/cairo.h" // IWYU pragma: keep -#include "pugl/gl.h" // IWYU pragma: keep -#include "pugl/pugl.h" // IWYU pragma: keep -#include "pugl/stub.h" // IWYU pragma: keep - -int -main(void) -{ - return 0; -} diff --git a/dpf/dgl/src/pugl-upstream/test/test_build.cpp b/dpf/dgl/src/pugl-upstream/test/test_build.cpp deleted file mode 100644 index 20235e8..0000000 --- a/dpf/dgl/src/pugl-upstream/test/test_build.cpp +++ /dev/null @@ -1,33 +0,0 @@ -/* - Copyright 2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/* - Tests that C++ headers compile without any warnings. -*/ - -#define PUGL_DISABLE_DEPRECATED - -#include "pugl/cairo.hpp" // IWYU pragma: keep -#include "pugl/gl.hpp" // IWYU pragma: keep -#include "pugl/pugl.h" // IWYU pragma: keep -#include "pugl/pugl.hpp" // IWYU pragma: keep -#include "pugl/stub.hpp" // IWYU pragma: keep - -int -main() -{ - return 0; -} diff --git a/dpf/dgl/src/pugl-upstream/test/test_cairo.c b/dpf/dgl/src/pugl-upstream/test/test_cairo.c deleted file mode 100644 index 2e14121..0000000 --- a/dpf/dgl/src/pugl-upstream/test/test_cairo.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - Copyright 2021 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -// Tests that creating a view with a Cairo backend works - -#undef NDEBUG - -#include "test_utils.h" - -#include "pugl/cairo.h" -#include "pugl/pugl.h" - -#include - -#include -#include - -typedef struct { - PuglWorld* world; - PuglView* view; - PuglTestOptions opts; - bool exposed; -} PuglTest; - -static void -onExpose(PuglView* const view, const PuglExposeEvent* const event) -{ - cairo_t* const cr = (cairo_t*)puglGetContext(view); - - assert(cr); - - cairo_rectangle(cr, event->x, event->y, event->width, event->height); - cairo_set_source_rgb(cr, 0, 1, 0); - cairo_fill(cr); -} - -static PuglStatus -onEvent(PuglView* const view, const PuglEvent* const event) -{ - PuglTest* const test = (PuglTest*)puglGetHandle(view); - - if (test->opts.verbose) { - printEvent(event, "Event: ", true); - } - - if (event->type == PUGL_EXPOSE) { - onExpose(view, &event->expose); - test->exposed = true; - } - - return PUGL_SUCCESS; -} - -int -main(int argc, char** argv) -{ - PuglWorld* const world = puglNewWorld(PUGL_PROGRAM, 0); - PuglView* const view = puglNewView(world); - const PuglTestOptions opts = puglParseTestOptions(&argc, &argv); - PuglTest test = {world, view, opts, false}; - - // Set up and show view - puglSetClassName(test.world, "Pugl Test"); - puglSetWindowTitle(test.view, "Pugl Cairo Test"); - puglSetHandle(test.view, &test); - puglSetBackend(test.view, puglCairoBackend()); - puglSetEventFunc(test.view, onEvent); - puglSetDefaultSize(test.view, 512, 512); - puglShow(test.view); - - // Drive event loop until the view gets exposed - while (!test.exposed) { - puglUpdate(test.world, -1.0); - } - - // Tear down - puglFreeView(test.view); - puglFreeWorld(test.world); - - return 0; -} diff --git a/dpf/dgl/src/pugl-upstream/test/test_clipboard.c b/dpf/dgl/src/pugl-upstream/test/test_clipboard.c deleted file mode 100644 index fc08afd..0000000 --- a/dpf/dgl/src/pugl-upstream/test/test_clipboard.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - Copyright 2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/* - Tests basic clipboard copy/paste functionality between two views. -*/ - -#undef NDEBUG - -#include "test_utils.h" - -#include "pugl/pugl.h" -#include "pugl/stub.h" - -#include -#include -#include -#include - -typedef struct { - PuglWorld* world; - PuglView* views[2]; - PuglTestOptions opts; - bool exposed; -} PuglTest; - -static PuglStatus -onEvent(PuglView* view, const PuglEvent* event) -{ - PuglTest* test = (PuglTest*)puglGetHandle(view); - - if (event->type == PUGL_EXPOSE) { - test->exposed = true; - } - - if (test->opts.verbose) { - printEvent(event, "Event: ", true); - } - - return PUGL_SUCCESS; -} - -int -main(int argc, char** argv) -{ - PuglTest test = {puglNewWorld(PUGL_PROGRAM, 0), - {NULL, NULL}, - puglParseTestOptions(&argc, &argv), - false}; - - puglSetClassName(test.world, "Pugl Test"); - - // Set up views - for (unsigned i = 0u; i < 2; ++i) { - test.views[i] = puglNewView(test.world); - puglSetWindowTitle(test.world, "Pugl Clipboard Test"); - puglSetBackend(test.views[i], puglStubBackend()); - puglSetHandle(test.views[i], &test); - puglSetEventFunc(test.views[i], onEvent); - puglSetDefaultSize(test.views[i], 512, 512); - - assert(!puglShow(test.views[i])); - } - - // Update until view is exposed - while (!test.exposed) { - assert(!puglUpdate(test.world, 0.0)); - } - - // Set clipboard text via the first view - puglSetClipboard(test.views[0], NULL, "Text", 5); - - // Get clipboard contents via the second view - const char* type = NULL; - size_t len = 0; - const void* const contents = puglGetClipboard(test.views[1], &type, &len); - - // Check that the data made it over - assert(!strcmp(type, "text/plain")); - assert(len == 5); - assert(contents); - assert(!strcmp((const char*)contents, "Text")); - - // Try setting the clipboard to an unsupported type - assert(puglSetClipboard(test.views[0], "text/csv", "a,b,c", 6)); - - // Tear down - puglFreeView(test.views[0]); - puglFreeView(test.views[1]); - puglFreeWorld(test.world); - - return 0; -} diff --git a/dpf/dgl/src/pugl-upstream/test/test_gl.c b/dpf/dgl/src/pugl-upstream/test/test_gl.c deleted file mode 100644 index a339939..0000000 --- a/dpf/dgl/src/pugl-upstream/test/test_gl.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - Copyright 2021 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -// Tests basic OpenGL support - -#undef NDEBUG - -#include "test_utils.h" - -#include "pugl/gl.h" -#include "pugl/pugl.h" - -#include -#include - -typedef struct { - PuglWorld* world; - PuglView* view; - PuglTestOptions opts; - bool exposed; -} PuglTest; - -static void -onConfigure(PuglView* const view, const PuglConfigureEvent* const event) -{ - (void)view; - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - glViewport(0, 0, (int)event->width, (int)event->height); -} - -static void -onExpose(PuglView* const view, const PuglExposeEvent* const event) -{ - (void)view; - (void)event; - - glClearColor(0.0f, 0.0f, 1.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); -} - -static PuglStatus -onEvent(PuglView* const view, const PuglEvent* const event) -{ - PuglTest* const test = (PuglTest*)puglGetHandle(view); - - if (test->opts.verbose) { - printEvent(event, "Event: ", true); - } - - switch (event->type) { - case PUGL_CONFIGURE: - onConfigure(view, &event->configure); - break; - - case PUGL_EXPOSE: - onExpose(view, &event->expose); - test->exposed = true; - break; - - default: - break; - } - - return PUGL_SUCCESS; -} - -int -main(int argc, char** argv) -{ - PuglWorld* const world = puglNewWorld(PUGL_PROGRAM, 0); - PuglView* const view = puglNewView(world); - const PuglTestOptions opts = puglParseTestOptions(&argc, &argv); - PuglTest test = {world, view, opts, false}; - - // Set up and show view - puglSetClassName(test.world, "Pugl OpenGL Test"); - puglSetHandle(test.view, &test); - puglSetBackend(test.view, puglGlBackend()); - puglSetEventFunc(test.view, onEvent); - puglSetDefaultSize(test.view, 512, 512); - puglShow(test.view); - - // Enter OpenGL context as if setting things up - puglEnterContext(test.view); - - const PuglGlFunc createProgram = puglGetProcAddress("glCreateProgram"); - assert(createProgram); - - puglLeaveContext(test.view); - - // Drive event loop until the view gets exposed - while (!test.exposed) { - puglUpdate(test.world, -1.0); - } - - // Tear down - puglFreeView(test.view); - puglFreeWorld(test.world); - - return 0; -} diff --git a/dpf/dgl/src/pugl-upstream/test/test_gl_hints.c b/dpf/dgl/src/pugl-upstream/test/test_gl_hints.c deleted file mode 100644 index 6fce42c..0000000 --- a/dpf/dgl/src/pugl-upstream/test/test_gl_hints.c +++ /dev/null @@ -1,102 +0,0 @@ -/* - Copyright 2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/* - Tests that all hints are set to real values after a view is realized. -*/ - -#undef NDEBUG - -#include "test_utils.h" - -#include "pugl/gl.h" -#include "pugl/pugl.h" - -#include - -static PuglStatus -onEvent(PuglView* view, const PuglEvent* event) -{ - (void)view; - (void)event; - - return PUGL_SUCCESS; -} - -int -main(void) -{ - PuglWorld* const world = puglNewWorld(PUGL_PROGRAM, 0); - PuglView* const view = puglNewView(world); - - // Set up view - puglSetClassName(world, "Pugl Test"); - puglSetWindowTitle(view, "Pugl OpenGL Hints Test"); - puglSetBackend(view, puglGlBackend()); - puglSetEventFunc(view, onEvent); - puglSetDefaultSize(view, 512, 512); - - // Check invalid cases - assert(puglSetViewHint(view, PUGL_USE_COMPAT_PROFILE, PUGL_DONT_CARE) == - PUGL_BAD_PARAMETER); - assert(puglSetViewHint(view, PUGL_USE_DEBUG_CONTEXT, PUGL_DONT_CARE) == - PUGL_BAD_PARAMETER); - assert(puglSetViewHint(view, PUGL_CONTEXT_VERSION_MAJOR, PUGL_DONT_CARE) == - PUGL_BAD_PARAMETER); - assert(puglSetViewHint(view, PUGL_CONTEXT_VERSION_MINOR, PUGL_DONT_CARE) == - PUGL_BAD_PARAMETER); - assert(puglSetViewHint(view, PUGL_SWAP_INTERVAL, PUGL_DONT_CARE) == - PUGL_BAD_PARAMETER); - - // Set all hints that support it to PUGL_DONT_CARE - assert(!puglSetViewHint(view, PUGL_RED_BITS, PUGL_DONT_CARE)); - assert(!puglSetViewHint(view, PUGL_GREEN_BITS, PUGL_DONT_CARE)); - assert(!puglSetViewHint(view, PUGL_BLUE_BITS, PUGL_DONT_CARE)); - assert(!puglSetViewHint(view, PUGL_ALPHA_BITS, PUGL_DONT_CARE)); - assert(!puglSetViewHint(view, PUGL_DEPTH_BITS, PUGL_DONT_CARE)); - assert(!puglSetViewHint(view, PUGL_STENCIL_BITS, PUGL_DONT_CARE)); - assert(!puglSetViewHint(view, PUGL_SAMPLES, PUGL_DONT_CARE)); - assert(!puglSetViewHint(view, PUGL_DOUBLE_BUFFER, PUGL_DONT_CARE)); - assert(!puglSetViewHint(view, PUGL_REFRESH_RATE, PUGL_DONT_CARE)); - - // Realize view and print all hints for debugging convenience - assert(!puglRealize(view)); - printViewHints(view); - - // Check that no hints are set to PUGL_DONT_CARE - assert(puglGetViewHint(view, PUGL_USE_COMPAT_PROFILE) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_USE_DEBUG_CONTEXT) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_CONTEXT_VERSION_MAJOR) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_CONTEXT_VERSION_MINOR) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_RED_BITS) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_GREEN_BITS) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_BLUE_BITS) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_ALPHA_BITS) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_DEPTH_BITS) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_STENCIL_BITS) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_SAMPLES) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_DOUBLE_BUFFER) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_SWAP_INTERVAL) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_RESIZABLE) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_IGNORE_KEY_REPEAT) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_REFRESH_RATE) != PUGL_DONT_CARE); - - // Tear down - puglFreeView(view); - puglFreeWorld(world); - - return 0; -} diff --git a/dpf/dgl/src/pugl-upstream/test/test_inline_cpp.cpp b/dpf/dgl/src/pugl-upstream/test/test_inline_cpp.cpp deleted file mode 100644 index de26d73..0000000 --- a/dpf/dgl/src/pugl-upstream/test/test_inline_cpp.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - Copyright 2021 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -// Tests that the implementation compiles as included C++ - -#define PUGL_API - -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" -# pragma clang diagnostic ignored "-Wold-style-cast" -#elif defined(__GNUC__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" -#endif - -#include "../src/implementation.c" // IWYU pragma: keep - -#if defined(_WIN32) -# include "../src/win.c" // IWYU pragma: keep -# include "../src/win.h" // IWYU pragma: keep -# include "../src/win_stub.c" // IWYU pragma: keep -# if defined(WITH_CAIRO) -# include "../src/win_cairo.c" // IWYU pragma: keep -# endif -# if defined(WITH_OPENGL) -# include "../src/win_gl.c" // IWYU pragma: keep -# endif -# if defined(WITH_VULKAN) -# include "../src/win_vulkan.c" // IWYU pragma: keep -# endif - -#else -# include "../src/x11.c" // IWYU pragma: keep -# include "../src/x11_stub.c" // IWYU pragma: keep -# if defined(WITH_CAIRO) -# include "../src/x11_cairo.c" // IWYU pragma: keep -# endif -# if defined(WITH_OPENGL) -# include "../src/x11_gl.c" // IWYU pragma: keep -# endif -# if defined(WITH_VULKAN) -# include "../src/x11_vulkan.c" // IWYU pragma: keep -# endif -#endif - -#if defined(__clang__) -# pragma clang diagnostic pop -#elif defined(__GNUC__) -# pragma GCC diagnostic pop -#endif - -int -main() -{ - return 0; -} diff --git a/dpf/dgl/src/pugl-upstream/test/test_inline_objcpp.mm b/dpf/dgl/src/pugl-upstream/test/test_inline_objcpp.mm deleted file mode 100644 index 7be9b50..0000000 --- a/dpf/dgl/src/pugl-upstream/test/test_inline_objcpp.mm +++ /dev/null @@ -1,50 +0,0 @@ -/* - Copyright 2021 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -// Tests that the implementation compiles as included ObjC++ - -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" -# pragma clang diagnostic ignored "-Wold-style-cast" -#endif - -#include "../src/implementation.c" // IWYU pragma: keep -#include "../src/mac.h" // IWYU pragma: keep -#include "../src/mac.m" // IWYU pragma: keep -#include "../src/mac_stub.m" // IWYU pragma: keep - -#if defined(WITH_CAIRO) -# include "../src/mac_cairo.m" // IWYU pragma: keep -#endif - -#if defined(WITH_OPENGL) -# include "../src/mac_gl.m" // IWYU pragma: keep -#endif - -#if defined(WITH_VULKAN) -# include "../src/mac_vulkan.m" // IWYU pragma: keep -#endif - -#if defined(__clang__) -# pragma clang diagnostic pop -#endif - -int -main(void) -{ - return 0; -} diff --git a/dpf/dgl/src/pugl-upstream/test/test_local_copy_paste.c b/dpf/dgl/src/pugl-upstream/test/test_local_copy_paste.c deleted file mode 100644 index 47beaff..0000000 --- a/dpf/dgl/src/pugl-upstream/test/test_local_copy_paste.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - Copyright 2020-2021 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -// Tests copy and paste within the same view - -#undef NDEBUG - -#include "test_utils.h" - -#include "pugl/pugl.h" -#include "pugl/stub.h" - -#include -#include -#include -#include -#include - -static const uintptr_t timerId = 1u; - -typedef enum { - START, - EXPOSED, - FINISHED, -} State; - -typedef struct { - PuglWorld* world; - PuglView* view; - PuglTestOptions opts; - size_t iteration; - State state; -} PuglTest; - -static PuglStatus -onEvent(PuglView* view, const PuglEvent* event) -{ - PuglTest* test = (PuglTest*)puglGetHandle(view); - - if (test->opts.verbose) { - printEvent(event, "Event: ", true); - } - - switch (event->type) { - case PUGL_EXPOSE: - if (test->state < EXPOSED) { - // Start timer on first expose - assert(!puglStartTimer(view, timerId, 1 / 60.0)); - test->state = EXPOSED; - } - break; - - case PUGL_TIMER: - assert(event->timer.id == timerId); - - if (test->iteration == 0) { - puglSetClipboard( - view, "text/plain", "Copied Text", strlen("Copied Text") + 1); - - } else if (test->iteration == 1) { - const char* type = NULL; - size_t len = 0; - const char* text = (const char*)puglGetClipboard(view, &type, &len); - - assert(!strcmp(type, "text/plain")); - assert(!strcmp(text, "Copied Text")); - - test->state = FINISHED; - } - - ++test->iteration; - break; - - default: - break; - } - - return PUGL_SUCCESS; -} - -int -main(int argc, char** argv) -{ - PuglTest app = {puglNewWorld(PUGL_PROGRAM, 0), - NULL, - puglParseTestOptions(&argc, &argv), - 0, - START}; - - // Set up view - app.view = puglNewView(app.world); - puglSetClassName(app.world, "Pugl Test"); - puglSetBackend(app.view, puglStubBackend()); - puglSetHandle(app.view, &app); - puglSetEventFunc(app.view, onEvent); - puglSetDefaultSize(app.view, 512, 512); - - // Create and show window - assert(!puglRealize(app.view)); - assert(!puglShow(app.view)); - - // Run until the test is finished - while (app.state != FINISHED) { - assert(!puglUpdate(app.world, 1 / 15.0)); - } - - puglFreeView(app.view); - puglFreeWorld(app.world); - - return 0; -} diff --git a/dpf/dgl/src/pugl-upstream/test/test_realize.c b/dpf/dgl/src/pugl-upstream/test/test_realize.c deleted file mode 100644 index bdd4f8a..0000000 --- a/dpf/dgl/src/pugl-upstream/test/test_realize.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - Copyright 2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/* - Tests that realize sends a create event, and can safely be called twice. - - Without handling this case, an application that accidentally calls realize - twice could end up in a very confusing situation where multiple windows have - been allocated (and ultimately leaked) for a view. -*/ - -#undef NDEBUG - -#include "test_utils.h" - -#include "pugl/pugl.h" -#include "pugl/stub.h" - -#include -#include -#include - -typedef enum { - START, - CREATED, -} State; - -typedef struct { - PuglWorld* world; - PuglView* view; - PuglTestOptions opts; - State state; -} PuglTest; - -static PuglStatus -onEvent(PuglView* view, const PuglEvent* event) -{ - PuglTest* test = (PuglTest*)puglGetHandle(view); - - if (test->opts.verbose) { - printEvent(event, "Event: ", true); - } - - switch (event->type) { - case PUGL_CREATE: - assert(test->state == START); - test->state = CREATED; - break; - default: - break; - } - - return PUGL_SUCCESS; -} - -int -main(int argc, char** argv) -{ - PuglTest test = {puglNewWorld(PUGL_PROGRAM, 0), - NULL, - puglParseTestOptions(&argc, &argv), - START}; - - // Set up view - test.view = puglNewView(test.world); - puglSetClassName(test.world, "Pugl Test"); - puglSetWindowTitle(test.view, "Pugl Realize Test"); - puglSetBackend(test.view, puglStubBackend()); - puglSetHandle(test.view, &test); - puglSetEventFunc(test.view, onEvent); - puglSetDefaultSize(test.view, 512, 512); - - // Create initially invisible window - assert(!puglRealize(test.view)); - assert(!puglGetVisible(test.view)); - while (test.state < CREATED) { - assert(!puglUpdate(test.world, -1.0)); - } - - // Check that calling realize() again is okay - assert(puglRealize(test.view) == PUGL_FAILURE); - - // Tear down - puglFreeView(test.view); - puglFreeWorld(test.world); - - return 0; -} diff --git a/dpf/dgl/src/pugl-upstream/test/test_redisplay.c b/dpf/dgl/src/pugl-upstream/test/test_redisplay.c deleted file mode 100644 index 816c9cb..0000000 --- a/dpf/dgl/src/pugl-upstream/test/test_redisplay.c +++ /dev/null @@ -1,155 +0,0 @@ -/* - Copyright 2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/* - Tests that redisplays posted in the event handler are dispatched at the end - of the same event loop iteration. -*/ - -#undef NDEBUG - -#include "test_utils.h" - -#include "pugl/pugl.h" -#include "pugl/stub.h" - -#include -#include -#include -#include - -#ifdef __APPLE__ -static const double timeout = 1 / 60.0; -#else -static const double timeout = -1.0; -#endif - -typedef enum { - START, - EXPOSED, - SHOULD_REDISPLAY, - POSTED_REDISPLAY, - REDISPLAYED, -} State; - -typedef struct { - PuglWorld* world; - PuglView* view; - PuglTestOptions opts; - State state; -} PuglTest; - -static const PuglRect redisplayRect = {2, 4, 8, 16}; -static const uintptr_t postRedisplayId = 42; - -static bool -rectContains(PuglRect outer, PuglRect inner) -{ - return outer.x <= inner.x && outer.y <= inner.y && - inner.x + inner.width <= outer.x + outer.width && - inner.y + inner.height <= outer.y + outer.height; -} - -static PuglRect -getExposeRect(PuglExposeEvent event) -{ - PuglRect result = { - .x = event.x, .y = event.y, .width = event.width, .height = event.height}; - return result; -} - -static PuglStatus -onEvent(PuglView* view, const PuglEvent* event) -{ - PuglTest* test = (PuglTest*)puglGetHandle(view); - - if (test->opts.verbose) { - printEvent(event, "Event: ", true); - } - - switch (event->type) { - case PUGL_UPDATE: - if (test->state == SHOULD_REDISPLAY) { - puglPostRedisplayRect(view, redisplayRect); - test->state = POSTED_REDISPLAY; - } - break; - - case PUGL_EXPOSE: - if (test->state == START) { - test->state = EXPOSED; - } else if (test->state == POSTED_REDISPLAY && - rectContains(getExposeRect(event->expose), redisplayRect)) { - test->state = REDISPLAYED; - } - break; - - case PUGL_CLIENT: - if (event->client.data1 == postRedisplayId) { - test->state = SHOULD_REDISPLAY; - } - break; - - default: - break; - } - - return PUGL_SUCCESS; -} - -int -main(int argc, char** argv) -{ - PuglTest test = {puglNewWorld(PUGL_PROGRAM, 0), - NULL, - puglParseTestOptions(&argc, &argv), - START}; - - // Set up view - test.view = puglNewView(test.world); - puglSetClassName(test.world, "Pugl Test"); - puglSetWindowTitle(test.view, "Pugl Redisplay Test"); - puglSetBackend(test.view, puglStubBackend()); - puglSetHandle(test.view, &test); - puglSetEventFunc(test.view, onEvent); - puglSetDefaultSize(test.view, 512, 512); - - // Create and show window - assert(!puglRealize(test.view)); - assert(!puglShow(test.view)); - while (test.state != EXPOSED) { - assert(!puglUpdate(test.world, timeout)); - } - - // Send a custom event to trigger a redisplay in the event loop - PuglEvent client_event = {{PUGL_CLIENT, 0}}; - client_event.client.data1 = postRedisplayId; - client_event.client.data2 = 0; - assert(!puglSendEvent(test.view, &client_event)); - - // Loop until an expose happens in the same iteration as the redisplay - test.state = SHOULD_REDISPLAY; - while (test.state != REDISPLAYED) { - assert(!puglUpdate(test.world, timeout)); - assert(test.state != POSTED_REDISPLAY); - } - - // Tear down - puglFreeView(test.view); - puglFreeWorld(test.world); - - return 0; -} diff --git a/dpf/dgl/src/pugl-upstream/test/test_remote_copy_paste.c b/dpf/dgl/src/pugl-upstream/test/test_remote_copy_paste.c deleted file mode 100644 index 92faca1..0000000 --- a/dpf/dgl/src/pugl-upstream/test/test_remote_copy_paste.c +++ /dev/null @@ -1,170 +0,0 @@ -/* - Copyright 2020-2021 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -// Tests copy and paste from one view to another - -#undef NDEBUG - -#include "test_utils.h" - -#include "pugl/pugl.h" -#include "pugl/stub.h" - -#include -#include -#include -#include -#include - -static const uintptr_t copierTimerId = 1u; -static const uintptr_t pasterTimerId = 2u; - -typedef enum { - START, - EXPOSED, - COPIED, - FINISHED, -} State; - -typedef struct { - PuglWorld* world; - PuglView* copierView; - PuglView* pasterView; - PuglTestOptions opts; - State state; - bool copierStarted; - bool pasterStarted; -} PuglTest; - -static PuglStatus -onCopierEvent(PuglView* const view, const PuglEvent* const event) -{ - PuglTest* const test = (PuglTest*)puglGetHandle(view); - - if (test->opts.verbose) { - printEvent(event, "Copier Event: ", true); - } - - switch (event->type) { - case PUGL_EXPOSE: - if (!test->copierStarted) { - // Start timer on first expose - assert(!puglStartTimer(view, copierTimerId, 1 / 15.0)); - test->copierStarted = true; - } - break; - - case PUGL_TIMER: - assert(event->timer.id == copierTimerId); - - if (test->state < COPIED) { - puglSetClipboard( - view, "text/plain", "Copied Text", strlen("Copied Text") + 1); - test->state = COPIED; - } - - break; - - default: - break; - } - - return PUGL_SUCCESS; -} - -static PuglStatus -onPasterEvent(PuglView* const view, const PuglEvent* const event) -{ - PuglTest* const test = (PuglTest*)puglGetHandle(view); - - if (test->opts.verbose) { - printEvent(event, "Paster Event: ", true); - } - - switch (event->type) { - case PUGL_EXPOSE: - if (!test->pasterStarted) { - // Start timer on first expose - assert(!puglStartTimer(view, pasterTimerId, 1 / 60.0)); - test->pasterStarted = true; - } - break; - - case PUGL_TIMER: - assert(event->timer.id == pasterTimerId); - - if (test->state == COPIED) { - const char* type = NULL; - size_t len = 0; - const char* text = (const char*)puglGetClipboard(view, &type, &len); - - assert(!strcmp(type, "text/plain")); - assert(!strcmp(text, "Copied Text")); - - test->state = FINISHED; - } - - break; - - default: - break; - } - - return PUGL_SUCCESS; -} - -int -main(int argc, char** argv) -{ - PuglTest app = {puglNewWorld(PUGL_PROGRAM, 0), - NULL, - NULL, - puglParseTestOptions(&argc, &argv), - START, - false, - false}; - - // Set up copier view - app.copierView = puglNewView(app.world); - puglSetClassName(app.world, "Pugl Test Copier"); - puglSetBackend(app.copierView, puglStubBackend()); - puglSetHandle(app.copierView, &app); - puglSetEventFunc(app.copierView, onCopierEvent); - puglSetDefaultSize(app.copierView, 256, 256); - - // Set up paster view - app.pasterView = puglNewView(app.world); - puglSetClassName(app.world, "Pugl Test Paster"); - puglSetBackend(app.pasterView, puglStubBackend()); - puglSetHandle(app.pasterView, &app); - puglSetEventFunc(app.pasterView, onPasterEvent); - puglSetDefaultSize(app.pasterView, 256, 256); - - // Create and show both views - assert(!puglShow(app.copierView)); - assert(!puglShow(app.pasterView)); - - // Run until the test is finished - while (app.state != FINISHED) { - assert(!puglUpdate(app.world, 1 / 60.0)); - } - - puglFreeView(app.copierView); - puglFreeView(app.pasterView); - puglFreeWorld(app.world); - - return 0; -} diff --git a/dpf/dgl/src/pugl-upstream/test/test_show_hide.c b/dpf/dgl/src/pugl-upstream/test/test_show_hide.c deleted file mode 100644 index b624735..0000000 --- a/dpf/dgl/src/pugl-upstream/test/test_show_hide.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - Copyright 2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/* - Tests the basic sanity of view/window create, configure, map, expose, unmap, - and destroy events. -*/ - -#undef NDEBUG - -#include "test_utils.h" - -#include "pugl/pugl.h" -#include "pugl/stub.h" - -#include -#include -#include - -typedef enum { - START, - CREATED, - CONFIGURED, - MAPPED, - EXPOSED, - UNMAPPED, - DESTROYED, -} State; - -typedef struct { - PuglWorld* world; - PuglView* view; - PuglTestOptions opts; - State state; -} PuglTest; - -static PuglStatus -onEvent(PuglView* view, const PuglEvent* event) -{ - PuglTest* test = (PuglTest*)puglGetHandle(view); - - if (test->opts.verbose) { - printEvent(event, "Event: ", true); - } - - switch (event->type) { - case PUGL_CREATE: - assert(test->state == START); - test->state = CREATED; - break; - case PUGL_CONFIGURE: - if (test->state == CREATED) { - test->state = CONFIGURED; - } - break; - case PUGL_MAP: - assert(test->state == CONFIGURED || test->state == UNMAPPED); - test->state = MAPPED; - break; - case PUGL_EXPOSE: - assert(test->state == MAPPED || test->state == EXPOSED); - test->state = EXPOSED; - break; - case PUGL_UNMAP: - assert(test->state == MAPPED || test->state == EXPOSED); - test->state = UNMAPPED; - break; - case PUGL_DESTROY: - assert(test->state == UNMAPPED); - test->state = DESTROYED; - break; - default: - break; - } - - return PUGL_SUCCESS; -} - -static void -tick(PuglWorld* world) -{ -#ifdef __APPLE__ - // FIXME: Expose events are not events on MacOS, so we can't block - // indefinitely here since it will block forever - assert(!puglUpdate(world, 1 / 30.0)); -#else - assert(!puglUpdate(world, -1)); -#endif -} - -int -main(int argc, char** argv) -{ - PuglTest test = {puglNewWorld(PUGL_PROGRAM, 0), - NULL, - puglParseTestOptions(&argc, &argv), - START}; - - // Set up view - test.view = puglNewView(test.world); - puglSetClassName(test.world, "Pugl Test"); - puglSetWindowTitle(test.view, "Pugl Show/Hide Test"); - puglSetBackend(test.view, puglStubBackend()); - puglSetHandle(test.view, &test); - puglSetEventFunc(test.view, onEvent); - puglSetDefaultSize(test.view, 512, 512); - - // Create initially invisible window - assert(!puglRealize(test.view)); - assert(!puglGetVisible(test.view)); - while (test.state < CREATED) { - tick(test.world); - } - - // Show and hide window a couple of times - for (unsigned i = 0u; i < 2u; ++i) { - assert(!puglShow(test.view)); - while (test.state != EXPOSED) { - tick(test.world); - } - - assert(puglGetVisible(test.view)); - assert(!puglHide(test.view)); - while (test.state != UNMAPPED) { - tick(test.world); - } - } - - // Tear down - assert(!puglGetVisible(test.view)); - puglFreeView(test.view); - assert(test.state == DESTROYED); - puglFreeWorld(test.world); - - return 0; -} diff --git a/dpf/dgl/src/pugl-upstream/test/test_size.c b/dpf/dgl/src/pugl-upstream/test/test_size.c deleted file mode 100644 index 4f6c029..0000000 --- a/dpf/dgl/src/pugl-upstream/test/test_size.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - Copyright 2021 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -// Tests basic view setup - -#undef NDEBUG - -#include "test_utils.h" - -#include "pugl/pugl.h" -#include "pugl/stub.h" - -#include -#include -#include - -typedef enum { - START, - CREATED, - CONFIGURED, - MAPPED, - DESTROYED, -} State; - -typedef struct { - PuglWorld* world; - PuglView* view; - PuglTestOptions opts; - State state; - PuglRect configuredRect; -} PuglTest; - -static PuglStatus -onEvent(PuglView* view, const PuglEvent* event) -{ - PuglTest* test = (PuglTest*)puglGetHandle(view); - - if (test->opts.verbose) { - printEvent(event, "Event: ", true); - } - - switch (event->type) { - case PUGL_CREATE: - assert(test->state == START); - test->state = CREATED; - break; - case PUGL_CONFIGURE: - if (test->state == CREATED) { - test->state = CONFIGURED; - } - test->configuredRect.x = event->configure.x; - test->configuredRect.y = event->configure.y; - test->configuredRect.width = event->configure.width; - test->configuredRect.height = event->configure.height; - break; - case PUGL_MAP: - test->state = MAPPED; - break; - case PUGL_DESTROY: - test->state = DESTROYED; - break; - default: - break; - } - - return PUGL_SUCCESS; -} - -int -main(int argc, char** argv) -{ - static const int minSize = 256; - static const int defaultSize = 512; - static const int maxSize = 1024; - - PuglTest test = {puglNewWorld(PUGL_PROGRAM, 0), - NULL, - puglParseTestOptions(&argc, &argv), - START, - {0.0, 0.0, 0.0, 0.0}}; - - // Set up view with size bounds and an aspect ratio - test.view = puglNewView(test.world); - puglSetClassName(test.world, "Pugl Test"); - puglSetWindowTitle(test.view, "Pugl Size Test"); - puglSetBackend(test.view, puglStubBackend()); - puglSetHandle(test.view, &test); - puglSetEventFunc(test.view, onEvent); - puglSetViewHint(test.view, PUGL_RESIZABLE, PUGL_TRUE); - puglSetMinSize(test.view, minSize, minSize); - puglSetDefaultSize(test.view, defaultSize, defaultSize); - puglSetMaxSize(test.view, maxSize, maxSize); - puglSetAspectRatio(test.view, 1, 1, 1, 1); - - // Create and show window - assert(!puglRealize(test.view)); - assert(!puglShow(test.view)); - while (test.state < MAPPED) { - assert(!puglUpdate(test.world, -1.0)); - } - - // Check that the frame matches the last configure event - const PuglRect frame = puglGetFrame(test.view); - assert(frame.x == test.configuredRect.x); - assert(frame.y == test.configuredRect.y); - assert(frame.width == test.configuredRect.width); - assert(frame.height == test.configuredRect.height); - -#if defined(_WIN32) || defined(__APPLE__) - /* Some window managers on Linux (particularly tiling ones) just disregard - these hints entirely, so we only check that the size is in bounds on MacOS - and Windows where this is more or less universally supported. */ - - assert(frame.width >= minSize); - assert(frame.height >= minSize); - assert(frame.width <= maxSize); - assert(frame.height <= maxSize); -#endif - - // Tear down - puglFreeView(test.view); - puglFreeWorld(test.world); - - return 0; -} diff --git a/dpf/dgl/src/pugl-upstream/test/test_strerror.c b/dpf/dgl/src/pugl-upstream/test/test_strerror.c deleted file mode 100644 index e87c226..0000000 --- a/dpf/dgl/src/pugl-upstream/test/test_strerror.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - Copyright 2021 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -// Tests puglStrerror - -#undef NDEBUG - -#include "pugl/pugl.h" - -#include -#include -#include - -int -main(void) -{ - for (unsigned i = 0; i <= PUGL_UNSUPPORTED_TYPE; ++i) { - const char* const string = puglStrerror((PuglStatus)i); - - assert(isupper(string[0])); - assert(string[strlen(string) - 1] != '.'); - assert(strcmp(string, "Unknown error")); - } - - assert(!strcmp(puglStrerror((PuglStatus)999), "Unknown error")); - - return 0; -} diff --git a/dpf/dgl/src/pugl-upstream/test/test_stub.c b/dpf/dgl/src/pugl-upstream/test/test_stub.c deleted file mode 100644 index 4295af9..0000000 --- a/dpf/dgl/src/pugl-upstream/test/test_stub.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - Copyright 2021 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -// Basic test that ensures a view can be created with a stub backend - -#undef NDEBUG - -#include "test_utils.h" - -#include "pugl/pugl.h" -#include "pugl/stub.h" - -#include -#include - -typedef struct { - PuglWorld* world; - PuglView* view; - PuglTestOptions opts; - bool exposed; -} PuglTest; - -static PuglStatus -onEvent(PuglView* const view, const PuglEvent* const event) -{ - PuglTest* const test = (PuglTest*)puglGetHandle(view); - - if (test->opts.verbose) { - printEvent(event, "Event: ", true); - } - - if (event->type == PUGL_EXPOSE) { - assert(!puglGetContext(view)); - test->exposed = true; - } - - return PUGL_SUCCESS; -} - -int -main(int argc, char** argv) -{ - PuglWorld* const world = puglNewWorld(PUGL_PROGRAM, 0); - PuglView* const view = puglNewView(world); - const PuglTestOptions opts = puglParseTestOptions(&argc, &argv); - PuglTest test = {world, view, opts, false}; - - // Set up and show view - puglSetClassName(test.world, "Pugl Stub Test"); - puglSetHandle(test.view, &test); - puglSetBackend(test.view, puglStubBackend()); - puglSetEventFunc(test.view, onEvent); - puglSetDefaultSize(test.view, 512, 512); - puglShow(test.view); - - // Drive event loop until the view gets exposed - while (!test.exposed) { - puglUpdate(test.world, -1.0); - } - - // Tear down - puglFreeView(test.view); - puglFreeWorld(test.world); - - return 0; -} diff --git a/dpf/dgl/src/pugl-upstream/test/test_stub_hints.c b/dpf/dgl/src/pugl-upstream/test/test_stub_hints.c deleted file mode 100644 index 2dea844..0000000 --- a/dpf/dgl/src/pugl-upstream/test/test_stub_hints.c +++ /dev/null @@ -1,103 +0,0 @@ -/* - Copyright 2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/* - Tests that all hints are set to real values after a view is realized. -*/ - -#undef NDEBUG - -#include "test_utils.h" - -#include "pugl/pugl.h" -#include "pugl/stub.h" - -#include - -static PuglStatus -onEvent(PuglView* view, const PuglEvent* event) -{ - (void)view; - (void)event; - - return PUGL_SUCCESS; -} - -int -main(void) -{ - PuglWorld* const world = puglNewWorld(PUGL_PROGRAM, 0); - PuglView* const view = puglNewView(world); - - // Set up view - puglSetClassName(world, "Pugl Test"); - puglSetWindowTitle(view, "Pugl Stub Hints Test"); - puglSetBackend(view, puglStubBackend()); - puglSetEventFunc(view, onEvent); - puglSetDefaultSize(view, 512, 512); - - // Check invalid cases - assert(puglSetViewHint(view, (PuglViewHint)9999, 0) == PUGL_BAD_PARAMETER); - assert(puglGetViewHint(view, (PuglViewHint)9999) == PUGL_DONT_CARE); - - // Set all relevant hints that support it to PUGL_DONT_CARE - assert(!puglSetViewHint(view, PUGL_RED_BITS, PUGL_DONT_CARE)); - assert(!puglSetViewHint(view, PUGL_GREEN_BITS, PUGL_DONT_CARE)); - assert(!puglSetViewHint(view, PUGL_BLUE_BITS, PUGL_DONT_CARE)); - assert(!puglSetViewHint(view, PUGL_ALPHA_BITS, PUGL_DONT_CARE)); - assert(!puglSetViewHint(view, PUGL_REFRESH_RATE, PUGL_DONT_CARE)); - - // Check failure to set PUGL_DONT_CARE for hints that don't support it - assert(puglSetViewHint(view, PUGL_USE_COMPAT_PROFILE, PUGL_DONT_CARE) == - PUGL_BAD_PARAMETER); - assert(puglSetViewHint(view, PUGL_USE_DEBUG_CONTEXT, PUGL_DONT_CARE) == - PUGL_BAD_PARAMETER); - assert(puglSetViewHint(view, PUGL_CONTEXT_VERSION_MAJOR, PUGL_DONT_CARE) == - PUGL_BAD_PARAMETER); - assert(puglSetViewHint(view, PUGL_CONTEXT_VERSION_MINOR, PUGL_DONT_CARE) == - PUGL_BAD_PARAMETER); - assert(puglSetViewHint(view, PUGL_SWAP_INTERVAL, PUGL_DONT_CARE) == - PUGL_BAD_PARAMETER); - - // Check failure to set out of range hints - assert(puglSetViewHint(view, (PuglViewHint)999, 1) == PUGL_BAD_PARAMETER); - - // Realize view and print all hints for debugging convenience - assert(!puglRealize(view)); - printViewHints(view); - - // Check that no relevant hints are set to PUGL_DONT_CARE - assert(puglGetViewHint(view, PUGL_USE_COMPAT_PROFILE) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_USE_DEBUG_CONTEXT) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_CONTEXT_VERSION_MAJOR) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_CONTEXT_VERSION_MINOR) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_RED_BITS) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_GREEN_BITS) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_BLUE_BITS) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_ALPHA_BITS) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_RESIZABLE) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_IGNORE_KEY_REPEAT) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_REFRESH_RATE) != PUGL_DONT_CARE); - - // Check failure to get out of range hints - assert(puglGetViewHint(view, (PuglViewHint)999) == PUGL_DONT_CARE); - - // Tear down - puglFreeView(view); - puglFreeWorld(world); - - return 0; -} diff --git a/dpf/dgl/src/pugl-upstream/test/test_timer.c b/dpf/dgl/src/pugl-upstream/test/test_timer.c deleted file mode 100644 index 686a078..0000000 --- a/dpf/dgl/src/pugl-upstream/test/test_timer.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - Copyright 2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/* - Tests that update events are received and than redisplays they trigger happen - immediately in the same event loop iteration. -*/ - -#undef NDEBUG - -#include "test_utils.h" - -#include "pugl/pugl.h" -#include "pugl/stub.h" - -#include -#include -#include -#include -#include -#include - -#ifdef __APPLE__ -static const double timeout = 1 / 60.0; -#else -static const double timeout = -1.0; -#endif - -// Windows SetTimer has a maximum resolution of 10ms -static const double tolerance = 0.012; - -static const uintptr_t timerId = 1u; -static const double timerPeriod = 1 / 60.0; - -typedef enum { - START, - EXPOSED, -} State; - -typedef struct { - PuglWorld* world; - PuglView* view; - PuglTestOptions opts; - size_t numAlarms; - double firstAlarmTime; - double lastAlarmTime; - State state; -} PuglTest; - -static void -onTimer(PuglView* const view, const PuglTimerEvent* const event) -{ - PuglTest* const test = (PuglTest*)puglGetHandle(view); - const double time = puglGetTime(puglGetWorld(view)); - - assert(event->id == timerId); - - if (test->numAlarms++ == 0) { - test->firstAlarmTime = time; - } - - test->lastAlarmTime = time; -} - -static PuglStatus -onEvent(PuglView* const view, const PuglEvent* const event) -{ - PuglTest* test = (PuglTest*)puglGetHandle(view); - - if (test->opts.verbose) { - printEvent(event, "Event: ", true); - } - - switch (event->type) { - case PUGL_EXPOSE: - test->state = EXPOSED; - break; - - case PUGL_TIMER: - onTimer(view, &event->timer); - break; - - default: - break; - } - - return PUGL_SUCCESS; -} - -static double -roundPeriod(const double period) -{ - return floor(period * 1000.0) / 1000.0; // Round down to milliseconds -} - -int -main(int argc, char** argv) -{ - PuglTest test = {puglNewWorld(PUGL_PROGRAM, 0), - NULL, - puglParseTestOptions(&argc, &argv), - 0, - 0.0, - 0.0, - START}; - - // Set up view - test.view = puglNewView(test.world); - puglSetClassName(test.world, "Pugl Test"); - puglSetWindowTitle(test.view, "Pugl Timer Test"); - puglSetBackend(test.view, puglStubBackend()); - puglSetHandle(test.view, &test); - puglSetEventFunc(test.view, onEvent); - puglSetDefaultSize(test.view, 512, 512); - - // Create and show window - assert(!puglRealize(test.view)); - assert(!puglShow(test.view)); - while (test.state != EXPOSED) { - assert(!puglUpdate(test.world, timeout)); - } - - // Register a timer with a longer period first - assert(!puglStartTimer(test.view, timerId, timerPeriod * 2.0)); - - // Replace it with the one we want (to ensure timers are replaced) - assert(!puglStartTimer(test.view, timerId, timerPeriod)); - - puglUpdate(test.world, timerPeriod * 90.0); - assert(test.numAlarms > 0); - - // Calculate the actual period of the timer - const double duration = test.lastAlarmTime - test.firstAlarmTime; - const double expected = roundPeriod(timerPeriod); - const double actual = roundPeriod(duration / (double)(test.numAlarms - 1)); - const double difference = fabs(actual - expected); - - if (difference > tolerance) { - fprintf(stderr, "error: Period not within %f of %f\n", tolerance, expected); - fprintf(stderr, "note: Actual period %f\n", actual); - } - - assert(difference <= tolerance); - - // Deregister timer and tick once to synchronize - assert(!puglStopTimer(test.view, timerId)); - puglUpdate(test.world, 0.0); - - // Update for a half second and check that we receive no more alarms - test.numAlarms = 0; - puglUpdate(test.world, 0.5); - assert(test.numAlarms == 0); - - puglFreeView(test.view); - puglFreeWorld(test.world); - - return 0; -} diff --git a/dpf/dgl/src/pugl-upstream/test/test_update.c b/dpf/dgl/src/pugl-upstream/test/test_update.c deleted file mode 100644 index 39415bc..0000000 --- a/dpf/dgl/src/pugl-upstream/test/test_update.c +++ /dev/null @@ -1,126 +0,0 @@ -/* - Copyright 2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/* - Tests that update events are received and that the redisplays they trigger - happen immediately in the same event loop iteration. -*/ - -#undef NDEBUG - -#include "test_utils.h" - -#include "pugl/pugl.h" -#include "pugl/stub.h" - -#include -#include -#include - -#ifdef __APPLE__ -static const double timeout = 1 / 60.0; -#else -static const double timeout = -1.0; -#endif - -typedef enum { - START, - EXPOSED1, - UPDATED, - EXPOSED2, -} State; - -typedef struct { - PuglWorld* world; - PuglView* view; - PuglTestOptions opts; - State state; -} PuglTest; - -static PuglStatus -onEvent(PuglView* view, const PuglEvent* event) -{ - PuglTest* test = (PuglTest*)puglGetHandle(view); - - if (test->opts.verbose) { - printEvent(event, "Event: ", true); - } - - switch (event->type) { - case PUGL_EXPOSE: - switch (test->state) { - case START: - test->state = EXPOSED1; - break; - case UPDATED: - test->state = EXPOSED2; - break; - default: - break; - } - break; - - case PUGL_UPDATE: - if (test->state == EXPOSED1) { - test->state = UPDATED; - puglPostRedisplay(view); - } - break; - - default: - break; - } - - return PUGL_SUCCESS; -} - -int -main(int argc, char** argv) -{ - PuglTest test = {puglNewWorld(PUGL_PROGRAM, 0), - NULL, - puglParseTestOptions(&argc, &argv), - START}; - - // Set up view - test.view = puglNewView(test.world); - puglSetClassName(test.world, "Pugl Test"); - puglSetWindowTitle(test.view, "Pugl Update Test"); - puglSetBackend(test.view, puglStubBackend()); - puglSetHandle(test.view, &test); - puglSetEventFunc(test.view, onEvent); - puglSetDefaultSize(test.view, 512, 512); - - // Create and show window - assert(!puglRealize(test.view)); - assert(!puglShow(test.view)); - - // Tick until an expose happens - while (test.state < EXPOSED1) { - assert(!puglUpdate(test.world, timeout)); - assert(test.state != UPDATED); - } - - // Tick once and ensure the update and the expose it posted both happened - assert(!puglUpdate(test.world, 0.0)); - assert(test.state == EXPOSED2); - - // Tear down - puglFreeView(test.view); - puglFreeWorld(test.world); - - return 0; -} diff --git a/dpf/dgl/src/pugl-upstream/test/test_utils.h b/dpf/dgl/src/pugl-upstream/test/test_utils.h deleted file mode 100644 index 2f80cbf..0000000 --- a/dpf/dgl/src/pugl-upstream/test/test_utils.h +++ /dev/null @@ -1,356 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef TEST_TEST_UTILS_H -#define TEST_TEST_UTILS_H - -#define __STDC_FORMAT_MACROS 1 - -#include "pugl/pugl.h" - -#include -#include -#include -#include -#include -#include - -#ifdef __GNUC__ -# define PUGL_LOG_FUNC(fmt, arg1) __attribute__((format(printf, fmt, arg1))) -#else -# define PUGL_LOG_FUNC(fmt, arg1) -#endif - -typedef struct { - int samples; - int doubleBuffer; - int sync; - bool continuous; - bool help; - bool ignoreKeyRepeat; - bool resizable; - bool verbose; - bool errorChecking; -} PuglTestOptions; - -PUGL_LOG_FUNC(1, 2) -static int -logError(const char* fmt, ...) -{ - fprintf(stderr, "error: "); - - va_list args; // NOLINT - va_start(args, fmt); - vfprintf(stderr, fmt, args); - va_end(args); - - return 1; -} - -static inline int -printModifiers(const uint32_t mods) -{ - return fprintf(stderr, - "Modifiers:%s%s%s%s\n", - (mods & PUGL_MOD_SHIFT) ? " Shift" : "", - (mods & PUGL_MOD_CTRL) ? " Ctrl" : "", - (mods & PUGL_MOD_ALT) ? " Alt" : "", - (mods & PUGL_MOD_SUPER) ? " Super" : ""); -} - -static inline const char* -crossingModeString(const PuglCrossingMode mode) -{ - switch (mode) { - case PUGL_CROSSING_NORMAL: - return "normal"; - case PUGL_CROSSING_GRAB: - return "grab"; - case PUGL_CROSSING_UNGRAB: - return "ungrab"; - } - - return "unknown"; -} - -static inline const char* -scrollDirectionString(const PuglScrollDirection direction) -{ - switch (direction) { - case PUGL_SCROLL_UP: - return "up"; - case PUGL_SCROLL_DOWN: - return "down"; - case PUGL_SCROLL_LEFT: - return "left"; - case PUGL_SCROLL_RIGHT: - return "right"; - case PUGL_SCROLL_SMOOTH: - return "smooth"; - } - - return "unknown"; -} - -static inline int -printEvent(const PuglEvent* event, const char* prefix, const bool verbose) -{ -#define FFMT "%6.1f" -#define PFMT FFMT " " FFMT -#define PRINT(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__) - - switch (event->type) { - case PUGL_NOTHING: - return 0; - case PUGL_CREATE: - return fprintf(stderr, "%sCreate\n", prefix); - case PUGL_DESTROY: - return fprintf(stderr, "%sDestroy\n", prefix); - case PUGL_MAP: - return fprintf(stderr, "%sMap\n", prefix); - case PUGL_UNMAP: - return fprintf(stderr, "%sUnmap\n", prefix); - case PUGL_KEY_PRESS: - return PRINT("%sKey press code %3u key U+%04X\n", - prefix, - event->key.keycode, - event->key.key); - case PUGL_KEY_RELEASE: - return PRINT("%sKey release code %3u key U+%04X\n", - prefix, - event->key.keycode, - event->key.key); - case PUGL_TEXT: - return PRINT("%sText entry code %3u char U+%04X (%s)\n", - prefix, - event->text.keycode, - event->text.character, - event->text.string); - case PUGL_BUTTON_PRESS: - case PUGL_BUTTON_RELEASE: - return (PRINT("%sMouse %u %s at " PFMT " ", - prefix, - event->button.button, - (event->type == PUGL_BUTTON_PRESS) ? "down" : "up ", - event->button.x, - event->button.y) + - printModifiers(event->scroll.state)); - case PUGL_SCROLL: - return (PRINT("%sScroll %5.1f %5.1f (%s) at " PFMT " ", - prefix, - event->scroll.dx, - event->scroll.dy, - scrollDirectionString(event->scroll.direction), - event->scroll.x, - event->scroll.y) + - printModifiers(event->scroll.state)); - case PUGL_POINTER_IN: - return PRINT("%sMouse enter at " PFMT " (%s)\n", - prefix, - event->crossing.x, - event->crossing.y, - crossingModeString(event->crossing.mode)); - case PUGL_POINTER_OUT: - return PRINT("%sMouse leave at " PFMT " (%s)\n", - prefix, - event->crossing.x, - event->crossing.y, - crossingModeString(event->crossing.mode)); - case PUGL_FOCUS_IN: - return PRINT( - "%sFocus in (%s)\n", prefix, crossingModeString(event->crossing.mode)); - case PUGL_FOCUS_OUT: - return PRINT( - "%sFocus out (%s)\n", prefix, crossingModeString(event->crossing.mode)); - case PUGL_CLIENT: - return PRINT("%sClient %" PRIXPTR " %" PRIXPTR "\n", - prefix, - event->client.data1, - event->client.data2); - case PUGL_LOOP_ENTER: - return PRINT("%sLoop enter\n", prefix); - case PUGL_LOOP_LEAVE: - return PRINT("%sLoop leave\n", prefix); - default: - break; - } - - if (verbose) { - switch (event->type) { - case PUGL_UPDATE: - return fprintf(stderr, "%sUpdate\n", prefix); - case PUGL_CONFIGURE: - return PRINT("%sConfigure " PFMT " " PFMT "\n", - prefix, - event->configure.x, - event->configure.y, - event->configure.width, - event->configure.height); - case PUGL_EXPOSE: - return PRINT("%sExpose " PFMT " " PFMT "\n", - prefix, - event->expose.x, - event->expose.y, - event->expose.width, - event->expose.height); - case PUGL_CLOSE: - return PRINT("%sClose\n", prefix); - case PUGL_MOTION: - return PRINT("%sMouse motion at " PFMT "\n", - prefix, - event->motion.x, - event->motion.y); - case PUGL_TIMER: - return PRINT("%sTimer %" PRIuPTR "\n", prefix, event->timer.id); - default: - return PRINT("%sUnknown event type %d\n", prefix, (int)event->type); - } - } - -#undef PRINT -#undef PFMT -#undef FFMT - - return 0; -} - -static inline const char* -puglViewHintString(const PuglViewHint hint) -{ - switch (hint) { - case PUGL_USE_COMPAT_PROFILE: - return "Use compatible profile"; - case PUGL_USE_DEBUG_CONTEXT: - return "Use debug context"; - case PUGL_CONTEXT_VERSION_MAJOR: - return "Context major version"; - case PUGL_CONTEXT_VERSION_MINOR: - return "Context minor version"; - case PUGL_RED_BITS: - return "Red bits"; - case PUGL_GREEN_BITS: - return "Green bits"; - case PUGL_BLUE_BITS: - return "Blue bits"; - case PUGL_ALPHA_BITS: - return "Alpha bits"; - case PUGL_DEPTH_BITS: - return "Depth bits"; - case PUGL_STENCIL_BITS: - return "Stencil bits"; - case PUGL_SAMPLES: - return "Samples"; - case PUGL_DOUBLE_BUFFER: - return "Double buffer"; - case PUGL_SWAP_INTERVAL: - return "Swap interval"; - case PUGL_RESIZABLE: - return "Resizable"; - case PUGL_IGNORE_KEY_REPEAT: - return "Ignore key repeat"; - case PUGL_REFRESH_RATE: - return "Refresh rate"; - case PUGL_NUM_VIEW_HINTS: - break; - } - - return "Unknown"; -} - -static inline void -printViewHints(const PuglView* view) -{ - for (int i = 0; i < PUGL_NUM_VIEW_HINTS; ++i) { - const PuglViewHint hint = (PuglViewHint)i; - fprintf(stderr, - "%s: %d\n", - puglViewHintString(hint), - puglGetViewHint(view, hint)); - } -} - -static inline void -puglPrintTestUsage(const char* prog, const char* posHelp) -{ - printf("Usage: %s [OPTION]... %s\n\n" - " -a Enable anti-aliasing\n" - " -c Continuously animate and draw\n" - " -d Directly draw to window (no double-buffering)\n" - " -e Enable platform error-checking\n" - " -f Fast drawing, explicitly disable vertical sync\n" - " -h Display this help\n" - " -i Ignore key repeat\n" - " -v Print verbose output\n" - " -r Resizable window\n" - " -s Explicitly enable vertical sync\n", - prog, - posHelp); -} - -static inline PuglTestOptions -puglParseTestOptions(int* pargc, char*** pargv) -{ - PuglTestOptions opts = { - 0, - PUGL_TRUE, - PUGL_DONT_CARE, - false, - false, - false, - false, - false, - false, - }; - - char** const argv = *pargv; - int i = 1; - for (; i < *pargc; ++i) { - if (!strcmp(argv[i], "-a")) { - opts.samples = 4; - } else if (!strcmp(argv[i], "-c")) { - opts.continuous = true; - } else if (!strcmp(argv[i], "-d")) { - opts.doubleBuffer = PUGL_FALSE; - } else if (!strcmp(argv[i], "-e")) { - opts.errorChecking = PUGL_TRUE; - } else if (!strcmp(argv[i], "-f")) { - opts.sync = PUGL_FALSE; - } else if (!strcmp(argv[i], "-h")) { - opts.help = true; - return opts; - } else if (!strcmp(argv[i], "-i")) { - opts.ignoreKeyRepeat = true; - } else if (!strcmp(argv[i], "-r")) { - opts.resizable = true; - } else if (!strcmp(argv[i], "-s")) { - opts.sync = PUGL_TRUE; - } else if (!strcmp(argv[i], "-v")) { - opts.verbose = true; - } else if (argv[i][0] != '-') { - break; - } else { - opts.help = true; - logError("Unknown option: %s\n", argv[i]); - } - } - - *pargc -= i; - *pargv += i; - - return opts; -} - -#endif // TEST_TEST_UTILS_H diff --git a/dpf/dgl/src/pugl-upstream/test/test_view.c b/dpf/dgl/src/pugl-upstream/test/test_view.c deleted file mode 100644 index 86182b7..0000000 --- a/dpf/dgl/src/pugl-upstream/test/test_view.c +++ /dev/null @@ -1,103 +0,0 @@ -/* - Copyright 2021 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -// Tests basic view setup - -#undef NDEBUG - -#include "test_utils.h" - -#include "pugl/pugl.h" -#include "pugl/stub.h" - -#include -#include -#include - -typedef enum { - START, - CREATED, - MAPPED, - DESTROYED, -} State; - -typedef struct { - PuglWorld* world; - PuglView* view; - PuglTestOptions opts; - State state; -} PuglTest; - -static PuglStatus -onEvent(PuglView* view, const PuglEvent* event) -{ - PuglTest* test = (PuglTest*)puglGetHandle(view); - - if (test->opts.verbose) { - printEvent(event, "Event: ", true); - } - - switch (event->type) { - case PUGL_CREATE: - assert(test->state == START); - test->state = CREATED; - break; - case PUGL_MAP: - test->state = MAPPED; - break; - case PUGL_DESTROY: - test->state = DESTROYED; - break; - default: - break; - } - - return PUGL_SUCCESS; -} - -int -main(int argc, char** argv) -{ - PuglTest test = {puglNewWorld(PUGL_PROGRAM, 0), - NULL, - puglParseTestOptions(&argc, &argv), - START}; - - // Set up view - test.view = puglNewView(test.world); - puglSetClassName(test.world, "Pugl Test"); - puglSetWindowTitle(test.view, "Pugl View Test"); - puglSetBackend(test.view, puglStubBackend()); - puglSetHandle(test.view, &test); - puglSetEventFunc(test.view, onEvent); - puglSetDefaultSize(test.view, 512, 512); - - // Create and show window - assert(!puglRealize(test.view)); - assert(!puglShow(test.view)); - while (test.state < MAPPED) { - assert(!puglUpdate(test.world, -1.0)); - } - - // Check that puglGetNativeWindow() returns something - assert(puglGetNativeWindow(test.view)); - - // Tear down - puglFreeView(test.view); - puglFreeWorld(test.world); - - return 0; -} diff --git a/dpf/dgl/src/pugl-upstream/test/test_vulkan.c b/dpf/dgl/src/pugl-upstream/test/test_vulkan.c deleted file mode 100644 index f0f582e..0000000 --- a/dpf/dgl/src/pugl-upstream/test/test_vulkan.c +++ /dev/null @@ -1,212 +0,0 @@ -/* - Copyright 2021 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -// Tests basic Vulkan support - -#undef NDEBUG - -#include "test_utils.h" - -#include "pugl/pugl.h" -#include "pugl/vulkan.h" - -#include - -#include -#include -#include -#include -#include - -// Vulkan allocation callbacks which can be used for debugging -#define ALLOC_VK NULL - -// Helper macro for allocating arrays by type, with C++ compatible cast -#define AALLOC(size, Type) ((Type*)calloc(size, sizeof(Type))) - -// Helper macro for counted array arguments to make clang-format behave -#define COUNTED(count, ...) count, __VA_ARGS__ - -typedef struct { - PuglWorld* world; - PuglView* view; - VkInstance instance; - VkSurfaceKHR surface; - PuglTestOptions opts; - bool exposed; -} PuglTest; - -static bool -hasExtension(const char* const name, - const VkExtensionProperties* const properties, - const uint32_t count) -{ - for (uint32_t i = 0; i < count; ++i) { - if (!strcmp(properties[i].extensionName, name)) { - return true; - } - } - - return false; -} - -static void -pushString(const char*** const array, - uint32_t* const count, - const char* const string) -{ - *array = (const char**)realloc(*array, (*count + 1) * sizeof(const char*)); - (*array)[*count] = string; - ++*count; -} - -static void -onExpose(PuglView* const view, const PuglExposeEvent* const event) -{ - (void)view; - (void)event; - - /* ... */ -} - -static PuglStatus -onEvent(PuglView* const view, const PuglEvent* const event) -{ - PuglTest* const test = (PuglTest*)puglGetHandle(view); - - if (test->opts.verbose) { - printEvent(event, "Event: ", true); - } - - if (event->type == PUGL_EXPOSE) { - onExpose(view, &event->expose); - test->exposed = true; - } - - return PUGL_SUCCESS; -} - -static VkResult -createInstance(PuglTest* const test) -{ - const VkApplicationInfo appInfo = { - VK_STRUCTURE_TYPE_APPLICATION_INFO, - NULL, - "Pugl Vulkan Test", - VK_MAKE_VERSION(0, 1, 0), - "Pugl Vulkan Test Engine", - VK_MAKE_VERSION(0, 1, 0), - VK_MAKE_VERSION(1, 0, 0), - }; - - // Get the number of supported extensions and layers - VkResult vr = VK_SUCCESS; - uint32_t nExtProps = 0; - uint32_t nLayerProps = 0; - if ((vr = vkEnumerateInstanceLayerProperties(&nLayerProps, NULL)) || - (vr = vkEnumerateInstanceExtensionProperties(NULL, &nExtProps, NULL))) { - return vr; - } - - // Get properties of supported extensions - VkExtensionProperties* extProps = AALLOC(nExtProps, VkExtensionProperties); - vkEnumerateInstanceExtensionProperties(NULL, &nExtProps, extProps); - - uint32_t nExtensions = 0; - const char** extensions = NULL; - - // Add extensions required by pugl - uint32_t nPuglExts = 0; - const char* const* puglExts = puglGetInstanceExtensions(&nPuglExts); - for (uint32_t i = 0; i < nPuglExts; ++i) { - pushString(&extensions, &nExtensions, puglExts[i]); - } - - // Add extra extensions we want to use if they are supported - if (hasExtension("VK_EXT_debug_report", extProps, nExtProps)) { - pushString(&extensions, &nExtensions, "VK_EXT_debug_report"); - } - - // Get properties of supported layers - VkLayerProperties* layerProps = AALLOC(nLayerProps, VkLayerProperties); - vkEnumerateInstanceLayerProperties(&nLayerProps, layerProps); - - const VkInstanceCreateInfo createInfo = { - VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, - NULL, - 0, - &appInfo, - COUNTED(0, NULL), - COUNTED(nExtensions, extensions), - }; - - if ((vr = vkCreateInstance(&createInfo, ALLOC_VK, &test->instance))) { - logError("Could not create Vulkan Instance: %d\n", vr); - } - - free(extensions); - free(layerProps); - free(extProps); - - return vr; -} - -int -main(int argc, char** argv) -{ - PuglWorld* const world = puglNewWorld(PUGL_PROGRAM, PUGL_WORLD_THREADS); - - PuglView* const view = puglNewView(world); - PuglVulkanLoader* const loader = puglNewVulkanLoader(world); - const PuglTestOptions opts = puglParseTestOptions(&argc, &argv); - - PuglTest test = {world, view, VK_NULL_HANDLE, VK_NULL_HANDLE, opts, false}; - - // Create Vulkan instance - assert(!createInstance(&test)); - - // Create window - puglSetClassName(test.world, "Pugl Vulkan Test"); - puglSetHandle(test.view, &test); - puglSetBackend(test.view, puglVulkanBackend()); - puglSetEventFunc(test.view, onEvent); - puglSetDefaultSize(test.view, 512, 512); - assert(!puglRealize(test.view)); - - // Create Vulkan surface for window - assert(!puglCreateSurface(puglGetInstanceProcAddrFunc(loader), - test.view, - test.instance, - ALLOC_VK, - &test.surface)); - - // Check that loading functions are available - assert(puglGetInstanceProcAddrFunc(loader)); - assert(puglGetDeviceProcAddrFunc(loader)); - - // Show view and drive event loop until the view gets exposed - puglShow(test.view); - while (!test.exposed) { - puglUpdate(test.world, -1.0); - } - - // Tear down - puglFreeVulkanLoader(loader); - puglFreeView(test.view); - puglFreeWorld(test.world); - - return 0; -} diff --git a/dpf/dgl/src/pugl-upstream/test/test_world.c b/dpf/dgl/src/pugl-upstream/test/test_world.c deleted file mode 100644 index 2c5229f..0000000 --- a/dpf/dgl/src/pugl-upstream/test/test_world.c +++ /dev/null @@ -1,50 +0,0 @@ -/* - Copyright 2021 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/* - Tests basic functionality of, and access to, the world. -*/ - -#undef NDEBUG - -#include "pugl/pugl.h" - -#include -#include - -int -main(void) -{ - PuglWorld* const world = puglNewWorld(PUGL_PROGRAM, 0); - PuglView* const view = puglNewView(world); - - // Check that the world can be accessed from the view - assert(puglGetWorld(view) == world); - - // Check that puglGetNativeWorld() returns something - assert(puglGetNativeWorld(world)); - - // Set and get world handle - uintptr_t data = 1234; - puglSetWorldHandle(world, &data); - assert(puglGetWorldHandle(world) == &data); - - // Tear down - puglFreeView(view); - puglFreeWorld(world); - - return 0; -} diff --git a/dpf/dgl/src/pugl.cpp b/dpf/dgl/src/pugl.cpp index f18dcb2..5ed3b5b 100644 --- a/dpf/dgl/src/pugl.cpp +++ b/dpf/dgl/src/pugl.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho + * Copyright (C) 2012-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -16,20 +16,32 @@ #include "pugl.hpp" +// -------------------------------------------------------------------------------------------------------------------- +// include base headers + +#ifdef DGL_CAIRO +# include +#endif +#ifdef DGL_OPENGL +# include "../OpenGL-include.hpp" +#endif +#ifdef DGL_VULKAN +# include +#endif + /* we will include all header files used in pugl in their C++ friendly form, then pugl stuff in custom namespace */ #include #include #include +#include #include #include -#if defined(DISTRHO_OS_HAIKU) -#elif defined(DISTRHO_OS_MAC) +#if defined(DISTRHO_OS_MAC) # import # include # include # ifdef DGL_CAIRO -# include # include # endif # ifdef DGL_OPENGL @@ -37,16 +49,20 @@ # endif # ifdef DGL_VULKAN # import -# include # include # endif +#elif defined(DISTRHO_OS_WASM) +# include +# include +# ifdef DGL_OPENGL +# include +# endif #elif defined(DISTRHO_OS_WINDOWS) # include # include # include # include # ifdef DGL_CAIRO -# include # include # endif # ifdef DGL_OPENGL @@ -56,11 +72,12 @@ # include # include # endif -#else +#elif defined(HAVE_X11) # include +# include # include # include -# include +// # include # include # include # include @@ -69,7 +86,7 @@ # include # ifdef HAVE_XCURSOR # include -# include +// # include # endif # ifdef HAVE_XRANDR # include @@ -79,25 +96,24 @@ # include # endif # ifdef DGL_CAIRO -# include # include # endif # ifdef DGL_OPENGL -# include # include # endif # ifdef DGL_VULKAN -# include # include # endif #endif #ifndef DGL_FILE_BROWSER_DISABLED -# ifdef DISTRHO_OS_MAC -# import "../../distrho/extra/FileBrowserDialog.cpp" -# else -# include "../../distrho/extra/FileBrowserDialog.cpp" -# endif +# define FILE_BROWSER_DIALOG_DGL_NAMESPACE +# define FILE_BROWSER_DIALOG_NAMESPACE DGL_NAMESPACE +# define DGL_FILE_BROWSER_DIALOG_HPP_INCLUDED +START_NAMESPACE_DGL +# include "../../distrho/extra/FileBrowserDialogImpl.hpp" +END_NAMESPACE_DGL +# include "../../distrho/extra/FileBrowserDialogImpl.cpp" #endif #ifndef DISTRHO_OS_MAC @@ -106,17 +122,17 @@ START_NAMESPACE_DGL // -------------------------------------------------------------------------------------------------------------------- -#if defined(DISTRHO_OS_HAIKU) -#elif defined(DISTRHO_OS_MAC) +#if defined(DISTRHO_OS_MAC) # ifndef DISTRHO_MACOS_NAMESPACE_MACRO # define DISTRHO_MACOS_NAMESPACE_MACRO_HELPER(NS, SEP, INTERFACE) NS ## SEP ## INTERFACE # define DISTRHO_MACOS_NAMESPACE_MACRO(NS, INTERFACE) DISTRHO_MACOS_NAMESPACE_MACRO_HELPER(NS, _, INTERFACE) -# define PuglStubView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PuglStubView) -# define PuglWrapperView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PuglWrapperView) -# define PuglWindow DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PuglWindow) -# endif -# ifndef __MAC_10_9 -# define NSModalResponseOK NSOKButton +# define PuglCairoView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PuglCairoView) +# define PuglOpenGLView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PuglOpenGLView) +# define PuglStubView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PuglStubView) +# define PuglVulkanView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PuglVulkanView) +# define PuglWindow DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PuglWindow) +# define PuglWindowDelegate DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PuglWindowDelegate) +# define PuglWrapperView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PuglWrapperView) # endif # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wdeprecated-declarations" @@ -132,6 +148,12 @@ START_NAMESPACE_DGL # import "pugl-upstream/src/mac_vulkan.m" # endif # pragma clang diagnostic pop +#elif defined(DISTRHO_OS_WASM) +# include "pugl-upstream/src/wasm.c" +# include "pugl-upstream/src/wasm_stub.c" +# ifdef DGL_OPENGL +# include "pugl-upstream/src/wasm_gl.c" +# endif #elif defined(DISTRHO_OS_WINDOWS) # include "pugl-upstream/src/win.c" # include "pugl-upstream/src/win_stub.c" @@ -144,7 +166,7 @@ START_NAMESPACE_DGL # ifdef DGL_VULKAN # include "pugl-upstream/src/win_vulkan.c" # endif -#else +#elif defined(HAVE_X11) # include "pugl-upstream/src/x11.c" # include "pugl-upstream/src/x11_stub.c" # ifdef DGL_CAIRO @@ -158,119 +180,41 @@ START_NAMESPACE_DGL # endif #endif -#include "pugl-upstream/src/implementation.c" +#include "pugl-upstream/src/common.c" +#include "pugl-upstream/src/internal.c" // -------------------------------------------------------------------------------------------------------------------- -// expose backend enter +// DGL specific, expose backend enter bool puglBackendEnter(PuglView* const view) { - return view->backend->enter(view, NULL) == PUGL_SUCCESS; -} - -// -------------------------------------------------------------------------------------------------------------------- -// expose backend leave - -void puglBackendLeave(PuglView* const view) -{ - view->backend->leave(view, NULL); -} - -// -------------------------------------------------------------------------------------------------------------------- -// clear minimum size to 0 - -void puglClearMinSize(PuglView* const view) -{ - view->minWidth = 0; - view->minHeight = 0; -} - -// -------------------------------------------------------------------------------------------------------------------- -// missing in pugl, directly returns transient parent - -PuglNativeView puglGetTransientParent(const PuglView* const view) -{ - return view->transientParent; + return view->backend->enter(view, nullptr) == PUGL_SUCCESS; } // -------------------------------------------------------------------------------------------------------------------- -// missing in pugl, directly returns title char* pointer +// DGL specific, expose backend leave -const char* puglGetWindowTitle(const PuglView* const view) +bool puglBackendLeave(PuglView* const view) { - return view->title; + return view->backend->leave(view, nullptr) == PUGL_SUCCESS; } // -------------------------------------------------------------------------------------------------------------------- -// get global scale factor +// DGL specific, assigns backend that matches current DGL build -double puglGetDesktopScaleFactor(const PuglView* const view) +void puglSetMatchingBackendForCurrentBuild(PuglView* const view) { -#if defined(DISTRHO_OS_MAC) - if (NSWindow* const window = view->impl->window ? view->impl->window - : [view->impl->wrapperView window]) - return [window screen].backingScaleFactor; - return [NSScreen mainScreen].backingScaleFactor; -#elif defined(DISTRHO_OS_WINDOWS) - if (const HMODULE Shcore = LoadLibraryA("Shcore.dll")) - { - typedef HRESULT(WINAPI* PFN_GetProcessDpiAwareness)(HANDLE, DWORD*); - typedef HRESULT(WINAPI* PFN_GetScaleFactorForMonitor)(HMONITOR, DWORD*); - -# if defined(__GNUC__) && (__GNUC__ >= 9) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wcast-function-type" -# endif - const PFN_GetProcessDpiAwareness GetProcessDpiAwareness - = (PFN_GetProcessDpiAwareness)GetProcAddress(Shcore, "GetProcessDpiAwareness"); - const PFN_GetScaleFactorForMonitor GetScaleFactorForMonitor - = (PFN_GetScaleFactorForMonitor)GetProcAddress(Shcore, "GetScaleFactorForMonitor"); -# if defined(__GNUC__) && (__GNUC__ >= 9) -# pragma GCC diagnostic pop -# endif - - DWORD dpiAware = 0; - if (GetProcessDpiAwareness && GetScaleFactorForMonitor - && GetProcessDpiAwareness(NULL, &dpiAware) == 0 && dpiAware != 0) - { - const HMONITOR hMon = MonitorFromWindow(view->impl->hwnd, MONITOR_DEFAULTTOPRIMARY); - - DWORD scaleFactor = 0; - if (GetScaleFactorForMonitor(hMon, &scaleFactor) == 0 && scaleFactor != 0) - { - FreeLibrary(Shcore); - return static_cast(scaleFactor) / 100.0; - } - } - - FreeLibrary(Shcore); - } -#elif defined(HAVE_X11) - XrmInitialize(); - - if (char* const rms = XResourceManagerString(view->world->impl->display)) - { - if (const XrmDatabase sdb = XrmGetStringDatabase(rms)) - { - char* type = nullptr; - XrmValue ret; - - if (XrmGetResource(sdb, "Xft.dpi", "String", &type, &ret) - && ret.addr != nullptr - && type != nullptr - && std::strncmp("String", type, 6) == 0) - { - if (const double dpi = std::atof(ret.addr)) - return dpi / 96; - } - } - } -#else - // unused - (void)view; +#ifdef DGL_CAIRO + puglSetBackend(view, puglCairoBackend()); #endif - - return 1.0; +#ifdef DGL_OPENGL + puglSetBackend(view, puglGlBackend()); +#endif +#ifdef DGL_VULKAN + puglSetBackend(view, puglVulkanBackend()); +#endif + if (view->backend == nullptr) + puglSetBackend(view, puglStubBackend()); } // -------------------------------------------------------------------------------------------------------------------- @@ -278,134 +222,173 @@ double puglGetDesktopScaleFactor(const PuglView* const view) void puglRaiseWindow(PuglView* const view) { -#if defined(DISTRHO_OS_HAIKU) - // nothing here yet -#elif defined(DISTRHO_OS_MAC) +#if defined(DISTRHO_OS_MAC) if (NSWindow* const window = view->impl->window ? view->impl->window : [view->impl->wrapperView window]) [window orderFrontRegardless]; +#elif defined(DISTRHO_OS_WASM) + // nothing #elif defined(DISTRHO_OS_WINDOWS) SetForegroundWindow(view->impl->hwnd); SetActiveWindow(view->impl->hwnd); -#else - XRaiseWindow(view->impl->display, view->impl->win); +#elif defined(HAVE_X11) + XRaiseWindow(view->world->impl->display, view->impl->win); #endif } // -------------------------------------------------------------------------------------------------------------------- -// set backend that matches current build +// get scale factor from parent window if possible, fallback to puglGetScaleFactor -void puglSetMatchingBackendForCurrentBuild(PuglView* const view) +double puglGetScaleFactorFromParent(const PuglView* const view) { -#ifdef DGL_CAIRO - puglSetBackend(view, puglCairoBackend()); -#endif -#ifdef DGL_OPENGL - puglSetBackend(view, puglGlBackend()); -#endif -#ifdef DGL_VULKAN - puglSetBackend(view, puglVulkanBackend()); + const PuglNativeView parent = view->parent ? view->parent : view->transientParent ? view->transientParent : 0; +#if defined(DISTRHO_OS_MAC) + // some of these can return 0 as backingScaleFactor, pick the most relevant valid one + const NSWindow* possibleWindows[] = { + parent != 0 ? [(NSView*)parent window] : nullptr, + view->impl->window, + [view->impl->wrapperView window] + }; + for (size_t i=0; iimpl->hwnd; + return puglWinGetViewScaleFactor(hwnd); +#else + return puglGetScaleFactor(view); + // unused + (void)parent; #endif - if (view->backend == nullptr) - puglSetBackend(view, puglStubBackend()); } // -------------------------------------------------------------------------------------------------------------------- -// Combine puglSetMinSize and puglSetAspectRatio +// Combined puglSetSizeHint using PUGL_MIN_SIZE and PUGL_FIXED_ASPECT PuglStatus puglSetGeometryConstraints(PuglView* const view, const uint width, const uint height, const bool aspect) { - view->minWidth = (int)width; - view->minHeight = (int)height; - - if (aspect) { - view->minAspectX = (int)width; - view->minAspectY = (int)height; - view->maxAspectX = (int)width; - view->maxAspectY = (int)height; + view->sizeHints[PUGL_MIN_SIZE].width = width; + view->sizeHints[PUGL_MIN_SIZE].height = height; + + if (aspect) + { + view->sizeHints[PUGL_FIXED_ASPECT].width = width; + view->sizeHints[PUGL_FIXED_ASPECT].height = height; } -#if defined(DISTRHO_OS_HAIKU) || defined(DISTRHO_OS_MAC) - puglSetMinSize(view, width, height); +#if defined(DISTRHO_OS_MAC) + if (view->impl->window) + { + PuglStatus status; - if (aspect) { - puglSetAspectRatio(view, width, height, width, height); + if ((status = updateSizeHint(view, PUGL_MIN_SIZE)) != PUGL_SUCCESS) + return status; + + if (aspect && (status = updateSizeHint(view, PUGL_FIXED_ASPECT)) != PUGL_SUCCESS) + return status; } +#elif defined(DISTRHO_OS_WASM) + // nothing #elif defined(DISTRHO_OS_WINDOWS) // nothing -#else +#elif defined(HAVE_X11) if (const PuglStatus status = updateSizeHints(view)) return status; - XFlush(view->impl->display); + XFlush(view->world->impl->display); #endif return PUGL_SUCCESS; } // -------------------------------------------------------------------------------------------------------------------- -// set window size with default size and without changing frame x/y position +// set view as resizable (or not) during runtime + +void puglSetResizable(PuglView* const view, const bool resizable) +{ + puglSetViewHint(view, PUGL_RESIZABLE, resizable ? PUGL_TRUE : PUGL_FALSE); + +#if defined(DISTRHO_OS_MAC) + if (PuglWindow* const window = view->impl->window) + { + const uint style = (NSClosableWindowMask | NSTitledWindowMask | NSMiniaturizableWindowMask) + | (resizable ? NSResizableWindowMask : 0x0); + [window setStyleMask:style]; + } + // FIXME use [view setAutoresizingMask:NSViewNotSizable] ? +#elif defined(DISTRHO_OS_WASM) + // nothing +#elif defined(DISTRHO_OS_WINDOWS) + if (const HWND hwnd = view->impl->hwnd) + { + const uint winFlags = resizable ? GetWindowLong(hwnd, GWL_STYLE) | (WS_SIZEBOX | WS_MAXIMIZEBOX) + : GetWindowLong(hwnd, GWL_STYLE) & ~(WS_SIZEBOX | WS_MAXIMIZEBOX); + SetWindowLong(hwnd, GWL_STYLE, winFlags); + } +#elif defined(HAVE_X11) + updateSizeHints(view); +#endif +} + +// -------------------------------------------------------------------------------------------------------------------- +// set window size while also changing default -PuglStatus puglSetWindowSize(PuglView* const view, const uint width, const uint height) +PuglStatus puglSetSizeAndDefault(PuglView* view, uint width, uint height) { - view->defaultWidth = width; - view->defaultHeight = height; - view->frame.width = width; - view->frame.height = height; - -#if defined(DISTRHO_OS_HAIKU) -#elif defined(DISTRHO_OS_MAC) - // replace setFrame with setFrameSize + if (width > INT16_MAX || height > INT16_MAX) + return PUGL_BAD_PARAMETER; + + view->sizeHints[PUGL_DEFAULT_SIZE].width = view->frame.width = static_cast(width); + view->sizeHints[PUGL_DEFAULT_SIZE].height = view->frame.height = static_cast(height); + +#if defined(DISTRHO_OS_MAC) + // mostly matches upstream pugl, simplified PuglInternals* const impl = view->impl; const PuglRect frame = view->frame; const NSRect framePx = rectToNsRect(frame); const NSRect framePt = nsRectToPoints(view, framePx); - if (impl->window) + if (PuglWindow* const window = view->impl->window) { - // Resize window to fit new content rect const NSRect screenPt = rectToScreen(viewScreen(view), framePt); - const NSRect winFrame = [impl->window frameRectForContentRect:screenPt]; - - [impl->window setFrame:winFrame display:NO]; + const NSRect winFrame = [window frameRectForContentRect:screenPt]; + [window setFrame:winFrame display:NO]; } - // Resize views const NSSize sizePx = NSMakeSize(frame.width, frame.height); const NSSize sizePt = [impl->drawView convertSizeFromBacking:sizePx]; - - [impl->wrapperView setFrameSize:(impl->window ? sizePt : framePt.size)]; + [impl->wrapperView setFrameSize:sizePt]; [impl->drawView setFrameSize:sizePt]; +#elif defined(DISTRHO_OS_WASM) + d_stdout("className is %s", view->world->className); + emscripten_set_canvas_element_size(view->world->className, width, height); #elif defined(DISTRHO_OS_WINDOWS) - // matches upstream pugl, except we add SWP_NOMOVE flag - if (view->impl->hwnd) + // matches upstream pugl, except we re-enter context after resize + if (const HWND hwnd = view->impl->hwnd) { - const PuglRect frame = view->frame; - - RECT rect = { (long)frame.x, - (long)frame.y, - (long)frame.x + (long)frame.width, - (long)frame.y + (long)frame.height }; - - AdjustWindowRectEx(&rect, puglWinGetWindowFlags(view), FALSE, puglWinGetWindowExFlags(view)); - - if (! SetWindowPos(view->impl->hwnd, - HWND_TOP, - rect.left, - rect.top, - rect.right - rect.left, - rect.bottom - rect.top, - SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER)) + const RECT rect = adjustedWindowRect(view, view->frame.x, view->frame.y, + static_cast(width), static_cast(height)); + + if (!SetWindowPos(hwnd, HWND_TOP, 0, 0, rect.right - rect.left, rect.bottom - rect.top, + SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOMOVE)) return PUGL_UNKNOWN_ERROR; + + // make sure to return context back to ourselves + puglBackendEnter(view); } -#else - // matches upstream pugl, except we use XResizeWindow instead of XMoveResizeWindow - if (view->impl->win) +#elif defined(HAVE_X11) + // matches upstream pugl, all in one + if (const Window window = view->impl->win) { - Display* const display = view->impl->display; + Display* const display = view->world->impl->display; - if (! XResizeWindow(display, view->impl->win, width, height)) + if (! XResizeWindow(display, window, width, height)) return PUGL_UNKNOWN_ERROR; if (const PuglStatus status = updateSizeHints(view)) @@ -425,7 +408,9 @@ void puglOnDisplayPrepare(PuglView*) { #ifdef DGL_OPENGL glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +# ifndef DGL_USE_GLES glLoadIdentity(); +# endif #endif } @@ -437,24 +422,26 @@ void puglFallbackOnResize(PuglView* const view) #ifdef DGL_OPENGL glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +# ifndef DGL_USE_GLES glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0.0, static_cast(view->frame.width), static_cast(view->frame.height), 0.0, 0.0, 1.0); glViewport(0, 0, static_cast(view->frame.width), static_cast(view->frame.height)); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); +# else + glViewport(0, 0, static_cast(view->frame.width), static_cast(view->frame.height)); +# endif +#else + return; + // unused + (void)view; #endif } -#ifdef DISTRHO_OS_MAC // -------------------------------------------------------------------------------------------------------------------- -// macOS specific, allow standalone window to gain focus -void puglMacOSActivateApp() -{ - [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; - [NSApp activateIgnoringOtherApps:YES]; -} +#if defined(DISTRHO_OS_MAC) // -------------------------------------------------------------------------------------------------------------------- // macOS specific, add another view's window as child @@ -512,8 +499,8 @@ void puglMacOSShowCentered(PuglView* const view) const NSRect ourFrame = [view->impl->window frame]; const NSRect transientFrame = [transientWindow frame]; - const int x = transientFrame.origin.x + transientFrame.size.width / 2 - ourFrame.size.width / 2; - const int y = transientFrame.origin.y + transientFrame.size.height / 2 + ourFrame.size.height / 2; + const int x = transientFrame.origin.x + (transientFrame.size.width - ourFrame.size.width) / 2; + const int y = transientFrame.origin.y + (transientFrame.size.height - ourFrame.size.height) / 2; [view->impl->window setFrameTopLeftPoint:NSMakePoint(x, y)]; } @@ -524,9 +511,9 @@ void puglMacOSShowCentered(PuglView* const view) } // -------------------------------------------------------------------------------------------------------------------- -#endif -#ifdef DISTRHO_OS_WINDOWS +#elif defined(DISTRHO_OS_WINDOWS) + // -------------------------------------------------------------------------------------------------------------------- // win32 specific, call ShowWindow with SW_RESTORE @@ -560,49 +547,62 @@ void puglWin32ShowCentered(PuglView* const view) } else { - ShowWindow(impl->hwnd, SW_SHOWNORMAL); +#ifdef DGL_WINDOWS_ICON_ID + WNDCLASSEX wClass; + std::memset(&wClass, 0, sizeof(wClass)); + + const HINSTANCE hInstance = GetModuleHandle(nullptr); + + if (GetClassInfoEx(hInstance, view->world->className, &wClass)) + wClass.hIcon = LoadIcon(nullptr, MAKEINTRESOURCE(DGL_WINDOWS_ICON_ID)); + + SetClassLongPtr(impl->hwnd, GCLP_HICON, (LONG_PTR) LoadIcon(hInstance, MAKEINTRESOURCE(DGL_WINDOWS_ICON_ID))); +#endif + + MONITORINFO mInfo; + std::memset(&mInfo, 0, sizeof(mInfo)); + mInfo.cbSize = sizeof(mInfo); + + if (GetMonitorInfo(MonitorFromWindow(impl->hwnd, MONITOR_DEFAULTTOPRIMARY), &mInfo)) + SetWindowPos(impl->hwnd, + HWND_TOP, + mInfo.rcWork.left + (mInfo.rcWork.right - mInfo.rcWork.left - view->frame.width) / 2, + mInfo.rcWork.top + (mInfo.rcWork.bottom - mInfo.rcWork.top - view->frame.height) / 2, + 0, 0, SWP_SHOWWINDOW|SWP_NOSIZE); + else + ShowWindow(impl->hwnd, SW_NORMAL); } SetFocus(impl->hwnd); } // -------------------------------------------------------------------------------------------------------------------- -// win32 specific, set or unset WS_SIZEBOX style flag -void puglWin32SetWindowResizable(PuglView* const view, const bool resizable) -{ - PuglInternals* impl = view->impl; - DISTRHO_SAFE_ASSERT_RETURN(impl->hwnd != nullptr,); +#elif defined(DISTRHO_OS_WASM) - const int winFlags = resizable ? GetWindowLong(impl->hwnd, GWL_STYLE) | WS_SIZEBOX - : GetWindowLong(impl->hwnd, GWL_STYLE) & ~WS_SIZEBOX; - SetWindowLong(impl->hwnd, GWL_STYLE, winFlags); -} +// nothing here yet // -------------------------------------------------------------------------------------------------------------------- -#endif -#ifdef HAVE_X11 -// -------------------------------------------------------------------------------------------------------------------- -// X11 specific, safer way to grab focus +#elif defined(HAVE_X11) -PuglStatus puglX11GrabFocus(const PuglView* const view) +PuglStatus puglX11UpdateWithoutExposures(PuglWorld* const world) { - const PuglInternals* const impl = view->impl; - - XWindowAttributes wa; - std::memset(&wa, 0, sizeof(wa)); + const bool wasDispatchingEvents = world->impl->dispatchingEvents; + world->impl->dispatchingEvents = true; + PuglStatus st = PUGL_SUCCESS; - DISTRHO_SAFE_ASSERT_RETURN(XGetWindowAttributes(impl->display, impl->win, &wa), PUGL_UNKNOWN_ERROR); + const double startTime = puglGetTime(world); + const double endTime = startTime + 0.03; - if (wa.map_state == IsViewable) + for (double t = startTime; !st && t < endTime; t = puglGetTime(world)) { - XRaiseWindow(impl->display, impl->win); - XSetInputFocus(impl->display, impl->win, RevertToPointerRoot, CurrentTime); - XSync(impl->display, False); + pollX11Socket(world, endTime - t); + st = dispatchX11Events(world); } - return PUGL_SUCCESS; + world->impl->dispatchingEvents = wasDispatchingEvents; + return st; } // -------------------------------------------------------------------------------------------------------------------- @@ -610,26 +610,28 @@ PuglStatus puglX11GrabFocus(const PuglView* const view) void puglX11SetWindowTypeAndPID(const PuglView* const view, const bool isStandalone) { - const PuglInternals* const impl = view->impl; + const PuglInternals* const impl = view->impl; + Display* const display = view->world->impl->display; const pid_t pid = getpid(); - const Atom _nwp = XInternAtom(impl->display, "_NET_WM_PID", False); - XChangeProperty(impl->display, impl->win, _nwp, XA_CARDINAL, 32, PropModeReplace, (const uchar*)&pid, 1); + const Atom _nwp = XInternAtom(display, "_NET_WM_PID", False); + XChangeProperty(display, impl->win, _nwp, XA_CARDINAL, 32, PropModeReplace, (const uchar*)&pid, 1); - const Atom _wt = XInternAtom(impl->display, "_NET_WM_WINDOW_TYPE", False); + const Atom _wt = XInternAtom(display, "_NET_WM_WINDOW_TYPE", False); Atom _wts[2]; int numAtoms = 0; if (! isStandalone) - _wts[numAtoms++] = XInternAtom(impl->display, "_NET_WM_WINDOW_TYPE_DIALOG", False); + _wts[numAtoms++] = XInternAtom(display, "_NET_WM_WINDOW_TYPE_DIALOG", False); - _wts[numAtoms++] = XInternAtom(impl->display, "_NET_WM_WINDOW_TYPE_NORMAL", False); + _wts[numAtoms++] = XInternAtom(display, "_NET_WM_WINDOW_TYPE_NORMAL", False); - XChangeProperty(impl->display, impl->win, _wt, XA_ATOM, 32, PropModeReplace, (const uchar*)&_wts, numAtoms); + XChangeProperty(display, impl->win, _wt, XA_ATOM, 32, PropModeReplace, (const uchar*)&_wts, numAtoms); } // -------------------------------------------------------------------------------------------------------------------- + #endif // HAVE_X11 #ifndef DISTRHO_OS_MAC diff --git a/dpf/dgl/src/pugl.hpp b/dpf/dgl/src/pugl.hpp index 2075627..d5d540b 100644 --- a/dpf/dgl/src/pugl.hpp +++ b/dpf/dgl/src/pugl.hpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho + * Copyright (C) 2012-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -19,7 +19,7 @@ #include "../Base.hpp" -/* we will include all header files used in pugl in their C++ friendly form, then pugl stuff in custom namespace */ +/* we will include all header files used in pugl.h in their C++ friendly form, then pugl stuff in custom namespace */ #include #ifdef DISTRHO_PROPER_CPP11_SUPPORT # include @@ -29,115 +29,84 @@ # include #endif +// hidden api #define PUGL_API #define PUGL_DISABLE_DEPRECATED +#define PUGL_NO_INCLUDE_GL_H #define PUGL_NO_INCLUDE_GLU_H -// -------------------------------------------------------------------------------------------------------------------- - #ifndef DISTRHO_OS_MAC START_NAMESPACE_DGL -#else -USE_NAMESPACE_DGL #endif #include "pugl-upstream/include/pugl/pugl.h" // -------------------------------------------------------------------------------------------------------------------- -PUGL_BEGIN_DECLS - -// expose backend enter -PUGL_API bool -puglBackendEnter(PuglView* view); - -// expose backend leave -PUGL_API void -puglBackendLeave(PuglView* view); +// DGL specific, expose backend enter +bool puglBackendEnter(PuglView* view); -// clear minimum size to 0 -PUGL_API void -puglClearMinSize(PuglView* view); +// DGL specific, expose backend leave +bool puglBackendLeave(PuglView* view); -// missing in pugl, directly returns transient parent -PUGL_API PuglNativeView -puglGetTransientParent(const PuglView* view); - -// missing in pugl, directly returns title char* pointer -PUGL_API const char* -puglGetWindowTitle(const PuglView* view); - -// get global scale factor -PUGL_API double -puglGetDesktopScaleFactor(const PuglView* view); +// DGL specific, assigns backend that matches current DGL build +void puglSetMatchingBackendForCurrentBuild(PuglView* view); // bring view window into the foreground, aka "raise" window -PUGL_API void -puglRaiseWindow(PuglView* view); +void puglRaiseWindow(PuglView* view); -// DGL specific, assigns backend that matches current DGL build -PUGL_API void -puglSetMatchingBackendForCurrentBuild(PuglView* view); +// get scale factor from parent window if possible, fallback to puglGetScaleFactor +double puglGetScaleFactorFromParent(const PuglView* view); -// Combine puglSetMinSize and puglSetAspectRatio -PUGL_API PuglStatus -puglSetGeometryConstraints(PuglView* view, unsigned int width, unsigned int height, bool aspect); +// combined puglSetSizeHint using PUGL_MIN_SIZE, PUGL_MIN_ASPECT and PUGL_MAX_ASPECT +PuglStatus puglSetGeometryConstraints(PuglView* view, uint width, uint height, bool aspect); -// set window size with default size and without changing frame x/y position -PUGL_API PuglStatus -puglSetWindowSize(PuglView* view, unsigned int width, unsigned int height); +// set view as resizable (or not) during runtime +void puglSetResizable(PuglView* view, bool resizable); + +// set window size while also changing default +PuglStatus puglSetSizeAndDefault(PuglView* view, uint width, uint height); // DGL specific, build-specific drawing prepare -PUGL_API void -puglOnDisplayPrepare(PuglView* view); +void puglOnDisplayPrepare(PuglView* view); // DGL specific, build-specific fallback resize -PUGL_API void -puglFallbackOnResize(PuglView* view); +void puglFallbackOnResize(PuglView* view); -#ifdef DISTRHO_OS_MAC -// macOS specific, allow standalone window to gain focus -PUGL_API void -puglMacOSActivateApp(); +#if defined(DISTRHO_OS_MAC) // macOS specific, add another view's window as child -PUGL_API PuglStatus -puglMacOSAddChildWindow(PuglView* view, PuglView* child); +PuglStatus puglMacOSAddChildWindow(PuglView* view, PuglView* child); // macOS specific, remove another view's window as child -PUGL_API PuglStatus -puglMacOSRemoveChildWindow(PuglView* view, PuglView* child); +PuglStatus puglMacOSRemoveChildWindow(PuglView* view, PuglView* child); // macOS specific, center view based on parent coordinates (if there is one) -PUGL_API void -puglMacOSShowCentered(PuglView* view); -#endif +void puglMacOSShowCentered(PuglView* view); + +#elif defined(DISTRHO_OS_WASM) + +// nothing here yet + +#elif defined(DISTRHO_OS_WINDOWS) -#ifdef DISTRHO_OS_WINDOWS // win32 specific, call ShowWindow with SW_RESTORE -PUGL_API void -puglWin32RestoreWindow(PuglView* view); +void puglWin32RestoreWindow(PuglView* view); // win32 specific, center view based on parent coordinates (if there is one) -PUGL_API void -puglWin32ShowCentered(PuglView* view); +void puglWin32ShowCentered(PuglView* view); -// win32 specific, set or unset WS_SIZEBOX style flag -PUGL_API void -puglWin32SetWindowResizable(PuglView* view, bool resizable); -#endif +#elif defined(HAVE_X11) + +#define DGL_USING_X11 -#ifdef HAVE_X11 -// X11 specific, safer way to grab focus -PUGL_API PuglStatus -puglX11GrabFocus(const PuglView* view); +// X11 specific, update world without triggering exposure evente +PuglStatus puglX11UpdateWithoutExposures(PuglWorld* world); // X11 specific, set dialog window type and pid hints -PUGL_API void -puglX11SetWindowTypeAndPID(const PuglView* view, bool isStandalone); -#endif +void puglX11SetWindowTypeAndPID(const PuglView* view, bool isStandalone); -PUGL_END_DECLS +#endif // -------------------------------------------------------------------------------------------------------------------- diff --git a/dpf/distrho/DistrhoPlugin.hpp b/dpf/distrho/DistrhoPlugin.hpp index 80de8c8..964acdc 100644 --- a/dpf/distrho/DistrhoPlugin.hpp +++ b/dpf/distrho/DistrhoPlugin.hpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho + * Copyright (C) 2012-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -135,6 +135,52 @@ static const uint32_t kParameterIsTrigger = 0x20 | kParameterIsBoolean; /** @} */ +/* ------------------------------------------------------------------------------------------------------------ + * State Hints */ + +/** + @defgroup StateHints State Hints + + Various state hints. + @see State::hints + @{ + */ + +/** + State is visible and readable by hosts that support string-type plugin parameters. + */ +static const uint32_t kStateIsHostReadable = 0x01; + +/** + State is writable by the host, allowing users to arbitrarily change the state.@n + For obvious reasons a writable state is also readable by the host. + */ +static const uint32_t kStateIsHostWritable = 0x02 | kStateIsHostReadable; + +/** + State is a filename path instead of a regular string.@n + The readable and writable hints are required for filenames to work, and thus are automatically set. + */ +static const uint32_t kStateIsFilenamePath = 0x04 | kStateIsHostWritable; + +/** + State is a base64 encoded string. + */ +static const uint32_t kStateIsBase64Blob = 0x08; + +/** + State is for Plugin/DSP side only, meaning there is never a need to notify the UI when it changes. + */ +static const uint32_t kStateIsOnlyForDSP = 0x10; + +/** + State is for UI side only.@n + If the DSP and UI are separate and the UI is not available, this property won't be saved. + */ +static const uint32_t kStateIsOnlyForUI = 0x20; + +/** @} */ + /* ------------------------------------------------------------------------------------------------------------ * Base Plugin structs */ @@ -616,6 +662,49 @@ struct PortGroup { String symbol; }; +/** + State. + + In DPF states refer to key:value string pairs, used to store arbitrary non-parameter data.@n + By default states are completely internal to the plugin and not visible by the host.@n + Flags can be set to allow hosts to see and/or change them. + + TODO API under construction + */ +struct State { + /** + Hints describing this state. + @note Changing these hints can break compatibility with previously saved data. + @see StateHints + */ + uint32_t hints; + + /** + The key or "symbol" of this state.@n + A state key is a short restricted name used as a machine and human readable identifier. + @note State keys MUST be unique within a plugin instance. + TODO define rules for allowed characters, must be usable as URI non-encoded parameters + */ + String key; + + /** + The default value of this state.@n + Can be left empty if considered a valid initial state. + */ + String defaultValue; + + /** + String representation of this state. + */ + String label; + + /** + An extensive description/comment about this state. + @note This value is optional and only used for LV2. + */ + String description; +}; + /** MIDI event. */ @@ -661,6 +750,8 @@ struct TimePosition { /** Current host transport position in frames. + @note This value is not always monotonic, + with some plugin hosts assigning it based on a source that can accumulate rounding errors. */ uint64_t frame; @@ -903,6 +994,19 @@ public: bool requestParameterValueChange(uint32_t index, float value) noexcept; #endif +#if DISTRHO_PLUGIN_WANT_STATE + /** + Set state value and notify the host about the change.@n + This function will call `setState()` and also trigger an update on the UI side as necessary.@n + It must not be called during run.@n + The state must be host readable. + @note this function does nothing on DSSI plugin format, as DSSI only supports UI->DSP messages. + + TODO API under construction + */ + bool updateStateValue(const char* key, const char* value) noexcept; +#endif + protected: /* -------------------------------------------------------------------------------------------------------- * Information */ @@ -988,18 +1092,17 @@ protected: #if DISTRHO_PLUGIN_WANT_STATE /** - Set the state key and default value of @a index.@n + Initialize the state @a index.@n This function will be called once, shortly after the plugin is created.@n Must be implemented by your plugin class only if DISTRHO_PLUGIN_WANT_STATE is enabled. */ - virtual void initState(uint32_t index, String& stateKey, String& defaultStateValue); -#endif + virtual void initState(uint32_t index, State& state); -#if DISTRHO_PLUGIN_WANT_STATEFILES - /** - TODO API under construction - */ - virtual bool isStateFile(uint32_t index) = 0; + DISTRHO_DEPRECATED_BY("initState(uint32_t,State&)") + virtual void initState(uint32_t, String&, String&) {} + + DISTRHO_DEPRECATED_BY("initState(uint32_t,State&)") + virtual bool isStateFile(uint32_t) { return false; } #endif /* -------------------------------------------------------------------------------------------------------- diff --git a/dpf/distrho/DistrhoPluginMain.cpp b/dpf/distrho/DistrhoPluginMain.cpp index 6affef3..2676cca 100644 --- a/dpf/distrho/DistrhoPluginMain.cpp +++ b/dpf/distrho/DistrhoPluginMain.cpp @@ -32,6 +32,10 @@ #elif defined(DISTRHO_PLUGIN_TARGET_SHARED) DISTRHO_PLUGIN_EXPORT DISTRHO_NAMESPACE::Plugin* createSharedPlugin(); DISTRHO_PLUGIN_EXPORT DISTRHO_NAMESPACE::Plugin* createSharedPlugin() { return DISTRHO_NAMESPACE::createPlugin(); } +#elif defined(DISTRHO_PLUGIN_TARGET_STATIC) +START_NAMESPACE_DISTRHO +Plugin* createStaticPlugin() { return createPlugin(); } +END_NAMESPACE_DISTRHO #else # error unsupported format #endif diff --git a/dpf/distrho/DistrhoStandaloneUtils.hpp b/dpf/distrho/DistrhoStandaloneUtils.hpp new file mode 100644 index 0000000..00d3ada --- /dev/null +++ b/dpf/distrho/DistrhoStandaloneUtils.hpp @@ -0,0 +1,86 @@ +/* + * DISTRHO Plugin Framework (DPF) + * Copyright (C) 2012-2022 Filipe Coelho + * + * Permission to use, copy, modify, and/or distribute this software for any purpose with + * or without fee is hereby granted, provided that the above copyright notice and this + * permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD + * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef DISTRHO_STANDALONE_UTILS_HPP_INCLUDED +#define DISTRHO_STANDALONE_UTILS_HPP_INCLUDED + +#include "src/DistrhoDefines.h" + +START_NAMESPACE_DISTRHO + +/* ------------------------------------------------------------------------------------------------------------ + * Standalone plugin related utilities */ + +/** + @defgroup PluginRelatedUtilities Plugin related utilities + + @{ + */ + +/** + Check if the current standalone supports audio input. +*/ +bool supportsAudioInput(); + +/** + Check if the current standalone supports dynamic buffer size changes. +*/ +bool supportsBufferSizeChanges(); + +/** + Check if the current standalone supports MIDI. +*/ +bool supportsMIDI(); + +/** + Check if the current standalone has audio input enabled. +*/ +bool isAudioInputEnabled(); + +/** + Check if the current standalone has MIDI enabled. +*/ +bool isMIDIEnabled(); + +/** + Get the current buffer size. +*/ +uint32_t getBufferSize(); + +/** + Request permissions to use audio input. + Only valid to call if audio input is supported but not currently enabled. +*/ +bool requestAudioInput(); + +/** + Request change to a new buffer size. +*/ +bool requestBufferSizeChange(uint32_t newBufferSize); + +/** + Request permissions to use MIDI. + Only valid to call if MIDI is supported but not currently enabled. +*/ +bool requestMIDI(); + +/** @} */ + +// ----------------------------------------------------------------------------------------------------------- + +END_NAMESPACE_DISTRHO + +#endif // DISTRHO_STANDALONE_UTILS_HPP_INCLUDED diff --git a/dpf/distrho/DistrhoUI.hpp b/dpf/distrho/DistrhoUI.hpp index dc09efd..950077b 100644 --- a/dpf/distrho/DistrhoUI.hpp +++ b/dpf/distrho/DistrhoUI.hpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho + * Copyright (C) 2012-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -48,16 +48,14 @@ typedef DGL_NAMESPACE::NanoTopLevelWidget UIWidget; typedef DGL_NAMESPACE::TopLevelWidget UIWidget; #endif -#ifndef DGL_FILE_BROWSER_DISABLED +#if DISTRHO_UI_FILE_BROWSER # include "extra/FileBrowserDialog.hpp" #endif -START_NAMESPACE_DGL -class PluginWindow; -END_NAMESPACE_DGL - START_NAMESPACE_DISTRHO +class PluginWindow; + /* ------------------------------------------------------------------------------------------------------------ * DPF UI */ @@ -89,7 +87,7 @@ public: /** Destructor. */ - virtual ~UI(); + ~UI() override; /* -------------------------------------------------------------------------------------------------------- * Host state */ @@ -164,9 +162,7 @@ public: @TODO Document this. */ void setState(const char* key, const char* value); -#endif -#if DISTRHO_PLUGIN_WANT_STATEFILES /** Request a new file from the host, matching the properties of a state key.@n This will use the native host file browser if available, otherwise a DPF built-in file browser is used.@n @@ -187,7 +183,7 @@ public: void sendNote(uint8_t channel, uint8_t note, uint8_t velocity); #endif -#ifndef DGL_FILE_BROWSER_DISABLED +#if DISTRHO_UI_FILE_BROWSER /** Open a file browser dialog with this window as transient parent.@n A few options can be specified to setup the dialog. @@ -200,7 +196,7 @@ public: @note This is exactly the same API as provided by the Window class, but redeclared here so that non-embed/DGL based UIs can still use file browser related functions. */ - bool openFileBrowser(const FileBrowserOptions& options = FileBrowserOptions()); + bool openFileBrowser(const DISTRHO_NAMESPACE::FileBrowserOptions& options = FileBrowserOptions()); #endif #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS @@ -298,6 +294,23 @@ protected: virtual void uiScaleFactorChanged(double scaleFactor); #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI + /** + Get the types available for the data in a clipboard. + Must only be called within the context of uiClipboardDataOffer. + */ + std::vector getClipboardDataOfferTypes(); + + /** + Window clipboard data offer function, called when clipboard has data present, possibly with several datatypes. + While handling this event, the data types can be investigated with getClipboardDataOfferTypes() to decide whether to accept the offer. + + Reimplement and return a non-zero id to accept the clipboard data offer for a particular type. + UIs must ignore any type they do not recognize. + + The default implementation accepts the "text/plain" mimetype. + */ + virtual uint32_t uiClipboardDataOffer(); + /** Windows focus function, called when the window gains or loses the keyboard focus. This function is for plugin UIs to be able to override Window::onFocus(bool, CrossingMode). @@ -319,7 +332,7 @@ protected: virtual void uiReshape(uint width, uint height); #endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI -#ifndef DGL_FILE_BROWSER_DISABLED +#if DISTRHO_UI_FILE_BROWSER /** Window file selected function, called when a path is selected by the user, as triggered by openFileBrowser(). This function is for plugin UIs to be able to override Window::onFileSelected(const char*). @@ -327,7 +340,7 @@ protected: This action happens after the user confirms the action, so the file browser dialog will be closed at this point. The default implementation does nothing. - If you need to use files as plugin state, please setup and use DISTRHO_PLUGIN_WANT_STATEFILES instead. + If you need to use files as plugin state, please setup and use states with kStateIsFilenamePath instead. */ virtual void uiFileBrowserSelected(const char* filename); #endif @@ -356,7 +369,7 @@ protected: private: struct PrivateData; PrivateData* const uiData; - friend class DGL_NAMESPACE::PluginWindow; + friend class PluginWindow; friend class UIExporter; #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI /** @internal */ diff --git a/dpf/distrho/DistrhoUIMain.cpp b/dpf/distrho/DistrhoUIMain.cpp index aeeade5..656eb30 100644 --- a/dpf/distrho/DistrhoUIMain.cpp +++ b/dpf/distrho/DistrhoUIMain.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho + * Copyright (C) 2012-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -28,13 +28,13 @@ // nothing #elif defined(DISTRHO_PLUGIN_TARGET_VST3) # include "src/DistrhoUIVST3.cpp" -#elif defined(DISTRHO_PLUGIN_TARGET_SHARED) +#elif defined(DISTRHO_PLUGIN_TARGET_SHARED) || defined(DISTRHO_PLUGIN_TARGET_STATIC) // nothing #else # error unsupported format #endif -#if !DISTRHO_PLUGIN_WANT_DIRECT_ACCESS && !DISTRHO_PLUGIN_TARGET_JACK && !DISTRHO_PLUGIN_TARGET_VST2 && !DISTRHO_PLUGIN_TARGET_VST3 +#if !DISTRHO_PLUGIN_WANT_DIRECT_ACCESS && !defined(DISTRHO_PLUGIN_TARGET_CARLA) && !defined(DISTRHO_PLUGIN_TARGET_JACK) && !defined(DISTRHO_PLUGIN_TARGET_VST2) && !defined(DISTRHO_PLUGIN_TARGET_VST3) # ifdef DISTRHO_PLUGIN_TARGET_DSSI # define DISTRHO_IS_STANDALONE 1 # else diff --git a/dpf/distrho/DistrhoUI_macOS.mm b/dpf/distrho/DistrhoUI_macOS.mm index 24f24f3..80b0618 100644 --- a/dpf/distrho/DistrhoUI_macOS.mm +++ b/dpf/distrho/DistrhoUI_macOS.mm @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho + * Copyright (C) 2012-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -14,23 +14,28 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef PUGL_NAMESPACE -# error PUGL_NAMESPACE must be set when compiling this file -#endif +// A few utils declared in DistrhoUI.cpp but defined here because they use Obj-C #include "src/DistrhoPluginChecks.h" #include "src/DistrhoDefines.h" -#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI - +#if DISTRHO_UI_FILE_BROWSER || DISTRHO_PLUGIN_HAS_EXTERNAL_UI # import +#endif + +#if DISTRHO_UI_FILE_BROWSER +# define DISTRHO_FILE_BROWSER_DIALOG_HPP_INCLUDED +# define FILE_BROWSER_DIALOG_NAMESPACE DISTRHO_NAMESPACE +# define FILE_BROWSER_DIALOG_DISTRHO_NAMESPACE +START_NAMESPACE_DISTRHO +# include "extra/FileBrowserDialogImpl.hpp" +END_NAMESPACE_DISTRHO +# include "extra/FileBrowserDialogImpl.cpp" +#endif + +#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI # include # include -# ifndef DGL_FILE_BROWSER_DISABLED -# import "extra/FileBrowserDialog.cpp" -# endif - -// Declared in DistrhoUI.cpp but defined here because it uses Obj-C START_NAMESPACE_DISTRHO double getDesktopScaleFactor(const uintptr_t parentWindowHandle) { @@ -45,19 +50,4 @@ double getDesktopScaleFactor(const uintptr_t parentWindowHandle) return [NSScreen mainScreen].backingScaleFactor; } END_NAMESPACE_DISTRHO - -#else // DISTRHO_PLUGIN_HAS_EXTERNAL_UI - -# include "../dgl/Base.hpp" -# define DISTRHO_MACOS_NAMESPACE_MACRO_HELPER(DGL_NS, SEP, PUGL_NS, INTERFACE) DGL_NS ## SEP ## PUGL_NS ## SEP ## INTERFACE -# define DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NS, PUGL_NS, INTERFACE) DISTRHO_MACOS_NAMESPACE_MACRO_HELPER(DGL_NS, _, PUGL_NS, INTERFACE) -# define PuglCairoView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PUGL_NAMESPACE, CairoView) -# define PuglOpenGLView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PUGL_NAMESPACE, OpenGLView) -# define PuglStubView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PUGL_NAMESPACE, StubView) -# define PuglVulkanView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PUGL_NAMESPACE, VulkanView) -# define PuglWindow DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PUGL_NAMESPACE, Window) -# define PuglWindowDelegate DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PUGL_NAMESPACE, WindowDelegate) -# define PuglWrapperView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PUGL_NAMESPACE, WrapperView) -# import "src/pugl.mm" - -#endif // DISTRHO_PLUGIN_HAS_EXTERNAL_UI +#endif diff --git a/dpf/distrho/extra/FileBrowserDialog.hpp b/dpf/distrho/extra/FileBrowserDialog.hpp index 2074e4c..786f280 100644 --- a/dpf/distrho/extra/FileBrowserDialog.hpp +++ b/dpf/distrho/extra/FileBrowserDialog.hpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho + * Copyright (C) 2012-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -21,113 +21,7 @@ START_NAMESPACE_DISTRHO -// -------------------------------------------------------------------------------------------------------------------- -// File Browser Dialog stuff - -struct FileBrowserData; -typedef FileBrowserData* FileBrowserHandle; - -// -------------------------------------------------------------------------------------------------------------------- - -/** - File browser options, for customizing the file browser dialog.@n - By default the file browser dialog will be work as "open file" in the current working directory. -*/ -struct FileBrowserOptions { - /** Whether we are saving, opening files otherwise (default) */ - bool saving; - - /** Start directory, uses current working directory if null */ - const char* startDir; - - /** File browser dialog window title, uses "FileBrowser" if null */ - const char* title; - - // TODO file filter - - /** - File browser button state. - This allows to customize the behaviour of the file browse dialog buttons. - Note these are merely hints, not all systems support them. - */ - enum ButtonState { - kButtonInvisible, - kButtonVisibleUnchecked, - kButtonVisibleChecked, - }; - - /** - File browser buttons. - */ - struct Buttons { - /** Whether to list all files vs only those with matching file extension */ - ButtonState listAllFiles; - /** Whether to show hidden files */ - ButtonState showHidden; - /** Whether to show list of places (bookmarks) */ - ButtonState showPlaces; - - /** Constructor for default values */ - Buttons() - : listAllFiles(kButtonVisibleChecked), - showHidden(kButtonVisibleUnchecked), - showPlaces(kButtonVisibleChecked) {} - } buttons; - - /** Constructor for default values */ - FileBrowserOptions() - : saving(false), - startDir(nullptr), - title(nullptr), - buttons() {} -}; - -// -------------------------------------------------------------------------------------------------------------------- - -#ifdef DISTRHO_FILE_BROWSER_DIALOG_EXTRA_NAMESPACE -namespace DISTRHO_FILE_BROWSER_DIALOG_EXTRA_NAMESPACE { -#endif - -/** - Create a new file browser dialog. - - @p isEmbed: Whether the window this dialog belongs to is an embed/child window (needed to close dialog on Windows) - @p windowId: The native window id to attach this dialog to as transient parent (X11 Window, HWND or NSView*) - @p scaleFactor: Scale factor to use (only used on X11) - @p options: Extra options, optional - By default the file browser dialog will be work as "open file" in the current working directory. -*/ -FileBrowserHandle fileBrowserCreate(bool isEmbed, - uintptr_t windowId, - double scaleFactor, - const FileBrowserOptions& options = FileBrowserOptions()); - -/** - Idle the file browser dialog handle.@n - Returns true if dialog was closed (with or without a file selection), - in which case the handle must not be used afterwards. - You can then call fileBrowserGetPath to know the selected file (or null if cancelled). -*/ -bool fileBrowserIdle(const FileBrowserHandle handle); - -/** - Close the file browser dialog, handle must not be used afterwards. -*/ -void fileBrowserClose(const FileBrowserHandle handle); - -/** - Get the path chosen by the user or null.@n - Should only be called after fileBrowserIdle returns true. -*/ -const char* fileBrowserGetPath(const FileBrowserHandle handle); - -// -------------------------------------------------------------------------------------------------------------------- - -#ifdef DISTRHO_FILE_BROWSER_DIALOG_EXTRA_NAMESPACE -} -#endif - -// -------------------------------------------------------------------------------------------------------------------- +#include "FileBrowserDialogImpl.hpp" END_NAMESPACE_DISTRHO diff --git a/dpf/distrho/extra/FileBrowserDialog.cpp b/dpf/distrho/extra/FileBrowserDialogImpl.cpp similarity index 59% rename from dpf/distrho/extra/FileBrowserDialog.cpp rename to dpf/distrho/extra/FileBrowserDialogImpl.cpp index ccaa4f1..2e9de42 100644 --- a/dpf/distrho/extra/FileBrowserDialog.cpp +++ b/dpf/distrho/extra/FileBrowserDialogImpl.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho + * Copyright (C) 2012-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -14,13 +14,22 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "FileBrowserDialog.hpp" +#if !defined(DISTRHO_FILE_BROWSER_DIALOG_HPP_INCLUDED) && !defined(DGL_FILE_BROWSER_DIALOG_HPP_INCLUDED) +# error bad include +#endif +#if !defined(FILE_BROWSER_DIALOG_DISTRHO_NAMESPACE) && !defined(FILE_BROWSER_DIALOG_DGL_NAMESPACE) +# error bad usage +#endif + #include "ScopedPointer.hpp" #include "String.hpp" #ifdef DISTRHO_OS_MAC # import #endif +#ifdef DISTRHO_OS_WASM +# include +#endif #ifdef DISTRHO_OS_WINDOWS # include # include @@ -40,13 +49,123 @@ # include "sofd/libsofd.c" #endif +#ifdef FILE_BROWSER_DIALOG_DGL_NAMESPACE +START_NAMESPACE_DGL +using DISTRHO_NAMESPACE::ScopedPointer; +using DISTRHO_NAMESPACE::String; +#else START_NAMESPACE_DISTRHO +#endif // -------------------------------------------------------------------------------------------------------------------- // static pointer used for signal null/none action taken static const char* const kSelectedFileCancelled = "__dpf_cancelled__"; +#ifdef HAVE_DBUS +static constexpr bool isHexChar(const char c) noexcept +{ + return c >= '0' && c <= 'f' && (c <= '9' || (c >= 'A' && c <= 'F') || c >= 'a'); +} + +static constexpr int toHexChar(const char c) noexcept +{ + return c >= '0' && c <= '9' ? c - '0' : (c >= 'A' && c <= 'F' ? c - 'A' : c - 'a') + 10; +} +#endif + +// -------------------------------------------------------------------------------------------------------------------- + +#ifdef DISTRHO_OS_WASM +# define DISTRHO_WASM_NAMESPACE_MACRO_HELPER(NS, SEP, FUNCTION) NS ## SEP ## FUNCTION +# define DISTRHO_WASM_NAMESPACE_MACRO(NS, FUNCTION) DISTRHO_WASM_NAMESPACE_MACRO_HELPER(NS, _, FUNCTION) +# define DISTRHO_WASM_NAMESPACE_HELPER(NS) #NS +# define DISTRHO_WASM_NAMESPACE(NS) DISTRHO_WASM_NAMESPACE_HELPER(NS) +# define fileBrowserSetPathNamespaced DISTRHO_WASM_NAMESPACE_MACRO(FILE_BROWSER_DIALOG_NAMESPACE, fileBrowserSetPath) +# define fileBrowserSetPathFuncName DISTRHO_WASM_NAMESPACE(FILE_BROWSER_DIALOG_NAMESPACE) "_fileBrowserSetPath" + +// FIXME use world class name as prefix +static bool openWebBrowserFileDialog(const char* const funcname, void* const handle) +{ + const char* const nameprefix = DISTRHO_WASM_NAMESPACE(FILE_BROWSER_DIALOG_NAMESPACE); + + return EM_ASM_INT({ + var canvasFileObjName = UTF8ToString($0) + "_file_open"; + var canvasFileOpenElem = document.getElementById(canvasFileObjName); + + var jsfuncname = UTF8ToString($1); + var jsfunc = Module.cwrap(jsfuncname, 'null', ['number', 'string']); + + if (canvasFileOpenElem) { + document.body.removeChild(canvasFileOpenElem); + } + + canvasFileOpenElem = document.createElement('input'); + canvasFileOpenElem.type = 'file'; + canvasFileOpenElem.id = canvasFileObjName; + canvasFileOpenElem.style.display = 'none'; + document.body.appendChild(canvasFileOpenElem); + + canvasFileOpenElem.onchange = function(e) { + if (!canvasFileOpenElem.files) { + jsfunc($2, ""); + return; + } + + var file = canvasFileOpenElem.files[0]; + var filename = '/' + file.name; + var reader = new FileReader(); + + reader.onloadend = function(e) { + var content = new Uint8Array(reader.result); + Module.FS.writeFile(filename, content); + jsfunc($2, filename); + }; + + reader.readAsArrayBuffer(file); + }; + + canvasFileOpenElem.click(); + return 1; + }, nameprefix, funcname, handle) != 0; +} + +static bool downloadWebBrowserFile(const char* const filename) +{ + const char* const nameprefix = DISTRHO_WASM_NAMESPACE(FILE_BROWSER_DIALOG_NAMESPACE); + + return EM_ASM_INT({ + var canvasFileObjName = UTF8ToString($0) + "_file_save"; + var jsfilename = UTF8ToString($1); + + var canvasFileSaveElem = document.getElementById(canvasFileObjName); + if (canvasFileSaveElem) { + // only 1 file save allowed at once + console.warn("One file save operation already in progress, refusing to open another"); + return 0; + } + + canvasFileSaveElem = document.createElement('a'); + canvasFileSaveElem.download = jsfilename; + canvasFileSaveElem.id = canvasFileObjName; + canvasFileSaveElem.style.display = 'none'; + document.body.appendChild(canvasFileSaveElem); + + var content = Module.FS.readFile('/' + jsfilename); + canvasFileSaveElem.href = URL.createObjectURL(new Blob([content])); + canvasFileSaveElem.click(); + + setTimeout(function() { + URL.revokeObjectURL(canvasFileSaveElem.href); + document.body.removeChild(canvasFileSaveElem); + }, 2000); + return 1; + }, nameprefix, filename) != 0; +} +#endif + +// -------------------------------------------------------------------------------------------------------------------- + struct FileBrowserData { const char* selectedFile; @@ -61,6 +180,11 @@ struct FileBrowserData { Display* x11display; #endif +#ifdef DISTRHO_OS_WASM + char* defaultName; + bool saving; +#endif + #ifdef DISTRHO_OS_WINDOWS OPENFILENAMEW ofn; volatile bool threadCancelled; @@ -87,8 +211,8 @@ struct FileBrowserData { ~FileBrowserData() { - if (cancelAndStop() && selectedFile != nullptr && selectedFile != kSelectedFileCancelled) - std::free(const_cast(selectedFile)); + if (cancelAndStop()) + free(); } void setupAndStart(const bool embed, @@ -197,11 +321,11 @@ struct FileBrowserData { return 0; } #else // DISTRHO_OS_WINDOWS - FileBrowserData(const bool saving) + FileBrowserData(const bool save) : selectedFile(nullptr) { #ifdef DISTRHO_OS_MAC - if (saving) + if (save) { nsOpenPanel = nullptr; nsBasePanel = [[NSSavePanel savePanel]retain]; @@ -212,6 +336,10 @@ struct FileBrowserData { nsBasePanel = nsOpenPanel; } #endif +#ifdef DISTRHO_OS_WASM + defaultName = nullptr; + saving = save; +#endif #ifdef HAVE_DBUS if ((dbuscon = dbus_bus_get(DBUS_BUS_SESSION, nullptr)) != nullptr) dbus_connection_set_exit_on_disconnect(dbuscon, false); @@ -221,7 +349,7 @@ struct FileBrowserData { #endif // maybe unused - return; (void)saving; + return; (void)save; } ~FileBrowserData() @@ -229,6 +357,9 @@ struct FileBrowserData { #ifdef DISTRHO_OS_MAC [nsBasePanel release]; #endif +#ifdef DISTRHO_OS_WASM + std::free(defaultName); +#endif #ifdef HAVE_DBUS if (dbuscon != nullptr) dbus_connection_unref(dbuscon); @@ -238,19 +369,42 @@ struct FileBrowserData { XCloseDisplay(x11display); #endif - if (selectedFile != nullptr && selectedFile != kSelectedFileCancelled) - std::free(const_cast(selectedFile)); + free(); } #endif + + void free() + { + if (selectedFile == nullptr) + return; + + if (selectedFile == kSelectedFileCancelled || std::strcmp(selectedFile, kSelectedFileCancelled) == 0) + { + selectedFile = nullptr; + return; + } + + std::free(const_cast(selectedFile)); + selectedFile = nullptr; + } }; // -------------------------------------------------------------------------------------------------------------------- -#ifdef DISTRHO_FILE_BROWSER_DIALOG_EXTRA_NAMESPACE -namespace DISTRHO_FILE_BROWSER_DIALOG_EXTRA_NAMESPACE { -#endif +#ifdef DISTRHO_OS_WASM +extern "C" { +EMSCRIPTEN_KEEPALIVE +void fileBrowserSetPathNamespaced(FileBrowserHandle handle, const char* filename) +{ + handle->free(); -// -------------------------------------------------------------------------------------------------------------------- + if (filename != nullptr && filename[0] != '\0') + handle->selectedFile = strdup(filename); + else + handle->selectedFile = kSelectedFileCancelled; +} +} +#endif FileBrowserHandle fileBrowserCreate(const bool isEmbed, const uintptr_t windowId, @@ -263,17 +417,13 @@ FileBrowserHandle fileBrowserCreate(const bool isEmbed, { #ifdef DISTRHO_OS_WINDOWS if (char* const cwd = _getcwd(nullptr, 0)) - { - startDir = cwd; - std::free(cwd); - } #else if (char* const cwd = getcwd(nullptr, 0)) +#endif { startDir = cwd; std::free(cwd); } -#endif } DISTRHO_SAFE_ASSERT_RETURN(startDir.isNotEmpty(), nullptr); @@ -289,6 +439,11 @@ FileBrowserHandle fileBrowserCreate(const bool isEmbed, ScopedPointer handle(new FileBrowserData(options.saving)); #ifdef DISTRHO_OS_MAC +# if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_8 + // unsupported + d_stderr2("fileBrowserCreate is unsupported on macos < 10.8"); + return nullptr; +# else NSSavePanel* const nsBasePanel = handle->nsBasePanel; DISTRHO_SAFE_ASSERT_RETURN(nsBasePanel != nullptr, nullptr); @@ -335,6 +490,29 @@ FileBrowserHandle fileBrowserCreate(const bool isEmbed, } }]; }); +# endif +#endif + +#ifdef DISTRHO_OS_WASM + if (options.saving) + { + const size_t len = options.defaultName != nullptr ? strlen(options.defaultName) : 0; + DISTRHO_SAFE_ASSERT_RETURN(len != 0, nullptr); + + char* const filename = static_cast(malloc(len + 2)); + filename[0] = '/'; + std::memcpy(filename + 1, options.defaultName, len + 1); + + handle->defaultName = strdup(options.defaultName); + handle->selectedFile = filename; + return handle.release(); + } + + const char* const funcname = fileBrowserSetPathFuncName; + if (openWebBrowserFileDialog(funcname, handle.get())) + return handle.release(); + + return nullptr; #endif #ifdef DISTRHO_OS_WINDOWS @@ -345,52 +523,77 @@ FileBrowserHandle fileBrowserCreate(const bool isEmbed, // optional, can be null DBusConnection* const dbuscon = handle->dbuscon; - if (dbuscon != nullptr && dbus_bus_name_has_owner(dbuscon, "org.freedesktop.portal.Desktop", nullptr)) + // https://flatpak.github.io/xdg-desktop-portal/portal-docs.html#gdbus-org.freedesktop.portal.FileChooser + if (dbuscon != nullptr) { - // https://flatpak.github.io/xdg-desktop-portal/portal-docs.html#gdbus-org.freedesktop.portal.FileChooser - if (DBusMessage* const message = dbus_message_new_method_call("org.freedesktop.portal.Desktop", - "/org/freedesktop/portal/desktop", - "org.freedesktop.portal.FileChooser", - options.saving ? "SaveFile" : "OpenFile")) + // if this is the first time we are calling into DBus, check if things are working + static bool checkAvailable = !dbus_bus_name_has_owner(dbuscon, "org.freedesktop.portal.Desktop", nullptr); + + if (checkAvailable) { - char windowIdStr[32]; - memset(windowIdStr, 0, sizeof(windowIdStr)); -# ifdef HAVE_X11 - snprintf(windowIdStr, sizeof(windowIdStr)-1, "x11:%llx", (ulonglong)windowId); -# endif - const char* windowIdStrPtr = windowIdStr; + checkAvailable = false; - dbus_message_append_args(message, - DBUS_TYPE_STRING, &windowIdStrPtr, - DBUS_TYPE_STRING, &windowTitle, - DBUS_TYPE_INVALID); + if (DBusMessage* const msg = dbus_message_new_method_call("org.freedesktop.portal.Desktop", + "/org/freedesktop/portal/desktop", + "org.freedesktop.portal.FileChooser", + "version")) + { + if (DBusMessage* const reply = dbus_connection_send_with_reply_and_block(dbuscon, msg, 250, nullptr)) + dbus_message_unref(reply); - DBusMessageIter iter, array; - dbus_message_iter_init_append(message, &iter); - dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &array); + dbus_message_unref(msg); + } + } + // Any subsquent calls should have this DBus service active + if (dbus_bus_name_has_owner(dbuscon, "org.freedesktop.portal.Desktop", nullptr)) + { + if (DBusMessage* const msg = dbus_message_new_method_call("org.freedesktop.portal.Desktop", + "/org/freedesktop/portal/desktop", + "org.freedesktop.portal.FileChooser", + options.saving ? "SaveFile" : "OpenFile")) { - DBusMessageIter dict, variant, variantArray; - const char* const current_folder_key = "current_folder"; - const char* const current_folder_val = startDir.buffer(); - - dbus_message_iter_open_container(&array, DBUS_TYPE_DICT_ENTRY, nullptr, &dict); - dbus_message_iter_append_basic(&dict, DBUS_TYPE_STRING, ¤t_folder_key); - dbus_message_iter_open_container(&dict, DBUS_TYPE_VARIANT, "ay", &variant); - dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, "y", &variantArray); - dbus_message_iter_append_fixed_array(&variantArray, DBUS_TYPE_BYTE, - ¤t_folder_val, startDir.length()+1); - dbus_message_iter_close_container(&variant, &variantArray); - dbus_message_iter_close_container(&dict, &variant); - dbus_message_iter_close_container(&array, &dict); + #ifdef HAVE_X11 + char windowIdStr[32]; + memset(windowIdStr, 0, sizeof(windowIdStr)); + snprintf(windowIdStr, sizeof(windowIdStr)-1, "x11:%llx", (ulonglong)windowId); + const char* windowIdStrPtr = windowIdStr; + #endif + + dbus_message_append_args(msg, + #ifdef HAVE_X11 + DBUS_TYPE_STRING, &windowIdStrPtr, + #endif + DBUS_TYPE_STRING, &windowTitle, + DBUS_TYPE_INVALID); + + DBusMessageIter iter, array; + dbus_message_iter_init_append(msg, &iter); + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &array); + + { + DBusMessageIter dict, variant, variantArray; + const char* const current_folder_key = "current_folder"; + const char* const current_folder_val = startDir.buffer(); + + dbus_message_iter_open_container(&array, DBUS_TYPE_DICT_ENTRY, nullptr, &dict); + dbus_message_iter_append_basic(&dict, DBUS_TYPE_STRING, ¤t_folder_key); + dbus_message_iter_open_container(&dict, DBUS_TYPE_VARIANT, "ay", &variant); + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, "y", &variantArray); + dbus_message_iter_append_fixed_array(&variantArray, DBUS_TYPE_BYTE, + ¤t_folder_val, startDir.length()+1); + dbus_message_iter_close_container(&variant, &variantArray); + dbus_message_iter_close_container(&dict, &variant); + dbus_message_iter_close_container(&array, &dict); + } + + dbus_message_iter_close_container(&iter, &array); + + dbus_connection_send(dbuscon, msg, nullptr); + + dbus_message_unref(msg); + return handle.release(); } - - dbus_message_iter_close_container(&iter, &array); - - dbus_connection_send(dbuscon, message, nullptr); - - dbus_message_unref(message); - return handle.release(); } } #endif @@ -518,7 +721,44 @@ bool fileBrowserIdle(const FileBrowserHandle handle) DISTRHO_SAFE_ASSERT_BREAK(value != nullptr); if (const char* const localvalue = std::strstr(value, "file:///")) - handle->selectedFile = strdup(localvalue + 7); + { + if (char* const decodedvalue = strdup(localvalue + 7)) + { + for (char* s = decodedvalue; (s = std::strchr(s, '%')) != nullptr; ++s) + { + if (! isHexChar(s[1]) || ! isHexChar(s[2])) + continue; + + const int decodedNum = toHexChar(s[1]) * 0x10 + toHexChar(s[2]); + + char replacementChar; + switch (decodedNum) + { + case 0x20: replacementChar = ' '; break; + case 0x22: replacementChar = '\"'; break; + case 0x23: replacementChar = '#'; break; + case 0x25: replacementChar = '%'; break; + case 0x3c: replacementChar = '<'; break; + case 0x3e: replacementChar = '>'; break; + case 0x5b: replacementChar = '['; break; + case 0x5c: replacementChar = '\\'; break; + case 0x5d: replacementChar = ']'; break; + case 0x5e: replacementChar = '^'; break; + case 0x60: replacementChar = '`'; break; + case 0x7b: replacementChar = '{'; break; + case 0x7c: replacementChar = '|'; break; + case 0x7d: replacementChar = '}'; break; + case 0x7e: replacementChar = '~'; break; + default: continue; + } + + s[0] = replacementChar; + std::memmove(s + 1, s + 3, std::strlen(s) - 2); + } + + handle->selectedFile = decodedvalue; + } + } } while(false); @@ -563,6 +803,11 @@ bool fileBrowserIdle(const FileBrowserHandle handle) void fileBrowserClose(const FileBrowserHandle handle) { +#ifdef DISTRHO_OS_WASM + if (handle->saving && fileBrowserGetPath(handle) != nullptr) + downloadWebBrowserFile(handle->defaultName); +#endif + #ifdef HAVE_X11 if (Display* const x11display = handle->x11display) x_fib_close(x11display); @@ -585,8 +830,15 @@ const char* fileBrowserGetPath(const FileBrowserHandle handle) // -------------------------------------------------------------------------------------------------------------------- -#ifdef DISTRHO_FILE_BROWSER_DIALOG_EXTRA_NAMESPACE -} +#ifdef FILE_BROWSER_DIALOG_DGL_NAMESPACE +END_NAMESPACE_DGL +#else +END_NAMESPACE_DISTRHO #endif -END_NAMESPACE_DISTRHO +#undef FILE_BROWSER_DIALOG_DISTRHO_NAMESPACE +#undef FILE_BROWSER_DIALOG_DGL_NAMESPACE +#undef FILE_BROWSER_DIALOG_NAMESPACE + +#undef fileBrowserSetPathNamespaced +#undef fileBrowserSetPathFuncName diff --git a/dpf/distrho/extra/FileBrowserDialogImpl.hpp b/dpf/distrho/extra/FileBrowserDialogImpl.hpp new file mode 100644 index 0000000..5b47a52 --- /dev/null +++ b/dpf/distrho/extra/FileBrowserDialogImpl.hpp @@ -0,0 +1,121 @@ +/* + * DISTRHO Plugin Framework (DPF) + * Copyright (C) 2012-2022 Filipe Coelho + * + * Permission to use, copy, modify, and/or distribute this software for any purpose with + * or without fee is hereby granted, provided that the above copyright notice and this + * permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD + * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(DISTRHO_FILE_BROWSER_DIALOG_HPP_INCLUDED) && !defined(DGL_FILE_BROWSER_DIALOG_HPP_INCLUDED) +# error bad include +#endif + +// -------------------------------------------------------------------------------------------------------------------- +// File Browser Dialog stuff + +struct FileBrowserData; +typedef FileBrowserData* FileBrowserHandle; + +// -------------------------------------------------------------------------------------------------------------------- + +/** + File browser options, for customizing the file browser dialog.@n + By default the file browser dialog will be work as "open file" in the current working directory. +*/ +struct FileBrowserOptions { + /** Whether we are saving, opening files otherwise (default) */ + bool saving; + + /** Default filename when saving, required in some platforms (basename without path separators) */ + const char* defaultName; + + /** Start directory, uses current working directory if null */ + const char* startDir; + + /** File browser dialog window title, uses "FileBrowser" if null */ + const char* title; + + // TODO file filter + + /** + File browser button state. + This allows to customize the behaviour of the file browse dialog buttons. + Note these are merely hints, not all systems support them. + */ + enum ButtonState { + kButtonInvisible, + kButtonVisibleUnchecked, + kButtonVisibleChecked, + }; + + /** + File browser buttons. + */ + struct Buttons { + /** Whether to list all files vs only those with matching file extension */ + ButtonState listAllFiles; + /** Whether to show hidden files */ + ButtonState showHidden; + /** Whether to show list of places (bookmarks) */ + ButtonState showPlaces; + + /** Constructor for default values */ + Buttons() + : listAllFiles(kButtonVisibleChecked), + showHidden(kButtonVisibleUnchecked), + showPlaces(kButtonVisibleChecked) {} + } buttons; + + /** Constructor for default values */ + FileBrowserOptions() + : saving(false), + defaultName(nullptr), + startDir(nullptr), + title(nullptr), + buttons() {} +}; + +// -------------------------------------------------------------------------------------------------------------------- + +/** + Create a new file browser dialog. + + @p isEmbed: Whether the window this dialog belongs to is an embed/child window (needed to close dialog on Windows) + @p windowId: The native window id to attach this dialog to as transient parent (X11 Window, HWND or NSView*) + @p scaleFactor: Scale factor to use (only used on X11) + @p options: Extra options, optional + By default the file browser dialog will be work as "open file" in the current working directory. +*/ +FileBrowserHandle fileBrowserCreate(bool isEmbed, + uintptr_t windowId, + double scaleFactor, + const FileBrowserOptions& options = FileBrowserOptions()); + +/** + Idle the file browser dialog handle.@n + Returns true if dialog was closed (with or without a file selection), + in which case the handle must not be used afterwards. + You can then call fileBrowserGetPath to know the selected file (or null if cancelled). +*/ +bool fileBrowserIdle(const FileBrowserHandle handle); + +/** + Close the file browser dialog, handle must not be used afterwards. +*/ +void fileBrowserClose(const FileBrowserHandle handle); + +/** + Get the path chosen by the user or null.@n + Should only be called after fileBrowserIdle returns true. +*/ +const char* fileBrowserGetPath(const FileBrowserHandle handle); + +// -------------------------------------------------------------------------------------------------------------------- diff --git a/dpf/distrho/extra/RingBuffer.hpp b/dpf/distrho/extra/RingBuffer.hpp index 9e80a6b..fc3f013 100644 --- a/dpf/distrho/extra/RingBuffer.hpp +++ b/dpf/distrho/extra/RingBuffer.hpp @@ -203,11 +203,23 @@ public: /* * Get the size of the data available to read. */ - uint32_t getAvailableDataSize() const noexcept + uint32_t getReadableDataSize() const noexcept { DISTRHO_SAFE_ASSERT_RETURN(buffer != nullptr, 0); - const uint32_t wrap((buffer->tail > buffer->wrtn) ? 0 : buffer->size); + const uint32_t wrap = buffer->head > buffer->tail ? 0 : buffer->size; + + return wrap + buffer->head - buffer->tail; + } + + /* + * Get the size of the data available to write. + */ + uint32_t getWritableDataSize() const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(buffer != nullptr, 0); + + const uint32_t wrap = (buffer->tail > buffer->wrtn) ? 0 : buffer->size; return wrap + buffer->tail - buffer->wrtn; } @@ -724,6 +736,15 @@ public: heapBuffer.size = 0; } + void copyFromAndClearOther(HeapRingBuffer& other) + { + DISTRHO_SAFE_ASSERT_RETURN(other.heapBuffer.size == heapBuffer.size,); + + std::memcpy(&heapBuffer, &other.heapBuffer, sizeof(HeapBuffer) - sizeof(uint8_t*)); + std::memcpy(heapBuffer.buf, other.heapBuffer.buf, sizeof(uint8_t) * heapBuffer.size); + other.clearData(); + } + private: /** The heap buffer used for this class. */ HeapBuffer heapBuffer; diff --git a/dpf/distrho/extra/Runner.hpp b/dpf/distrho/extra/Runner.hpp new file mode 100644 index 0000000..c1fd658 --- /dev/null +++ b/dpf/distrho/extra/Runner.hpp @@ -0,0 +1,251 @@ +/* + * DISTRHO Plugin Framework (DPF) + * Copyright (C) 2012-2022 Filipe Coelho + * + * Permission to use, copy, modify, and/or distribute this software for any purpose with + * or without fee is hereby granted, provided that the above copyright notice and this + * permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD + * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef DISTRHO_RUNNER_HPP_INCLUDED +#define DISTRHO_RUNNER_HPP_INCLUDED + +#include "../DistrhoUtils.hpp" + +#ifndef DISTRHO_OS_WASM +# include "Thread.hpp" +#else +# include "String.hpp" +# include +#endif + +START_NAMESPACE_DISTRHO + +#ifdef DISTRHO_RUNNER_INDIRECT_WASM_CALLS +long d_emscripten_set_interval(void (*)(void*), double, void*); +void d_emscripten_clear_interval(long); +#else +# define d_emscripten_set_interval emscripten_set_interval +# define d_emscripten_clear_interval emscripten_clear_interval +#endif + +// ------------------------------------------------------------------------------------------------------------------- +// Runner class + +/** + Runner class for DPF. + + This is a handy class that handles "idle" time in either background or main thread, + whichever is more suitable to the target platform. + Typically background threads on desktop platforms, main thread on web. + + A single function is expected to be implemented by subclasses, + which directly allows it to stop the runner by returning false. + + You can use it for quick operations that do not need to be handled in the main thread if possible. + The target is to spread out execution over many runs, instead of spending a lot of time on a single task. + */ +class Runner +{ +protected: + /* + * Constructor. + */ + Runner(const char* const runnerName = nullptr) noexcept + #ifndef DISTRHO_OS_WASM + : fRunnerThread(this, runnerName), + fTimeInterval(0) + #else + : fRunnerName(runnerName), + fIntervalId(0) + #endif + { + } + + /* + * Destructor. + */ + virtual ~Runner() /*noexcept*/ + { + DISTRHO_SAFE_ASSERT(! isRunnerActive()); + + stopRunner(); + } + + /* + * Virtual function to be implemented by the subclass. + * Return true to keep running, false to stop execution. + */ + virtual bool run() = 0; + + /* + * Check if the runner should stop. + * To be called from inside the runner to know if a stop request has been made. + */ + bool shouldRunnerStop() const noexcept + { + #ifndef DISTRHO_OS_WASM + return fRunnerThread.shouldThreadExit(); + #else + return fIntervalId == 0; + #endif + } + + // --------------------------------------------------------------------------------------------------------------- + +public: + /* + * Check if the runner is active. + */ + bool isRunnerActive() noexcept + { + #ifndef DISTRHO_OS_WASM + return fRunnerThread.isThreadRunning(); + #else + return fIntervalId != 0; + #endif + } + + /* + * Start the thread. + */ + bool startRunner(const uint timeIntervalMilliseconds = 0) noexcept + { + #ifndef DISTRHO_OS_WASM + DISTRHO_SAFE_ASSERT_RETURN(!fRunnerThread.isThreadRunning(), false); + fTimeInterval = timeIntervalMilliseconds; + return fRunnerThread.startThread(); + #else + DISTRHO_SAFE_ASSERT_RETURN(fIntervalId == 0, false); + fIntervalId = d_emscripten_set_interval(_entryPoint, timeIntervalMilliseconds, this); + return true; + #endif + } + + /* + * Stop the runner. + * This will signal the runner to stop if active, and wait until it finishes. + */ + bool stopRunner() noexcept + { + #ifndef DISTRHO_OS_WASM + return fRunnerThread.stopThread(-1); + #else + signalRunnerShouldStop(); + return true; + #endif + } + + /* + * Tell the runner to stop as soon as possible. + */ + void signalRunnerShouldStop() noexcept + { + #ifndef DISTRHO_OS_WASM + fRunnerThread.signalThreadShouldExit(); + #else + if (fIntervalId != 0) + { + d_emscripten_clear_interval(fIntervalId); + fIntervalId = 0; + } + #endif + } + + // --------------------------------------------------------------------------------------------------------------- + + /* + * Returns the name of the runner. + * This is the name that gets set in the constructor. + */ + const String& getRunnerName() const noexcept + { + #ifndef DISTRHO_OS_WASM + return fRunnerThread.getThreadName(); + #else + return fRunnerName; + #endif + } + + // --------------------------------------------------------------------------------------------------------------- + +private: +#ifndef DISTRHO_OS_WASM + class RunnerThread : public Thread + { + Runner* const runner; + + public: + RunnerThread(Runner* const r, const char* const rn) + : Thread(rn), + runner(r) {} + + protected: + void run() override + { + const uint timeInterval = runner->fTimeInterval; + + while (!shouldThreadExit()) + { + bool stillRunning = false; + + try { + stillRunning = runner->run(); + } catch(...) {} + + if (stillRunning && !shouldThreadExit()) + { + if (timeInterval != 0) + d_msleep(timeInterval); + + // FIXME + // pthread_yield(); + continue; + } + + break; + } + } + } fRunnerThread; + + uint fTimeInterval; +#else + const String fRunnerName; + long fIntervalId; + + void _runEntryPoint() noexcept + { + bool stillRunning = false; + + try { + stillRunning = run(); + } catch(...) {} + + if (fIntervalId != 0 && !stillRunning) + { + d_emscripten_clear_interval(fIntervalId); + fIntervalId = 0; + } + } + + static void _entryPoint(void* const userData) noexcept + { + static_cast(userData)->_runEntryPoint(); + } +#endif + + DISTRHO_DECLARE_NON_COPYABLE(Runner) +}; + +// ------------------------------------------------------------------------------------------------------------------- + +END_NAMESPACE_DISTRHO + +#endif // DISTRHO_RUNNER_HPP_INCLUDED diff --git a/dpf/distrho/extra/String.hpp b/dpf/distrho/extra/String.hpp index 88a7501..0238395 100644 --- a/dpf/distrho/extra/String.hpp +++ b/dpf/distrho/extra/String.hpp @@ -861,7 +861,7 @@ public: std::memcpy(newBuf, fBuffer, fBufferLen); std::memcpy(newBuf + fBufferLen, strBuf, strBufLen + 1); - return String(newBuf); + return String(newBuf, false); } String operator+(const String& str) noexcept @@ -869,6 +869,12 @@ public: return operator+(str.fBuffer); } + // needed for std::map compatibility + bool operator<(const String& str) const noexcept + { + return std::strcmp(fBuffer, str.fBuffer) < 0; + } + // ------------------------------------------------------------------- private: diff --git a/dpf/distrho/extra/Thread.hpp b/dpf/distrho/extra/Thread.hpp index ec6f13d..63a01ac 100644 --- a/dpf/distrho/extra/Thread.hpp +++ b/dpf/distrho/extra/Thread.hpp @@ -25,6 +25,10 @@ # include #endif +#ifdef DISTRHO_OS_WASM +# error Threads do not work under wasm! +#endif + START_NAMESPACE_DISTRHO // ----------------------------------------------------------------------- diff --git a/dpf/distrho/extra/sofd/libsofd.c b/dpf/distrho/extra/sofd/libsofd.c index ad8eca4..6aaeb68 100644 --- a/dpf/distrho/extra/sofd/libsofd.c +++ b/dpf/distrho/extra/sofd/libsofd.c @@ -338,7 +338,6 @@ const char *x_fib_recent_file(const char *appname) { } #ifdef HAVE_X11 -#include #include #include @@ -347,6 +346,11 @@ const char *x_fib_recent_file(const char *appname) { #include #include +#if defined(__linux__) || defined(__linux) +#define HAVE_MNTENT +#include +#endif + #ifndef MIN #define MIN(A,B) ( (A) < (B) ? (A) : (B) ) #endif @@ -495,7 +499,9 @@ static int query_font_geometry (Display *dpy, GC gc, const char *txt, int *w, in if (h) *h = text_structure.ascent + text_structure.descent; if (a) *a = text_structure.ascent; if (d) *d = text_structure.descent; +#ifndef DISTRHO_OS_HAIKU // FIXME XFreeFontInfo (NULL, fontinfo, 1); +#endif return 0; } @@ -1766,6 +1772,7 @@ static int parse_gtk_bookmarks (Display *dpy, const char *fn) { return found; } +#ifdef HAVE_MNTENT static const char *ignore_mountpoints[] = { "/bin", "/boot", "/dev", "/etc", "/lib", "/live", "/mnt", "/opt", @@ -1840,6 +1847,7 @@ static int read_mtab (Display *dpy, const char *mtab) { fclose (mt); return found; } +#endif static void populate_places (Display *dpy) { char tmp[1024]; @@ -1868,9 +1876,11 @@ static void populate_places (Display *dpy) { parse_gtk_bookmarks (dpy, _fib_cfg_custom_places); } +#ifdef HAVE_MNTENT if (read_mtab (dpy, "/proc/mounts") < 1) { read_mtab (dpy, "/etc/mtab"); } +#endif int parsed_bookmarks = 0; if (!parsed_bookmarks && getenv ("HOME")) { diff --git a/dpf/distrho/src/DistrhoDefines.h b/dpf/distrho/src/DistrhoDefines.h index b3d2de6..e42eec2 100644 --- a/dpf/distrho/src/DistrhoDefines.h +++ b/dpf/distrho/src/DistrhoDefines.h @@ -27,10 +27,12 @@ /* Check OS */ #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) +# define DISTRHO_API # define DISTRHO_PLUGIN_EXPORT extern "C" __declspec (dllexport) # define DISTRHO_OS_WINDOWS 1 # define DISTRHO_DLL_EXTENSION "dll" #else +# define DISTRHO_API # define DISTRHO_PLUGIN_EXPORT extern "C" __attribute__ ((visibility("default"))) # if defined(__APPLE__) # define DISTRHO_OS_MAC 1 @@ -43,6 +45,8 @@ # define DISTRHO_OS_BSD 1 # elif defined(__GNU__) # define DISTRHO_OS_GNU_HURD 1 +# elif defined(__EMSCRIPTEN__) +# define DISTRHO_OS_WASM 1 # endif #endif @@ -71,6 +75,13 @@ # define nullptr NULL #endif +/* Define unlikely */ +#ifdef __GNUC__ +# define unlikely(x) __builtin_expect(x,0) +#else +# define unlikely(x) x +#endif + /* Define DISTRHO_DEPRECATED */ #if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 480 # define DISTRHO_DEPRECATED __attribute__((deprecated)) @@ -81,49 +92,49 @@ #endif /* Define DISTRHO_DEPRECATED_BY */ -#if defined(__clang__) && defined(DISTRHO_PROPER_CPP11_SUPPORT) +#if defined(__clang__) && (__clang_major__ * 100 + __clang_minor__) >= 502 # define DISTRHO_DEPRECATED_BY(other) __attribute__((deprecated("", other))) -#elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 480 +#elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 408 # define DISTRHO_DEPRECATED_BY(other) __attribute__((deprecated("Use " other))) #else # define DISTRHO_DEPRECATED_BY(other) DISTRHO_DEPRECATED #endif /* Define DISTRHO_SAFE_ASSERT* */ -#define DISTRHO_SAFE_ASSERT(cond) if (! (cond)) d_safe_assert (#cond, __FILE__, __LINE__); -#define DISTRHO_SAFE_ASSERT_INT(cond, value) if (! (cond)) d_safe_assert_int (#cond, __FILE__, __LINE__, static_cast(value)); -#define DISTRHO_SAFE_ASSERT_INT2(cond, v1, v2) if (! (cond)) d_safe_assert_int2 (#cond, __FILE__, __LINE__, static_cast(v1), static_cast(v2)); -#define DISTRHO_SAFE_ASSERT_UINT(cond, value) if (! (cond)) d_safe_assert_uint (#cond, __FILE__, __LINE__, static_cast(value)); -#define DISTRHO_SAFE_ASSERT_UINT2(cond, v1, v2) if (! (cond)) d_safe_assert_uint2(#cond, __FILE__, __LINE__, static_cast(v1), static_cast(v2)); - -#define DISTRHO_SAFE_ASSERT_BREAK(cond) if (! (cond)) { d_safe_assert(#cond, __FILE__, __LINE__); break; } -#define DISTRHO_SAFE_ASSERT_CONTINUE(cond) if (! (cond)) { d_safe_assert(#cond, __FILE__, __LINE__); continue; } -#define DISTRHO_SAFE_ASSERT_RETURN(cond, ret) if (! (cond)) { d_safe_assert(#cond, __FILE__, __LINE__); return ret; } - -#define DISTRHO_CUSTOM_SAFE_ASSERT(msg, cond) if (! (cond)) d_custom_safe_assert(msg, #cond, __FILE__, __LINE__); -#define DISTRHO_CUSTOM_SAFE_ASSERT_BREAK(msg, cond) if (! (cond)) { d_custom_safe_assert(msg, #cond, __FILE__, __LINE__); break; } -#define DISTRHO_CUSTOM_SAFE_ASSERT_CONTINUE(msg, cond) if (! (cond)) { d_custom_safe_assert(msg, #cond, __FILE__, __LINE__); continue; } -#define DISTRHO_CUSTOM_SAFE_ASSERT_RETURN(msg, cond, ret) if (! (cond)) { d_custom_safe_assert(msg, #cond, __FILE__, __LINE__); return ret; } - -#define DISTRHO_CUSTOM_SAFE_ASSERT_ONCE_BREAK(msg, cond) if (! (cond)) { static bool _p; if (!_p) { _p = true; d_custom_safe_assert(msg, #cond, __FILE__, __LINE__); } break; } -#define DISTRHO_CUSTOM_SAFE_ASSERT_ONCE_CONTINUE(msg, cond) if (! (cond)) { static bool _p; if (!_p) { _p = true; d_custom_safe_assert(msg, #cond, __FILE__, __LINE__); } continue; } -#define DISTRHO_CUSTOM_SAFE_ASSERT_ONCE_RETURN(msg, cond, ret) if (! (cond)) { static bool _p; if (!_p) { _p = true; d_custom_safe_assert(msg, #cond, __FILE__, __LINE__); } return ret; } - -#define DISTRHO_SAFE_ASSERT_INT_BREAK(cond, value) if (! (cond)) { d_safe_assert_int(#cond, __FILE__, __LINE__, static_cast(value)); break; } -#define DISTRHO_SAFE_ASSERT_INT_CONTINUE(cond, value) if (! (cond)) { d_safe_assert_int(#cond, __FILE__, __LINE__, static_cast(value)); continue; } -#define DISTRHO_SAFE_ASSERT_INT_RETURN(cond, value, ret) if (! (cond)) { d_safe_assert_int(#cond, __FILE__, __LINE__, static_cast(value)); return ret; } - -#define DISTRHO_SAFE_ASSERT_INT2_BREAK(cond, v1, v2) if (! (cond)) { d_safe_assert_int2(#cond, __FILE__, __LINE__, static_cast(v1), static_cast(v2)); break; } -#define DISTRHO_SAFE_ASSERT_INT2_CONTINUE(cond, v1, v2) if (! (cond)) { d_safe_assert_int2(#cond, __FILE__, __LINE__, static_cast(v1), static_cast(v2)); continue; } -#define DISTRHO_SAFE_ASSERT_INT2_RETURN(cond, v1, v2, ret) if (! (cond)) { d_safe_assert_int2(#cond, __FILE__, __LINE__, static_cast(v1), static_cast(v2)); return ret; } - -#define DISTRHO_SAFE_ASSERT_UINT_BREAK(cond, value) if (! (cond)) { d_safe_assert_uint(#cond, __FILE__, __LINE__, static_cast(value)); break; } -#define DISTRHO_SAFE_ASSERT_UINT_CONTINUE(cond, value) if (! (cond)) { d_safe_assert_uint(#cond, __FILE__, __LINE__, static_cast(value)); continue; } -#define DISTRHO_SAFE_ASSERT_UINT_RETURN(cond, value, ret) if (! (cond)) { d_safe_assert_uint(#cond, __FILE__, __LINE__, static_cast(value)); return ret; } - -#define DISTRHO_SAFE_ASSERT_UINT2_BREAK(cond, v1, v2) if (! (cond)) { d_safe_assert_uint2(#cond, __FILE__, __LINE__, static_cast(v1), static_cast(v2)); break; } -#define DISTRHO_SAFE_ASSERT_UINT2_CONTINUE(cond, v1, v2) if (! (cond)) { d_safe_assert_uint2(#cond, __FILE__, __LINE__, static_cast(v1), static_cast(v2)); continue; } -#define DISTRHO_SAFE_ASSERT_UINT2_RETURN(cond, v1, v2, ret) if (! (cond)) { d_safe_assert_uint2(#cond, __FILE__, __LINE__, static_cast(v1), static_cast(v2)); return ret; } +#define DISTRHO_SAFE_ASSERT(cond) if (unlikely(!(cond))) d_safe_assert (#cond, __FILE__, __LINE__); +#define DISTRHO_SAFE_ASSERT_INT(cond, value) if (unlikely(!(cond))) d_safe_assert_int (#cond, __FILE__, __LINE__, static_cast(value)); +#define DISTRHO_SAFE_ASSERT_INT2(cond, v1, v2) if (unlikely(!(cond))) d_safe_assert_int2 (#cond, __FILE__, __LINE__, static_cast(v1), static_cast(v2)); +#define DISTRHO_SAFE_ASSERT_UINT(cond, value) if (unlikely(!(cond))) d_safe_assert_uint (#cond, __FILE__, __LINE__, static_cast(value)); +#define DISTRHO_SAFE_ASSERT_UINT2(cond, v1, v2) if (unlikely(!(cond))) d_safe_assert_uint2(#cond, __FILE__, __LINE__, static_cast(v1), static_cast(v2)); + +#define DISTRHO_SAFE_ASSERT_BREAK(cond) if (unlikely(!(cond))) { d_safe_assert(#cond, __FILE__, __LINE__); break; } +#define DISTRHO_SAFE_ASSERT_CONTINUE(cond) if (unlikely(!(cond))) { d_safe_assert(#cond, __FILE__, __LINE__); continue; } +#define DISTRHO_SAFE_ASSERT_RETURN(cond, ret) if (unlikely(!(cond))) { d_safe_assert(#cond, __FILE__, __LINE__); return ret; } + +#define DISTRHO_CUSTOM_SAFE_ASSERT(msg, cond) if (unlikely(!(cond))) d_custom_safe_assert(msg, #cond, __FILE__, __LINE__); +#define DISTRHO_CUSTOM_SAFE_ASSERT_BREAK(msg, cond) if (unlikely(!(cond))) { d_custom_safe_assert(msg, #cond, __FILE__, __LINE__); break; } +#define DISTRHO_CUSTOM_SAFE_ASSERT_CONTINUE(msg, cond) if (unlikely(!(cond))) { d_custom_safe_assert(msg, #cond, __FILE__, __LINE__); continue; } +#define DISTRHO_CUSTOM_SAFE_ASSERT_RETURN(msg, cond, ret) if (unlikely(!(cond))) { d_custom_safe_assert(msg, #cond, __FILE__, __LINE__); return ret; } + +#define DISTRHO_CUSTOM_SAFE_ASSERT_ONCE_BREAK(msg, cond) if (unlikely(!(cond))) { static bool _p; if (!_p) { _p = true; d_custom_safe_assert(msg, #cond, __FILE__, __LINE__); } break; } +#define DISTRHO_CUSTOM_SAFE_ASSERT_ONCE_CONTINUE(msg, cond) if (unlikely(!(cond))) { static bool _p; if (!_p) { _p = true; d_custom_safe_assert(msg, #cond, __FILE__, __LINE__); } continue; } +#define DISTRHO_CUSTOM_SAFE_ASSERT_ONCE_RETURN(msg, cond, ret) if (unlikely(!(cond))) { static bool _p; if (!_p) { _p = true; d_custom_safe_assert(msg, #cond, __FILE__, __LINE__); } return ret; } + +#define DISTRHO_SAFE_ASSERT_INT_BREAK(cond, value) if (unlikely(!(cond))) { d_safe_assert_int(#cond, __FILE__, __LINE__, static_cast(value)); break; } +#define DISTRHO_SAFE_ASSERT_INT_CONTINUE(cond, value) if (unlikely(!(cond))) { d_safe_assert_int(#cond, __FILE__, __LINE__, static_cast(value)); continue; } +#define DISTRHO_SAFE_ASSERT_INT_RETURN(cond, value, ret) if (unlikely(!(cond))) { d_safe_assert_int(#cond, __FILE__, __LINE__, static_cast(value)); return ret; } + +#define DISTRHO_SAFE_ASSERT_INT2_BREAK(cond, v1, v2) if (unlikely(!(cond))) { d_safe_assert_int2(#cond, __FILE__, __LINE__, static_cast(v1), static_cast(v2)); break; } +#define DISTRHO_SAFE_ASSERT_INT2_CONTINUE(cond, v1, v2) if (unlikely(!(cond))) { d_safe_assert_int2(#cond, __FILE__, __LINE__, static_cast(v1), static_cast(v2)); continue; } +#define DISTRHO_SAFE_ASSERT_INT2_RETURN(cond, v1, v2, ret) if (unlikely(!(cond))) { d_safe_assert_int2(#cond, __FILE__, __LINE__, static_cast(v1), static_cast(v2)); return ret; } + +#define DISTRHO_SAFE_ASSERT_UINT_BREAK(cond, value) if (unlikely(!(cond))) { d_safe_assert_uint(#cond, __FILE__, __LINE__, static_cast(value)); break; } +#define DISTRHO_SAFE_ASSERT_UINT_CONTINUE(cond, value) if (unlikely(!(cond))) { d_safe_assert_uint(#cond, __FILE__, __LINE__, static_cast(value)); continue; } +#define DISTRHO_SAFE_ASSERT_UINT_RETURN(cond, value, ret) if (unlikely(!(cond))) { d_safe_assert_uint(#cond, __FILE__, __LINE__, static_cast(value)); return ret; } + +#define DISTRHO_SAFE_ASSERT_UINT2_BREAK(cond, v1, v2) if (unlikely(!(cond))) { d_safe_assert_uint2(#cond, __FILE__, __LINE__, static_cast(v1), static_cast(v2)); break; } +#define DISTRHO_SAFE_ASSERT_UINT2_CONTINUE(cond, v1, v2) if (unlikely(!(cond))) { d_safe_assert_uint2(#cond, __FILE__, __LINE__, static_cast(v1), static_cast(v2)); continue; } +#define DISTRHO_SAFE_ASSERT_UINT2_RETURN(cond, v1, v2, ret) if (unlikely(!(cond))) { d_safe_assert_uint2(#cond, __FILE__, __LINE__, static_cast(v1), static_cast(v2)); return ret; } /* Define DISTRHO_SAFE_EXCEPTION */ #define DISTRHO_SAFE_EXCEPTION(msg) catch(...) { d_safe_exception(msg, __FILE__, __LINE__); } diff --git a/dpf/distrho/src/DistrhoPlugin.cpp b/dpf/distrho/src/DistrhoPlugin.cpp index 2242b16..9c4c9b6 100644 --- a/dpf/distrho/src/DistrhoPlugin.cpp +++ b/dpf/distrho/src/DistrhoPlugin.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho + * Copyright (C) 2012-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -72,9 +72,8 @@ Plugin::Plugin(uint32_t parameterCount, uint32_t programCount, uint32_t stateCou if (stateCount > 0) { #if DISTRHO_PLUGIN_WANT_STATE - pData->stateCount = stateCount; - pData->stateKeys = new String[stateCount]; - pData->stateDefValues = new String[stateCount]; + pData->stateCount = stateCount; + pData->states = new State[stateCount]; #else d_stderr2("DPF warning: Plugins with state must define `DISTRHO_PLUGIN_WANT_STATE` to 1"); DPF_ABORT @@ -145,6 +144,13 @@ bool Plugin::requestParameterValueChange(const uint32_t index, const float value } #endif +#if DISTRHO_PLUGIN_WANT_STATE +bool Plugin::updateStateValue(const char* const key, const char* const value) noexcept +{ + return pData->updateStateValueCallback(key, value); +} +#endif + /* ------------------------------------------------------------------------------------------------------------ * Init */ @@ -178,11 +184,32 @@ void Plugin::initProgramName(uint32_t, String&) {} #endif #if DISTRHO_PLUGIN_WANT_STATE -void Plugin::initState(uint32_t, String&, String&) {} -#endif - -#if DISTRHO_PLUGIN_WANT_STATEFILES -bool Plugin::isStateFile(uint32_t) { return false; } +void Plugin::initState(const uint32_t index, State& state) +{ + uint hints = 0x0; + String stateKey, defaultStateValue; + + #if defined(__clang__) + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wdeprecated-declarations" + #elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdeprecated-declarations" + #endif + initState(index, stateKey, defaultStateValue); + if (isStateFile(index)) + hints = kStateIsFilenamePath; + #if defined(__clang__) + #pragma clang diagnostic pop + #elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) + #pragma GCC diagnostic pop + #endif + + state.hints = hints; + state.key = stateKey; + state.label = stateKey; + state.defaultValue = defaultStateValue; +} #endif /* ------------------------------------------------------------------------------------------------------------ diff --git a/dpf/distrho/src/DistrhoPluginCarla.cpp b/dpf/distrho/src/DistrhoPluginCarla.cpp index 5f375f0..4878fad 100644 --- a/dpf/distrho/src/DistrhoPluginCarla.cpp +++ b/dpf/distrho/src/DistrhoPluginCarla.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho + * Copyright (C) 2012-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -31,11 +31,13 @@ START_NAMESPACE_DISTRHO #if ! DISTRHO_PLUGIN_WANT_MIDI_OUTPUT -static const writeMidiFunc writeMidiCallback = nullptr; +static constexpr const writeMidiFunc writeMidiCallback = nullptr; #endif #if ! DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST -static const requestParameterValueChangeFunc requestParameterValueChangeCallback = nullptr; +static constexpr const requestParameterValueChangeFunc requestParameterValueChangeCallback = nullptr; #endif +// TODO +static constexpr const updateStateValueFunc updateStateValueCallback = nullptr; #if DISTRHO_PLUGIN_HAS_UI // ----------------------------------------------------------------------- @@ -53,7 +55,12 @@ class UICarla public: UICarla(const NativeHostDescriptor* const host, PluginExporter* const plugin) : fHost(host), - fUI(this, 0, editParameterCallback, setParameterCallback, setStateCallback, sendNoteCallback, setSizeCallback, plugin->getInstancePointer()) + fUI(this, 0, plugin->getSampleRate(), + editParameterCallback, setParameterCallback, setStateCallback, sendNoteCallback, + nullptr, // window size + nullptr, // TODO file request + nullptr, // bundle path + plugin->getInstancePointer()) { fUI.setWindowTitle(host->uiName); @@ -75,7 +82,7 @@ public: bool carla_idle() { - return fUI.idle(); + return fUI.plugin_idle(); } void carla_setParameterValue(const uint32_t index, const float value) @@ -129,11 +136,6 @@ protected: } #endif - void handleSetSize(const uint width, const uint height) - { - fUI.setWindowSize(width, height); - } - // --------------------------------------------- private: @@ -172,11 +174,6 @@ private: } #endif - static void setSizeCallback(void* ptr, uint width, uint height) - { - handlePtr->handleSetSize(width, height); - } - #undef handlePtr CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(UICarla) @@ -191,7 +188,7 @@ class PluginCarla : public NativePluginClass public: PluginCarla(const NativeHostDescriptor* const host) : NativePluginClass(host), - fPlugin(this, writeMidiCallback, requestParameterValueChangeCallback), + fPlugin(this, writeMidiCallback, requestParameterValueChangeCallback, updateStateValueCallback), fScalePointsCache(nullptr) { #if DISTRHO_PLUGIN_HAS_UI @@ -367,7 +364,8 @@ protected: } #if DISTRHO_PLUGIN_WANT_MIDI_INPUT - void process(float** const inBuffer, float** const outBuffer, const uint32_t frames, const NativeMidiEvent* const midiEvents, const uint32_t midiEventCount) override + void process(const float* const* const inBuffer, float** const outBuffer, const uint32_t frames, + const NativeMidiEvent* const midiEvents, const uint32_t midiEventCount) override { MidiEvent realMidiEvents[midiEventCount]; @@ -391,7 +389,8 @@ protected: fPlugin.run(const_cast(inBuffer), outBuffer, frames, realMidiEvents, midiEventCount); } #else - void process(float** const inBuffer, float** const outBuffer, const uint32_t frames, const NativeMidiEvent* const, const uint32_t) override + void process(const float* const* const inBuffer, float** const outBuffer, const uint32_t frames, + const NativeMidiEvent* const, const uint32_t) override { fPlugin.run(const_cast(inBuffer), outBuffer, frames); } @@ -498,10 +497,7 @@ private: void createUiIfNeeded() { if (fUiPtr == nullptr) - { - d_lastUiSampleRate = getSampleRate(); fUiPtr = new UICarla(getHostHandle(), &fPlugin); - } } #endif @@ -539,8 +535,8 @@ private: public: static NativePluginHandle _instantiate(const NativeHostDescriptor* host) { - d_lastBufferSize = host->get_buffer_size(host->handle); - d_lastSampleRate = host->get_sample_rate(host->handle); + d_nextBufferSize = host->get_buffer_size(host->handle); + d_nextSampleRate = host->get_sample_rate(host->handle); return new PluginCarla(host); } diff --git a/dpf/distrho/src/DistrhoPluginChecks.h b/dpf/distrho/src/DistrhoPluginChecks.h index dfcda68..dd838b9 100644 --- a/dpf/distrho/src/DistrhoPluginChecks.h +++ b/dpf/distrho/src/DistrhoPluginChecks.h @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2019 Filipe Coelho + * Copyright (C) 2012-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -81,10 +81,6 @@ # define DISTRHO_PLUGIN_WANT_STATE 0 #endif -#ifndef DISTRHO_PLUGIN_WANT_STATEFILES -# define DISTRHO_PLUGIN_WANT_STATEFILES 0 -#endif - #ifndef DISTRHO_PLUGIN_WANT_FULL_STATE # define DISTRHO_PLUGIN_WANT_FULL_STATE 0 # define DISTRHO_PLUGIN_WANT_FULL_STATE_WAS_NOT_SET @@ -94,6 +90,14 @@ # define DISTRHO_PLUGIN_WANT_TIMEPOS 0 #endif +#ifndef DISTRHO_UI_FILE_BROWSER +# if defined(DGL_FILE_BROWSER_DISABLED) || DISTRHO_PLUGIN_HAS_EXTERNAL_UI +# define DISTRHO_UI_FILE_BROWSER 0 +# else +# define DISTRHO_UI_FILE_BROWSER 1 +# endif +#endif + #ifndef DISTRHO_UI_USER_RESIZABLE # define DISTRHO_UI_USER_RESIZABLE 0 #endif @@ -137,11 +141,15 @@ #endif // ----------------------------------------------------------------------- -// Enable state if plugin wants state files - -#if DISTRHO_PLUGIN_WANT_STATEFILES && ! DISTRHO_PLUGIN_WANT_STATE -# undef DISTRHO_PLUGIN_WANT_STATE -# define DISTRHO_PLUGIN_WANT_STATE 1 +// Enable state if plugin wants state files (deprecated) + +#ifdef DISTRHO_PLUGIN_WANT_STATEFILES +# warning DISTRHO_PLUGIN_WANT_STATEFILES is deprecated +# undef DISTRHO_PLUGIN_WANT_STATEFILES +# if ! DISTRHO_PLUGIN_WANT_STATE +# undef DISTRHO_PLUGIN_WANT_STATE +# define DISTRHO_PLUGIN_WANT_STATE 1 +# endif #endif // ----------------------------------------------------------------------- @@ -154,7 +162,16 @@ #endif // ----------------------------------------------------------------------- -// Disable UI if DGL or External UI is not available +// Disable file browser if using external UI + +#if DISTRHO_UI_FILE_BROWSER && DISTRHO_PLUGIN_HAS_EXTERNAL_UI +# warning file browser APIs do not work for external UIs +# undef DISTRHO_UI_FILE_BROWSER 0 +# define DISTRHO_UI_FILE_BROWSER 0 +#endif + +// ----------------------------------------------------------------------- +// Disable UI if DGL or external UI is not available #if (defined(DGL_CAIRO) && ! defined(HAVE_CAIRO)) || (defined(DGL_OPENGL) && ! defined(HAVE_OPENGL)) # undef DISTRHO_PLUGIN_HAS_EMBED_UI diff --git a/dpf/distrho/src/DistrhoPluginInternal.hpp b/dpf/distrho/src/DistrhoPluginInternal.hpp index 017eb23..37cdb7c 100644 --- a/dpf/distrho/src/DistrhoPluginInternal.hpp +++ b/dpf/distrho/src/DistrhoPluginInternal.hpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho + * Copyright (C) 2012-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -20,7 +20,7 @@ #include "../DistrhoPlugin.hpp" #ifdef DISTRHO_PLUGIN_TARGET_VST3 -# include "DistrhoPluginVST3.hpp" +# include "DistrhoPluginVST.hpp" #endif #include @@ -46,6 +46,7 @@ extern bool d_nextCanRequestParameterValueChanges; typedef bool (*writeMidiFunc) (void* ptr, const MidiEvent& midiEvent); typedef bool (*requestParameterValueChangeFunc) (void* ptr, uint32_t index, float value); +typedef bool (*updateStateValueFunc) (void* ptr, const char* key, const char* value); // ----------------------------------------------------------------------- // Helpers @@ -111,8 +112,7 @@ struct Plugin::PrivateData { #if DISTRHO_PLUGIN_WANT_STATE uint32_t stateCount; - String* stateKeys; - String* stateDefValues; + State* states; #endif #if DISTRHO_PLUGIN_WANT_LATENCY @@ -127,6 +127,7 @@ struct Plugin::PrivateData { void* callbacksPtr; writeMidiFunc writeMidiCallbackFunc; requestParameterValueChangeFunc requestParameterValueChangeCallbackFunc; + updateStateValueFunc updateStateValueCallbackFunc; uint32_t bufferSize; double sampleRate; @@ -150,8 +151,7 @@ struct Plugin::PrivateData { #endif #if DISTRHO_PLUGIN_WANT_STATE stateCount(0), - stateKeys(nullptr), - stateDefValues(nullptr), + states(nullptr), #endif #if DISTRHO_PLUGIN_WANT_LATENCY latency(0), @@ -159,6 +159,7 @@ struct Plugin::PrivateData { callbacksPtr(nullptr), writeMidiCallbackFunc(nullptr), requestParameterValueChangeCallbackFunc(nullptr), + updateStateValueCallbackFunc(nullptr), bufferSize(d_nextBufferSize), sampleRate(d_nextSampleRate), bundlePath(d_nextBundlePath != nullptr ? strdup(d_nextBundlePath) : nullptr) @@ -218,16 +219,10 @@ struct Plugin::PrivateData { #endif #if DISTRHO_PLUGIN_WANT_STATE - if (stateKeys != nullptr) + if (states != nullptr) { - delete[] stateKeys; - stateKeys = nullptr; - } - - if (stateDefValues != nullptr) - { - delete[] stateDefValues; - stateDefValues = nullptr; + delete[] states; + states = nullptr; } #endif @@ -257,6 +252,17 @@ struct Plugin::PrivateData { return false; } #endif + +#if DISTRHO_PLUGIN_WANT_STATE + bool updateStateValueCallback(const char* const key, const char* const value) + { + d_stdout("updateStateValueCallback %p", updateStateValueCallbackFunc); + if (updateStateValueCallbackFunc != nullptr) + return updateStateValueCallbackFunc(callbacksPtr, key, value); + + return false; + } +#endif }; // ----------------------------------------------------------------------- @@ -267,7 +273,8 @@ class PluginExporter public: PluginExporter(void* const callbacksPtr, const writeMidiFunc writeMidiCall, - const requestParameterValueChangeFunc requestParameterValueChangeCall) + const requestParameterValueChangeFunc requestParameterValueChangeCall, + const updateStateValueFunc updateStateValueCall) : fPlugin(createPlugin()), fData((fPlugin != nullptr) ? fPlugin->pData : nullptr), fIsActive(false) @@ -403,12 +410,13 @@ public: #if DISTRHO_PLUGIN_WANT_STATE for (uint32_t i=0, count=fData->stateCount; i < count; ++i) - fPlugin->initState(i, fData->stateKeys[i], fData->stateDefValues[i]); + fPlugin->initState(i, fData->states[i]); #endif fData->callbacksPtr = callbacksPtr; fData->writeMidiCallbackFunc = writeMidiCall; fData->requestParameterValueChangeCallbackFunc = requestParameterValueChangeCall; + fData->updateStateValueCallbackFunc = updateStateValueCall; } ~PluginExporter() @@ -727,31 +735,43 @@ public: return fData->stateCount; } + uint32_t getStateHints(const uint32_t index) const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->stateCount, 0x0); + + return fData->states[index].hints; + } + const String& getStateKey(const uint32_t index) const noexcept { DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->stateCount, sFallbackString); - return fData->stateKeys[index]; + return fData->states[index].key; } const String& getStateDefaultValue(const uint32_t index) const noexcept { DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->stateCount, sFallbackString); - return fData->stateDefValues[index]; + return fData->states[index].defaultValue; } -# if DISTRHO_PLUGIN_WANT_STATEFILES - bool isStateFile(const uint32_t index) const + const String& getStateLabel(const uint32_t index) const noexcept { - DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->stateCount, false); + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->stateCount, sFallbackString); - return fPlugin->isStateFile(index); + return fData->states[index].label; + } + + const String& getStateDescription(const uint32_t index) const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->stateCount, sFallbackString); + + return fData->states[index].description; } -# endif # if DISTRHO_PLUGIN_WANT_FULL_STATE - String getState(const char* key) const + String getStateValue(const char* const key) const { DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, sFallbackString); DISTRHO_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0', sFallbackString); @@ -776,7 +796,7 @@ public: for (uint32_t i=0; i < fData->stateCount; ++i) { - if (fData->stateKeys[i] == key) + if (fData->states[i].key == key) return true; } @@ -934,9 +954,6 @@ private: static const PortGroupWithId sFallbackPortGroup; DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginExporter) -#ifndef DISTRHO_PLUGIN_TARGET_VST3 /* there is no way around this for VST3 */ - DISTRHO_PREVENT_HEAP_ALLOCATION -#endif }; // ----------------------------------------------------------------------- diff --git a/dpf/distrho/src/DistrhoPluginJACK.cpp b/dpf/distrho/src/DistrhoPluginJACK.cpp index 4044693..44b932f 100644 --- a/dpf/distrho/src/DistrhoPluginJACK.cpp +++ b/dpf/distrho/src/DistrhoPluginJACK.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho + * Copyright (C) 2012-2022 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -15,7 +15,10 @@ */ #include "DistrhoPluginInternal.hpp" -#include "../DistrhoPluginUtils.hpp" + +#if !defined(DISTRHO_OS_WINDOWS) && !defined(STATIC_BUILD) +# include "../DistrhoPluginUtils.hpp" +#endif #if DISTRHO_PLUGIN_HAS_UI # include "DistrhoUIInternal.hpp" @@ -28,6 +31,10 @@ # include "../extra/Thread.hpp" #endif +#if defined(STATIC_BUILD) && !defined(DISTRHO_OS_WASM) +# define JACKBRIDGE_DIRECT +#endif + #include "jackbridge/JackBridge.cpp" #include "lv2/lv2.h" @@ -116,11 +123,11 @@ class PluginJack #endif { public: - PluginJack(jack_client_t* const client) - : fPlugin(this, writeMidiCallback, requestParameterValueChangeCallback), + PluginJack(jack_client_t* const client, const uintptr_t winId) + : fPlugin(this, writeMidiCallback, requestParameterValueChangeCallback, nullptr), #if DISTRHO_PLUGIN_HAS_UI fUI(this, - 0, // winId + winId, d_nextSampleRate, nullptr, // edit param setParameterValueCallback, @@ -224,6 +231,9 @@ public: #else while (! gCloseSignalReceived) d_sleep(1); + + // unused + (void)winId; #endif } @@ -900,6 +910,36 @@ int main(int argc, char* argv[]) return runSelfTests() ? 0 : 1; #endif +#if defined(DISTRHO_OS_WINDOWS) && DISTRHO_PLUGIN_HAS_UI + /* the code below is based on + * https://www.tillett.info/2013/05/13/how-to-create-a-windows-program-that-works-as-both-as-a-gui-and-console-application/ + */ + bool hasConsole = false; + + HANDLE consoleHandleOut, consoleHandleError; + + if (AttachConsole(ATTACH_PARENT_PROCESS)) + { + // Redirect unbuffered STDOUT to the console + consoleHandleOut = GetStdHandle(STD_OUTPUT_HANDLE); + if (consoleHandleOut != INVALID_HANDLE_VALUE) + { + freopen("CONOUT$", "w", stdout); + setvbuf(stdout, NULL, _IONBF, 0); + } + + // Redirect unbuffered STDERR to the console + consoleHandleError = GetStdHandle(STD_ERROR_HANDLE); + if (consoleHandleError != INVALID_HANDLE_VALUE) + { + freopen("CONOUT$", "w", stderr); + setvbuf(stderr, NULL, _IONBF, 0); + } + + hasConsole = true; + } +#endif + jack_status_t status = jack_status_t(0x0); jack_client_t* client = jackbridge_client_open(DISTRHO_PLUGIN_NAME, JackNoStartServer, &status); @@ -937,10 +977,32 @@ int main(int argc, char* argv[]) if (errorString.isNotEmpty()) { errorString[errorString.length()-2] = '.'; - d_stderr("Failed to create jack client, reason was:\n%s", errorString.buffer()); + d_stderr("Failed to create the JACK client, reason was:\n%s", errorString.buffer()); } else - d_stderr("Failed to create jack client, cannot continue!"); + d_stderr("Failed to create the JACK client, cannot continue!"); + + #if defined(DISTRHO_OS_WINDOWS) && DISTRHO_PLUGIN_HAS_UI + // make sure message box is high-dpi aware + if (const HMODULE user32 = LoadLibrary("user32.dll")) + { + typedef BOOL(WINAPI* SPDA)(void); + #if defined(__GNUC__) && (__GNUC__ >= 9) + # pragma GCC diagnostic push + # pragma GCC diagnostic ignored "-Wcast-function-type" + #endif + const SPDA SetProcessDPIAware = (SPDA)GetProcAddress(user32, "SetProcessDPIAware"); + #if defined(__GNUC__) && (__GNUC__ >= 9) + # pragma GCC diagnostic pop + #endif + if (SetProcessDPIAware) + SetProcessDPIAware(); + FreeLibrary(user32); + } + + const String win32error = "Failed to create JACK client, reason was:\n" + errorString; + MessageBoxA(nullptr, win32error.buffer(), "", MB_ICONERROR); + #endif return 1; } @@ -951,7 +1013,7 @@ int main(int argc, char* argv[]) d_nextSampleRate = jackbridge_get_sample_rate(client); d_nextCanRequestParameterValueChanges = true; - #ifndef DISTRHO_OS_WINDOWS + #if !defined(DISTRHO_OS_WINDOWS) && !defined(STATIC_BUILD) // find plugin bundle static String bundlePath; if (bundlePath.isEmpty()) @@ -979,7 +1041,41 @@ int main(int argc, char* argv[]) } #endif - const PluginJack p(client); + uintptr_t winId = 0; +#if DISTRHO_PLUGIN_HAS_UI + if (argc == 3 && std::strcmp(argv[1], "embed") == 0) + winId = static_cast(std::atoll(argv[2])); +#endif + + const PluginJack p(client, winId); + +#if defined(DISTRHO_OS_WINDOWS) && DISTRHO_PLUGIN_HAS_UI + /* the code below is based on + * https://www.tillett.info/2013/05/13/how-to-create-a-windows-program-that-works-as-both-as-a-gui-and-console-application/ + */ + + // Send "enter" to release application from the console + // This is a hack, but if not used the console doesn't know the application has + // returned. The "enter" key only sent if the console window is in focus. + if (hasConsole && (GetConsoleWindow() == GetForegroundWindow() || SetFocus(GetConsoleWindow()) != nullptr)) + { + INPUT ip; + // Set up a generic keyboard event. + ip.type = INPUT_KEYBOARD; + ip.ki.wScan = 0; // hardware scan code for key + ip.ki.time = 0; + ip.ki.dwExtraInfo = 0; + + // Send the "Enter" key + ip.ki.wVk = 0x0D; // virtual-key code for the "Enter" key + ip.ki.dwFlags = 0; // 0 for key press + SendInput(1, &ip, sizeof(INPUT)); + + // Release the "Enter" key + ip.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release + SendInput(1, &ip, sizeof(INPUT)); + } +#endif return 0; diff --git a/dpf/distrho/src/DistrhoPluginLADSPA+DSSI.cpp b/dpf/distrho/src/DistrhoPluginLADSPA+DSSI.cpp index 48b68eb..07ce113 100644 --- a/dpf/distrho/src/DistrhoPluginLADSPA+DSSI.cpp +++ b/dpf/distrho/src/DistrhoPluginLADSPA+DSSI.cpp @@ -50,7 +50,7 @@ class PluginLadspaDssi { public: PluginLadspaDssi() - : fPlugin(nullptr, nullptr, nullptr), + : fPlugin(nullptr, nullptr, nullptr, nullptr), fPortControls(nullptr), fLastControlValues(nullptr) { @@ -554,7 +554,7 @@ static const struct DescriptorInitializer d_nextBufferSize = 512; d_nextSampleRate = 44100.0; d_nextPluginIsDummy = true; - const PluginExporter plugin(nullptr, nullptr, nullptr); + const PluginExporter plugin(nullptr, nullptr, nullptr, nullptr); d_nextBufferSize = 0; d_nextSampleRate = 0.0; d_nextPluginIsDummy = false; diff --git a/dpf/distrho/src/DistrhoPluginLV2.cpp b/dpf/distrho/src/DistrhoPluginLV2.cpp index 60378f2..b3e7956 100644 --- a/dpf/distrho/src/DistrhoPluginLV2.cpp +++ b/dpf/distrho/src/DistrhoPluginLV2.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho + * Copyright (C) 2012-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -17,6 +17,7 @@ #include "DistrhoPluginInternal.hpp" #include "lv2/atom.h" +#include "lv2/atom-forge.h" #include "lv2/atom-util.h" #include "lv2/buf-size.h" #include "lv2/data-access.h" @@ -47,8 +48,8 @@ # define DISTRHO_PLUGIN_LV2_STATE_PREFIX "urn:distrho:" #endif -#define DISTRHO_LV2_USE_EVENTS_IN (DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_TIMEPOS || (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI) || DISTRHO_PLUGIN_WANT_STATEFILES) -#define DISTRHO_LV2_USE_EVENTS_OUT (DISTRHO_PLUGIN_WANT_MIDI_OUTPUT || (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI)) +#define DISTRHO_LV2_USE_EVENTS_IN (DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_TIMEPOS || DISTRHO_PLUGIN_WANT_STATE) +#define DISTRHO_LV2_USE_EVENTS_OUT (DISTRHO_PLUGIN_WANT_MIDI_OUTPUT || DISTRHO_PLUGIN_WANT_STATE) START_NAMESPACE_DISTRHO @@ -61,6 +62,9 @@ static const writeMidiFunc writeMidiCallback = nullptr; #if ! DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST static const requestParameterValueChangeFunc requestParameterValueChangeCallback = nullptr; #endif +#if ! DISTRHO_PLUGIN_WANT_STATE +static const updateStateValueFunc updateStateValueCallback = nullptr; +#endif // ----------------------------------------------------------------------- @@ -72,7 +76,7 @@ public: const LV2_Worker_Schedule* const worker, const LV2_ControlInputPort_Change_Request* const ctrlInPortChangeReq, const bool usingNominal) - : fPlugin(this, writeMidiCallback, requestParameterValueChangeCallback), + : fPlugin(this, writeMidiCallback, requestParameterValueChangeCallback, updateStateValueCallback), fUsingNominal(usingNominal), #ifdef DISTRHO_PLUGIN_LICENSED_FOR_MOD fRunCount(0), @@ -126,29 +130,29 @@ public: #endif #if DISTRHO_PLUGIN_WANT_STATE + std::memset(&fAtomForge, 0, sizeof(fAtomForge)); + lv2_atom_forge_init(&fAtomForge, uridMap); + if (const uint32_t count = fPlugin.getStateCount()) { + fUrids = new LV2_URID[count]; fNeededUiSends = new bool[count]; for (uint32_t i=0; i < count; ++i) { fNeededUiSends[i] = false; - const String& dkey(fPlugin.getStateKey(i)); - fStateMap[dkey] = fPlugin.getStateDefaultValue(i); + const String& statekey(fPlugin.getStateKey(i)); + fStateMap[statekey] = fPlugin.getStateDefaultValue(i); -# if DISTRHO_PLUGIN_WANT_STATEFILES - if (fPlugin.isStateFile(i)) - { - const String dpf_lv2_key(DISTRHO_PLUGIN_URI "#" + dkey); - const LV2_URID urid = uridMap->map(uridMap->handle, dpf_lv2_key.buffer()); - fUridStateFileMap[urid] = dkey; - } -# endif + const String lv2key(DISTRHO_PLUGIN_URI "#" + statekey); + const LV2_URID urid = fUrids[i] = uridMap->map(uridMap->handle, lv2key.buffer()); + fUridStateMap[urid] = statekey; } } else { + fUrids = nullptr; fNeededUiSends = nullptr; } #else @@ -183,6 +187,12 @@ public: fNeededUiSends = nullptr; } + if (fUrids != nullptr) + { + delete[] fUrids; + fUrids = nullptr; + } + fStateMap.clear(); #endif } @@ -544,13 +554,14 @@ public: } #endif - // check for messages from UI or files -#if DISTRHO_PLUGIN_WANT_STATE && (DISTRHO_PLUGIN_HAS_UI || DISTRHO_PLUGIN_WANT_STATEFILES) + // check for messages from UI or host +#if DISTRHO_PLUGIN_WANT_STATE LV2_ATOM_SEQUENCE_FOREACH(fPortEventsIn, event) { if (event == nullptr) break; + #if DISTRHO_PLUGIN_HAS_UI if (event->body.type == fURIDs.dpfKeyValue) { const void* const data = (const void*)(event + 1); @@ -559,7 +570,11 @@ public: if (std::strcmp((const char*)data, "__dpf_ui_data__") == 0) { for (uint32_t i=0, count=fPlugin.getStateCount(); i < count; ++i) + { + if (fPlugin.getStateHints(i) & kStateIsOnlyForDSP) + continue; fNeededUiSends[i] = true; + } } // no, send to DSP as usual else if (fWorker != nullptr) @@ -567,8 +582,9 @@ public: fWorker->schedule_work(fWorker->handle, sizeof(LV2_Atom)+event->body.size, &event->body); } } -# if DISTRHO_PLUGIN_WANT_STATEFILES - else if (event->body.type == fURIDs.atomObject && fWorker != nullptr) + else + #endif + if (event->body.type == fURIDs.atomObject && fWorker != nullptr) { const LV2_Atom_Object* const object = (const LV2_Atom_Object*)&event->body; @@ -577,12 +593,11 @@ public: lv2_atom_object_get(object, fURIDs.patchProperty, &property, fURIDs.patchValue, &value, nullptr); if (property != nullptr && property->type == fURIDs.atomURID && - value != nullptr && value->type == fURIDs.atomPath) + value != nullptr && (value->type == fURIDs.atomPath || value->type == fURIDs.atomString)) { fWorker->schedule_work(fWorker->handle, sizeof(LV2_Atom)+event->body.size, &event->body); } } -# endif } #endif @@ -681,7 +696,7 @@ public: updateParameterOutputsAndTriggers(); -#if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI +#if DISTRHO_PLUGIN_WANT_STATE fEventsOutData.initIfNeeded(fURIDs.atomSequence); LV2_Atom_Event* aev; @@ -692,6 +707,16 @@ public: if (! fNeededUiSends[i]) continue; + const uint32_t hints = fPlugin.getStateHints(i); + + #if ! DISTRHO_PLUGIN_HAS_UI + if ((hints & kStateIsHostReadable) == 0x0) + { + fNeededUiSends[i] = false; + continue; + } + #endif + const String& curKey(fPlugin.getStateKey(i)); for (StringToStringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit) @@ -703,30 +728,71 @@ public: const String& value(cit->second); - // set msg size (key + value + separator + 2x null terminator) - const uint32_t msgSize = static_cast(key.length()+value.length())+3U; + // set msg size + uint32_t msgSize; + + if (hints & kStateIsHostReadable) + { + // object, prop key, prop urid, value key, value + msgSize = sizeof(LV2_Atom_Object) + + sizeof(LV2_Atom_Property_Body) * 4 + + sizeof(LV2_Atom_URID) * 3 + + sizeof(LV2_Atom_String) + + value.length() + 1; + } + else + { + // key + value + 2x null terminator + separator + msgSize = static_cast(key.length()+value.length())+3U; + } if (sizeof(LV2_Atom_Event) + msgSize > capacity - fEventsOutData.offset) { - d_stdout("Sending key '%s' to UI failed, out of space", key.buffer()); + d_stdout("Sending key '%s' to UI failed, out of space (needs %u bytes)", + key.buffer(), msgSize); break; } // put data aev = (LV2_Atom_Event*)(LV2_ATOM_CONTENTS(LV2_Atom_Sequence, fEventsOutData.port) + fEventsOutData.offset); aev->time.frames = 0; - aev->body.type = fURIDs.dpfKeyValue; - aev->body.size = msgSize; - uint8_t* const msgBuf = LV2_ATOM_BODY(&aev->body); - std::memset(msgBuf, 0, msgSize); + if (hints & kStateIsHostReadable) + { + uint8_t* const msgBuf = (uint8_t*)&aev->body; + LV2_Atom_Forge atomForge = fAtomForge; + lv2_atom_forge_set_buffer(&atomForge, msgBuf, msgSize); - // write key and value in atom buffer - std::memcpy(msgBuf, key.buffer(), key.length()+1); - std::memcpy(msgBuf+(key.length()+1), value.buffer(), value.length()+1); + LV2_Atom_Forge_Frame forgeFrame; + lv2_atom_forge_object(&atomForge, &forgeFrame, 0, fURIDs.patchSet); - fEventsOutData.growBy(lv2_atom_pad_size(sizeof(LV2_Atom_Event) + msgSize)); + lv2_atom_forge_key(&atomForge, fURIDs.patchProperty); + lv2_atom_forge_urid(&atomForge, fUrids[i]); + + lv2_atom_forge_key(&atomForge, fURIDs.patchValue); + if ((hints & kStateIsFilenamePath) == kStateIsFilenamePath) + lv2_atom_forge_path(&atomForge, value.buffer(), static_cast(value.length()+1)); + else + lv2_atom_forge_string(&atomForge, value.buffer(), static_cast(value.length()+1)); + lv2_atom_forge_pop(&atomForge, &forgeFrame); + + msgSize = ((LV2_Atom*)msgBuf)->size; + } + else + { + aev->body.type = fURIDs.dpfKeyValue; + aev->body.size = msgSize; + + uint8_t* const msgBuf = LV2_ATOM_BODY(&aev->body); + std::memset(msgBuf, 0, msgSize); + + // write key and value in atom buffer + std::memcpy(msgBuf, key.buffer(), key.length()+1); + std::memcpy(msgBuf+(key.length()+1), value.buffer(), value.length()+1); + } + + fEventsOutData.growBy(lv2_atom_pad_size(sizeof(LV2_Atom_Event) + msgSize)); fNeededUiSends[i] = false; break; } @@ -834,7 +900,7 @@ public: for (StringToStringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit) { const String& key = cit->first; - fStateMap[key] = fPlugin.getState(key); + fStateMap[key] = fPlugin.getStateValue(key); } # endif } @@ -850,11 +916,11 @@ public: for (StringToStringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit) { const String& key = cit->first; - fStateMap[key] = fPlugin.getState(key); + fStateMap[key] = fPlugin.getStateValue(key); } # endif - String dpf_lv2_key; + String lv2key; LV2_URID urid; for (uint32_t i=0, count=fPlugin.getStateCount(); i < count; ++i) @@ -868,30 +934,40 @@ public: if (curKey != key) continue; - const String& value(cit->second); + const uint32_t hints = fPlugin.getStateHints(i); -# if DISTRHO_PLUGIN_WANT_STATEFILES - if (fPlugin.isStateFile(i)) + #if ! DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + // do not save UI-only messages if there is no UI available + if (hints & kStateIsOnlyForUI) + break; + #endif + + if (hints & kStateIsHostReadable) { - dpf_lv2_key = DISTRHO_PLUGIN_URI "#"; - urid = fURIDs.atomPath; + lv2key = DISTRHO_PLUGIN_URI "#"; + urid = (hints & kStateIsFilenamePath) == kStateIsFilenamePath + ? fURIDs.atomPath + : fURIDs.atomString; } else -# endif { - dpf_lv2_key = DISTRHO_PLUGIN_LV2_STATE_PREFIX; + lv2key = DISTRHO_PLUGIN_LV2_STATE_PREFIX; urid = fURIDs.atomString; } - dpf_lv2_key += key; + lv2key += key; + + const String& value(cit->second); // some hosts need +1 for the null terminator, even though the type is string store(handle, - fUridMap->map(fUridMap->handle, dpf_lv2_key.buffer()), + fUridMap->map(fUridMap->handle, lv2key.buffer()), value.buffer(), value.length()+1, urid, LV2_STATE_IS_POD|LV2_STATE_IS_PORTABLE); + + break; } } @@ -903,33 +979,35 @@ public: size_t size; uint32_t type, flags; - String dpf_lv2_key; + String lv2key; LV2_URID urid; for (uint32_t i=0, count=fPlugin.getStateCount(); i < count; ++i) { const String& key(fPlugin.getStateKey(i)); -# if DISTRHO_PLUGIN_WANT_STATEFILES - if (fPlugin.isStateFile(i)) + const uint32_t hints = fPlugin.getStateHints(i); + + if (hints & kStateIsHostReadable) { - dpf_lv2_key = DISTRHO_PLUGIN_URI "#"; - urid = fURIDs.atomPath; + lv2key = DISTRHO_PLUGIN_URI "#"; + urid = (hints & kStateIsFilenamePath) == kStateIsFilenamePath + ? fURIDs.atomPath + : fURIDs.atomString; } else -# endif { - dpf_lv2_key = DISTRHO_PLUGIN_LV2_STATE_PREFIX; + lv2key = DISTRHO_PLUGIN_LV2_STATE_PREFIX; urid = fURIDs.atomString; } - dpf_lv2_key += key; + lv2key += key; size = 0; type = 0; flags = LV2_STATE_IS_POD|LV2_STATE_IS_PORTABLE; const void* data = retrieve(handle, - fUridMap->map(fUridMap->handle, dpf_lv2_key.buffer()), + fUridMap->map(fUridMap->handle, lv2key.buffer()), &size, &type, &flags); if (data == nullptr || size == 0) @@ -943,9 +1021,10 @@ public: setState(key, value); -#if DISTRHO_LV2_USE_EVENTS_OUT +#if DISTRHO_PLUGIN_WANT_STATE // signal msg needed for UI - fNeededUiSends[i] = true; + if ((hints & kStateIsOnlyForDSP) == 0x0) + fNeededUiSends[i] = true; #endif } @@ -967,7 +1046,6 @@ public: return LV2_WORKER_SUCCESS; } -# if DISTRHO_PLUGIN_WANT_STATEFILES if (eventBody->type == fURIDs.atomObject) { const LV2_Atom_Object* const object = (const LV2_Atom_Object*)eventBody; @@ -978,7 +1056,8 @@ public: DISTRHO_SAFE_ASSERT_RETURN(property != nullptr, LV2_WORKER_ERR_UNKNOWN); DISTRHO_SAFE_ASSERT_RETURN(property->type == fURIDs.atomURID, LV2_WORKER_ERR_UNKNOWN); DISTRHO_SAFE_ASSERT_RETURN(value != nullptr, LV2_WORKER_ERR_UNKNOWN); - DISTRHO_SAFE_ASSERT_RETURN(value->type == fURIDs.atomPath, LV2_WORKER_ERR_UNKNOWN); + DISTRHO_SAFE_ASSERT_RETURN(value->type == fURIDs.atomPath || + value->type == fURIDs.atomString, LV2_WORKER_ERR_UNKNOWN); const LV2_URID urid = ((const LV2_Atom_URID*)property)->body; const char* const filename = (const char*)(value + 1); @@ -986,8 +1065,8 @@ public: String key; try { - key = fUridStateFileMap[urid]; - } DISTRHO_SAFE_EXCEPTION_RETURN("lv2_work fUridStateFileMap[urid]", LV2_WORKER_ERR_UNKNOWN); + key = fUridStateMap[urid]; + } DISTRHO_SAFE_EXCEPTION_RETURN("lv2_work fUridStateMap[urid]", LV2_WORKER_ERR_UNKNOWN); setState(key, filename); @@ -995,14 +1074,14 @@ public: { if (fPlugin.getStateKey(i) == key) { - fNeededUiSends[i] = true; + if ((fPlugin.getStateHints(i) & kStateIsOnlyForDSP) == 0x0) + fNeededUiSends[i] = true; break; } } return LV2_WORKER_SUCCESS; } -# endif return LV2_WORKER_ERR_UNKNOWN; } @@ -1136,6 +1215,7 @@ private: LV2_URID atomURID; LV2_URID dpfKeyValue; LV2_URID midiEvent; + LV2_URID patchSet; LV2_URID patchProperty; LV2_URID patchValue; LV2_URID timePosition; @@ -1162,6 +1242,7 @@ private: atomURID(map(LV2_ATOM__URID)), dpfKeyValue(map(DISTRHO_PLUGIN_LV2_STATE_PREFIX "KeyValueState")), midiEvent(map(LV2_MIDI__MidiEvent)), + patchSet(map(LV2_PATCH__Set)), patchProperty(map(LV2_PATCH__property)), patchValue(map(LV2_PATCH__value)), timePosition(map(LV2_TIME__Position)), @@ -1188,18 +1269,30 @@ private: const LV2_Worker_Schedule* const fWorker; #if DISTRHO_PLUGIN_WANT_STATE + LV2_Atom_Forge fAtomForge; StringToStringMap fStateMap; + UridToStringMap fUridStateMap; + LV2_URID* fUrids; bool* fNeededUiSends; void setState(const char* const key, const char* const newValue) { fPlugin.setState(key, newValue); - // check if we want to save this key - if (! fPlugin.wantStateKey(key)) - return; + // save this key if necessary + if (fPlugin.wantStateKey(key)) + updateInternalState(key, newValue, false); + } - // check if key already exists + bool updateState(const char* const key, const char* const newValue) + { + fPlugin.setState(key, newValue); + return updateInternalState(key, newValue, true); + } + + bool updateInternalState(const char* const key, const char* const newValue, const bool sendToUI) + { + // key must already exist for (StringToStringMap::iterator it=fStateMap.begin(), ite=fStateMap.end(); it != ite; ++it) { const String& dkey(it->first); @@ -1207,16 +1300,27 @@ private: if (dkey == key) { it->second = newValue; - return; + + if (sendToUI) + { + for (uint32_t i=0, count=fPlugin.getStateCount(); i < count; ++i) + { + if (fPlugin.getStateKey(i) == key) + { + if ((fPlugin.getStateHints(i) & kStateIsOnlyForDSP) == 0x0) + fNeededUiSends[i] = true; + break; + } + } + } + + return true; } } d_stderr("Failed to find plugin state with key \"%s\"", key); + return false; } - -# if DISTRHO_PLUGIN_WANT_STATEFILES - UridToStringMap fUridStateFileMap; -# endif #endif void updateParameterOutputsAndTriggers() @@ -1257,6 +1361,13 @@ private: } #endif +#if DISTRHO_PLUGIN_WANT_STATE + static bool updateStateValueCallback(void* const ptr, const char* const key, const char* const value) + { + return ((PluginLv2*)ptr)->updateState(key, value); + } +#endif + #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT bool writeMidi(const MidiEvent& midiEvent) { @@ -1375,6 +1486,9 @@ static LV2_Handle lv2_instantiate(const LV2_Descriptor*, double sampleRate, cons d_nextBundlePath = bundlePath; d_nextCanRequestParameterValueChanges = ctrlInPortChangeReq != nullptr; + if (std::getenv("RUNNING_UNDER_LV2LINT") != nullptr) + d_nextPluginIsDummy = true; + return new PluginLv2(sampleRate, uridMap, worker, ctrlInPortChangeReq, usingNominal); } diff --git a/dpf/distrho/src/DistrhoPluginLV2export.cpp b/dpf/distrho/src/DistrhoPluginLV2export.cpp index a857140..a42a50f 100644 --- a/dpf/distrho/src/DistrhoPluginLV2export.cpp +++ b/dpf/distrho/src/DistrhoPluginLV2export.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho + * Copyright (C) 2012-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -42,6 +42,10 @@ # include "mod-license.h" #endif +#ifndef DISTRHO_OS_WINDOWS +# include +#endif + #include #include @@ -75,8 +79,8 @@ # define DISTRHO_LV2_UI_TYPE "UI" #endif -#define DISTRHO_LV2_USE_EVENTS_IN (DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_TIMEPOS || (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI) || DISTRHO_PLUGIN_WANT_STATEFILES) -#define DISTRHO_LV2_USE_EVENTS_OUT (DISTRHO_PLUGIN_WANT_MIDI_OUTPUT || (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI)) +#define DISTRHO_LV2_USE_EVENTS_IN (DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_TIMEPOS || DISTRHO_PLUGIN_WANT_STATE) +#define DISTRHO_LV2_USE_EVENTS_OUT (DISTRHO_PLUGIN_WANT_MIDI_OUTPUT || DISTRHO_PLUGIN_WANT_STATE) #define DISTRHO_BYPASS_PARAMETER_NAME "lv2_enabled" @@ -148,9 +152,7 @@ static const char* const lv2ManifestUiOptionalFeatures[] = "ui:parent", "ui:touch", #endif -#if DISTRHO_PLUGIN_WANT_STATEFILES "ui:requestValue", -#endif nullptr }; @@ -225,14 +227,24 @@ void lv2_generate_ttl(const char* const basename) USE_NAMESPACE_DISTRHO String bundlePath(getBinaryFilename()); - bundlePath.truncate(bundlePath.rfind(DISTRHO_OS_SEP)); + if (bundlePath.isNotEmpty()) + { + bundlePath.truncate(bundlePath.rfind(DISTRHO_OS_SEP)); + } +#ifndef DISTRHO_OS_WINDOWS + else if (char* const cwd = ::getcwd(nullptr, 0)) + { + bundlePath = cwd; + std::free(cwd); + } +#endif d_nextBundlePath = bundlePath.buffer(); // Dummy plugin to get data from d_nextBufferSize = 512; d_nextSampleRate = 44100.0; d_nextPluginIsDummy = true; - PluginExporter plugin(nullptr, nullptr, nullptr); + PluginExporter plugin(nullptr, nullptr, nullptr, nullptr); d_nextBufferSize = 0; d_nextSampleRate = 0.0; d_nextPluginIsDummy = false; @@ -356,21 +368,36 @@ void lv2_generate_ttl(const char* const basename) pluginString += "@prefix unit: <" LV2_UNITS_PREFIX "> .\n"; pluginString += "\n"; -#if DISTRHO_PLUGIN_WANT_STATEFILES - // define writable states as lv2 parameters - bool hasStateFiles = false; +#if DISTRHO_PLUGIN_WANT_STATE + bool hasHostVisibleState = false; for (uint32_t i=0, count=plugin.getStateCount(); i < count; ++i) { - if (! plugin.isStateFile(i)) + const uint32_t hints = plugin.getStateHints(i); + + if ((hints & kStateIsHostReadable) == 0x0) continue; - const String& key(plugin.getStateKey(i)); - pluginString += "<" DISTRHO_PLUGIN_URI "#" + key + ">\n"; + pluginString += "<" DISTRHO_PLUGIN_URI "#" + plugin.getStateKey(i) + ">\n"; pluginString += " a lv2:Parameter ;\n"; - pluginString += " rdfs:label \"" + key + "\" ;\n"; - pluginString += " rdfs:range atom:Path .\n\n"; - hasStateFiles = true; + pluginString += " rdfs:label \"" + plugin.getStateLabel(i) + "\" ;\n"; + + const String& comment(plugin.getStateDescription(i)); + + if (comment.isNotEmpty()) + { + if (comment.contains('"') || comment.contains('\n')) + pluginString += " rdfs:comment \"\"\"" + comment + "\"\"\" ;\n"; + else + pluginString += " rdfs:comment \"" + comment + "\" ;\n"; + } + + if ((hints & kStateIsFilenamePath) == kStateIsFilenamePath) + pluginString += " rdfs:range atom:Path .\n\n"; + else + pluginString += " rdfs:range atom:String .\n\n"; + + hasHostVisibleState = true; } #endif @@ -390,16 +417,22 @@ void lv2_generate_ttl(const char* const basename) addAttribute(pluginString, "lv2:requiredFeature", lv2ManifestPluginRequiredFeatures, 4); addAttribute(pluginString, "opts:supportedOption", lv2ManifestPluginSupportedOptions, 4); -#if DISTRHO_PLUGIN_WANT_STATEFILES - if (hasStateFiles) +#if DISTRHO_PLUGIN_WANT_STATE + if (hasHostVisibleState) { for (uint32_t i=0, count=plugin.getStateCount(); i < count; ++i) { - if (! plugin.isStateFile(i)) + const uint32_t hints = plugin.getStateHints(i); + + if ((hints & kStateIsHostReadable) == 0x0) continue; const String& key(plugin.getStateKey(i)); - pluginString += " patch:writable <" DISTRHO_PLUGIN_URI "#" + key + ">;\n"; + + if ((hints & kStateIsHostWritable) == kStateIsHostWritable) + pluginString += " patch:writable <" DISTRHO_PLUGIN_URI "#" + key + "> ;\n"; + else + pluginString += " patch:readable <" DISTRHO_PLUGIN_URI "#" + key + "> ;\n"; } pluginString += "\n"; } @@ -439,20 +472,23 @@ void lv2_generate_ttl(const char* const basename) if (port.hints & kAudioPortIsSidechain) pluginString += " lv2:portProperty lv2:isSideChain;\n"; - switch (port.groupId) + if (port.groupId != kPortGroupNone) { - case kPortGroupNone: - break; - case kPortGroupMono: - pluginString += " pg:group pg:MonoGroup ;\n"; - break; - case kPortGroupStereo: - pluginString += " pg:group pg:StereoGroup ;\n"; - break; - default: pluginString += " pg:group <" DISTRHO_PLUGIN_URI "#portGroup_" + plugin.getPortGroupSymbolForId(port.groupId) + "> ;\n"; - break; + + switch (port.groupId) + { + case kPortGroupMono: + pluginString += " lv2:designation pg:center ;\n"; + break; + case kPortGroupStereo: + if (i == 1) + pluginString += " lv2:designation pg:right ;\n"; + else + pluginString += " lv2:designation pg:left ;\n"; + break; + } } // set ranges @@ -529,20 +565,23 @@ void lv2_generate_ttl(const char* const basename) if (port.hints & kAudioPortIsSidechain) pluginString += " lv2:portProperty lv2:isSideChain;\n"; - switch (port.groupId) + if (port.groupId != kPortGroupNone) { - case kPortGroupNone: - break; - case kPortGroupMono: - pluginString += " pg:group pg:MonoGroup ;\n"; - break; - case kPortGroupStereo: - pluginString += " pg:group pg:StereoGroup ;\n"; - break; - default: pluginString += " pg:group <" DISTRHO_PLUGIN_URI "#portGroup_" + plugin.getPortGroupSymbolForId(port.groupId) + "> ;\n"; - break; + + switch (port.groupId) + { + case kPortGroupMono: + pluginString += " lv2:designation pg:center ;\n"; + break; + case kPortGroupStereo: + if (i == 1) + pluginString += " lv2:designation pg:right ;\n"; + else + pluginString += " lv2:designation pg:left ;\n"; + break; + } } // set ranges @@ -608,11 +647,15 @@ void lv2_generate_ttl(const char* const basename) # if DISTRHO_PLUGIN_WANT_MIDI_INPUT pluginString += " atom:supports midi:MidiEvent ;\n"; # endif -# if DISTRHO_PLUGIN_WANT_STATEFILES - pluginString += " atom:supports <" LV2_PATCH__Message "> ;\n"; -# endif # if DISTRHO_PLUGIN_WANT_TIMEPOS pluginString += " atom:supports <" LV2_TIME__Position "> ;\n"; +# endif +# if DISTRHO_PLUGIN_WANT_STATE + if (hasHostVisibleState) + { + pluginString += " atom:supports <" LV2_PATCH__Message "> ;\n"; + pluginString += " lv2:designation lv2:control ;\n"; + } # endif pluginString += " ] ;\n\n"; ++portIndex; @@ -632,8 +675,12 @@ void lv2_generate_ttl(const char* const basename) # if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT pluginString += " atom:supports midi:MidiEvent ;\n"; # endif -# if DISTRHO_PLUGIN_WANT_STATEFILES - pluginString += " atom:supports <" LV2_PATCH__Message "> ;\n"; +# if DISTRHO_PLUGIN_WANT_STATE + if (hasHostVisibleState) + { + pluginString += " atom:supports <" LV2_PATCH__Message "> ;\n"; + pluginString += " lv2:designation lv2:control ;\n"; + } # endif pluginString += " ] ;\n\n"; ++portIndex; @@ -860,21 +907,9 @@ void lv2_generate_ttl(const char* const basename) // group const uint32_t groupId = plugin.getParameterGroupId(i); - switch (groupId) - { - case kPortGroupNone: - break; - case kPortGroupMono: - pluginString += " pg:group pg:MonoGroup ;\n"; - break; - case kPortGroupStereo: - pluginString += " pg:group pg:StereoGroup ;\n"; - break; - default: + if (groupId != kPortGroupNone) pluginString += " pg:group <" DISTRHO_PLUGIN_URI "#portGroup_" + plugin.getPortGroupSymbolForId(groupId) + "> ;\n"; - break; - } } // ! designated @@ -987,6 +1022,7 @@ void lv2_generate_ttl(const char* const basename) else if (uplicense == "GPL-2.0-OR-LATER" || uplicense == "GPL2+" || uplicense == "GPLV2+" || + uplicense == "GPLV2.0+" || uplicense == "GPL V2+") { pluginString += " doap:license ;\n\n"; @@ -1000,6 +1036,7 @@ void lv2_generate_ttl(const char* const basename) else if (uplicense == "GPL-3.0-OR-LATER" || uplicense == "GPL3+" || uplicense == "GPLV3+" || + uplicense == "GPLV3.0+" || uplicense == "GPL V3+") { pluginString += " doap:license ;\n\n"; @@ -1052,11 +1089,11 @@ void lv2_generate_ttl(const char* const basename) // generic fallbacks else if (uplicense.startsWith("GPL")) { - pluginString += " doap:license ;\n\n"; + pluginString += " doap:license ;\n\n"; } else if (uplicense.startsWith("LGPL")) { - pluginString += " doap:license ;\n\n"; + pluginString += " doap:license ;\n\n"; } // unknown or not handled yet, log a warning @@ -1090,8 +1127,8 @@ void lv2_generate_ttl(const char* const basename) const uint32_t version(plugin.getVersion()); const uint32_t majorVersion = (version & 0xFF0000) >> 16; - const uint32_t microVersion = (version & 0x00FF00) >> 8; - /* */ uint32_t minorVersion = (version & 0x0000FF) >> 0; + /* */ uint32_t minorVersion = (version & 0x00FF00) >> 8; + const uint32_t microVersion = (version & 0x0000FF) >> 0; // NOTE: LV2 ignores 'major' version and says 0 for minor is pre-release/unstable. if (majorVersion > 0) @@ -1112,13 +1149,6 @@ void lv2_generate_ttl(const char* const basename) DISTRHO_SAFE_ASSERT_CONTINUE(portGroup.groupId != kPortGroupNone); DISTRHO_SAFE_ASSERT_CONTINUE(portGroup.symbol.isNotEmpty()); - switch (portGroup.groupId) - { - case kPortGroupMono: - case kPortGroupStereo: - continue; - } - pluginString += "\n<" DISTRHO_PLUGIN_URI "#portGroup_" + portGroup.symbol + ">\n"; isInput = isOutput = false; @@ -1142,19 +1172,28 @@ void lv2_generate_ttl(const char* const basename) } pluginString += " a "; + if (isInput && !isOutput) pluginString += "pg:InputGroup"; else if (isOutput && !isInput) pluginString += "pg:OutputGroup"; else pluginString += "pg:Group"; + + switch (portGroup.groupId) + { + case kPortGroupMono: + pluginString += " , pg:MonoGroup"; + break; + case kPortGroupStereo: + pluginString += " , pg:StereoGroup"; + break; + } + pluginString += " ;\n"; -#if 0 - pluginString += " rdfs:label \"" + portGroup.name + "\" ;\n"; -#else + // pluginString += " rdfs:label \"" + portGroup.name + "\" ;\n"; pluginString += " lv2:name \"" + portGroup.name + "\" ;\n"; -#endif pluginString += " lv2:symbol \"" + portGroup.symbol + "\" .\n"; } } @@ -1229,10 +1268,11 @@ void lv2_generate_ttl(const char* const basename) # if DISTRHO_PLUGIN_WANT_FULL_STATE for (uint32_t i=0; i\n"; presetString += " a owl:DatatypeProperty ;\n"; presetString += " rdfs:label \"Plugin state key-value string pair\" ;\n"; @@ -1255,9 +1295,16 @@ void lv2_generate_ttl(const char* const basename) for (uint32_t j=0; j"; + presetString += key + ">"; if (value.length() < 10) presetString += " \"" + value + "\" ;\n"; diff --git a/dpf/distrho/src/DistrhoPluginVST3.hpp b/dpf/distrho/src/DistrhoPluginVST.hpp similarity index 68% rename from dpf/distrho/src/DistrhoPluginVST3.hpp rename to dpf/distrho/src/DistrhoPluginVST.hpp index a67c221..7d08adc 100644 --- a/dpf/distrho/src/DistrhoPluginVST3.hpp +++ b/dpf/distrho/src/DistrhoPluginVST.hpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho + * Copyright (C) 2012-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -14,8 +14,8 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef DISTRHO_PLUGIN_VST3_HPP_INCLUDED -#define DISTRHO_PLUGIN_VST3_HPP_INCLUDED +#ifndef DISTRHO_PLUGIN_VST_HPP_INCLUDED +#define DISTRHO_PLUGIN_VST_HPP_INCLUDED #include "DistrhoPluginChecks.h" #include "../DistrhoUtils.hpp" @@ -33,6 +33,10 @@ # define DISTRHO_PLUGIN_HAS_UI 0 #endif +#if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_HAS_EXTERNAL_UI +# include "Base.hpp" +#endif + #if DISTRHO_PLUGIN_HAS_UI == 1 && DISTRHO_PLUGIN_WANT_DIRECT_ACCESS == 0 # define DPF_VST3_USES_SEPARATE_CONTROLLER 1 #else @@ -219,6 +223,18 @@ static void snprintf_utf16_t(int16_t* const dst, const T value, const char* cons std::free(tmpbuf); } +static inline +void snprintf_f32(char* const dst, const float value, const size_t size) +{ + return snprintf_t(dst, value, "%f", size); +} + +static inline +void snprintf_i32(char* const dst, const int32_t value, const size_t size) +{ + return snprintf_t(dst, value, "%d", size); +} + static inline void snprintf_u32(char* const dst, const uint32_t value, const size_t size) { @@ -232,11 +248,128 @@ void snprintf_f32_utf16(int16_t* const dst, const float value, const size_t size } static inline -void snprintf_i32_utf16(int16_t* const dst, const int value, const size_t size) +void snprintf_i32_utf16(int16_t* const dst, const int32_t value, const size_t size) +{ + return snprintf_utf16_t(dst, value, "%d", size); +} + +static inline +void snprintf_u32_utf16(int16_t* const dst, const uint32_t value, const size_t size) { - return snprintf_utf16_t(dst, value, "%d", size); + return snprintf_utf16_t(dst, value, "%u", size); } +#if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_HAS_EXTERNAL_UI +// -------------------------------------------------------------------------------------------------------------------- +// translate a vstgui-based key character and code to matching values used by DPF + +static inline +uint translateVstKeyCode(bool& special, const int16_t keychar, const int16_t keycode) noexcept +{ + using namespace DGL_NAMESPACE; + + // special stuff first + special = true; + switch (keycode) + { + case 1: return kKeyBackspace; + // 2 \t (handled below) + // 3 clear + // 4 \r (handled below) + case 6: return kKeyEscape; + // 7 space (handled below) + // 8 next + // 17 select + // 18 print + // 19 \n (handled below) + // 20 snapshot + case 22: return kKeyDelete; + // 23 help + // 57 = (handled below) + // numpad stuff follows + // 24 0 (handled below) + // 25 1 (handled below) + // 26 2 (handled below) + // 27 3 (handled below) + // 28 4 (handled below) + // 29 5 (handled below) + // 30 6 (handled below) + // 31 7 (handled below) + // 32 8 (handled below) + // 33 9 (handled below) + // 34 * (handled below) + // 35 + (handled below) + // 36 separator + // 37 - (handled below) + // 38 . (handled below) + // 39 / (handled below) + // handle rest of special keys + /* these special keys are missing: + - kKeySuper + - kKeyCapsLock + - kKeyPrintScreen + */ + case 40: return kKeyF1; + case 41: return kKeyF2; + case 42: return kKeyF3; + case 43: return kKeyF4; + case 44: return kKeyF5; + case 45: return kKeyF6; + case 46: return kKeyF7; + case 47: return kKeyF8; + case 48: return kKeyF9; + case 49: return kKeyF10; + case 50: return kKeyF11; + case 51: return kKeyF12; + case 11: return kKeyLeft; + case 12: return kKeyUp; + case 13: return kKeyRight; + case 14: return kKeyDown; + case 15: return kKeyPageUp; + case 16: return kKeyPageDown; + case 10: return kKeyHome; + case 9: return kKeyEnd; + case 21: return kKeyInsert; + case 54: return kKeyShift; + case 55: return kKeyControl; + case 56: return kKeyAlt; + case 58: return kKeyMenu; + case 52: return kKeyNumLock; + case 53: return kKeyScrollLock; + case 5: return kKeyPause; + } + + // regular keys next + special = false; + switch (keycode) + { + case 2: return '\t'; + case 4: return '\r'; + case 7: return ' '; + case 19: return '\n'; + case 57: return '='; + case 24: return '0'; + case 25: return '1'; + case 26: return '2'; + case 27: return '3'; + case 28: return '4'; + case 29: return '5'; + case 30: return '6'; + case 31: return '7'; + case 32: return '8'; + case 33: return '9'; + case 34: return '*'; + case 35: return '+'; + case 37: return '-'; + case 38: return '.'; + case 39: return '/'; + } + + // fallback + return keychar; +} +#endif + // -------------------------------------------------------------------------------------------------------------------- // handy way to create a utf16 string from a utf8 one on the current function scope, used for message strings @@ -285,4 +418,4 @@ END_NAMESPACE_DISTRHO // -------------------------------------------------------------------------------------------------------------------- -#endif // DISTRHO_PLUGIN_VST3_HPP_INCLUDED +#endif // DISTRHO_PLUGIN_VST_HPP_INCLUDED diff --git a/dpf/distrho/src/DistrhoPluginVST2.cpp b/dpf/distrho/src/DistrhoPluginVST2.cpp index fc2ef31..8f47a98 100644 --- a/dpf/distrho/src/DistrhoPluginVST2.cpp +++ b/dpf/distrho/src/DistrhoPluginVST2.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho + * Copyright (C) 2012-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -15,18 +15,10 @@ */ #include "DistrhoPluginInternal.hpp" +#include "DistrhoPluginVST.hpp" #include "../DistrhoPluginUtils.hpp" #include "../extra/ScopedSafeLocale.hpp" - -#if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_HAS_EMBED_UI -# undef DISTRHO_PLUGIN_HAS_UI -# define DISTRHO_PLUGIN_HAS_UI 0 -#endif - -#if DISTRHO_PLUGIN_HAS_UI && ! defined(HAVE_DGL) && ! DISTRHO_PLUGIN_HAS_EXTERNAL_UI -# undef DISTRHO_PLUGIN_HAS_UI -# define DISTRHO_PLUGIN_HAS_UI 0 -#endif +#include "../extra/ScopedPointer.hpp" #if DISTRHO_PLUGIN_HAS_UI # include "DistrhoUIInternal.hpp" @@ -84,37 +76,6 @@ static const requestParameterValueChangeFunc requestParameterValueChangeCallback // ----------------------------------------------------------------------- -void strncpy(char* const dst, const char* const src, const size_t size) -{ - DISTRHO_SAFE_ASSERT_RETURN(size > 0,); - - if (const size_t len = std::min(std::strlen(src), size-1U)) - { - std::memcpy(dst, src, len); - dst[len] = '\0'; - } - else - { - dst[0] = '\0'; - } -} - -void snprintf_param(char* const dst, const float value, const size_t size) -{ - DISTRHO_SAFE_ASSERT_RETURN(size > 0,); - std::snprintf(dst, size-1, "%f", value); - dst[size-1] = '\0'; -} - -void snprintf_iparam(char* const dst, const int32_t value, const size_t size) -{ - DISTRHO_SAFE_ASSERT_RETURN(size > 0,); - std::snprintf(dst, size-1, "%d", value); - dst[size-1] = '\0'; -} - -// ----------------------------------------------------------------------- - struct ParameterAndNotesHelper { float* parameterValues; @@ -256,85 +217,16 @@ public: # endif # if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI - int handlePluginKeyEvent(const bool down, int32_t index, const intptr_t value) + int handlePluginKeyEvent(const bool down, const int32_t index, const intptr_t value) { d_stdout("handlePluginKeyEvent %i %i %li\n", down, index, (long int)value); using namespace DGL_NAMESPACE; - switch (value) - { - // convert some VST special values to normal keys - case 1: index = kKeyBackspace; break; - case 2: index = '\t'; break; - // 3 clear - case 4: index = '\r'; break; - case 6: index = kKeyEscape; break; - case 7: index = ' '; break; - // 8 next - // 17 select - // 18 print - case 19: index = '\n'; break; - // 20 snapshot - case 22: index = kKeyDelete; break; - // 23 help - case 57: index = '='; break; - - // numpad stuff follows - case 24: index = '0'; break; - case 25: index = '1'; break; - case 26: index = '2'; break; - case 27: index = '3'; break; - case 28: index = '4'; break; - case 29: index = '5'; break; - case 30: index = '6'; break; - case 31: index = '7'; break; - case 32: index = '8'; break; - case 33: index = '9'; break; - case 34: index = '*'; break; - case 35: index = '+'; break; - // 36 separator - case 37: index = '-'; break; - case 38: index = '.'; break; - case 39: index = '/'; break; - - // handle rest of special keys - /* these special keys are missing: - - kKeySuper - - kKeyCapsLock - - kKeyPrintScreen - */ - case 40: index = kKeyF1; break; - case 41: index = kKeyF2; break; - case 42: index = kKeyF3; break; - case 43: index = kKeyF4; break; - case 44: index = kKeyF5; break; - case 45: index = kKeyF6; break; - case 46: index = kKeyF7; break; - case 47: index = kKeyF8; break; - case 48: index = kKeyF9; break; - case 49: index = kKeyF10; break; - case 50: index = kKeyF11; break; - case 51: index = kKeyF12; break; - case 11: index = kKeyLeft; break; - case 12: index = kKeyUp; break; - case 13: index = kKeyRight; break; - case 14: index = kKeyDown; break; - case 15: index = kKeyPageUp; break; - case 16: index = kKeyPageDown; break; - case 10: index = kKeyHome; break; - case 9: index = kKeyEnd; break; - case 21: index = kKeyInsert; break; - case 54: index = kKeyShift; break; - case 55: index = kKeyControl; break; - case 56: index = kKeyAlt; break; - case 58: index = kKeyMenu; break; - case 52: index = kKeyNumLock; break; - case 53: index = kKeyScrollLock; break; - case 5: index = kKeyPause; break; - } + bool special; + const uint key = translateVstKeyCode(special, index, static_cast(value)); - switch (index) + switch (key) { case kKeyShift: if (down) @@ -356,30 +248,9 @@ public: break; } - if (index > 0) - { - // keyboard events must always be lowercase - bool needsShiftRevert = false; - if (index >= 'A' && index <= 'Z') - { - index += 'a' - 'A'; // A-Z -> a-z - - if ((fKeyboardModifiers & kModifierShift) == 0x0) - { - needsShiftRevert = true; - fKeyboardModifiers |= kModifierShift; - } - } - - fUI.handlePluginKeyboardVST2(down, static_cast(index), fKeyboardModifiers); - - if (needsShiftRevert) - fKeyboardModifiers &= ~kModifierShift; - - return 1; - } - - return 0; + return fUI.handlePluginKeyboardVST(down, special, key, + value >= 0 ? static_cast(value) : 0, + fKeyboardModifiers) ? 1 : 0; } # endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI @@ -498,11 +369,11 @@ class PluginVst : public ParameterAndNotesHelper { public: PluginVst(const audioMasterCallback audioMaster, AEffect* const effect) - : fPlugin(this, writeMidiCallback, requestParameterValueChangeCallback), + : fPlugin(this, writeMidiCallback, requestParameterValueChangeCallback, nullptr), fAudioMaster(audioMaster), fEffect(effect) { - std::memset(fProgramName, 0, sizeof(char)*(32+1)); + std::memset(fProgramName, 0, sizeof(fProgramName)); std::strcpy(fProgramName, "Default"); const uint32_t parameterCount = fPlugin.getParameterCount(); @@ -587,7 +458,7 @@ public: case effSetProgramName: if (char* const programName = (char*)ptr) { - DISTRHO_NAMESPACE::strncpy(fProgramName, programName, 32); + strncpy(fProgramName, programName, 32); return 1; } break; @@ -595,7 +466,7 @@ public: case effGetProgramName: if (char* const programName = (char*)ptr) { - DISTRHO_NAMESPACE::strncpy(programName, fProgramName, 24); + strncpy(programName, fProgramName, 24); return 1; } break; @@ -603,7 +474,7 @@ public: case effGetProgramNameIndexed: if (char* const programName = (char*)ptr) { - DISTRHO_NAMESPACE::strncpy(programName, fProgramName, 24); + strncpy(programName, fProgramName, 24); return 1; } break; @@ -633,14 +504,14 @@ public: if (d_isNotEqual(value, enumValues.values[i].value)) continue; - DISTRHO_NAMESPACE::strncpy((char*)ptr, enumValues.values[i].label.buffer(), 24); + strncpy((char*)ptr, enumValues.values[i].label.buffer(), 24); return 1; } if (hints & kParameterIsInteger) - DISTRHO_NAMESPACE::snprintf_iparam((char*)ptr, (int32_t)value, 24); + snprintf_i32((char*)ptr, (int32_t)value, 24); else - DISTRHO_NAMESPACE::snprintf_param((char*)ptr, value, 24); + snprintf_f32((char*)ptr, value, 24); return 1; } @@ -737,7 +608,7 @@ public: for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit) { const String& key = cit->first; - fStateMap[key] = fPlugin.getState(key); + fStateMap[key] = fPlugin.getStateValue(key); } # endif @@ -813,7 +684,7 @@ public: for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit) { const String& key = cit->first; - fStateMap[key] = fPlugin.getState(key); + fStateMap[key] = fPlugin.getStateValue(key); } # endif @@ -1032,6 +903,8 @@ public: #else return -1; #endif + if (std::strcmp(canDo, "offline") == 0) + return -1; } break; @@ -1111,9 +984,8 @@ public: if (const VstTimeInfo* const vstTimeInfo = (const VstTimeInfo*)hostCallback(audioMasterGetTime, 0, kWantVstTimeFlags)) { - fTimePosition.frame = vstTimeInfo->samplePos; - fTimePosition.playing = (vstTimeInfo->flags & kVstTransportPlaying); - fTimePosition.bbt.valid = ((vstTimeInfo->flags & kVstTempoValid) != 0 || (vstTimeInfo->flags & kVstTimeSigValid) != 0); + fTimePosition.frame = vstTimeInfo->samplePos; + fTimePosition.playing = vstTimeInfo->flags & kVstTransportPlaying; // ticksPerBeat is not possible with VST2 fTimePosition.bbt.ticksPerBeat = 1920.0; @@ -1130,6 +1002,7 @@ public: const double barBeats = (std::fmod(ppqPos, ppqPerBar) / ppqPerBar) * vstTimeInfo->timeSigNumerator; const double rest = std::fmod(barBeats, 1.0); + fTimePosition.bbt.valid = true; fTimePosition.bbt.bar = static_cast(ppqPos) / ppqPerBar + 1; fTimePosition.bbt.beat = static_cast(barBeats - rest + 0.5) + 1; fTimePosition.bbt.tick = rest * fTimePosition.bbt.ticksPerBeat; @@ -1145,6 +1018,7 @@ public: } else { + fTimePosition.bbt.valid = false; fTimePosition.bbt.bar = 1; fTimePosition.bbt.beat = 1; fTimePosition.bbt.tick = 0.0; @@ -1205,7 +1079,7 @@ private: AEffect* const fEffect; // Temporary data - char fProgramName[32+1]; + char fProgramName[32]; #if DISTRHO_PLUGIN_WANT_MIDI_INPUT uint32_t fMidiEventCount; @@ -1396,33 +1270,38 @@ struct VstObject { #define vstObjectPtr (VstObject*)effect->object #define pluginPtr (vstObjectPtr)->plugin +static ScopedPointer sPlugin; + static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t index, intptr_t value, void* ptr, float opt) { // first internal init const bool doInternalInit = (opcode == -1729 && index == 0xdead && value == 0xf00d); - if (doInternalInit) + if (doInternalInit || opcode == effOpen) { - // set valid but dummy values - d_nextBufferSize = 512; - d_nextSampleRate = 44100.0; - d_nextPluginIsDummy = true; - d_nextCanRequestParameterValueChanges = true; - } + if (sPlugin == nullptr) + { + // set valid but dummy values + d_nextBufferSize = 512; + d_nextSampleRate = 44100.0; + d_nextPluginIsDummy = true; + d_nextCanRequestParameterValueChanges = true; - // Create dummy plugin to get data from - static PluginExporter plugin(nullptr, nullptr, nullptr); + // Create dummy plugin to get data from + sPlugin = new PluginExporter(nullptr, nullptr, nullptr, nullptr); - if (doInternalInit) - { - // unset - d_nextBufferSize = 0; - d_nextSampleRate = 0.0; - d_nextPluginIsDummy = false; - d_nextCanRequestParameterValueChanges = false; + // unset + d_nextBufferSize = 0; + d_nextSampleRate = 0.0; + d_nextPluginIsDummy = false; + d_nextCanRequestParameterValueChanges = false; + } - *(PluginExporter**)ptr = &plugin; - return 0; + if (doInternalInit) + { + *(PluginExporter**)ptr = sPlugin.get(); + return 0; + } } // handle base opcodes @@ -1472,53 +1351,54 @@ static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t delete obj; #endif + sPlugin = nullptr; return 1; } //delete effect; return 0; case effGetParamLabel: - if (ptr != nullptr && index < static_cast(plugin.getParameterCount())) + if (ptr != nullptr && index < static_cast(sPlugin->getParameterCount())) { - DISTRHO_NAMESPACE::strncpy((char*)ptr, plugin.getParameterUnit(index), 8); + strncpy((char*)ptr, sPlugin->getParameterUnit(index), 8); return 1; } return 0; case effGetParamName: - if (ptr != nullptr && index < static_cast(plugin.getParameterCount())) + if (ptr != nullptr && index < static_cast(sPlugin->getParameterCount())) { - const String& shortName(plugin.getParameterShortName(index)); + const String& shortName(sPlugin->getParameterShortName(index)); if (shortName.isNotEmpty()) - DISTRHO_NAMESPACE::strncpy((char*)ptr, shortName, 16); + strncpy((char*)ptr, shortName, 16); else - DISTRHO_NAMESPACE::strncpy((char*)ptr, plugin.getParameterName(index), 16); + strncpy((char*)ptr, sPlugin->getParameterName(index), 16); return 1; } return 0; case effGetParameterProperties: - if (ptr != nullptr && index < static_cast(plugin.getParameterCount())) + if (ptr != nullptr && index < static_cast(sPlugin->getParameterCount())) { if (VstParameterProperties* const properties = (VstParameterProperties*)ptr) { memset(properties, 0, sizeof(VstParameterProperties)); // full name - DISTRHO_NAMESPACE::strncpy(properties->label, - plugin.getParameterName(index), - sizeof(properties->label)); + strncpy(properties->label, + sPlugin->getParameterName(index), + sizeof(properties->label)); // short name - const String& shortName(plugin.getParameterShortName(index)); + const String& shortName(sPlugin->getParameterShortName(index)); if (shortName.isNotEmpty()) - DISTRHO_NAMESPACE::strncpy(properties->shortLabel, - plugin.getParameterShortName(index), - sizeof(properties->shortLabel)); + strncpy(properties->shortLabel, + sPlugin->getParameterShortName(index), + sizeof(properties->shortLabel)); // parameter hints - const uint32_t hints = plugin.getParameterHints(index); + const uint32_t hints = sPlugin->getParameterHints(index); if (hints & kParameterIsOutput) return 1; @@ -1530,7 +1410,7 @@ static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t if (hints & kParameterIsInteger) { - const ParameterRanges& ranges(plugin.getParameterRanges(index)); + const ParameterRanges& ranges(sPlugin->getParameterRanges(index)); properties->flags |= kVstParameterUsesIntegerMinMax; properties->minInteger = static_cast(ranges.min); properties->maxInteger = static_cast(ranges.max); @@ -1542,29 +1422,29 @@ static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t } // parameter group (category in vst) - const uint32_t groupId = plugin.getParameterGroupId(index); + const uint32_t groupId = sPlugin->getParameterGroupId(index); if (groupId != kPortGroupNone) { // we can't use groupId directly, so use the index array where this group is stored in - for (uint32_t i=0, count=plugin.getPortGroupCount(); i < count; ++i) + for (uint32_t i=0, count=sPlugin->getPortGroupCount(); i < count; ++i) { - const PortGroupWithId& portGroup(plugin.getPortGroupByIndex(i)); + const PortGroupWithId& portGroup(sPlugin->getPortGroupByIndex(i)); if (portGroup.groupId == groupId) { properties->category = i + 1; - DISTRHO_NAMESPACE::strncpy(properties->categoryLabel, - portGroup.name.buffer(), - sizeof(properties->categoryLabel)); + strncpy(properties->categoryLabel, + portGroup.name.buffer(), + sizeof(properties->categoryLabel)); break; } } if (properties->category != 0) { - for (uint32_t i=0, count=plugin.getParameterCount(); i < count; ++i) - if (plugin.getParameterGroupId(i) == groupId) + for (uint32_t i=0, count=sPlugin->getParameterCount(); i < count; ++i) + if (sPlugin->getParameterGroupId(i) == groupId) ++properties->numParametersInCategory; } } @@ -1584,7 +1464,7 @@ static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t case effGetEffectName: if (char* const cptr = (char*)ptr) { - DISTRHO_NAMESPACE::strncpy(cptr, plugin.getName(), 32); + strncpy(cptr, sPlugin->getName(), 32); return 1; } return 0; @@ -1592,7 +1472,7 @@ static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t case effGetVendorString: if (char* const cptr = (char*)ptr) { - DISTRHO_NAMESPACE::strncpy(cptr, plugin.getMaker(), 32); + strncpy(cptr, sPlugin->getMaker(), 32); return 1; } return 0; @@ -1600,13 +1480,13 @@ static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t case effGetProductString: if (char* const cptr = (char*)ptr) { - DISTRHO_NAMESPACE::strncpy(cptr, plugin.getLabel(), 32); + strncpy(cptr, sPlugin->getLabel(), 32); return 1; } return 0; case effGetVendorVersion: - return plugin.getVersion(); + return sPlugin->getVersion(); case effGetVstVersion: return kVstVersion; @@ -1668,7 +1548,7 @@ static struct Cleanup { END_NAMESPACE_DISTRHO DISTRHO_PLUGIN_EXPORT -#if DISTRHO_OS_WINDOWS || DISTRHO_OS_MAC +#if DISTRHO_OS_MAC || DISTRHO_OS_WASM || DISTRHO_OS_WINDOWS const AEffect* VSTPluginMain(audioMasterCallback audioMaster); #else const AEffect* VSTPluginMain(audioMasterCallback audioMaster) asm ("main"); diff --git a/dpf/distrho/src/DistrhoPluginVST3.cpp b/dpf/distrho/src/DistrhoPluginVST3.cpp index 68644c6..c22706e 100644 --- a/dpf/distrho/src/DistrhoPluginVST3.cpp +++ b/dpf/distrho/src/DistrhoPluginVST3.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho + * Copyright (C) 2012-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -42,7 +42,6 @@ * - have parameter outputs host-provided UI working in at least 1 host * - parameter groups via unit ids * - test parameter changes from DSP (aka requestParameterValueChange) - * - test receiving midi CC * - implement getParameterNormalized/setParameterNormalized for MIDI CC params ? * - fully implemented parameter stuff and verify * - float to int safe casting @@ -51,10 +50,9 @@ * - MIDI CC changes (need to store value to give to the host?) * - MIDI program changes * - MIDI sysex - * - append MIDI input events in a sorted way * == BUSES * - bus arrangements - * - optional audio buses, create dummy buffer of max_block_size length for them + * - optional audio buses * - routing info, do we care? * - set sidechain bus name from port group * == CV @@ -128,7 +126,45 @@ const char* tuid2str(const v3_tuid iid) { V3_ID(0xF89F8CDF,0x699E4BA5,0x96AAC9A4,0x81452B01), "{v3_unit_handler2|NOT}" }, { V3_ID(0x3D4BD6B5,0x913A4FD2,0xA886E768,0xA5EB92C1), "{v3_unit_info|NOT}" }, // misc + { V3_ID(0x309ECE78,0xEB7D4FAE,0x8B2225D9,0x09FD08B6), "{v3_audio_presentation_latency|NOT}" }, + { V3_ID(0xB4E8287F,0x1BB346AA,0x83A46667,0x68937BAB), "{v3_automation_state|NOT}" }, { V3_ID(0x0F194781,0x8D984ADA,0xBBA0C1EF,0xC011D8D0), "{v3_info_listener|NOT}" }, + { V3_ID(0x6D21E1DC,0x91199D4B,0xA2A02FEF,0x6C1AE55C), "{v3_parameter_function_name|NOT}" }, + { V3_ID(0x8AE54FDA,0xE93046B9,0xA28555BC,0xDC98E21E), "{v3_prefetchable_support|NOT}" }, + { V3_ID(0xA81A0471,0x48C34DC4,0xAC30C9E1,0x3C8393D5), "{v3_xml_representation_stream|NOT}" }, + /* + // seen in the wild but unknown, related to component + { V3_ID(0x6548D671,0x997A4EA5,0x9B336A6F,0xB3E93B50), "{v3_|NOT}" }, + { V3_ID(0xC2B7896B,0x069844D5,0x8F06E937,0x33A35FF7), "{v3_|NOT}" }, + { V3_ID(0xE123DE93,0xE0F642A4,0xAE53867E,0x53F059EE), "{v3_|NOT}" }, + { V3_ID(0x83850D7B,0xC12011D8,0xA143000A,0x959B31C6), "{v3_|NOT}" }, + { V3_ID(0x9598D418,0xA00448AC,0x9C6D8248,0x065B2E5C), "{v3_|NOT}" }, + { V3_ID(0xBD386132,0x45174BAD,0xA324390B,0xFD297506), "{v3_|NOT}" }, + { V3_ID(0xD7296A84,0x23B1419C,0xAAD0FAA3,0x53BB16B7), "{v3_|NOT}" }, + { V3_ID(0x181A0AF6,0xA10947BA,0x8A6F7C7C,0x3FF37129), "{v3_|NOT}" }, + { V3_ID(0xC2B7896B,0x69A844D5,0x8F06E937,0x33A35FF7), "{v3_|NOT}" }, + // seen in the wild but unknown, related to edit controller + { V3_ID(0x1F2F76D3,0xBFFB4B96,0xB99527A5,0x5EBCCEF4), "{v3_|NOT}" }, + { V3_ID(0x6B2449CC,0x419740B5,0xAB3C79DA,0xC5FE5C86), "{v3_|NOT}" }, + { V3_ID(0x67800560,0x5E784D90,0xB97BAB4C,0x8DC5BAA3), "{v3_|NOT}" }, + { V3_ID(0xDB51DA00,0x8FD5416D,0xB84894D8,0x7FDE73E4), "{v3_|NOT}" }, + { V3_ID(0xE90FC54F,0x76F24235,0x8AF8BD15,0x68C663D6), "{v3_|NOT}" }, + { V3_ID(0x07938E89,0xBA0D4CA8,0x8C7286AB,0xA9DDA95B), "{v3_|NOT}" }, + { V3_ID(0x42879094,0xA2F145ED,0xAC90E82A,0x99458870), "{v3_|NOT}" }, + { V3_ID(0xC3B17BC0,0x2C174494,0x80293402,0xFBC4BBF8), "{v3_|NOT}" }, + { V3_ID(0x31E29A7A,0xE55043AD,0x8B95B9B8,0xDA1FBE1E), "{v3_|NOT}" }, + { V3_ID(0x8E3C292C,0x95924F9D,0xB2590B1E,0x100E4198), "{v3_|NOT}" }, + { V3_ID(0x50553FD9,0x1D2C4C24,0xB410F484,0xC5FB9F3F), "{v3_|NOT}" }, + { V3_ID(0xF185556C,0x5EE24FC7,0x92F28754,0xB7759EA8), "{v3_|NOT}" }, + { V3_ID(0xD2CE9317,0xF24942C9,0x9742E82D,0xB10CCC52), "{v3_|NOT}" }, + { V3_ID(0xDA57E6D1,0x1F3242D1,0xAD9C1A82,0xFDB95695), "{v3_|NOT}" }, + { V3_ID(0x3ABDFC3E,0x4B964A66,0xFCD86F10,0x0D554023), "{v3_|NOT}" }, + // seen in the wild but unknown, related to view + { V3_ID(0xAA3E50FF,0xB78840EE,0xADCD48E8,0x094CEDB7), "{v3_|NOT}" }, + { V3_ID(0x2CAE14DB,0x4DE04C6E,0x8BD2E611,0x1B31A9C2), "{v3_|NOT}" }, + { V3_ID(0xD868D61D,0x20F445F4,0x947D069E,0xC811D1E4), "{v3_|NOT}" }, + { V3_ID(0xEE49E3CA,0x6FCB44FB,0xAEBEE6C3,0x48625122), "{v3_|NOT}" }, + */ }; if (v3_tuid_match(iid, v3_audio_processor_iid)) @@ -249,9 +285,293 @@ class PluginVst3 numCV(0) {} } inputBuses, outputBuses; + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT + /* handy class for storing and sorting events and MIDI CC parameters + * only stores events for which a MIDI conversion is possible. + */ + struct InputEventsList { + enum Type { + NoteOn, + NoteOff, + SysexData, + PolyPressure, + CC_Normal, + CC_ChannelPressure, + CC_Pitchbend, + UI_MIDI // event from UI + }; + struct InputEventStorage { + Type type; + union { + v3_event_note_on noteOn; + v3_event_note_off noteOff; + v3_event_data sysexData; + v3_event_poly_pressure polyPressure; + uint8_t midi[3]; + }; + } eventListStorage[kMaxMidiEvents]; + + struct InputEventTiming { + int32_t sampleOffset; + const InputEventStorage* storage; + InputEventTiming* next; + } eventList[kMaxMidiEvents]; + + uint16_t numUsed; + int32_t firstSampleOffset; + int32_t lastSampleOffset; + InputEventTiming* firstEvent; + InputEventTiming* lastEvent; + + void init() + { + numUsed = 0; + firstSampleOffset = lastSampleOffset = 0; + firstEvent = nullptr; + } + + uint32_t convert(MidiEvent midiEvents[kMaxMidiEvents]) const noexcept + { + uint32_t count = 0; + + for (const InputEventTiming* event = firstEvent; event != nullptr; event = event->next) + { + MidiEvent& midiEvent(midiEvents[count++]); + midiEvent.frame = event->sampleOffset; + + const InputEventStorage& eventStorage(*event->storage); + + switch (eventStorage.type) + { + case NoteOn: + midiEvent.size = 3; + midiEvent.data[0] = 0x90 | (eventStorage.noteOn.channel & 0xf); + midiEvent.data[1] = eventStorage.noteOn.pitch; + midiEvent.data[2] = std::max(0, std::min(127, (int)(eventStorage.noteOn.velocity * 127))); + midiEvent.data[3] = 0; + break; + case NoteOff: + midiEvent.size = 3; + midiEvent.data[0] = 0x80 | (eventStorage.noteOff.channel & 0xf); + midiEvent.data[1] = eventStorage.noteOff.pitch; + midiEvent.data[2] = std::max(0, std::min(127, (int)(eventStorage.noteOff.velocity * 127))); + midiEvent.data[3] = 0; + break; + /* TODO + case SysexData: + break; + */ + case PolyPressure: + midiEvent.size = 3; + midiEvent.data[0] = 0xA0 | (eventStorage.polyPressure.channel & 0xf); + midiEvent.data[1] = eventStorage.polyPressure.pitch; + midiEvent.data[2] = std::max(0, std::min(127, (int)(eventStorage.polyPressure.pressure * 127))); + midiEvent.data[3] = 0; + break; + case CC_Normal: + midiEvent.size = 3; + midiEvent.data[0] = 0xB0 | (eventStorage.midi[0] & 0xf); + midiEvent.data[1] = eventStorage.midi[1]; + midiEvent.data[2] = eventStorage.midi[2]; + break; + case CC_ChannelPressure: + midiEvent.size = 2; + midiEvent.data[0] = 0xD0 | (eventStorage.midi[0] & 0xf); + midiEvent.data[1] = eventStorage.midi[1]; + midiEvent.data[2] = 0; + break; + case CC_Pitchbend: + midiEvent.size = 3; + midiEvent.data[0] = 0xE0 | (eventStorage.midi[0] & 0xf); + midiEvent.data[1] = eventStorage.midi[1]; + midiEvent.data[2] = eventStorage.midi[2]; + break; + case UI_MIDI: + midiEvent.size = 3; + midiEvent.data[0] = eventStorage.midi[0]; + midiEvent.data[1] = eventStorage.midi[1]; + midiEvent.data[2] = eventStorage.midi[2]; + break; + default: + midiEvent.size = 0; + break; + } + } + + return count; + } + + bool appendEvent(const v3_event& event) noexcept + { + // only save events that can be converted directly into MIDI + switch (event.type) + { + case V3_EVENT_NOTE_ON: + case V3_EVENT_NOTE_OFF: + // case V3_EVENT_DATA: + case V3_EVENT_POLY_PRESSURE: + break; + default: + return false; + } + + InputEventStorage& eventStorage(eventListStorage[numUsed]); + + switch (event.type) + { + case V3_EVENT_NOTE_ON: + eventStorage.type = NoteOn; + eventStorage.noteOn = event.note_on; + break; + case V3_EVENT_NOTE_OFF: + eventStorage.type = NoteOff; + eventStorage.noteOff = event.note_off; + break; + case V3_EVENT_DATA: + eventStorage.type = SysexData; + eventStorage.sysexData = event.data; + break; + case V3_EVENT_POLY_PRESSURE: + eventStorage.type = PolyPressure; + eventStorage.polyPressure = event.poly_pressure; + break; + default: + return false; + } + + eventList[numUsed].sampleOffset = event.sample_offset; + eventList[numUsed].storage = &eventStorage; + + return placeSorted(event.sample_offset); + } + + bool appendCC(const int32_t sampleOffset, v3_param_id paramId, const double value) noexcept + { + InputEventStorage& eventStorage(eventListStorage[numUsed]); + + paramId -= kVst3InternalParameterMidiCC_start; + + const uint8_t cc = paramId % 130; + + switch (cc) + { + case 128: + eventStorage.type = CC_ChannelPressure; + eventStorage.midi[1] = std::max(0, std::min(127, (int)(value * 127))); + eventStorage.midi[2] = 0; + break; + case 129: + eventStorage.type = CC_Pitchbend; + eventStorage.midi[1] = std::max(0, std::min(16384, (int)(value * 16384))) & 0x7f; + eventStorage.midi[2] = std::max(0, std::min(16384, (int)(value * 16384))) >> 7; + break; + default: + eventStorage.type = CC_Normal; + eventStorage.midi[1] = cc; + eventStorage.midi[2] = std::max(0, std::min(127, (int)(value * 127))); + break; + } + + eventStorage.midi[0] = paramId / 130; + + eventList[numUsed].sampleOffset = sampleOffset; + eventList[numUsed].storage = &eventStorage; + + return placeSorted(sampleOffset); + } + + #if DISTRHO_PLUGIN_HAS_UI + // NOTE always runs first + bool appendFromUI(const uint8_t midiData[3]) + { + InputEventStorage& eventStorage(eventListStorage[numUsed]); + + eventStorage.type = UI_MIDI; + std::memcpy(eventStorage.midi, midiData, sizeof(uint8_t)*3); + + InputEventTiming* const event = &eventList[numUsed]; + + event->sampleOffset = 0; + event->storage = &eventStorage; + event->next = nullptr; + + if (numUsed == 0) + { + firstEvent = lastEvent = event; + } + else + { + lastEvent->next = event; + lastEvent = event; + } + + return ++numUsed == kMaxMidiEvents; + } + #endif + + private: + bool placeSorted(const int32_t sampleOffset) noexcept + { + InputEventTiming* const event = &eventList[numUsed]; + + // initialize + if (numUsed == 0) + { + firstSampleOffset = lastSampleOffset = sampleOffset; + firstEvent = lastEvent = event; + event->next = nullptr; + } + // push to the back + else if (sampleOffset >= lastSampleOffset) + { + lastSampleOffset = sampleOffset; + lastEvent->next = event; + lastEvent = event; + event->next = nullptr; + } + // push to the front + else if (sampleOffset < firstSampleOffset) + { + firstSampleOffset = sampleOffset; + event->next = firstEvent; + firstEvent = event; + } + // find place in between events + else + { + // keep reference out of the loop so we can check validity afterwards + InputEventTiming* event2 = firstEvent; + + // iterate all events + for (; event2 != nullptr; event2 = event2->next) + { + // if offset is higher than iterated event, stop and insert in-between + if (sampleOffset > event2->sampleOffset) + break; + + // if offset matches, find the last event with the same offset so we can push after it + if (sampleOffset == event2->sampleOffset) + { + event2 = event2->next; + for (; event2 != nullptr && sampleOffset == event2->sampleOffset; event2 = event2->next) {} + break; + } + } + + DISTRHO_SAFE_ASSERT_RETURN(event2 != nullptr, true); + + event->next = event2->next; + event2->next = event; + } + + return ++numUsed == kMaxMidiEvents; + } + } inputEventList; + #endif // DISTRHO_PLUGIN_WANT_MIDI_INPUT + public: PluginVst3(v3_host_application** const host) - : fPlugin(this, writeMidiCallback, requestParameterValueChangeCallback), + : fPlugin(this, writeMidiCallback, requestParameterValueChangeCallback, nullptr), fComponentHandler(nullptr), #if DISTRHO_PLUGIN_HAS_UI # if DPF_VST3_USES_SEPARATE_CONTROLLER @@ -263,6 +583,7 @@ public: fParameterCount(fPlugin.getParameterCount()), fVst3ParameterCount(fParameterCount + kVst3InternalParameterCount), fCachedParameterValues(nullptr), + fDummyAudioBuffer(nullptr), fParameterValuesChangedDuringProcessing(nullptr) #if DISTRHO_PLUGIN_HAS_UI , fParameterValueChangesForUI(nullptr) @@ -371,18 +692,18 @@ public: #endif } -#if DISTRHO_PLUGIN_WANT_STATE + #if DISTRHO_PLUGIN_WANT_STATE for (uint32_t i=0, count=fPlugin.getStateCount(); i 0 int32_t numChannels; - v3_bus_flags flags; + uint32_t flags; v3_bus_types busType; v3_str_128 busName = {}; @@ -515,7 +842,7 @@ public: { numChannels = inputBuses.numSidechain; busType = V3_AUX; - flags = static_cast(0); + flags = 0; break; } // fall-through @@ -568,7 +895,7 @@ public: { numChannels = outputBuses.numSidechain; busType = V3_AUX; - flags = static_cast(0); + flags = 0; break; } // fall-through @@ -692,22 +1019,22 @@ public: buffer[sizeof(buffer)-1] = '\xff'; v3_result res; - for (int32_t pos = 0, term = 0, read; term == 0; pos += read) + for (int32_t terminated = 0, read; terminated == 0;) { + read = -1; res = v3_cpp_obj(stream)->read(stream, buffer, sizeof(buffer)-1, &read); DISTRHO_SAFE_ASSERT_INT_RETURN(res == V3_OK, res, res); + DISTRHO_SAFE_ASSERT_INT_RETURN(read > 0, read, V3_INTERNAL_ERR); if (read == 0) return V3_OK; - DISTRHO_SAFE_ASSERT_INT_RETURN(read > 0, read, V3_INTERNAL_ERR); - for (int32_t i = 0; i < read; ++i) { // found terminator, stop here if (buffer[i] == '\xfe') { - term = 1; + terminated = 1; break; } @@ -791,38 +1118,38 @@ public: d_stdout("found program '%s'", value.buffer()); -#if DISTRHO_PLUGIN_WANT_PROGRAMS + #if DISTRHO_PLUGIN_WANT_PROGRAMS const int program = std::atoi(value.buffer()); DISTRHO_SAFE_ASSERT_CONTINUE(program >= 0); fCurrentProgram = static_cast(program); fPlugin.loadProgram(fCurrentProgram); -# if DISTRHO_PLUGIN_HAS_UI + #if DISTRHO_PLUGIN_HAS_UI if (connectedToUI) { fParameterValueChangesForUI[kVst3InternalParameterProgram] = false; sendParameterSetToUI(kVst3InternalParameterProgram, program); } -# endif -#endif + #endif + #endif } else if (queryingType == 's') { d_stdout("found state '%s' '%s'", key.buffer(), value.buffer()); -#if DISTRHO_PLUGIN_WANT_STATE + #if DISTRHO_PLUGIN_WANT_STATE if (fPlugin.wantStateKey(key)) { fStateMap[key] = value; fPlugin.setState(key, value); -# if DISTRHO_PLUGIN_HAS_UI + #if DISTRHO_PLUGIN_HAS_UI if (connectedToUI) sendStateSetToUI(key, value); -# endif + #endif } -#endif + #endif } else if (queryingType == 'p') { @@ -843,13 +1170,13 @@ public: fvalue = std::atof(value.buffer()); fCachedParameterValues[kVst3InternalParameterBaseCount + j] = fvalue; -#if DISTRHO_PLUGIN_HAS_UI + #if DISTRHO_PLUGIN_HAS_UI if (connectedToUI) { // UI parameter updates are handled outside the read loop (after host param restart) fParameterValueChangesForUI[kVst3InternalParameterBaseCount + j] = true; } -#endif + #endif fPlugin.setParameterValue(j, fvalue); break; } @@ -865,7 +1192,7 @@ public: if (fComponentHandler != nullptr) v3_cpp_obj(fComponentHandler)->restart_component(fComponentHandler, V3_RESTART_PARAM_VALUES_CHANGED); -#if DISTRHO_PLUGIN_HAS_UI + #if DISTRHO_PLUGIN_HAS_UI if (connectedToUI) { for (uint32_t i=0; iwrite(stream, &buffer, 1, &ignored); } -#if DISTRHO_PLUGIN_WANT_FULL_STATE + #if DISTRHO_PLUGIN_WANT_FULL_STATE // Update current state for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit) { const String& key = cit->first; - fStateMap[key] = fPlugin.getState(key); + fStateMap[key] = fPlugin.getStateValue(key); } -#endif + #endif String state; -#if DISTRHO_PLUGIN_WANT_PROGRAMS + #if DISTRHO_PLUGIN_WANT_PROGRAMS { String tmpStr("__dpf_program__\xff"); tmpStr += String(fCurrentProgram); @@ -917,9 +1244,9 @@ public: state += tmpStr; } -#endif + #endif -#if DISTRHO_PLUGIN_WANT_STATE + #if DISTRHO_PLUGIN_WANT_STATE if (stateCount != 0) { state += "__dpf_state_begin__\xff"; @@ -941,7 +1268,7 @@ public: state += "__dpf_state_end__\xff"; } -#endif + #endif if (paramCount != 0) { @@ -1000,26 +1327,125 @@ public: return V3_NOT_IMPLEMENTED; } - v3_result getBusArrangement(const int32_t direction, const int32_t /*idx*/, v3_speaker_arrangement*) + v3_result getBusArrangement(const int32_t busDirection, const int32_t busId, v3_speaker_arrangement* const speaker) const noexcept { - switch (direction) + DISTRHO_SAFE_ASSERT_INT_RETURN(busDirection == V3_INPUT || busDirection == V3_OUTPUT, busDirection, V3_INVALID_ARG); + DISTRHO_SAFE_ASSERT_INT_RETURN(busId >= 0, busId, V3_INVALID_ARG); + DISTRHO_SAFE_ASSERT_RETURN(speaker != nullptr, V3_INVALID_ARG); + + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 || DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + const uint32_t ubusId = static_cast(busId); + #endif + + if (busDirection == V3_INPUT) { - case V3_INPUT: - case V3_OUTPUT: - // TODO - return V3_NOT_IMPLEMENTED; + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 + for (uint32_t i=0; i 0 + for (uint32_t i=0; imax_block_size]; return V3_OK; } @@ -1080,8 +1507,7 @@ public: #if DISTRHO_PLUGIN_WANT_TIMEPOS if (v3_process_context* const ctx = data->ctx) { - fTimePosition.playing = ctx->state & V3_PROCESS_CTX_PLAYING; - fTimePosition.bbt.valid = ctx->state & (V3_PROCESS_CTX_TEMPO_VALID|V3_PROCESS_CTX_TIME_SIG_VALID); + fTimePosition.playing = ctx->state & V3_PROCESS_CTX_PLAYING; // ticksPerBeat is not possible with VST3 fTimePosition.bbt.ticksPerBeat = 1920.0; @@ -1103,6 +1529,7 @@ public: const double barBeats = (std::fmod(ppqPos, ppqPerBar) / ppqPerBar) * ctx->time_sig_numerator; const double rest = std::fmod(barBeats, 1.0); + fTimePosition.bbt.valid = true; fTimePosition.bbt.bar = static_cast(ppqPos) / ppqPerBar + 1; fTimePosition.bbt.beat = static_cast(barBeats - rest + 0.5) + 1; fTimePosition.bbt.tick = rest * fTimePosition.bbt.ticksPerBeat; @@ -1118,6 +1545,7 @@ public: } else { + fTimePosition.bbt.valid = false; fTimePosition.bbt.bar = 1; fTimePosition.bbt.beat = 1; fTimePosition.bbt.tick = 0.0; @@ -1142,6 +1570,8 @@ public: const float* inputs[DISTRHO_PLUGIN_NUM_INPUTS != 0 ? DISTRHO_PLUGIN_NUM_INPUTS : 1]; /* */ float* outputs[DISTRHO_PLUGIN_NUM_OUTPUTS != 0 ? DISTRHO_PLUGIN_NUM_OUTPUTS : 1]; + std::memset(fDummyAudioBuffer, 0, sizeof(float)*data->nframes); + { int32_t i = 0; if (data->inputs != nullptr) @@ -1153,7 +1583,7 @@ public: } } for (; i < std::max(1, DISTRHO_PLUGIN_NUM_INPUTS); ++i) - inputs[i] = nullptr; // TODO use dummy buffer + inputs[i] = fDummyAudioBuffer; } { @@ -1167,138 +1597,52 @@ public: } } for (; i < std::max(1, DISTRHO_PLUGIN_NUM_OUTPUTS); ++i) - outputs[i] = nullptr; // TODO use dummy buffer + outputs[i] = fDummyAudioBuffer; } -#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT fHostEventOutputHandle = data->output_events; -#endif + #endif -#if DISTRHO_PLUGIN_WANT_MIDI_INPUT - uint32_t midiEventCount = 0; + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT + bool canAppendMoreEvents = true; + inputEventList.init(); -# if DISTRHO_PLUGIN_HAS_UI + #if DISTRHO_PLUGIN_HAS_UI while (fNotesRingBuffer.isDataAvailableForReading()) { uint8_t midiData[3]; if (! fNotesRingBuffer.readCustomData(midiData, 3)) break; - MidiEvent& midiEvent(fMidiEvents[midiEventCount++]); - midiEvent.frame = 0; - midiEvent.size = 3; - std::memcpy(midiEvent.data, midiData, 3); - - if (midiEventCount == kMaxMidiEvents) + if (inputEventList.appendFromUI(midiData)) + { + canAppendMoreEvents = false; break; + } } -# endif + #endif - if (v3_event_list** const eventptr = data->input_events) + if (canAppendMoreEvents) { - v3_event event; - for (uint32_t i = 0, count = v3_cpp_obj(eventptr)->get_event_count(eventptr); i < count; ++i) + if (v3_event_list** const eventptr = data->input_events) { - if (v3_cpp_obj(eventptr)->get_event(eventptr, i, &event) != V3_OK) - break; - - // check if event can be encoded as MIDI - switch (event.type) + v3_event event; + for (uint32_t i = 0, count = v3_cpp_obj(eventptr)->get_event_count(eventptr); i < count; ++i) { - case V3_EVENT_NOTE_ON: - case V3_EVENT_NOTE_OFF: - // case V3_EVENT_DATA: - case V3_EVENT_POLY_PRESSURE: - break; - // case V3_EVENT_NOTE_EXP_VALUE: - // case V3_EVENT_NOTE_EXP_TEXT: - // case V3_EVENT_CHORD: - // case V3_EVENT_SCALE: - // case V3_EVENT_LEGACY_MIDI_CC_OUT: - default: - continue; - } - - MidiEvent& midiEvent(fMidiEvents[midiEventCount++]); - midiEvent.frame = event.sample_offset; + if (v3_cpp_obj(eventptr)->get_event(eventptr, i, &event) != V3_OK) + break; - // encode event as MIDI - switch (event.type) - { - case V3_EVENT_NOTE_ON: - midiEvent.size = 3; - midiEvent.data[0] = 0x90 | (event.note_on.channel & 0xf); - midiEvent.data[1] = event.note_on.pitch; - midiEvent.data[2] = std::max(0, std::min(127, (int)(event.note_on.velocity * 127))); - midiEvent.data[3] = 0; - break; - case V3_EVENT_NOTE_OFF: - midiEvent.size = 3; - midiEvent.data[0] = 0x80 | (event.note_off.channel & 0xf); - midiEvent.data[1] = event.note_off.pitch; - midiEvent.data[2] = std::max(0, std::min(127, (int)(event.note_off.velocity * 127))); - midiEvent.data[3] = 0; - break; - case V3_EVENT_POLY_PRESSURE: - midiEvent.size = 3; - midiEvent.data[0] = 0xA0 | (event.poly_pressure.channel & 0xf); - midiEvent.data[1] = event.poly_pressure.pitch; - midiEvent.data[2] = std::max(0, std::min(127, (int)(event.poly_pressure.pressure * 127))); - midiEvent.data[3] = 0; - break; - default: - midiEvent.size = 0; - break; + if (inputEventList.appendEvent(event)) + { + canAppendMoreEvents = false; + break; + } } - - if (midiEventCount == kMaxMidiEvents) - break; } } + #endif - // TODO append parameter MIDI events in a sorted way - /* -#if DISTRHO_PLUGIN_WANT_PROGRAMS - if (rindex == 0) - continue; - --rindex; -#endif -#if DISTRHO_PLUGIN_WANT_MIDI_INPUT - MidiEvent& midiEvent(fMidiEvents[midiEventCount++]); - midiEvent.frame = offset; - midiEvent.size = 3; - midiEvent.data[0] = (rindex / 130) & 0xf; - - switch (rindex) - { - case 128: // channel pressure - midiEvent.data[0] |= 0xD0; - midiEvent.data[1] = std::max(0, std::min(127, (int)(value * 127))); - midiEvent.data[2] = 0; - midiEvent.data[3] = 0; - break; - case 129: // pitchbend - midiEvent.data[0] |= 0xE0; - midiEvent.data[1] = std::max(0, std::min(16384, (int)(value * 16384))) & 0x7f; - midiEvent.data[2] = std::max(0, std::min(16384, (int)(value * 16384))) >> 7; - midiEvent.data[3] = 0; - break; - default: - midiEvent.data[0] |= 0xB0; - midiEvent.data[1] = rindex % 130; - midiEvent.data[2] = std::max(0, std::min(127, (int)(value * 127))); - midiEvent.data[3] = 0; - break; - } - - if (midiEventCount == kMaxMidiEvents) - break; - } -#endif - */ -#endif - - // if there are any parameter changes at frame 0, set them here if (v3_param_changes** const inparamsptr = data->input_params) { int32_t offset; @@ -1314,12 +1658,32 @@ public: #if DPF_VST3_HAS_INTERNAL_PARAMETERS if (rindex < kVst3InternalParameterCount) + { + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT + // if there are any MIDI CC events as parameter changes, handle them here + if (canAppendMoreEvents && rindex >= kVst3InternalParameterMidiCC_start && rindex <= kVst3InternalParameterMidiCC_end) + { + for (int32_t j = 0, pcount = v3_cpp_obj(queue)->get_point_count(queue); j < pcount; ++j) + { + if (v3_cpp_obj(queue)->get_point(queue, j, &offset, &value) != V3_OK) + break; + + if (inputEventList.appendCC(offset, rindex, value)) + { + canAppendMoreEvents = false; + break; + } + } + } + #endif continue; + } #endif if (v3_cpp_obj(queue)->get_point_count(queue) <= 0) continue; + // if there are any parameter changes at frame 0, handle them here if (v3_cpp_obj(queue)->get_point(queue, 0, &offset, &value) != V3_OK) break; @@ -1332,6 +1696,7 @@ public: } #if DISTRHO_PLUGIN_WANT_MIDI_INPUT + const uint32_t midiEventCount = inputEventList.convert(fMidiEvents); fPlugin.run(inputs, outputs, data->nframes, fMidiEvents, midiEventCount); #else fPlugin.run(inputs, outputs, data->nframes); @@ -1443,9 +1808,9 @@ public: info->flags = V3_PARAM_CAN_AUTOMATE | V3_PARAM_IS_HIDDEN; info->step_count = 127; char ccstr[24]; - snprintf(ccstr, sizeof(ccstr)-1, "MIDI Ch. %d CC %d", static_cast(index / 130) + 1, index % 130); + snprintf(ccstr, sizeof(ccstr), "MIDI Ch. %d CC %d", static_cast(index / 130) + 1, index % 130); strncpy_utf16(info->title, ccstr, 128); - snprintf(ccstr, sizeof(ccstr)-1, "Ch.%d CC%d", index / 130 + 1, index % 130); + snprintf(ccstr, sizeof(ccstr), "Ch.%d CC%d", index / 130 + 1, index % 130); strncpy_utf16(info->short_title, ccstr+5, 128); return V3_OK; } @@ -1544,7 +1909,7 @@ public: if (hints & kParameterIsBoolean) { - const float midRange = ranges.min + (ranges.max - ranges.min) / 2.0f; + const float midRange = ranges.min + (ranges.max - ranges.min) * 0.5f; value = value > midRange ? ranges.max : ranges.min; } else if (hints & kParameterIsInteger) @@ -1914,7 +2279,7 @@ public: for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit) { const String& key = cit->first; - fStateMap[key] = fPlugin.getState(key); + fStateMap[key] = fPlugin.getStateValue(key); } #endif @@ -2046,11 +2411,17 @@ public: #if DISTRHO_PLUGIN_WANT_STATE if (std::strcmp(msgid, "state-set") == 0) { + const v3_result res = notify_state(attrs); + #if DPF_VST3_USES_SEPARATE_CONTROLLER + if (res != V3_OK) + return res; + + // notify component of the change DISTRHO_SAFE_ASSERT_RETURN(fConnectionFromCompToCtrl != nullptr, V3_INTERNAL_ERR); return v3_cpp_obj(fConnectionFromCompToCtrl)->notify(fConnectionFromCompToCtrl, message); #else - return notify_state(attrs); + return res; #endif } #endif @@ -2081,12 +2452,12 @@ public: int16_t* const value16 = (int16_t*)std::malloc(sizeof(int16_t)*(valueLength + 1)); DISTRHO_SAFE_ASSERT_RETURN(value16 != nullptr, V3_NOMEM); - res = v3_cpp_obj(attrs)->get_string(attrs, "key", key16, sizeof(int16_t)*keyLength); + res = v3_cpp_obj(attrs)->get_string(attrs, "key", key16, sizeof(int16_t)*(keyLength+1)); DISTRHO_SAFE_ASSERT_INT2_RETURN(res == V3_OK, res, keyLength, res); if (valueLength != 0) { - res = v3_cpp_obj(attrs)->get_string(attrs, "value", value16, sizeof(int16_t)*valueLength); + res = v3_cpp_obj(attrs)->get_string(attrs, "value", value16, sizeof(int16_t)*(valueLength+1)); DISTRHO_SAFE_ASSERT_INT2_RETURN(res == V3_OK, res, valueLength, res); } @@ -2167,6 +2538,7 @@ private: const uint32_t fParameterCount; const uint32_t fVst3ParameterCount; // full offset + real float* fCachedParameterValues; // basic offset + real + float* fDummyAudioBuffer; bool* fParameterValuesChangedDuringProcessing; // basic offset + real #if DISTRHO_PLUGIN_HAS_UI bool* fParameterValueChangesForUI; // basic offset + real @@ -2248,9 +2620,9 @@ private: } fCachedParameterValues[kVst3InternalParameterBaseCount + i] = curValue; -#if DISTRHO_PLUGIN_HAS_UI + #if DISTRHO_PLUGIN_HAS_UI fParameterValueChangesForUI[kVst3InternalParameterBaseCount + i] = true; -#endif + #endif paramId = kVst3InternalParameterCount + i; curValue = fPlugin.getParameterRanges(i).getNormalizedValue(curValue); @@ -2259,7 +2631,7 @@ private: break; } -#if DISTRHO_PLUGIN_WANT_LATENCY + #if DISTRHO_PLUGIN_WANT_LATENCY const uint32_t latency = fPlugin.getLatency(); if (fLastKnownLatency != latency) @@ -2270,7 +2642,7 @@ private: fCachedParameterValues[kVst3InternalParameterLatency]); addParameterDataToHostOutputEvents(outparamsptr, kVst3InternalParameterLatency, curValue); } -#endif + #endif } bool addParameterDataToHostOutputEvents(v3_param_changes** const outparamsptr, @@ -2610,7 +2982,7 @@ struct dpf_comp2ctrl_connection_point : v3_connection_point_cpp { #if DISTRHO_PLUGIN_HAS_UI // -------------------------------------------------------------------------------------------------------------------- -// dpf_comp2ctrl_connection_point +// dpf_ctrl2view_connection_point struct dpf_ctrl2view_connection_point : v3_connection_point_cpp { ScopedPointer& vst3; @@ -2769,6 +3141,7 @@ struct dpf_edit_controller : v3_edit_controller_cpp { v3_host_application** const hostApplicationFromFactory; #if !DPF_VST3_USES_SEPARATE_CONTROLLER v3_host_application** const hostApplicationFromComponent; + v3_host_application** hostApplicationFromComponentInitialize; #endif v3_host_application** hostApplicationFromInitialize; @@ -2786,6 +3159,7 @@ struct dpf_edit_controller : v3_edit_controller_cpp { hostApplicationFromFactory(hostApp), #if !DPF_VST3_USES_SEPARATE_CONTROLLER hostApplicationFromComponent(hostComp), + hostApplicationFromComponentInitialize(nullptr), #endif hostApplicationFromInitialize(nullptr) { @@ -2860,20 +3234,24 @@ struct dpf_edit_controller : v3_edit_controller_cpp { return V3_OK; } -#if DISTRHO_PLUGIN_WANT_MIDI_INPUT if (v3_tuid_match(iid, v3_midi_mapping_iid)) { +#if DISTRHO_PLUGIN_WANT_MIDI_INPUT d_stdout("query_interface_edit_controller => %p %s %p | OK convert static", self, tuid2str(iid), iface); static dpf_midi_mapping midi_mapping; static dpf_midi_mapping* midi_mapping_ptr = &midi_mapping; *iface = &midi_mapping_ptr; return V3_OK; - } +#else + d_stdout("query_interface_edit_controller => %p %s %p | reject unused", self, tuid2str(iid), iface); + *iface = nullptr; + return V3_NO_INTERFACE; #endif + } -#if DPF_VST3_USES_SEPARATE_CONTROLLER if (v3_tuid_match(iid, v3_connection_point_iid)) { +#if DPF_VST3_USES_SEPARATE_CONTROLLER d_stdout("query_interface_edit_controller => %p %s %p | OK convert %p", self, tuid2str(iid), iface, controller->connectionComp2Ctrl.get()); @@ -2883,11 +3261,14 @@ struct dpf_edit_controller : v3_edit_controller_cpp { ++controller->connectionComp2Ctrl->refcounter; *iface = &controller->connectionComp2Ctrl; return V3_OK; - } +#else + d_stdout("query_interface_edit_controller => %p %s %p | reject unwanted", self, tuid2str(iid), iface); + *iface = nullptr; + return V3_NO_INTERFACE; #endif + } d_stdout("query_interface_edit_controller => %p %s %p | WARNING UNSUPPORTED", self, tuid2str(iid), iface); - *iface = nullptr; return V3_NO_INTERFACE; } @@ -2945,7 +3326,7 @@ struct dpf_edit_controller : v3_edit_controller_cpp { // ---------------------------------------------------------------------------------------------------------------- // v3_plugin_base - static v3_result V3_API initialize(void* const self, v3_plugin_base::v3_funknown** const context) + static v3_result V3_API initialize(void* const self, v3_funknown** const context) { dpf_edit_controller* const controller = *static_cast(self); @@ -3116,7 +3497,7 @@ struct dpf_edit_controller : v3_edit_controller_cpp { static v3_result V3_API get_parameter_value_for_string(void* self, v3_param_id index, int16_t* input, double* output) { - d_stdout("dpf_edit_controller::get_parameter_value_for_string => %p %u %p %p", self, index, input, output); + d_debug("dpf_edit_controller::get_parameter_value_for_string => %p %u %p %p", self, index, input, output); dpf_edit_controller* const controller = *static_cast(self); PluginVst3* const vst3 = controller->vst3; @@ -3127,7 +3508,7 @@ struct dpf_edit_controller : v3_edit_controller_cpp { static double V3_API normalised_parameter_to_plain(void* self, v3_param_id index, double normalised) { - d_stdout("dpf_edit_controller::normalised_parameter_to_plain => %p %u %f", self, index, normalised); + d_debug("dpf_edit_controller::normalised_parameter_to_plain => %p %u %f", self, index, normalised); dpf_edit_controller* const controller = *static_cast(self); PluginVst3* const vst3 = controller->vst3; @@ -3138,7 +3519,7 @@ struct dpf_edit_controller : v3_edit_controller_cpp { static double V3_API plain_parameter_to_normalised(void* self, v3_param_id index, double plain) { - d_stdout("dpf_edit_controller::plain_parameter_to_normalised => %p %u %f", self, index, plain); + d_debug("dpf_edit_controller::plain_parameter_to_normalised => %p %u %f", self, index, plain); dpf_edit_controller* const controller = *static_cast(self); PluginVst3* const vst3 = controller->vst3; @@ -3205,6 +3586,8 @@ struct dpf_edit_controller : v3_edit_controller_cpp { #if !DPF_VST3_USES_SEPARATE_CONTROLLER : controller->hostApplicationFromComponent != nullptr ? controller->hostApplicationFromComponent + : controller->hostApplicationFromComponentInitialize != nullptr + ? controller->hostApplicationFromComponentInitialize #endif : controller->hostApplicationFromFactory; DISTRHO_SAFE_ASSERT_RETURN(host != nullptr, nullptr); @@ -3370,7 +3753,7 @@ struct dpf_audio_processor : v3_audio_processor_cpp { static v3_result V3_API get_bus_arrangement(void* const self, const int32_t bus_direction, const int32_t idx, v3_speaker_arrangement* const arr) { - d_stdout("dpf_audio_processor::get_bus_arrangement => %p %s %p", + d_stdout("dpf_audio_processor::get_bus_arrangement => %p %s %i %p", self, v3_bus_direction_str(bus_direction), idx, arr); dpf_audio_processor* const processor = *static_cast(self); @@ -3406,6 +3789,8 @@ struct dpf_audio_processor : v3_audio_processor_cpp { PluginVst3* const vst3 = processor->vst3; DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALIZED); + d_stdout("dpf_audio_processor::setup_processing => %p %p | %d %f", self, setup, setup->max_block_size, setup->sample_rate); + d_nextBufferSize = setup->max_block_size; d_nextSampleRate = setup->sample_rate; return processor->vst3->setupProcessing(setup); @@ -3525,16 +3910,20 @@ struct dpf_component : v3_component_cpp { return V3_OK; } -#if DISTRHO_PLUGIN_WANT_MIDI_INPUT if (v3_tuid_match(iid, v3_midi_mapping_iid)) { +#if DISTRHO_PLUGIN_WANT_MIDI_INPUT d_stdout("query_interface_component => %p %s %p | OK convert static", self, tuid2str(iid), iface); static dpf_midi_mapping midi_mapping; static dpf_midi_mapping* midi_mapping_ptr = &midi_mapping; *iface = &midi_mapping_ptr; return V3_OK; - } +#else + d_stdout("query_interface_component => %p %s %p | reject unused", self, tuid2str(iid), iface); + *iface = nullptr; + return V3_NO_INTERFACE; #endif + } if (v3_tuid_match(iid, v3_audio_processor_iid)) { @@ -3549,9 +3938,9 @@ struct dpf_component : v3_component_cpp { return V3_OK; } -#if DPF_VST3_USES_SEPARATE_CONTROLLER if (v3_tuid_match(iid, v3_connection_point_iid)) { +#if DPF_VST3_USES_SEPARATE_CONTROLLER d_stdout("query_interface_component => %p %s %p | OK convert %p", self, tuid2str(iid), iface, component->connectionComp2Ctrl.get()); @@ -3561,10 +3950,16 @@ struct dpf_component : v3_component_cpp { ++component->connectionComp2Ctrl->refcounter; *iface = &component->connectionComp2Ctrl; return V3_OK; - } #else + d_stdout("query_interface_component => %p %s %p | reject unwanted", self, tuid2str(iid), iface); + *iface = nullptr; + return V3_NO_INTERFACE; +#endif + } + if (v3_tuid_match(iid, v3_edit_controller_iid)) { +#if !DPF_VST3_USES_SEPARATE_CONTROLLER d_stdout("query_interface_component => %p %s %p | OK convert %p", self, tuid2str(iid), iface, component->controller.get()); @@ -3576,11 +3971,14 @@ struct dpf_component : v3_component_cpp { ++component->controller->refcounter; *iface = &component->controller; return V3_OK; - } +#else + d_stdout("query_interface_component => %p %s %p | reject unwanted", self, tuid2str(iid), iface); + *iface = nullptr; + return V3_NO_INTERFACE; #endif + } d_stdout("query_interface_component => %p %s %p | WARNING UNSUPPORTED", self, tuid2str(iid), iface); - *iface = nullptr; return V3_NO_INTERFACE; } @@ -3654,7 +4052,7 @@ struct dpf_component : v3_component_cpp { // ---------------------------------------------------------------------------------------------------------------- // v3_plugin_base - static v3_result V3_API initialize(void* const self, v3_plugin_base::v3_funknown** const context) + static v3_result V3_API initialize(void* const self, v3_funknown** const context) { dpf_component* const component = *static_cast(self); @@ -3671,6 +4069,12 @@ struct dpf_component : v3_component_cpp { // save it for later so we can unref it component->hostApplicationFromInitialize = hostApplication; + #if !DPF_VST3_USES_SEPARATE_CONTROLLER + // save it in edit controller too, needed for some hosts + if (component->controller != nullptr) + component->controller->hostApplicationFromComponentInitialize = hostApplication; + #endif + // provide the factory application to the plugin if this new one is missing if (hostApplication == nullptr) hostApplication = component->hostApplicationFromFactory; @@ -3709,6 +4113,12 @@ struct dpf_component : v3_component_cpp { // delete actual plugin component->vst3 = nullptr; + #if !DPF_VST3_USES_SEPARATE_CONTROLLER + // remove previous host application saved during initialize + if (component->controller != nullptr) + component->controller->hostApplicationFromComponentInitialize = nullptr; + #endif + // unref host application received during initialize if (component->hostApplicationFromInitialize != nullptr) { @@ -3839,7 +4249,7 @@ static const PluginExporter& _getPluginInfo() d_nextSampleRate = 44100.0; d_nextPluginIsDummy = true; d_nextCanRequestParameterValueChanges = true; - static const PluginExporter gPluginInfo(nullptr, nullptr, nullptr); + static const PluginExporter gPluginInfo(nullptr, nullptr, nullptr, nullptr); d_nextBufferSize = 0; d_nextSampleRate = 0.0; d_nextPluginIsDummy = false; @@ -3890,10 +4300,10 @@ static const char* getPluginVersion() const uint32_t versionNum = getPluginInfo().getVersion(); char versionBuf[64]; - snprintf(versionBuf, sizeof(versionBuf)-1, "%d.%d.%d", - (versionNum >> 16) & 0xff, - (versionNum >> 8) & 0xff, - (versionNum >> 0) & 0xff); + std::snprintf(versionBuf, sizeof(versionBuf)-1, "%d.%d.%d", + (versionNum >> 16) & 0xff, + (versionNum >> 8) & 0xff, + (versionNum >> 0) & 0xff); versionBuf[sizeof(versionBuf)-1] = '\0'; version = versionBuf; } @@ -4069,7 +4479,8 @@ struct dpf_factory : v3_plugin_factory_cpp { v3_cpp_obj_query_interface(factory->hostContext, v3_host_application_iid, &hostApplication); // create component - if (v3_tuid_match(class_id, *(const v3_tuid*)&dpf_tuid_class) && v3_tuid_match(iid, v3_component_iid)) + if (v3_tuid_match(class_id, *(const v3_tuid*)&dpf_tuid_class) && (v3_tuid_match(iid, v3_component_iid) || + v3_tuid_match(iid, v3_funknown_iid))) { dpf_component** const componentptr = new dpf_component*; *componentptr = new dpf_component(hostApplication); @@ -4079,7 +4490,8 @@ struct dpf_factory : v3_plugin_factory_cpp { #if DPF_VST3_USES_SEPARATE_CONTROLLER // create edit controller - if (v3_tuid_match(class_id, *(const v3_tuid*)&dpf_tuid_controller) && v3_tuid_match(iid, v3_edit_controller_iid)) + if (v3_tuid_match(class_id, *(const v3_tuid*)&dpf_tuid_controller) && (v3_tuid_match(iid, v3_edit_controller_iid) || + v3_tuid_match(iid, v3_funknown_iid))) { dpf_edit_controller** const controllerptr = new dpf_edit_controller*; *controllerptr = new dpf_edit_controller(hostApplication); @@ -4114,7 +4526,7 @@ struct dpf_factory : v3_plugin_factory_cpp { DISTRHO_NAMESPACE::strncpy(info->name, getPluginInfo().getName(), ARRAY_SIZE(info->name)); DISTRHO_NAMESPACE::strncpy(info->vendor, getPluginInfo().getMaker(), ARRAY_SIZE(info->vendor)); DISTRHO_NAMESPACE::strncpy(info->version, getPluginVersion(), ARRAY_SIZE(info->version)); - DISTRHO_NAMESPACE::strncpy(info->sdk_version, "Travesty", ARRAY_SIZE(info->sdk_version)); + DISTRHO_NAMESPACE::strncpy(info->sdk_version, "Travesty 3.7.4", ARRAY_SIZE(info->sdk_version)); return V3_OK; } @@ -4137,7 +4549,7 @@ struct dpf_factory : v3_plugin_factory_cpp { DISTRHO_NAMESPACE::strncpy_utf16(info->name, getPluginInfo().getName(), ARRAY_SIZE(info->name)); DISTRHO_NAMESPACE::strncpy_utf16(info->vendor, getPluginInfo().getMaker(), ARRAY_SIZE(info->vendor)); DISTRHO_NAMESPACE::strncpy_utf16(info->version, getPluginVersion(), ARRAY_SIZE(info->version)); - DISTRHO_NAMESPACE::strncpy_utf16(info->sdk_version, "Travesty", ARRAY_SIZE(info->sdk_version)); + DISTRHO_NAMESPACE::strncpy_utf16(info->sdk_version, "Travesty 3.7.4", ARRAY_SIZE(info->sdk_version)); return V3_OK; } @@ -4182,19 +4594,22 @@ const void* GetPluginFactory(void) #if defined(DISTRHO_OS_MAC) # define ENTRYFNNAME bundleEntry +# define ENTRYFNNAMEARGS void* # define EXITFNNAME bundleExit #elif defined(DISTRHO_OS_WINDOWS) # define ENTRYFNNAME InitDll +# define ENTRYFNNAMEARGS void # define EXITFNNAME ExitDll #else # define ENTRYFNNAME ModuleEntry +# define ENTRYFNNAMEARGS void* # define EXITFNNAME ModuleExit #endif DISTRHO_PLUGIN_EXPORT -bool ENTRYFNNAME(void*); +bool ENTRYFNNAME(ENTRYFNNAMEARGS); -bool ENTRYFNNAME(void*) +bool ENTRYFNNAME(ENTRYFNNAMEARGS) { USE_NAMESPACE_DISTRHO; @@ -4205,9 +4620,9 @@ bool ENTRYFNNAME(void*) String tmpPath(getBinaryFilename()); tmpPath.truncate(tmpPath.rfind(DISTRHO_OS_SEP)); tmpPath.truncate(tmpPath.rfind(DISTRHO_OS_SEP)); - DISTRHO_SAFE_ASSERT_RETURN(tmpPath.endsWith("/Contents"), true); + DISTRHO_SAFE_ASSERT_RETURN(tmpPath.endsWith(DISTRHO_OS_SEP_STR "Contents"), true); - tmpPath.truncate(tmpPath.rfind('/')); + tmpPath.truncate(tmpPath.rfind(DISTRHO_OS_SEP)); bundlePath = tmpPath; d_nextBundlePath = bundlePath.buffer(); } diff --git a/dpf/distrho/src/DistrhoUI.cpp b/dpf/distrho/src/DistrhoUI.cpp index 7366be3..3af6926 100644 --- a/dpf/distrho/src/DistrhoUI.cpp +++ b/dpf/distrho/src/DistrhoUI.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho + * Copyright (C) 2012-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -17,26 +17,39 @@ #include "src/DistrhoPluginChecks.h" #include "src/DistrhoDefines.h" -#if !defined(DGL_FILE_BROWSER_DISABLED) && !defined(DISTRHO_OS_MAC) +#include + +#ifdef DISTRHO_PROPER_CPP11_SUPPORT +# include +#else +# include +#endif + +#if DISTRHO_UI_FILE_BROWSER && !defined(DISTRHO_OS_MAC) # define DISTRHO_PUGL_NAMESPACE_MACRO_HELPER(NS, SEP, FUNCTION) NS ## SEP ## FUNCTION # define DISTRHO_PUGL_NAMESPACE_MACRO(NS, FUNCTION) DISTRHO_PUGL_NAMESPACE_MACRO_HELPER(NS, _, FUNCTION) -# define DISTRHO_FILE_BROWSER_DIALOG_EXTRA_NAMESPACE Plugin -# define x_fib_add_recent DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_add_recent) -# define x_fib_cfg_buttons DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_cfg_buttons) -# define x_fib_cfg_filter_callback DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_cfg_filter_callback) -# define x_fib_close DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_close) -# define x_fib_configure DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_configure) -# define x_fib_filename DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_filename) -# define x_fib_free_recent DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_free_recent) -# define x_fib_handle_events DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_handle_events) -# define x_fib_load_recent DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_load_recent) -# define x_fib_recent_at DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_recent_at) -# define x_fib_recent_count DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_recent_count) -# define x_fib_recent_file DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_recent_file) -# define x_fib_save_recent DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_save_recent) -# define x_fib_show DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_show) -# define x_fib_status DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_status) -# include "../extra/FileBrowserDialog.cpp" +# define x_fib_add_recent DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_add_recent) +# define x_fib_cfg_buttons DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_cfg_buttons) +# define x_fib_cfg_filter_callback DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_cfg_filter_callback) +# define x_fib_close DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_close) +# define x_fib_configure DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_configure) +# define x_fib_filename DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_filename) +# define x_fib_free_recent DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_free_recent) +# define x_fib_handle_events DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_handle_events) +# define x_fib_load_recent DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_load_recent) +# define x_fib_recent_at DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_recent_at) +# define x_fib_recent_count DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_recent_count) +# define x_fib_recent_file DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_recent_file) +# define x_fib_save_recent DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_save_recent) +# define x_fib_show DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_show) +# define x_fib_status DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_status) +# define DISTRHO_FILE_BROWSER_DIALOG_HPP_INCLUDED +# define FILE_BROWSER_DIALOG_NAMESPACE DISTRHO_NAMESPACE +# define FILE_BROWSER_DIALOG_DISTRHO_NAMESPACE +START_NAMESPACE_DISTRHO +# include "../extra/FileBrowserDialogImpl.hpp" +END_NAMESPACE_DISTRHO +# include "../extra/FileBrowserDialogImpl.cpp" #endif #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI @@ -96,22 +109,18 @@ static double getDesktopScaleFactor(const uintptr_t parentWindowHandle) # endif DWORD dpiAware = 0; + DWORD scaleFactor = 100; if (GetProcessDpiAwareness && GetScaleFactorForMonitor - && GetProcessDpiAwareness(NULL, &dpiAware) == 0 && dpiAware != 0) + && GetProcessDpiAwareness(nullptr, &dpiAware) == 0 && dpiAware != 0) { const HMONITOR hMon = parentWindowHandle != 0 ? MonitorFromWindow((HWND)parentWindowHandle, MONITOR_DEFAULTTOPRIMARY) : MonitorFromPoint(POINT{0,0}, MONITOR_DEFAULTTOPRIMARY); - - DWORD scaleFactor = 0; - if (GetScaleFactorForMonitor(hMon, &scaleFactor) == 0 && scaleFactor != 0) - { - FreeLibrary(Shcore); - return static_cast(scaleFactor) / 100.0; - } + GetScaleFactorForMonitor(hMon, &scaleFactor); } FreeLibrary(Shcore); + return static_cast(scaleFactor) / 100.0; } #elif defined(HAVE_X11) ::Display* const display = XOpenDisplay(nullptr); @@ -119,28 +128,31 @@ static double getDesktopScaleFactor(const uintptr_t parentWindowHandle) XrmInitialize(); + double dpi = 96.0; if (char* const rms = XResourceManagerString(display)) { - if (const XrmDatabase sdb = XrmGetStringDatabase(rms)) + if (const XrmDatabase db = XrmGetStringDatabase(rms)) { char* type = nullptr; - XrmValue ret; + XrmValue value = {}; - if (XrmGetResource(sdb, "Xft.dpi", "String", &type, &ret) - && ret.addr != nullptr + if (XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value) && type != nullptr - && std::strncmp("String", type, 6) == 0) + && std::strcmp(type, "String") == 0 + && value.addr != nullptr) { - if (const double dpi = std::atof(ret.addr)) - { - XCloseDisplay(display); - return dpi / 96; - } + char* end = nullptr; + const double xftDpi = std::strtod(value.addr, &end); + if (xftDpi > 0.0 && xftDpi < HUGE_VAL) + dpi = xftDpi; } + + XrmDestroyDatabase(db); } } XCloseDisplay(display); + return dpi / 96; #endif return 1.0; @@ -264,7 +276,7 @@ void UI::setState(const char* key, const char* value) } #endif -#if DISTRHO_PLUGIN_WANT_STATEFILES +#if DISTRHO_PLUGIN_WANT_STATE bool UI::requestStateFile(const char* key) { return uiData->fileRequestCallback(key); @@ -278,16 +290,10 @@ void UI::sendNote(uint8_t channel, uint8_t note, uint8_t velocity) } #endif -#ifndef DGL_FILE_BROWSER_DISABLED +#if DISTRHO_UI_FILE_BROWSER bool UI::openFileBrowser(const FileBrowserOptions& options) { -# if DISTRHO_PLUGIN_HAS_EXTERNAL_UI - // TODO - return false; - (void)options; -# else - return getWindow().openFileBrowser(options); -# endif + return getWindow().openFileBrowser((DGL_NAMESPACE::FileBrowserOptions&)options); } #endif @@ -338,6 +344,25 @@ void UI::uiScaleFactorChanged(double) } #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI +std::vector UI::getClipboardDataOfferTypes() +{ + return uiData->window->getClipboardDataOfferTypes(); +} + +uint32_t UI::uiClipboardDataOffer() +{ + std::vector offers(uiData->window->getClipboardDataOfferTypes()); + + for (std::vector::iterator it=offers.begin(), end=offers.end(); it != end;++it) + { + const DGL_NAMESPACE::ClipboardDataOffer offer = *it; + if (std::strcmp(offer.type, "text/plain") == 0) + return offer.id; + } + + return 0; +} + void UI::uiFocus(bool, DGL_NAMESPACE::CrossingMode) { } @@ -349,7 +374,7 @@ void UI::uiReshape(uint, uint) } #endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI -#ifndef DGL_FILE_BROWSER_DISABLED +#if DISTRHO_UI_FILE_BROWSER void UI::uiFileBrowserSelected(const char*) { } diff --git a/dpf/distrho/src/DistrhoUIInternal.hpp b/dpf/distrho/src/DistrhoUIInternal.hpp index 31d97f0..b470224 100644 --- a/dpf/distrho/src/DistrhoUIInternal.hpp +++ b/dpf/distrho/src/DistrhoUIInternal.hpp @@ -262,7 +262,16 @@ public: // ------------------------------------------------------------------- -#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI && defined(DISTRHO_PLUGIN_TARGET_VST3) && (defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WINDOWS)) +#if defined(DISTRHO_PLUGIN_TARGET_VST3) && (defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WINDOWS)) + void idleForVST3() + { + DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); + + uiData->app.triggerIdleCallbacks(); + ui->uiIdle(); + } + +# if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI void addIdleCallbackForVST3(IdleCallback* const cb, const uint timerFrequencyInMs) { uiData->window->addIdleCallback(cb, timerFrequencyInMs); @@ -272,18 +281,21 @@ public: { uiData->window->removeIdleCallback(cb); } - - void idleForVST3() - { - DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); - - uiData->app.triggerIdleCallbacks(); - ui->uiIdle(); - } +# endif #endif // ------------------------------------------------------------------- + void setWindowOffset(const int x, const int y) + { +#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI + // TODO + (void)x; (void)y; +#else + uiData->window->setOffset(x, y); +#endif + } + #ifdef DISTRHO_PLUGIN_TARGET_VST3 void setWindowSizeForVST3(const uint width, const uint height) { @@ -300,14 +312,12 @@ public: uiData->window->setTitle(uiTitle); } - void setWindowTransientWinId(const uintptr_t winId) + void setWindowTransientWinId(const uintptr_t transientParentWindowHandle) { #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI - ui->setTransientWindowId(winId); -#elif 0 /* TODO */ - glWindow.setTransientWinId(winId); + ui->setTransientWindowId(transientParentWindowHandle); #else - (void)winId; + uiData->window->setTransientParent(transientParentWindowHandle); #endif } @@ -319,53 +329,36 @@ public: } #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI - bool handlePluginKeyboardVST2(const bool press, const uint key, const uint16_t mods) + bool handlePluginKeyboardVST(const bool press, const bool special, const uint keychar, const uint keycode, const uint16_t mods) { - DGL_NAMESPACE::Widget::KeyboardEvent ev; - ev.mod = mods; - ev.press = press; - ev.key = key; - - const bool ret = ui->onKeyboard(ev); + using namespace DGL_NAMESPACE; - if (! press) - return ret; - - DGL_NAMESPACE::Widget::CharacterInputEvent cev; - cev.mod = mods; - cev.character = key; - - // if shift modifier is on, convert a-z -> A-Z for character input - if (key >= 'a' && key <= 'z' && (mods & DGL_NAMESPACE::kModifierShift) != 0) - cev.character -= 'a' - 'A'; - - ui->onCharacterInput(cev); - return ret; - } - - bool handlePluginKeyboardVST3(const bool press, const uint keychar, const uint keycode, const uint16_t mods) - { - DGL_NAMESPACE::Widget::KeyboardEvent ev; + Widget::KeyboardEvent ev; ev.mod = mods; ev.press = press; ev.key = keychar; ev.keycode = keycode; + // keyboard events must always be lowercase + if (ev.key >= 'A' && ev.key <= 'Z') + ev.key += 'a' - 'A'; // A-Z -> a-z + const bool ret = ui->onKeyboard(ev); - if (! press) - return ret; + if (press && !special && (mods & (kModifierControl|kModifierAlt|kModifierSuper)) == 0) + { + Widget::CharacterInputEvent cev; + cev.mod = mods; + cev.character = keychar; + cev.keycode = keycode; - DGL_NAMESPACE::Widget::CharacterInputEvent cev; - cev.mod = mods; - cev.keycode = keycode; - cev.character = keychar; + // if shift modifier is on, convert a-z -> A-Z for character input + if (cev.character >= 'a' && cev.character <= 'z' && (mods & kModifierShift) != 0) + cev.character -= 'a' - 'A'; - // if shift modifier is on, convert a-z -> A-Z for character input - if (keychar >= 'a' && keychar <= 'z' && (mods & DGL_NAMESPACE::kModifierShift) != 0) - cev.character -= 'a' - 'A'; + ui->onCharacterInput(cev); + } - ui->onCharacterInput(cev); return ret; } #endif diff --git a/dpf/distrho/src/DistrhoUILV2.cpp b/dpf/distrho/src/DistrhoUILV2.cpp index 19df7a1..0bb2158 100644 --- a/dpf/distrho/src/DistrhoUILV2.cpp +++ b/dpf/distrho/src/DistrhoUILV2.cpp @@ -181,6 +181,33 @@ public: fUI.stateChanged(key, value); } + else if (atom->type == fURIDs.atomObject) + { + /* TODO + const LV2_Atom_Object* const obj = (const LV2_Atom_Object*)LV2_ATOM_BODY_CONST(atom); + + const LV2_Atom* property = nullptr; + const LV2_Atom* avalue = nullptr; + lv2_atom_object_get(obj, fURIDs.patchProperty, &property, fURIDs.patchValue, &avalue, 0); + + DISTRHO_SAFE_ASSERT_RETURN(property != nullptr,); + DISTRHO_SAFE_ASSERT_RETURN(avalue != nullptr,); + + DISTRHO_SAFE_ASSERT_RETURN(property->type == fURIDs.atomURID,); + DISTRHO_SAFE_ASSERT_RETURN(avalue->type == fURIDs.atomPath || avalue->type == fURIDs.atomString,); + + if (property != nullptr && property->type == fURIDs.atomURID && + avalue != nullptr && (avalue->type == fURIDs.atomPath || avalue->type == fURIDs.atomString)) + { + const char* const key = (const char*)LV2_ATOM_BODY_CONST(property); + const char* const value = (const char*)LV2_ATOM_BODY_CONST(avalue); + + d_stdout("received atom object '%s' '%s'", key, value); + + fUI.stateChanged(key, value); + } + */ + } else { d_stdout("received atom not dpfKeyValue"); @@ -368,15 +395,19 @@ private: // LV2 URIDs const struct URIDs { const LV2_URID_Map* _uridMap; - LV2_URID dpfKeyValue; - LV2_URID atomEventTransfer; - LV2_URID atomFloat; - LV2_URID atomLong; - LV2_URID atomPath; - LV2_URID atomString; - LV2_URID midiEvent; - LV2_URID paramSampleRate; - LV2_URID patchSet; + const LV2_URID dpfKeyValue; + const LV2_URID atomEventTransfer; + const LV2_URID atomFloat; + const LV2_URID atomLong; + const LV2_URID atomObject; + const LV2_URID atomPath; + const LV2_URID atomString; + const LV2_URID atomURID; + const LV2_URID midiEvent; + const LV2_URID paramSampleRate; + const LV2_URID patchProperty; + const LV2_URID patchSet; + const LV2_URID patchValue; URIDs(const LV2_URID_Map* const uridMap) : _uridMap(uridMap), @@ -384,11 +415,15 @@ private: atomEventTransfer(map(LV2_ATOM__eventTransfer)), atomFloat(map(LV2_ATOM__Float)), atomLong(map(LV2_ATOM__Long)), + atomObject(map(LV2_ATOM__Object)), atomPath(map(LV2_ATOM__Path)), atomString(map(LV2_ATOM__String)), + atomURID(map(LV2_ATOM__URID)), midiEvent(map(LV2_MIDI__MidiEvent)), paramSampleRate(map(LV2_PARAMETERS__sampleRate)), - patchSet(map(LV2_PATCH__Set)) {} + patchProperty(map(LV2_PATCH__property)), + patchSet(map(LV2_PATCH__Set)), + patchValue(map(LV2_PATCH__value)) {} inline LV2_URID map(const char* const uri) const { diff --git a/dpf/distrho/src/DistrhoUIPrivateData.hpp b/dpf/distrho/src/DistrhoUIPrivateData.hpp index e3e846d..ee4503e 100644 --- a/dpf/distrho/src/DistrhoUIPrivateData.hpp +++ b/dpf/distrho/src/DistrhoUIPrivateData.hpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho + * Copyright (C) 2012-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -20,11 +20,12 @@ #include "../DistrhoUI.hpp" #ifdef DISTRHO_PLUGIN_TARGET_VST3 -# include "DistrhoPluginVST3.hpp" +# include "DistrhoPluginVST.hpp" #endif #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI # include "../extra/Sleep.hpp" +// TODO import and use file browser here #else # include "../../dgl/src/ApplicationPrivateData.hpp" # include "../../dgl/src/WindowPrivateData.hpp" @@ -48,13 +49,7 @@ # define DISTRHO_UI_USER_RESIZABLE 0 #endif -// ----------------------------------------------------------------------- - -#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI START_NAMESPACE_DISTRHO -#else -START_NAMESPACE_DGL -#endif // ----------------------------------------------------------------------- // Plugin Application, will set class name based on plugin details @@ -107,12 +102,13 @@ struct PluginApplication DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginApplication) }; #else -class PluginApplication : public Application +class PluginApplication : public DGL_NAMESPACE::Application { public: explicit PluginApplication() - : Application(DISTRHO_UI_IS_STANDALONE) + : DGL_NAMESPACE::Application(DISTRHO_UI_IS_STANDALONE) { +#ifndef DISTRHO_OS_WASM const char* const className = ( #ifdef DISTRHO_PLUGIN_BRAND DISTRHO_PLUGIN_BRAND @@ -122,6 +118,7 @@ public: "-" DISTRHO_PLUGIN_NAME ); setClassName(className); +#endif } void triggerIdleCallbacks() @@ -172,14 +169,14 @@ public: DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginWindow) }; #else // DISTRHO_PLUGIN_HAS_EXTERNAL_UI -class PluginWindow : public Window +class PluginWindow : public DGL_NAMESPACE::Window { - DISTRHO_NAMESPACE::UI* const ui; + UI* const ui; bool initializing; bool receivedReshapeDuringInit; public: - explicit PluginWindow(DISTRHO_NAMESPACE::UI* const uiPtr, + explicit PluginWindow(UI* const uiPtr, PluginApplication& app, const uintptr_t parentWindowHandle, const uint width, @@ -199,7 +196,7 @@ public: puglBackendEnter(pData->view); } - ~PluginWindow() + ~PluginWindow() override { if (pData->view != nullptr) puglBackendLeave(pData->view); @@ -234,11 +231,26 @@ public: #ifdef DISTRHO_PLUGIN_TARGET_VST3 void setSizeForVST3(const uint width, const uint height) { - puglSetWindowSize(pData->view, width, height); + puglSetSizeAndDefault(pData->view, width, height); } #endif + std::vector getClipboardDataOfferTypes() + { + return Window::getClipboardDataOfferTypes(); + } + protected: + uint32_t onClipboardDataOffer() override + { + DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr, 0); + + if (initializing) + return 0; + + return ui->uiClipboardDataOffer(); + } + void onFocus(const bool focus, const DGL_NAMESPACE::CrossingMode mode) override { DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); @@ -272,7 +284,7 @@ protected: ui->uiScaleFactorChanged(scaleFactor); } -# ifndef DGL_FILE_BROWSER_DISABLED +# if DISTRHO_UI_FILE_BROWSER void onFileSelected(const char* filename) override; # endif @@ -280,21 +292,6 @@ protected: }; #endif // DISTRHO_PLUGIN_HAS_EXTERNAL_UI -#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI -END_NAMESPACE_DISTRHO -#else -END_NAMESPACE_DGL -#endif - -// ----------------------------------------------------------------------- - -START_NAMESPACE_DISTRHO - -#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI -using DGL_NAMESPACE::PluginApplication; -using DGL_NAMESPACE::PluginWindow; -#endif - // ----------------------------------------------------------------------- // UI callbacks @@ -323,7 +320,7 @@ struct UI::PrivateData { uint fgColor; double scaleFactor; uintptr_t winId; -#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI && !defined(DGL_FILE_BROWSER_DISABLED) +#if DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI char* uiStateFileKeyRequest; #endif char* bundlePath; @@ -350,7 +347,7 @@ struct UI::PrivateData { fgColor(0xffffffff), scaleFactor(1.0), winId(0), -#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI && !defined(DGL_FILE_BROWSER_DISABLED) +#if DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI uiStateFileKeyRequest(nullptr), #endif bundlePath(nullptr), @@ -386,7 +383,7 @@ struct UI::PrivateData { ~PrivateData() noexcept { -#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI && !defined(DGL_FILE_BROWSER_DISABLED) +#if DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI std::free(uiStateFileKeyRequest); #endif std::free(bundlePath); @@ -441,7 +438,7 @@ inline bool UI::PrivateData::fileRequestCallback(const char* const key) if (fileRequestCallbackFunc != nullptr) return fileRequestCallbackFunc(callbacksPtr, key); -#if DISTRHO_PLUGIN_WANT_STATEFILES && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI && !defined(DGL_FILE_BROWSER_DISABLED) +#if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI std::free(uiStateFileKeyRequest); uiStateFileKeyRequest = strdup(key); DISTRHO_SAFE_ASSERT_RETURN(uiStateFileKeyRequest != nullptr, false); @@ -450,7 +447,7 @@ inline bool UI::PrivateData::fileRequestCallback(const char* const key) snprintf(title, sizeof(title)-1u, DISTRHO_PLUGIN_NAME ": %s", key); title[sizeof(title)-1u] = '\0'; - FileBrowserOptions opts; + DGL_NAMESPACE::FileBrowserOptions opts; opts.title = title; return window->openFileBrowser(opts); #endif @@ -458,14 +455,10 @@ inline bool UI::PrivateData::fileRequestCallback(const char* const key) return false; } -END_NAMESPACE_DISTRHO - // ----------------------------------------------------------------------- // PluginWindow onFileSelected that require UI::PrivateData definitions -#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI && !defined(DGL_FILE_BROWSER_DISABLED) -START_NAMESPACE_DGL - +#if DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI inline void PluginWindow::onFileSelected(const char* const filename) { DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); @@ -473,7 +466,7 @@ inline void PluginWindow::onFileSelected(const char* const filename) if (initializing) return; -# if DISTRHO_PLUGIN_WANT_STATEFILES + #if DISTRHO_PLUGIN_WANT_STATE if (char* const key = ui->uiData->uiStateFileKeyRequest) { ui->uiData->uiStateFileKeyRequest = nullptr; @@ -487,14 +480,16 @@ inline void PluginWindow::onFileSelected(const char* const filename) std::free(key); return; } -# endif + #endif + puglBackendEnter(pData->view); ui->uiFileBrowserSelected(filename); + puglBackendLeave(pData->view); } - -END_NAMESPACE_DGL #endif // ----------------------------------------------------------------------- +END_NAMESPACE_DISTRHO + #endif // DISTRHO_UI_PRIVATE_DATA_HPP_INCLUDED diff --git a/dpf/distrho/src/DistrhoUIVST3.cpp b/dpf/distrho/src/DistrhoUIVST3.cpp index d0e8422..f3c7622 100644 --- a/dpf/distrho/src/DistrhoUIVST3.cpp +++ b/dpf/distrho/src/DistrhoUIVST3.cpp @@ -21,15 +21,24 @@ #include "travesty/host.h" #include "travesty/view.h" +#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI +# if defined(DISTRHO_OS_MAC) +# include +# elif defined(DISTRHO_OS_WINDOWS) +# include +# define DPF_VST3_WIN32_TIMER_ID 1 +# endif +#endif + /* TODO items: * - mousewheel event - * - key down/up events - * - host-side resizing * - file request? */ #if !(defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WINDOWS)) -# define DPF_VST3_USING_HOST_RUN_LOOP +# define DPF_VST3_USING_HOST_RUN_LOOP 1 +#else +# define DPF_VST3_USING_HOST_RUN_LOOP 0 #endif #ifndef DPF_VST3_TIMER_INTERVAL @@ -96,6 +105,155 @@ static void applyGeometryConstraints(const uint minimumWidth, // -------------------------------------------------------------------------------------------------------------------- +#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI +static uint translateVST3Modifiers(const int64_t modifiers) noexcept +{ + using namespace DGL_NAMESPACE; + + uint dglmods = 0; + if (modifiers & (1 << 0)) + dglmods |= kModifierShift; + if (modifiers & (1 << 1)) + dglmods |= kModifierAlt; + #ifdef DISTRHO_OS_MAC + if (modifiers & (1 << 2)) + dglmods |= kModifierSuper; + if (modifiers & (1 << 3)) + dglmods |= kModifierControl; + #else + if (modifiers & (1 << 2)) + dglmods |= kModifierControl; + if (modifiers & (1 << 3)) + dglmods |= kModifierSuper; + #endif + + return dglmods; +} +#endif + +// -------------------------------------------------------------------------------------------------------------------- + +/** + * Helper class for getting a native idle timer, either through pugl or via native APIs. + */ +#if !DPF_VST3_USING_HOST_RUN_LOOP +class NativeIdleCallback : public IdleCallback +{ +public: + NativeIdleCallback(UIExporter& ui) + : fUI(ui), + fCallbackRegistered(false) + #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI + #if defined(DISTRHO_OS_MAC) + , fTimerRef(nullptr) + #elif defined(DISTRHO_OS_WINDOWS) + , fTimerWindow(nullptr) + , fTimerWindowClassName() + #endif + #endif + { + } + + void registerNativeIdleCallback() + { + DISTRHO_SAFE_ASSERT_RETURN(!fCallbackRegistered,); + fCallbackRegistered = true; + + #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI + fUI.addIdleCallbackForVST3(this, DPF_VST3_TIMER_INTERVAL); + #elif defined(DISTRHO_OS_MAC) + constexpr const CFTimeInterval interval = DPF_VST3_TIMER_INTERVAL * 0.0001; + + CFRunLoopTimerContext context = {}; + context.info = this; + fTimerRef = CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + interval, interval, 0, 0, + platformIdleTimerCallback, &context); + DISTRHO_SAFE_ASSERT_RETURN(fTimerRef != nullptr,); + + CFRunLoopAddTimer(CFRunLoopGetCurrent(), fTimerRef, kCFRunLoopCommonModes); + #elif defined(DISTRHO_OS_WINDOWS) + /* We cannot assume anything about the native parent window passed as a parameter (winId) to the + * UIVst3 constructor because we do not own it. + * These parent windows have class names like 'reaperPluginHostWrapProc' and 'JUCE_nnnnnn'. + * + * Create invisible window to handle a timer instead. + * There is no need for implementing a window proc because DefWindowProc already calls the + * callback function when processing WM_TIMER messages. + */ + fTimerWindowClassName = ( + #ifdef DISTRHO_PLUGIN_BRAND + DISTRHO_PLUGIN_BRAND + #else + DISTRHO_MACRO_AS_STRING(DISTRHO_NAMESPACE) + #endif + "-" DISTRHO_PLUGIN_NAME "-" + ); + + char suffix[9]; + std::snprintf(suffix, sizeof(suffix), "%08x", std::rand()); + suffix[sizeof(suffix)-1] = '\0'; + fTimerWindowClassName += suffix; + + WNDCLASSEX cls; + ZeroMemory(&cls, sizeof(cls)); + cls.cbSize = sizeof(WNDCLASSEX); + cls.cbWndExtra = sizeof(LONG_PTR); + cls.lpszClassName = fTimerWindowClassName.buffer(); + cls.lpfnWndProc = DefWindowProc; + RegisterClassEx(&cls); + + fTimerWindow = CreateWindowEx(0, cls.lpszClassName, "DPF Timer Helper", + 0, 0, 0, 0, 0, HWND_MESSAGE, nullptr, nullptr, nullptr); + DISTRHO_SAFE_ASSERT_RETURN(fTimerWindow != nullptr,); + + SetWindowLongPtr(fTimerWindow, GWLP_USERDATA, reinterpret_cast(static_cast(this))); + SetTimer(fTimerWindow, DPF_VST3_WIN32_TIMER_ID, DPF_VST3_TIMER_INTERVAL, + static_cast(platformIdleTimerCallback)); + #endif + } + + void unregisterNativeIdleCallback() + { + #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI + fUI.removeIdleCallbackForVST3(this); + #elif defined(DISTRHO_OS_MAC) + CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), fTimerRef, kCFRunLoopCommonModes); + CFRelease(fTimerRef); + #elif defined(DISTRHO_OS_WINDOWS) + DISTRHO_SAFE_ASSERT_RETURN(fTimerWindow != nullptr,); + KillTimer(fTimerWindow, DPF_VST3_WIN32_TIMER_ID); + DestroyWindow(fTimerWindow); + UnregisterClass(fTimerWindowClassName, nullptr); + #endif + } + +private: + UIExporter& fUI; + bool fCallbackRegistered; + + #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI + #if defined(DISTRHO_OS_MAC) + CFRunLoopTimerRef fTimerRef; + + static void platformIdleTimerCallback(CFRunLoopTimerRef, void* const info) + { + static_cast(info)->idleCallback(); + } + #elif defined(DISTRHO_OS_WINDOWS) + HWND fTimerWindow; + String fTimerWindowClassName; + + WINAPI static void platformIdleTimerCallback(const HWND hwnd, UINT, UINT_PTR, DWORD) + { + reinterpret_cast(GetWindowLongPtr(hwnd, GWLP_USERDATA))->idleCallback(); + } + #endif + #endif +}; +#endif + +// -------------------------------------------------------------------------------------------------------------------- + /** * VST3 UI class. * @@ -105,8 +263,8 @@ static void applyGeometryConstraints(const uint minimumWidth, * The low-level VST3 stuff comes after. */ class UIVst3 -#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI && (defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WINDOWS)) - : public IdleCallback +#if !DPF_VST3_USING_HOST_RUN_LOOP + : public NativeIdleCallback #endif { public: @@ -118,15 +276,22 @@ public: const float scaleFactor, const double sampleRate, void* const instancePointer, - const bool willResizeFromHost) - : fView(view), + const bool willResizeFromHost, + const bool needsResizeFromPlugin) + : +#if !DPF_VST3_USING_HOST_RUN_LOOP + NativeIdleCallback(fUI), +#endif + fView(view), fHostApplication(host), fConnection(connection), fFrame(frame), - fReadyForPluginData(false), fScaleFactor(scaleFactor), + fReadyForPluginData(false), fIsResizingFromPlugin(false), fIsResizingFromHost(willResizeFromHost), + fNeedsResizeFromPlugin(needsResizeFromPlugin), + fNextPluginRect(), fUI(this, winId, sampleRate, editParameterCallback, setParameterCallback, @@ -142,9 +307,10 @@ public: ~UIVst3() { -#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI && (defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WINDOWS)) - fUI.removeIdleCallbackForVST3(this); -#endif + #if !DPF_VST3_USING_HOST_RUN_LOOP + unregisterNativeIdleCallback(); + #endif + if (fConnection != nullptr) disconnect(); } @@ -153,24 +319,30 @@ public: { if (fIsResizingFromHost && nextWidth > 0 && nextHeight > 0) { -#ifdef DISTRHO_OS_MAC + #ifdef DISTRHO_OS_MAC const double scaleFactor = fUI.getScaleFactor(); nextWidth *= scaleFactor; nextHeight *= scaleFactor; -#endif + #endif + if (fUI.getWidth() != nextWidth || fUI.getHeight() != nextHeight) { d_stdout("postInit sets new size as %u %u", nextWidth, nextHeight); fUI.setWindowSizeForVST3(nextWidth, nextHeight); } } + else if (fNeedsResizeFromPlugin) + { + d_stdout("postInit forcely sets size from plugin as %u %u", fUI.getWidth(), fUI.getHeight()); + setSize(fUI.getWidth(), fUI.getHeight()); + } if (fConnection != nullptr) connect(fConnection); -#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI && (defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WINDOWS)) - fUI.addIdleCallbackForVST3(this, DPF_VST3_TIMER_INTERVAL); -#endif + #if !DPF_VST3_USING_HOST_RUN_LOOP + registerNativeIdleCallback(); + #endif } // ---------------------------------------------------------------------------------------------------------------- @@ -185,64 +357,28 @@ public: v3_result onKeyDown(const int16_t keychar, const int16_t keycode, const int16_t modifiers) { - d_stdout("onKeyDown %i %i %x\n", keychar, keycode, modifiers); DISTRHO_SAFE_ASSERT_INT_RETURN(keychar >= 0 && keychar < 0x7f, keychar, V3_FALSE); - using namespace DGL_NAMESPACE; - - // TODO - uint dglcode = 0; - - // TODO verify these - uint dglmods = 0; - if (modifiers & (1 << 0)) - dglmods |= kModifierShift; - if (modifiers & (1 << 1)) - dglmods |= kModifierAlt; -# ifdef DISTRHO_OS_MAC - if (modifiers & (1 << 2)) - dglmods |= kModifierSuper; - if (modifiers & (1 << 3)) - dglmods |= kModifierControl; -# else - if (modifiers & (1 << 2)) - dglmods |= kModifierControl; - if (modifiers & (1 << 3)) - dglmods |= kModifierSuper; -# endif + bool special; + const uint key = translateVstKeyCode(special, keychar, keycode); + d_debug("onKeyDown %d %d %x -> %d %d", keychar, keycode, modifiers, special, key); - return fUI.handlePluginKeyboardVST3(true, static_cast(keychar), dglcode, dglmods) ? V3_TRUE : V3_FALSE; + return fUI.handlePluginKeyboardVST(true, special, key, + keycode >= 0 ? static_cast(keycode) : 0, + translateVST3Modifiers(modifiers)) ? V3_TRUE : V3_FALSE; } v3_result onKeyUp(const int16_t keychar, const int16_t keycode, const int16_t modifiers) { - d_stdout("onKeyDown %i %i %x\n", keychar, keycode, modifiers); DISTRHO_SAFE_ASSERT_INT_RETURN(keychar >= 0 && keychar < 0x7f, keychar, V3_FALSE); - using namespace DGL_NAMESPACE; - - // TODO - uint dglcode = 0; - - // TODO verify these - uint dglmods = 0; - if (modifiers & (1 << 0)) - dglmods |= kModifierShift; - if (modifiers & (1 << 1)) - dglmods |= kModifierAlt; -# ifdef DISTRHO_OS_MAC - if (modifiers & (1 << 2)) - dglmods |= kModifierSuper; - if (modifiers & (1 << 3)) - dglmods |= kModifierControl; -# else - if (modifiers & (1 << 2)) - dglmods |= kModifierControl; - if (modifiers & (1 << 3)) - dglmods |= kModifierSuper; -# endif + bool special; + const uint key = translateVstKeyCode(special, keychar, keycode); + d_debug("onKeyUp %d %d %x -> %d %d", keychar, keycode, modifiers, special, key); - return fUI.handlePluginKeyboardVST3(false, static_cast(keychar), dglcode, dglmods) ? V3_TRUE : V3_FALSE; + return fUI.handlePluginKeyboardVST(false, special, key, + keycode >= 0 ? static_cast(keycode) : 0, + translateVST3Modifiers(modifiers)) ? V3_TRUE : V3_FALSE; } v3_result onFocus(const bool state) @@ -256,14 +392,22 @@ public: v3_result getSize(v3_view_rect* const rect) const noexcept { - rect->left = rect->top = 0; - rect->right = fUI.getWidth(); - rect->bottom = fUI.getHeight(); -#ifdef DISTRHO_OS_MAC - const double scaleFactor = fUI.getScaleFactor(); - rect->right /= scaleFactor; - rect->bottom /= scaleFactor; -#endif + if (fIsResizingFromPlugin) + { + *rect = fNextPluginRect; + } + else + { + rect->left = rect->top = 0; + rect->right = fUI.getWidth(); + rect->bottom = fUI.getHeight(); + #ifdef DISTRHO_OS_MAC + const double scaleFactor = fUI.getScaleFactor(); + rect->right /= scaleFactor; + rect->bottom /= scaleFactor; + #endif + } + d_stdout("getSize request returning %i %i", rect->right, rect->bottom); return V3_OK; } @@ -271,22 +415,26 @@ public: v3_result onSize(v3_view_rect* const orect) { v3_view_rect rect = *orect; -#ifdef DISTRHO_OS_MAC + + #ifdef DISTRHO_OS_MAC const double scaleFactor = fUI.getScaleFactor(); rect.top *= scaleFactor; rect.left *= scaleFactor; rect.right *= scaleFactor; rect.bottom *= scaleFactor; -#endif + #endif if (fIsResizingFromPlugin) { - d_stdout("host->plugin onSize request %i %i (IGNORED, plugin resize active)", + d_stdout("host->plugin onSize request %i %i (plugin resize was active, unsetting now)", rect.right - rect.left, rect.bottom - rect.top); - return V3_OK; + fIsResizingFromPlugin = false; + } + else + { + d_stdout("host->plugin onSize request %i %i (OK)", rect.right - rect.left, rect.bottom - rect.top); } - d_stdout("host->plugin onSize request %i %i (OK)", rect.right - rect.left, rect.bottom - rect.top); fIsResizingFromHost = true; fUI.setWindowSizeForVST3(rect.right - rect.left, rect.bottom - rect.top); return V3_OK; @@ -308,11 +456,13 @@ public: uint minimumWidth, minimumHeight; bool keepAspectRatio; fUI.getGeometryConstraints(minimumWidth, minimumHeight, keepAspectRatio); -#ifdef DISTRHO_OS_MAC + + #ifdef DISTRHO_OS_MAC const double scaleFactor = fUI.getScaleFactor(); minimumWidth /= scaleFactor; minimumHeight /= scaleFactor; -#endif + #endif + applyGeometryConstraints(minimumWidth, minimumHeight, keepAspectRatio, rect); return V3_TRUE; } @@ -414,7 +564,7 @@ public: return V3_OK; } -#if DISTRHO_PLUGIN_WANT_STATE + #if DISTRHO_PLUGIN_WANT_STATE if (std::strcmp(msgid, "state-set") == 0) { int64_t keyLength = -1; @@ -435,12 +585,12 @@ public: int16_t* const value16 = (int16_t*)std::malloc(sizeof(int16_t)*(valueLength + 1)); DISTRHO_SAFE_ASSERT_RETURN(value16 != nullptr, V3_NOMEM); - res = v3_cpp_obj(attrs)->get_string(attrs, "key", key16, sizeof(int16_t)*keyLength); + res = v3_cpp_obj(attrs)->get_string(attrs, "key", key16, sizeof(int16_t)*(keyLength+1)); DISTRHO_SAFE_ASSERT_INT2_RETURN(res == V3_OK, res, keyLength, res); if (valueLength != 0) { - res = v3_cpp_obj(attrs)->get_string(attrs, "value", value16, sizeof(int16_t)*valueLength); + res = v3_cpp_obj(attrs)->get_string(attrs, "value", value16, sizeof(int16_t)*(valueLength+1)); DISTRHO_SAFE_ASSERT_INT2_RETURN(res == V3_OK, res, valueLength, res); } @@ -462,7 +612,7 @@ public: std::free(value16); return V3_OK; } -#endif + #endif d_stdout("UIVst3 received unknown msg '%s'", msgid); @@ -482,25 +632,25 @@ public: return V3_OK; } + #if DPF_VST3_USING_HOST_RUN_LOOP // ---------------------------------------------------------------------------------------------------------------- - // special idle callback on macOS and Windows + // v3_timer_handler interface calls -#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI && (defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WINDOWS)) - void idleCallback() override + void onTimer() { - fUI.idleForVST3(); + fUI.plugin_idle(); doIdleStuff(); } -#else + #else // ---------------------------------------------------------------------------------------------------------------- - // v3_timer_handler interface calls + // special idle callback without v3_timer_handler - void onTimer() + void idleCallback() override { - fUI.plugin_idle(); + fUI.idleForVST3(); doIdleStuff(); } -#endif + #endif void doIdleStuff() { @@ -510,6 +660,12 @@ public: requestMorePluginData(); } + if (fNeedsResizeFromPlugin) + { + fNeedsResizeFromPlugin = false; + d_stdout("first resize forced behaviour is now stopped"); + } + if (fIsResizingFromHost) { fIsResizingFromHost = false; @@ -533,10 +689,12 @@ private: v3_plugin_frame** fFrame; // Temporary data - bool fReadyForPluginData; float fScaleFactor; + bool fReadyForPluginData; bool fIsResizingFromPlugin; bool fIsResizingFromHost; + bool fNeedsResizeFromPlugin; + v3_view_rect fNextPluginRect; // for when plugin requests a new size // Plugin UI (after VST3 stuff so the UI can call into us during its constructor) UIExporter fUI; @@ -629,19 +787,28 @@ private: DISTRHO_SAFE_ASSERT_RETURN(fView != nullptr,); DISTRHO_SAFE_ASSERT_RETURN(fFrame != nullptr,); -#ifdef DISTRHO_OS_MAC + #ifdef DISTRHO_OS_MAC const double scaleFactor = fUI.getScaleFactor(); width /= scaleFactor; height /= scaleFactor; -#endif + #endif if (fIsResizingFromHost) { - d_stdout("plugin->host setSize %u %u (IGNORED, host resize active)", width, height); - return; + if (fNeedsResizeFromPlugin) + { + d_stdout("plugin->host setSize %u %u (FORCED, exception for first resize)", width, height); + } + else + { + d_stdout("plugin->host setSize %u %u (IGNORED, host resize active)", width, height); + return; + } + } + else + { + d_stdout("plugin->host setSize %u %u (OK)", width, height); } - - d_stdout("plugin->host setSize %u %u (OK)", width, height); fIsResizingFromPlugin = true; @@ -649,6 +816,7 @@ private: rect.left = rect.top = 0; rect.right = width; rect.bottom = height; + fNextPluginRect = rect; v3_cpp_obj(fFrame)->resize_view(fFrame, fView, &rect); } @@ -657,7 +825,7 @@ private: ((UIVst3*)ptr)->setSize(width, height); } -#if DISTRHO_PLUGIN_WANT_MIDI_INPUT + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT void sendNote(const uint8_t channel, const uint8_t note, const uint8_t velocity) { DISTRHO_SAFE_ASSERT_RETURN(fConnection != nullptr,); @@ -684,9 +852,9 @@ private: { ((UIVst3*)ptr)->sendNote(channel, note, velocity); } -#endif + #endif -#if DISTRHO_PLUGIN_WANT_STATE + #if DISTRHO_PLUGIN_WANT_STATE void setState(const char* const key, const char* const value) { DISTRHO_SAFE_ASSERT_RETURN(fConnection != nullptr,); @@ -711,7 +879,7 @@ private: { ((UIVst3*)ptr)->setState(key, value); } -#endif + #endif }; // -------------------------------------------------------------------------------------------------------------------- @@ -887,7 +1055,7 @@ struct dpf_plugin_view_content_scale : v3_plugin_view_content_scale_cpp { } }; -#ifdef DPF_VST3_USING_HOST_RUN_LOOP +#if DPF_VST3_USING_HOST_RUN_LOOP // -------------------------------------------------------------------------------------------------------------------- // dpf_timer_handler @@ -963,9 +1131,9 @@ struct dpf_plugin_view : v3_plugin_view_cpp { std::atomic_int refcounter; ScopedPointer connection; ScopedPointer scale; -#ifdef DPF_VST3_USING_HOST_RUN_LOOP + #if DPF_VST3_USING_HOST_RUN_LOOP ScopedPointer timer; -#endif + #endif ScopedPointer uivst3; // cached values v3_host_application** const hostApplication; @@ -974,6 +1142,7 @@ struct dpf_plugin_view : v3_plugin_view_cpp { v3_plugin_frame** frame; v3_run_loop** runloop; uint32_t nextWidth, nextHeight; + bool sizeRequestedBeforeBeingAttached; dpf_plugin_view(v3_host_application** const host, void* const instance, const double sr) : refcounter(1), @@ -983,7 +1152,8 @@ struct dpf_plugin_view : v3_plugin_view_cpp { frame(nullptr), runloop(nullptr), nextWidth(0), - nextHeight(0) + nextHeight(0), + sizeRequestedBeforeBeingAttached(false) { d_stdout("dpf_plugin_view() with hostApplication %p", hostApplication); @@ -1017,7 +1187,7 @@ struct dpf_plugin_view : v3_plugin_view_cpp { connection = nullptr; scale = nullptr; - #ifdef DPF_VST3_USING_HOST_RUN_LOOP + #if DPF_VST3_USING_HOST_RUN_LOOP timer = nullptr; #endif uivst3 = nullptr; @@ -1055,7 +1225,7 @@ struct dpf_plugin_view : v3_plugin_view_cpp { return V3_OK; } -#ifndef DISTRHO_OS_MAC + #ifndef DISTRHO_OS_MAC if (v3_tuid_match(v3_plugin_view_content_scale_iid, iid)) { d_stdout("query_interface_view => %p %s %p | OK convert %p", @@ -1068,7 +1238,7 @@ struct dpf_plugin_view : v3_plugin_view_cpp { *iface = &view->scale; return V3_OK; } -#endif + #endif d_stdout("query_interface_view => %p %s %p | WARNING UNSUPPORTED", self, tuid2str(iid), iface); @@ -1116,7 +1286,7 @@ struct dpf_plugin_view : v3_plugin_view_cpp { } } -#ifndef DISTRHO_OS_MAC + #ifndef DISTRHO_OS_MAC if (dpf_plugin_view_content_scale* const scale = view->scale) { if (const int refcount = scale->refcounter) @@ -1125,7 +1295,7 @@ struct dpf_plugin_view : v3_plugin_view_cpp { d_stderr("DPF warning: asked to delete view while content scale still active (refcount %d)", refcount); } } -#endif + #endif if (unclean) return 0; @@ -1163,7 +1333,7 @@ struct dpf_plugin_view : v3_plugin_view_cpp { { if (std::strcmp(kSupportedPlatforms[i], platform_type) == 0) { - #ifdef DPF_VST3_USING_HOST_RUN_LOOP + #if DPF_VST3_USING_HOST_RUN_LOOP // find host run loop to plug ourselves into (required on some systems) DISTRHO_SAFE_ASSERT_RETURN(view->frame != nullptr, V3_INVALID_ARG); @@ -1183,13 +1353,15 @@ struct dpf_plugin_view : v3_plugin_view_cpp { lastScaleFactor, view->sampleRate, view->instancePointer, - view->nextWidth > 0 && view->nextHeight > 0); + view->nextWidth > 0 && view->nextHeight > 0, + view->sizeRequestedBeforeBeingAttached); view->uivst3->postInit(view->nextWidth, view->nextHeight); view->nextWidth = 0; view->nextHeight = 0; + view->sizeRequestedBeforeBeingAttached = false; - #ifdef DPF_VST3_USING_HOST_RUN_LOOP + #if DPF_VST3_USING_HOST_RUN_LOOP // register a timer host run loop stuff view->timer = new dpf_timer_handler(view->uivst3); v3_cpp_obj(runloop)->register_timer(runloop, @@ -1210,7 +1382,7 @@ struct dpf_plugin_view : v3_plugin_view_cpp { dpf_plugin_view* const view = *static_cast(self); DISTRHO_SAFE_ASSERT_RETURN(view->uivst3 != nullptr, V3_INVALID_ARG); - #ifdef DPF_VST3_USING_HOST_RUN_LOOP + #if DPF_VST3_USING_HOST_RUN_LOOP // unregister our timer as needed if (v3_run_loop** const runloop = view->runloop) { @@ -1297,26 +1469,16 @@ struct dpf_plugin_view : v3_plugin_view_cpp { if (UIVst3* const uivst3 = view->uivst3) return uivst3->getSize(rect); - const float lastScaleFactor = view->scale != nullptr ? view->scale->scaleFactor : 0.0f; - UIExporter tmpUI(nullptr, 0, view->sampleRate, - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - view->instancePointer, lastScaleFactor); - rect->left = rect->top = 0; - view->nextWidth = tmpUI.getWidth(); - view->nextHeight = tmpUI.getHeight(); -#ifdef DISTRHO_OS_MAC - const double scaleFactor = tmpUI.getScaleFactor(); - view->nextWidth /= scaleFactor; - view->nextHeight /= scaleFactor; -#endif - rect->right = view->nextWidth; - rect->bottom = view->nextHeight; - d_stdout("dpf_plugin_view::get_size => %p | next size %u %u with scale factor %f", self, view->nextWidth, view->nextHeight, lastScaleFactor); - return V3_OK; + d_stdout("dpf_plugin_view::get_size => %p | V3_NOT_INITIALIZED", self); + std::memset(rect, 0, sizeof(v3_view_rect)); + view->sizeRequestedBeforeBeingAttached = true; + return V3_NOT_INITIALIZED; } static v3_result V3_API on_size(void* const self, v3_view_rect* const rect) { + d_stdout("dpf_plugin_view::on_size => %p {%d,%d,%d,%d}", + self, rect->top, rect->left, rect->right, rect->bottom); DISTRHO_SAFE_ASSERT_INT2_RETURN(rect->right > rect->left, rect->right, rect->left, V3_INVALID_ARG); DISTRHO_SAFE_ASSERT_INT2_RETURN(rect->bottom > rect->top, rect->bottom, rect->top, V3_INVALID_ARG); @@ -1349,6 +1511,7 @@ struct dpf_plugin_view : v3_plugin_view_cpp { static v3_result V3_API set_frame(void* const self, v3_plugin_frame** const frame) { + d_stdout("dpf_plugin_view::set_frame => %p %p", self, frame); dpf_plugin_view* const view = *static_cast(self); view->frame = frame; @@ -1356,7 +1519,7 @@ struct dpf_plugin_view : v3_plugin_view_cpp { if (UIVst3* const uivst3 = view->uivst3) return uivst3->setFrame(frame); - return V3_NOT_INITIALIZED; + return V3_OK; } static v3_result V3_API can_resize(void* const self) @@ -1378,25 +1541,14 @@ struct dpf_plugin_view : v3_plugin_view_cpp { static v3_result V3_API check_size_constraint(void* const self, v3_view_rect* const rect) { + d_stdout("dpf_plugin_view::check_size_constraint => %p {%d,%d,%d,%d}", + self, rect->top, rect->left, rect->right, rect->bottom); dpf_plugin_view* const view = *static_cast(self); if (UIVst3* const uivst3 = view->uivst3) return uivst3->checkSizeConstraint(rect); - const float lastScaleFactor = view->scale != nullptr ? view->scale->scaleFactor : 0.0f; - UIExporter tmpUI(nullptr, 0, view->sampleRate, - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - view->instancePointer, lastScaleFactor); - uint minimumWidth, minimumHeight; - bool keepAspectRatio; - tmpUI.getGeometryConstraints(minimumWidth, minimumHeight, keepAspectRatio); -#ifdef DISTRHO_OS_MAC - const double scaleFactor = tmpUI.getScaleFactor(); - minimumWidth /= scaleFactor; - minimumHeight /= scaleFactor; -#endif - applyGeometryConstraints(minimumWidth, minimumHeight, keepAspectRatio, rect); - return V3_TRUE; + return V3_NOT_INITIALIZED; } }; diff --git a/dpf/distrho/src/DistrhoUtils.cpp b/dpf/distrho/src/DistrhoUtils.cpp index 772f4b6..fc0ff25 100644 --- a/dpf/distrho/src/DistrhoUtils.cpp +++ b/dpf/distrho/src/DistrhoUtils.cpp @@ -23,12 +23,14 @@ #ifdef DISTRHO_OS_WINDOWS # include #else -# include +# ifndef STATIC_BUILD +# include +# endif # include # include #endif -#if defined(DISTRHO_OS_WINDOWS) && !DISTRHO_IS_STANDALONE +#if defined(DISTRHO_OS_WINDOWS) && !defined(STATIC_BUILD) && !DISTRHO_IS_STANDALONE static HINSTANCE hInstance = nullptr; DISTRHO_PLUGIN_EXPORT @@ -48,22 +50,24 @@ const char* getBinaryFilename() { static String filename; +#ifndef STATIC_BUILD if (filename.isNotEmpty()) return filename; -#ifdef DISTRHO_OS_WINDOWS -# if DISTRHO_IS_STANDALONE +# ifdef DISTRHO_OS_WINDOWS +# if DISTRHO_IS_STANDALONE constexpr const HINSTANCE hInstance = nullptr; -# endif +# endif CHAR filenameBuf[MAX_PATH]; filenameBuf[0] = '\0'; - GetModuleFileName(hInstance, filenameBuf, sizeof(filenameBuf)); + GetModuleFileNameA(hInstance, filenameBuf, sizeof(filenameBuf)); filename = filenameBuf; -#else +# else Dl_info info; dladdr((void*)getBinaryFilename, &info); char filenameBuf[PATH_MAX]; filename = realpath(info.dli_fname, filenameBuf); +# endif #endif return filename; @@ -74,7 +78,11 @@ const char* getPluginFormatName() noexcept #if defined(DISTRHO_PLUGIN_TARGET_CARLA) return "Carla"; #elif defined(DISTRHO_PLUGIN_TARGET_JACK) +# ifdef DISTRHO_OS_WASM + return "Wasm/Standalone"; +# else return "JACK/Standalone"; +# endif #elif defined(DISTRHO_PLUGIN_TARGET_LADSPA) return "LADSPA"; #elif defined(DISTRHO_PLUGIN_TARGET_DSSI) diff --git a/dpf/distrho/src/jackbridge/JackBridge.cpp b/dpf/distrho/src/jackbridge/JackBridge.cpp index 02adf0f..02c3049 100644 --- a/dpf/distrho/src/jackbridge/JackBridge.cpp +++ b/dpf/distrho/src/jackbridge/JackBridge.cpp @@ -1,6 +1,6 @@ /* * JackBridge for DPF - * Copyright (C) 2013-2021 Filipe Coelho + * Copyright (C) 2013-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -15,6 +15,7 @@ */ #include "JackBridge.hpp" +#include "../../DistrhoStandaloneUtils.hpp" #if ! (defined(JACKBRIDGE_DIRECT) || defined(JACKBRIDGE_DUMMY)) @@ -35,14 +36,36 @@ #include #include "../../extra/LibraryUtils.hpp" -// in case JACK fails, we fallback to RtAudio's native API -#if defined(DISTRHO_PROPER_CPP11_SUPPORT) && !defined(DPF_JACK_STANDALONE_SKIP_RTAUDIO_FALLBACK) +// in case JACK fails, we fallback to native bridges simulating JACK API +#include "NativeBridge.hpp" + +#if defined(DISTRHO_OS_WASM) +# include "WebBridge.hpp" +#endif + +#ifndef DISTRHO_PROPER_CPP11_SUPPORT +# undef HAVE_RTAUDIO +#endif + +#ifdef DPF_JACK_STANDALONE_SKIP_RTAUDIO_FALLBACK +# undef HAVE_RTAUDIO +#endif + +#ifdef DPF_JACK_STANDALONE_SKIP_SDL2_FALLBACK +# undef HAVE_SDL2 +#endif + +#if defined(HAVE_RTAUDIO) && DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 # include "RtAudioBridge.hpp" # ifdef RTAUDIO_API_TYPE # include "rtaudio/RtAudio.cpp" # endif #endif +#if defined(HAVE_SDL2) && DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 +# include "SDL2Bridge.hpp" +#endif + // ----------------------------------------------------------------------------- extern "C" { @@ -312,11 +335,6 @@ struct JackBridge { jacksym_set_thread_creator set_thread_creator_ptr; #endif - static bool usingRtAudio; -#ifdef RTAUDIO_API_TYPE - static RtAudioBridge rtAudio; -#endif - JackBridge() : lib(nullptr), get_version_ptr(nullptr), @@ -415,15 +433,21 @@ struct JackBridge { , set_thread_creator_ptr(nullptr) #endif { -# if defined(DISTRHO_OS_MAC) - const char* const filename("libjack.dylib"); -# elif defined(DISTRHO_OS_WINDOWS) && defined(_WIN64) - const char* const filename("libjack64.dll"); -# elif defined(DISTRHO_OS_WINDOWS) - const char* const filename("libjack.dll"); -# else - const char* const filename("libjack.so.0"); -# endif + #ifdef DISTRHO_OS_WASM + // never use jack in wasm + return; + #endif + + #if defined(DISTRHO_OS_MAC) + const char* const filename = "libjack.dylib"; + #elif defined(DISTRHO_OS_WINDOWS) && defined(_WIN64) + const char* const filename = "libjack64.dll"; + #elif defined(DISTRHO_OS_WINDOWS) + const char* const filename = "libjack.dll"; + #else + const char* const filename = "libjack.so.0"; + #endif + USE_NAMESPACE_DISTRHO lib = lib_open(filename); @@ -576,10 +600,9 @@ struct JackBridge { DISTRHO_DECLARE_NON_COPYABLE(JackBridge); }; -bool JackBridge::usingRtAudio = false; -#ifdef RTAUDIO_API_TYPE -RtAudioBridge JackBridge::rtAudio; -#endif +static bool usingNativeBridge = false; +static bool usingRealJACK = true; +static NativeBridge* nativeBridge = nullptr; // ----------------------------------------------------------------------------- @@ -808,7 +831,7 @@ bool jackbridge_is_ok() noexcept { #if defined(JACKBRIDGE_DUMMY) return false; -#elif defined(JACKBRIDGE_DIRECT) || defined(RTAUDIO_API_TYPE) +#elif defined(JACKBRIDGE_DIRECT) || defined(DISTRHO_OS_WASM) || defined(RTAUDIO_API_TYPE) return true; #else return (getBridgeInstance().lib != nullptr); @@ -817,7 +840,7 @@ bool jackbridge_is_ok() noexcept void jackbridge_init() { -#if defined(__WINE__) && ! defined(JACKBRIDGE_DIRECT) +#if defined(__WINE__) && !defined(JACKBRIDGE_DIRECT) if (getBridgeInstance().set_thread_creator_ptr != nullptr) getBridgeInstance().set_thread_creator_ptr(WineBridge::thread_creator); #endif @@ -831,9 +854,8 @@ void jackbridge_get_version(int* major_ptr, int* minor_ptr, int* micro_ptr, int* #elif defined(JACKBRIDGE_DIRECT) return jack_get_version(major_ptr, minor_ptr, micro_ptr, proto_ptr); #else - if (! JackBridge::usingRtAudio) - if (getBridgeInstance().get_version_ptr != nullptr) - return getBridgeInstance().get_version_ptr(major_ptr, minor_ptr, micro_ptr, proto_ptr); + if (usingRealJACK && getBridgeInstance().get_version_ptr != nullptr) + return getBridgeInstance().get_version_ptr(major_ptr, minor_ptr, micro_ptr, proto_ptr); #endif if (major_ptr != nullptr) *major_ptr = 0; @@ -851,11 +873,7 @@ const char* jackbridge_get_version_string() #elif defined(JACKBRIDGE_DIRECT) return jack_get_version_string(); #else -# ifdef RTAUDIO_API_TYPE - if (JackBridge::usingRtAudio) - return RTAUDIO_VERSION; -# endif - if (getBridgeInstance().get_version_string_ptr != nullptr) + if (usingRealJACK && getBridgeInstance().get_version_string_ptr != nullptr) return getBridgeInstance().get_version_string_ptr(); #endif return nullptr; @@ -869,17 +887,40 @@ jack_client_t* jackbridge_client_open(const char* client_name, uint32_t options, #elif defined(JACKBRIDGE_DIRECT) return jack_client_open(client_name, static_cast(options), status); #else + #ifndef DISTRHO_OS_WASM if (getBridgeInstance().client_open_ptr != nullptr) if (jack_client_t* const client = getBridgeInstance().client_open_ptr(client_name, static_cast(options), status)) return client; -# ifdef RTAUDIO_API_TYPE - if (JackBridge::rtAudio.open()) - { - d_stdout("JACK setup failed, using RtAudio instead"); - JackBridge::usingRtAudio = true; - return (jack_client_t*)0x1; // return non-null - } -# endif + #endif + + static jack_client_t* const kValidClient = (jack_client_t*)0x1; + + // maybe unused + (void)kValidClient; + + usingNativeBridge = true; + usingRealJACK = false; + + #ifdef DISTRHO_OS_WASM + nativeBridge = new WebBridge; + if (nativeBridge->open(client_name)) + return kValidClient; + delete nativeBridge; + #endif + + #if defined(HAVE_RTAUDIO) && defined(RTAUDIO_API_TYPE) + nativeBridge = new RtAudioBridge; + if (nativeBridge->open(client_name)) + return kValidClient; + delete nativeBridge; + #endif + + #if defined(HAVE_SDL2) && DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + nativeBridge = new SDL2Bridge; + if (nativeBridge->open(client_name)) + return kValidClient; + delete nativeBridge; + #endif #endif if (status != nullptr) *status = JackServerError; @@ -892,13 +933,18 @@ bool jackbridge_client_close(jack_client_t* client) #elif defined(JACKBRIDGE_DIRECT) return (jack_client_close(client) == 0); #else -# ifdef RTAUDIO_API_TYPE - if (JackBridge::usingRtAudio) + if (usingNativeBridge) { - JackBridge::usingRtAudio = false; - return JackBridge::rtAudio.close(); + if (nativeBridge != nullptr) + { + nativeBridge->close(); + delete nativeBridge; + nativeBridge = nullptr; + } + usingNativeBridge = false; + usingRealJACK = true; + return true; } -# endif if (getBridgeInstance().client_close_ptr != nullptr) return (getBridgeInstance().client_close_ptr(client) == 0); #endif @@ -913,24 +959,20 @@ int jackbridge_client_name_size() #elif defined(JACKBRIDGE_DIRECT) return jack_client_name_size(); #else - if (! JackBridge::usingRtAudio) - if (getBridgeInstance().client_name_size_ptr != nullptr) - return getBridgeInstance().client_name_size_ptr(); + if (usingRealJACK && getBridgeInstance().client_name_size_ptr != nullptr) + return getBridgeInstance().client_name_size_ptr(); #endif return 33; } -char* jackbridge_get_client_name(jack_client_t* client) +const char* jackbridge_get_client_name(jack_client_t* client) { #if defined(JACKBRIDGE_DUMMY) #elif defined(JACKBRIDGE_DIRECT) return jack_get_client_name(client); #else - if (JackBridge::usingRtAudio) - { - char* const name = (char*)DISTRHO_PLUGIN_NAME; - return name; - } + if (usingNativeBridge) + return DISTRHO_PLUGIN_NAME; if (getBridgeInstance().get_client_name_ptr != nullptr) return getBridgeInstance().get_client_name_ptr(client); #endif @@ -945,7 +987,7 @@ char* jackbridge_client_get_uuid(jack_client_t* client) #elif defined(JACKBRIDGE_DIRECT) return jack_client_get_uuid(client); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (const jacksym_client_get_uuid func = getBridgeInstance().client_get_uuid_ptr) return func(client); #endif @@ -958,7 +1000,7 @@ char* jackbridge_get_uuid_for_client_name(jack_client_t* client, const char* nam #elif defined(JACKBRIDGE_DIRECT) return jack_get_uuid_for_client_name(client, name); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().get_uuid_for_client_name_ptr != nullptr) return getBridgeInstance().get_uuid_for_client_name_ptr(client, name); #endif @@ -971,7 +1013,7 @@ char* jackbridge_get_client_name_by_uuid(jack_client_t* client, const char* uuid #elif defined(JACKBRIDGE_DIRECT) return jack_get_client_name_by_uuid(client, uuid); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().get_client_name_by_uuid_ptr != nullptr) return getBridgeInstance().get_client_name_by_uuid_ptr(client, uuid); #endif @@ -986,7 +1028,7 @@ bool jackbridge_uuid_parse(const char* buf, jack_uuid_t* uuid) #elif defined(JACKBRIDGE_DIRECT) return (jack_uuid_parse(buf, uuid) == 0); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (const jacksym_uuid_parse func = getBridgeInstance().uuid_parse_ptr) return (func(buf, uuid) == 0); #endif @@ -999,7 +1041,7 @@ void jackbridge_uuid_unparse(jack_uuid_t uuid, char buf[JACK_UUID_STRING_SIZE]) #elif defined(JACKBRIDGE_DIRECT) jack_uuid_unparse(uuid, buf); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (const jacksym_uuid_unparse func = getBridgeInstance().uuid_unparse_ptr) return func(uuid, buf); #endif @@ -1013,10 +1055,8 @@ bool jackbridge_activate(jack_client_t* client) #elif defined(JACKBRIDGE_DIRECT) return (jack_activate(client) == 0); #else -# ifdef RTAUDIO_API_TYPE - if (JackBridge::usingRtAudio) - return JackBridge::rtAudio.activate(); -# endif + if (usingNativeBridge) + return nativeBridge->activate(); if (getBridgeInstance().activate_ptr != nullptr) return (getBridgeInstance().activate_ptr(client) == 0); #endif @@ -1029,10 +1069,8 @@ bool jackbridge_deactivate(jack_client_t* client) #elif defined(JACKBRIDGE_DIRECT) return (jack_deactivate(client) == 0); #else -# ifdef RTAUDIO_API_TYPE - if (JackBridge::usingRtAudio) - return JackBridge::rtAudio.deactivate(); -# endif + if (usingNativeBridge) + return nativeBridge->deactivate(); if (getBridgeInstance().deactivate_ptr != nullptr) return (getBridgeInstance().deactivate_ptr(client) == 0); #endif @@ -1045,7 +1083,7 @@ bool jackbridge_is_realtime(jack_client_t* client) #elif defined(JACKBRIDGE_DIRECT) return jack_is_realtime(client); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().is_realtime_ptr != nullptr) return getBridgeInstance().is_realtime_ptr(client); #endif @@ -1060,7 +1098,7 @@ bool jackbridge_set_thread_init_callback(jack_client_t* client, JackThreadInitCa #elif defined(JACKBRIDGE_DIRECT) return (jack_set_thread_init_callback(client, thread_init_callback, arg) == 0); #else - if (! JackBridge::usingRtAudio && getBridgeInstance().set_thread_init_callback_ptr != nullptr) + if (usingRealJACK && getBridgeInstance().set_thread_init_callback_ptr != nullptr) { # ifdef __WINE__ WineBridge::getInstance().set_thread_init(thread_init_callback); @@ -1079,7 +1117,7 @@ void jackbridge_on_shutdown(jack_client_t* client, JackShutdownCallback shutdown #elif defined(JACKBRIDGE_DIRECT) jack_on_shutdown(client, shutdown_callback, arg); #else - if (! JackBridge::usingRtAudio && getBridgeInstance().on_shutdown_ptr != nullptr) + if (usingRealJACK && getBridgeInstance().on_shutdown_ptr != nullptr) { # ifdef __WINE__ WineBridge::getInstance().set_shutdown(shutdown_callback); @@ -1097,7 +1135,7 @@ void jackbridge_on_info_shutdown(jack_client_t* client, JackInfoShutdownCallback #elif defined(JACKBRIDGE_DIRECT) jack_on_info_shutdown(client, shutdown_callback, arg); #else - if (! JackBridge::usingRtAudio && getBridgeInstance().on_info_shutdown_ptr != nullptr) + if (usingRealJACK && getBridgeInstance().on_info_shutdown_ptr != nullptr) { # ifdef __WINE__ WineBridge::getInstance().set_info_shutdown(shutdown_callback); @@ -1115,14 +1153,12 @@ bool jackbridge_set_process_callback(jack_client_t* client, JackProcessCallback #elif defined(JACKBRIDGE_DIRECT) return (jack_set_process_callback(client, process_callback, arg) == 0); #else -# ifdef RTAUDIO_API_TYPE - if (JackBridge::usingRtAudio) + if (usingNativeBridge) { - JackBridge::rtAudio.jackProcessCallback = process_callback; - JackBridge::rtAudio.jackProcessArg = arg; + nativeBridge->jackProcessCallback = process_callback; + nativeBridge->jackProcessArg = arg; return true; } -# endif if (getBridgeInstance().set_process_callback_ptr != nullptr) { # ifdef __WINE__ @@ -1142,7 +1178,7 @@ bool jackbridge_set_freewheel_callback(jack_client_t* client, JackFreewheelCallb #elif defined(JACKBRIDGE_DIRECT) return (jack_set_freewheel_callback(client, freewheel_callback, arg) == 0); #else - if (! JackBridge::usingRtAudio && getBridgeInstance().set_freewheel_callback_ptr != nullptr) + if (usingRealJACK && getBridgeInstance().set_freewheel_callback_ptr != nullptr) { # ifdef __WINE__ WineBridge::getInstance().set_freewheel(freewheel_callback); @@ -1161,7 +1197,13 @@ bool jackbridge_set_buffer_size_callback(jack_client_t* client, JackBufferSizeCa #elif defined(JACKBRIDGE_DIRECT) return (jack_set_buffer_size_callback(client, bufsize_callback, arg) == 0); #else - if (! JackBridge::usingRtAudio && getBridgeInstance().set_buffer_size_callback_ptr != nullptr) + if (usingNativeBridge) + { + nativeBridge->bufferSizeCallback = bufsize_callback; + nativeBridge->jackBufferSizeArg = arg; + return true; + } + if (getBridgeInstance().set_buffer_size_callback_ptr != nullptr) { # ifdef __WINE__ WineBridge::getInstance().set_bufsize(bufsize_callback); @@ -1180,7 +1222,7 @@ bool jackbridge_set_sample_rate_callback(jack_client_t* client, JackSampleRateCa #elif defined(JACKBRIDGE_DIRECT) return (jack_set_sample_rate_callback(client, srate_callback, arg) == 0); #else - if (! JackBridge::usingRtAudio && getBridgeInstance().set_sample_rate_callback_ptr != nullptr) + if (usingRealJACK && getBridgeInstance().set_sample_rate_callback_ptr != nullptr) { # ifdef __WINE__ WineBridge::getInstance().set_srate(srate_callback); @@ -1199,7 +1241,7 @@ bool jackbridge_set_client_registration_callback(jack_client_t* client, JackClie #elif defined(JACKBRIDGE_DIRECT) return (jack_set_client_registration_callback(client, registration_callback, arg) == 0); #else - if (! JackBridge::usingRtAudio && getBridgeInstance().set_client_registration_callback_ptr != nullptr) + if (usingRealJACK && getBridgeInstance().set_client_registration_callback_ptr != nullptr) { # ifdef __WINE__ WineBridge::getInstance().set_client_reg(registration_callback); @@ -1218,7 +1260,7 @@ bool jackbridge_set_port_registration_callback(jack_client_t* client, JackPortRe #elif defined(JACKBRIDGE_DIRECT) return (jack_set_port_registration_callback(client, registration_callback, arg) == 0); #else - if (! JackBridge::usingRtAudio && getBridgeInstance().set_port_registration_callback_ptr != nullptr) + if (usingRealJACK && getBridgeInstance().set_port_registration_callback_ptr != nullptr) { # ifdef __WINE__ WineBridge::getInstance().set_port_reg(registration_callback); @@ -1237,7 +1279,7 @@ bool jackbridge_set_port_rename_callback(jack_client_t* client, JackPortRenameCa #elif defined(JACKBRIDGE_DIRECT) return (jack_set_port_rename_callback(client, rename_callback, arg) == 0); #else - if (! JackBridge::usingRtAudio && getBridgeInstance().set_port_rename_callback_ptr != nullptr) + if (usingRealJACK && getBridgeInstance().set_port_rename_callback_ptr != nullptr) { # ifdef __WINE__ WineBridge::getInstance().set_port_rename(rename_callback); @@ -1256,7 +1298,7 @@ bool jackbridge_set_port_connect_callback(jack_client_t* client, JackPortConnect #elif defined(JACKBRIDGE_DIRECT) return (jack_set_port_connect_callback(client, connect_callback, arg) == 0); #else - if (! JackBridge::usingRtAudio && getBridgeInstance().set_port_connect_callback_ptr != nullptr) + if (usingRealJACK && getBridgeInstance().set_port_connect_callback_ptr != nullptr) { # ifdef __WINE__ WineBridge::getInstance().set_port_conn(connect_callback); @@ -1275,7 +1317,7 @@ bool jackbridge_set_graph_order_callback(jack_client_t* client, JackGraphOrderCa #elif defined(JACKBRIDGE_DIRECT) return (jack_set_graph_order_callback(client, graph_callback, arg) == 0); #else - if (! JackBridge::usingRtAudio && getBridgeInstance().set_graph_order_callback_ptr != nullptr) + if (usingRealJACK && getBridgeInstance().set_graph_order_callback_ptr != nullptr) { # ifdef __WINE__ WineBridge::getInstance().set_graph_order(graph_callback); @@ -1294,7 +1336,7 @@ bool jackbridge_set_xrun_callback(jack_client_t* client, JackXRunCallback xrun_c #elif defined(JACKBRIDGE_DIRECT) return (jack_set_xrun_callback(client, xrun_callback, arg) == 0); #else - if (! JackBridge::usingRtAudio && getBridgeInstance().set_xrun_callback_ptr != nullptr) + if (usingRealJACK && getBridgeInstance().set_xrun_callback_ptr != nullptr) { # ifdef __WINE__ WineBridge::getInstance().set_xrun(xrun_callback); @@ -1313,7 +1355,7 @@ bool jackbridge_set_latency_callback(jack_client_t* client, JackLatencyCallback #elif defined(JACKBRIDGE_DIRECT) return (jack_set_latency_callback(client, latency_callback, arg) == 0); #else - if (! JackBridge::usingRtAudio && getBridgeInstance().set_latency_callback_ptr != nullptr) + if (usingRealJACK && getBridgeInstance().set_latency_callback_ptr != nullptr) { # ifdef __WINE__ WineBridge::getInstance().set_latency(latency_callback); @@ -1334,7 +1376,7 @@ bool jackbridge_set_freewheel(jack_client_t* client, bool onoff) #elif defined(JACKBRIDGE_DIRECT) return jack_set_freewheel(client, onoff); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().set_freewheel_ptr != nullptr) return getBridgeInstance().set_freewheel_ptr(client, onoff); #endif @@ -1347,9 +1389,10 @@ bool jackbridge_set_buffer_size(jack_client_t* client, jack_nframes_t nframes) #elif defined(JACKBRIDGE_DIRECT) return jack_set_buffer_size(client, nframes); #else - if (! JackBridge::usingRtAudio) - if (getBridgeInstance().set_buffer_size_ptr != nullptr) - return getBridgeInstance().set_buffer_size_ptr(client, nframes); + if (usingNativeBridge) + return nativeBridge->requestBufferSizeChange(nframes); + if (getBridgeInstance().set_buffer_size_ptr != nullptr) + return getBridgeInstance().set_buffer_size_ptr(client, nframes); #endif return false; } @@ -1362,10 +1405,8 @@ jack_nframes_t jackbridge_get_sample_rate(jack_client_t* client) #elif defined(JACKBRIDGE_DIRECT) return jack_get_sample_rate(client); #else -# ifdef RTAUDIO_API_TYPE - if (JackBridge::usingRtAudio) - return JackBridge::rtAudio.sampleRate; -# endif + if (usingNativeBridge) + return nativeBridge->sampleRate; if (getBridgeInstance().get_sample_rate_ptr != nullptr) return getBridgeInstance().get_sample_rate_ptr(client); #endif @@ -1378,10 +1419,8 @@ jack_nframes_t jackbridge_get_buffer_size(jack_client_t* client) #elif defined(JACKBRIDGE_DIRECT) return jack_get_buffer_size(client); #else -# ifdef RTAUDIO_API_TYPE - if (JackBridge::usingRtAudio) - return JackBridge::rtAudio.bufferSize; -# endif + if (usingNativeBridge) + return nativeBridge->bufferSize; if (getBridgeInstance().get_buffer_size_ptr != nullptr) return getBridgeInstance().get_buffer_size_ptr(client); #endif @@ -1394,7 +1433,7 @@ float jackbridge_cpu_load(jack_client_t* client) #elif defined(JACKBRIDGE_DIRECT) return jack_cpu_load(client); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().cpu_load_ptr != nullptr) return getBridgeInstance().cpu_load_ptr(client); #endif @@ -1409,10 +1448,8 @@ jack_port_t* jackbridge_port_register(jack_client_t* client, const char* port_na #elif defined(JACKBRIDGE_DIRECT) return jack_port_register(client, port_name, type, flags, buffer_size); #else -# ifdef RTAUDIO_API_TYPE - if (JackBridge::usingRtAudio) - return JackBridge::rtAudio.registerPort(type, flags); -# endif + if (usingNativeBridge) + return nativeBridge->registerPort(type, flags); if (getBridgeInstance().port_register_ptr != nullptr) return getBridgeInstance().port_register_ptr(client, port_name, type, static_cast(flags), @@ -1427,7 +1464,7 @@ bool jackbridge_port_unregister(jack_client_t* client, jack_port_t* port) #elif defined(JACKBRIDGE_DIRECT) return (jack_port_unregister(client, port) == 0); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().port_unregister_ptr != nullptr) return (getBridgeInstance().port_unregister_ptr(client, port) == 0); #endif @@ -1440,10 +1477,8 @@ void* jackbridge_port_get_buffer(jack_port_t* port, jack_nframes_t nframes) #elif defined(JACKBRIDGE_DIRECT) return jack_port_get_buffer(port, nframes); #else -# ifdef RTAUDIO_API_TYPE - if (JackBridge::usingRtAudio) - return JackBridge::rtAudio.getPortBuffer(port); -# endif + if (usingNativeBridge) + return nativeBridge->getPortBuffer(port); if (getBridgeInstance().port_get_buffer_ptr != nullptr) return getBridgeInstance().port_get_buffer_ptr(port, nframes); #endif @@ -1458,7 +1493,7 @@ const char* jackbridge_port_name(const jack_port_t* port) #elif defined(JACKBRIDGE_DIRECT) return jack_port_name(port); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().port_name_ptr != nullptr) return getBridgeInstance().port_name_ptr(port); #endif @@ -1471,7 +1506,7 @@ jack_uuid_t jackbridge_port_uuid(const jack_port_t* port) #elif defined(JACKBRIDGE_DIRECT) return jack_port_uuid(port); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().port_uuid_ptr != nullptr) return getBridgeInstance().port_uuid_ptr(port); #endif @@ -1484,7 +1519,7 @@ const char* jackbridge_port_short_name(const jack_port_t* port) #elif defined(JACKBRIDGE_DIRECT) return jack_port_short_name(port); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().port_short_name_ptr != nullptr) return getBridgeInstance().port_short_name_ptr(port); #endif @@ -1497,7 +1532,7 @@ int jackbridge_port_flags(const jack_port_t* port) #elif defined(JACKBRIDGE_DIRECT) return jack_port_flags(port); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().port_flags_ptr != nullptr) return getBridgeInstance().port_flags_ptr(port); #endif @@ -1510,7 +1545,7 @@ const char* jackbridge_port_type(const jack_port_t* port) #elif defined(JACKBRIDGE_DIRECT) return jack_port_type(port); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().port_type_ptr != nullptr) return getBridgeInstance().port_type_ptr(port); #endif @@ -1523,7 +1558,7 @@ bool jackbridge_port_is_mine(const jack_client_t* client, const jack_port_t* por #elif defined(JACKBRIDGE_DIRECT) return jack_port_is_mine(client, port); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().port_is_mine_ptr != nullptr) return getBridgeInstance().port_is_mine_ptr(client, port); #endif @@ -1536,7 +1571,7 @@ int jackbridge_port_connected(const jack_port_t* port) #elif defined(JACKBRIDGE_DIRECT) return jack_port_connected(port); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().port_connected_ptr != nullptr) return getBridgeInstance().port_connected_ptr(port); #endif @@ -1549,7 +1584,7 @@ bool jackbridge_port_connected_to(const jack_port_t* port, const char* port_name #elif defined(JACKBRIDGE_DIRECT) return jack_port_connected_to(port, port_name); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().port_connected_to_ptr != nullptr) return getBridgeInstance().port_connected_to_ptr(port, port_name); #endif @@ -1562,7 +1597,7 @@ const char** jackbridge_port_get_connections(const jack_port_t* port) #elif defined(JACKBRIDGE_DIRECT) return jack_port_get_connections(port); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().port_get_connections_ptr != nullptr) return getBridgeInstance().port_get_connections_ptr(port); #endif @@ -1575,7 +1610,7 @@ const char** jackbridge_port_get_all_connections(const jack_client_t* client, co #elif defined(JACKBRIDGE_DIRECT) return jack_port_get_all_connections(client, port); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().port_get_all_connections_ptr != nullptr) return getBridgeInstance().port_get_all_connections_ptr(client, port); #endif @@ -1590,7 +1625,7 @@ bool jackbridge_port_rename(jack_client_t* client, jack_port_t* port, const char #elif defined(JACKBRIDGE_DIRECT) return (jack_port_rename(client, port, port_name) == 0); #else - if (JackBridge::usingRtAudio) + if (usingNativeBridge) return false; // Try new API first if (getBridgeInstance().port_rename_ptr != nullptr) @@ -1608,7 +1643,7 @@ bool jackbridge_port_set_alias(jack_port_t* port, const char* alias) #elif defined(JACKBRIDGE_DIRECT) return (jack_port_set_alias(port, alias) == 0); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().port_set_alias_ptr != nullptr) return (getBridgeInstance().port_set_alias_ptr(port, alias) == 0); #endif @@ -1621,7 +1656,7 @@ bool jackbridge_port_unset_alias(jack_port_t* port, const char* alias) #elif defined(JACKBRIDGE_DIRECT) return (jack_port_unset_alias(port, alias) == 0); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().port_unset_alias_ptr != nullptr) return (getBridgeInstance().port_unset_alias_ptr(port, alias) == 0); #endif @@ -1634,7 +1669,7 @@ int jackbridge_port_get_aliases(const jack_port_t* port, char* const aliases[2]) #elif defined(JACKBRIDGE_DIRECT) return (jack_port_get_aliases(port, aliases) == 0); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().port_get_aliases_ptr != nullptr) return getBridgeInstance().port_get_aliases_ptr(port, aliases); #endif @@ -1649,7 +1684,7 @@ bool jackbridge_port_request_monitor(jack_port_t* port, bool onoff) #elif defined(JACKBRIDGE_DIRECT) return (jack_port_request_monitor(port, onoff) == 0); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().port_request_monitor_ptr != nullptr) return (getBridgeInstance().port_request_monitor_ptr(port, onoff) == 0); #endif @@ -1662,7 +1697,7 @@ bool jackbridge_port_request_monitor_by_name(jack_client_t* client, const char* #elif defined(JACKBRIDGE_DIRECT) return (jack_port_request_monitor_by_name(client, port_name, onoff) == 0); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().port_request_monitor_by_name_ptr != nullptr) return (getBridgeInstance().port_request_monitor_by_name_ptr(client, port_name, onoff) == 0); #endif @@ -1675,7 +1710,7 @@ bool jackbridge_port_ensure_monitor(jack_port_t* port, bool onoff) #elif defined(JACKBRIDGE_DIRECT) return (jack_port_ensure_monitor(port, onoff) == 0); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().port_ensure_monitor_ptr != nullptr) return (getBridgeInstance().port_ensure_monitor_ptr(port, onoff) == 0); #endif @@ -1688,7 +1723,7 @@ bool jackbridge_port_monitoring_input(jack_port_t* port) #elif defined(JACKBRIDGE_DIRECT) return jack_port_monitoring_input(port); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().port_monitoring_input_ptr != nullptr) return getBridgeInstance().port_monitoring_input_ptr(port); #endif @@ -1703,7 +1738,7 @@ bool jackbridge_connect(jack_client_t* client, const char* source_port, const ch #elif defined(JACKBRIDGE_DIRECT) return (jack_connect(client, source_port, destination_port) == 0); #else - if (! JackBridge::usingRtAudio && getBridgeInstance().connect_ptr != nullptr) + if (usingRealJACK && getBridgeInstance().connect_ptr != nullptr) { const int ret = getBridgeInstance().connect_ptr(client, source_port, destination_port); return ret == 0 || ret == EEXIST; @@ -1718,7 +1753,7 @@ bool jackbridge_disconnect(jack_client_t* client, const char* source_port, const #elif defined(JACKBRIDGE_DIRECT) return (jack_disconnect(client, source_port, destination_port) == 0); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().disconnect_ptr != nullptr) return (getBridgeInstance().disconnect_ptr(client, source_port, destination_port) == 0); #endif @@ -1731,7 +1766,7 @@ bool jackbridge_port_disconnect(jack_client_t* client, jack_port_t* port) #elif defined(JACKBRIDGE_DIRECT) return (jack_port_disconnect(client, port) == 0); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().port_disconnect_ptr != nullptr) return (getBridgeInstance().port_disconnect_ptr(client, port) == 0); #endif @@ -1746,7 +1781,7 @@ int jackbridge_port_name_size() #elif defined(JACKBRIDGE_DIRECT) return jack_port_name_size(); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().port_name_size_ptr != nullptr) return getBridgeInstance().port_name_size_ptr(); #endif @@ -1759,7 +1794,7 @@ int jackbridge_port_type_size() #elif defined(JACKBRIDGE_DIRECT) return jack_port_type_size(); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().port_type_size_ptr != nullptr) return getBridgeInstance().port_type_size_ptr(); #endif @@ -1772,7 +1807,7 @@ uint32_t jackbridge_port_type_get_buffer_size(jack_client_t* client, const char* #elif defined(JACKBRIDGE_DIRECT) return static_cast(jack_port_type_get_buffer_size(client, port_type)); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().port_type_get_buffer_size_ptr != nullptr) return static_cast(getBridgeInstance().port_type_get_buffer_size_ptr(client, port_type)); #endif @@ -1787,7 +1822,7 @@ void jackbridge_port_get_latency_range(jack_port_t* port, uint32_t mode, jack_la #elif defined(JACKBRIDGE_DIRECT) return jack_port_get_latency_range(port, static_cast(mode), range); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().port_get_latency_range_ptr != nullptr) return getBridgeInstance().port_get_latency_range_ptr(port, static_cast(mode), @@ -1803,7 +1838,7 @@ void jackbridge_port_set_latency_range(jack_port_t* port, uint32_t mode, jack_la #elif defined(JACKBRIDGE_DIRECT) jack_port_set_latency_range(port, static_cast(mode), range); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().port_set_latency_range_ptr != nullptr) getBridgeInstance().port_set_latency_range_ptr(port, static_cast(mode), @@ -1817,7 +1852,7 @@ bool jackbridge_recompute_total_latencies(jack_client_t* client) #elif defined(JACKBRIDGE_DIRECT) return (jack_recompute_total_latencies(client) == 0); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().recompute_total_latencies_ptr != nullptr) return (getBridgeInstance().recompute_total_latencies_ptr(client) == 0); #endif @@ -1832,7 +1867,7 @@ const char** jackbridge_get_ports(jack_client_t* client, const char* port_name_p #elif defined(JACKBRIDGE_DIRECT) return jack_get_ports(client, port_name_pattern, type_name_pattern, flags); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().get_ports_ptr != nullptr) return getBridgeInstance().get_ports_ptr(client, port_name_pattern, type_name_pattern, static_cast(flags)); @@ -1846,7 +1881,7 @@ jack_port_t* jackbridge_port_by_name(jack_client_t* client, const char* port_nam #elif defined(JACKBRIDGE_DIRECT) return jack_port_by_name(client, port_name); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().port_by_name_ptr != nullptr) return getBridgeInstance().port_by_name_ptr(client, port_name); #endif @@ -1859,7 +1894,7 @@ jack_port_t* jackbridge_port_by_id(jack_client_t* client, jack_port_id_t port_id #elif defined(JACKBRIDGE_DIRECT) return jack_port_by_id(client, port_id); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().port_by_id_ptr != nullptr) return getBridgeInstance().port_by_id_ptr(client, port_id); #endif @@ -1874,7 +1909,7 @@ void jackbridge_free(void* ptr) #elif defined(JACKBRIDGE_DIRECT) return jack_free(ptr); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().free_ptr != nullptr) return getBridgeInstance().free_ptr(ptr); @@ -1891,9 +1926,10 @@ uint32_t jackbridge_midi_get_event_count(void* port_buffer) #elif defined(JACKBRIDGE_DIRECT) return jack_midi_get_event_count(port_buffer); #else - if (! JackBridge::usingRtAudio) - if (getBridgeInstance().midi_get_event_count_ptr != nullptr) - return getBridgeInstance().midi_get_event_count_ptr(port_buffer); + if (usingNativeBridge) + return nativeBridge->getEventCount(); + if (getBridgeInstance().midi_get_event_count_ptr != nullptr) + return getBridgeInstance().midi_get_event_count_ptr(port_buffer); #endif return 0; } @@ -1904,9 +1940,10 @@ bool jackbridge_midi_event_get(jack_midi_event_t* event, void* port_buffer, uint #elif defined(JACKBRIDGE_DIRECT) return (jack_midi_event_get(event, port_buffer, event_index) == 0); #else - if (! JackBridge::usingRtAudio) - if (getBridgeInstance().midi_event_get_ptr != nullptr) - return (getBridgeInstance().midi_event_get_ptr(event, port_buffer, event_index) == 0); + if (usingNativeBridge) + return nativeBridge->getEvent(event); + if (getBridgeInstance().midi_event_get_ptr != nullptr) + return (getBridgeInstance().midi_event_get_ptr(event, port_buffer, event_index) == 0); #endif return false; } @@ -1917,9 +1954,10 @@ void jackbridge_midi_clear_buffer(void* port_buffer) #elif defined(JACKBRIDGE_DIRECT) jack_midi_clear_buffer(port_buffer); #else - if (! JackBridge::usingRtAudio) - if (getBridgeInstance().midi_clear_buffer_ptr != nullptr) - getBridgeInstance().midi_clear_buffer_ptr(port_buffer); + if (usingNativeBridge) + return nativeBridge->clearEventBuffer(); + if (getBridgeInstance().midi_clear_buffer_ptr != nullptr) + getBridgeInstance().midi_clear_buffer_ptr(port_buffer); #endif } @@ -1929,9 +1967,10 @@ bool jackbridge_midi_event_write(void* port_buffer, jack_nframes_t time, const j #elif defined(JACKBRIDGE_DIRECT) return (jack_midi_event_write(port_buffer, time, data, data_size) == 0); #else - if (! JackBridge::usingRtAudio) - if (getBridgeInstance().midi_event_write_ptr != nullptr) - return (getBridgeInstance().midi_event_write_ptr(port_buffer, time, data, data_size) == 0); + if (usingNativeBridge) + return nativeBridge->writeEvent(time, data, data_size); + if (getBridgeInstance().midi_event_write_ptr != nullptr) + return (getBridgeInstance().midi_event_write_ptr(port_buffer, time, data, data_size) == 0); #endif return false; } @@ -1942,7 +1981,7 @@ jack_midi_data_t* jackbridge_midi_event_reserve(void* port_buffer, jack_nframes_ #elif defined(JACKBRIDGE_DIRECT) return jack_midi_event_reserve(port_buffer, time, data_size); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().midi_event_reserve_ptr != nullptr) return getBridgeInstance().midi_event_reserve_ptr(port_buffer, time, data_size); #endif @@ -1957,7 +1996,7 @@ bool jackbridge_release_timebase(jack_client_t* client) #elif defined(JACKBRIDGE_DIRECT) return (jack_release_timebase(client) == 0); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().release_timebase_ptr != nullptr) return (getBridgeInstance().release_timebase_ptr(client) == 0); #endif @@ -1970,7 +2009,7 @@ bool jackbridge_set_sync_callback(jack_client_t* client, JackSyncCallback sync_c #elif defined(JACKBRIDGE_DIRECT) return (jack_set_sync_callback(client, sync_callback, arg) == 0); #else - if (! JackBridge::usingRtAudio && getBridgeInstance().set_sync_callback_ptr != nullptr) + if (usingRealJACK && getBridgeInstance().set_sync_callback_ptr != nullptr) { # ifdef __WINE__ WineBridge::getInstance().set_sync(sync_callback); @@ -1989,7 +2028,7 @@ bool jackbridge_set_sync_timeout(jack_client_t* client, jack_time_t timeout) #elif defined(JACKBRIDGE_DIRECT) return (jack_set_sync_timeout(client, timeout) == 0); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().set_sync_timeout_ptr != nullptr) return (getBridgeInstance().set_sync_timeout_ptr(client, timeout) == 0); #endif @@ -2002,7 +2041,7 @@ bool jackbridge_set_timebase_callback(jack_client_t* client, bool conditional, J #elif defined(JACKBRIDGE_DIRECT) return (jack_set_timebase_callback(client, conditional, timebase_callback, arg) == 0); #else - if (! JackBridge::usingRtAudio && getBridgeInstance().set_timebase_callback_ptr != nullptr) + if (usingRealJACK && getBridgeInstance().set_timebase_callback_ptr != nullptr) { # ifdef __WINE__ WineBridge::getInstance().set_timebase(timebase_callback); @@ -2021,7 +2060,7 @@ bool jackbridge_transport_locate(jack_client_t* client, jack_nframes_t frame) #elif defined(JACKBRIDGE_DIRECT) return (jack_transport_locate(client, frame) == 0); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().transport_locate_ptr != nullptr) return (getBridgeInstance().transport_locate_ptr(client, frame) == 0); #endif @@ -2034,7 +2073,7 @@ uint32_t jackbridge_transport_query(const jack_client_t* client, jack_position_t #elif defined(JACKBRIDGE_DIRECT) return jack_transport_query(client, pos); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().transport_query_ptr != nullptr) return getBridgeInstance().transport_query_ptr(client, pos); #endif @@ -2054,7 +2093,7 @@ jack_nframes_t jackbridge_get_current_transport_frame(const jack_client_t* clien #elif defined(JACKBRIDGE_DIRECT) return jack_get_current_transport_frame(client); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().get_current_transport_frame_ptr != nullptr) return getBridgeInstance().get_current_transport_frame_ptr(client); #endif @@ -2067,7 +2106,7 @@ bool jackbridge_transport_reposition(jack_client_t* client, const jack_position_ #elif defined(JACKBRIDGE_DIRECT) return (jack_transport_reposition(client, pos) == 0); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().transport_reposition_ptr != nullptr) return (getBridgeInstance().transport_reposition_ptr(client, pos) == 0); #endif @@ -2080,7 +2119,7 @@ void jackbridge_transport_start(jack_client_t* client) #elif defined(JACKBRIDGE_DIRECT) jack_transport_start(client); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().transport_start_ptr != nullptr) getBridgeInstance().transport_start_ptr(client); #endif @@ -2092,7 +2131,7 @@ void jackbridge_transport_stop(jack_client_t* client) #elif defined(JACKBRIDGE_DIRECT) jack_transport_stop(client); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().transport_stop_ptr != nullptr) getBridgeInstance().transport_stop_ptr(client); #endif @@ -2106,7 +2145,7 @@ bool jackbridge_set_property(jack_client_t* client, jack_uuid_t subject, const c #elif defined(JACKBRIDGE_DIRECT) return (jack_set_property(client, subject, key, value, type) == 0); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().set_property_ptr != nullptr) return (getBridgeInstance().set_property_ptr(client, subject, key, value, type) == 0); #endif @@ -2119,7 +2158,7 @@ bool jackbridge_get_property(jack_uuid_t subject, const char* key, char** value, #elif defined(JACKBRIDGE_DIRECT) return (jack_get_property(subject, key, value, type) == 0); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().get_property_ptr != nullptr) return (getBridgeInstance().get_property_ptr(subject, key, value, type) == 0); #endif @@ -2132,7 +2171,7 @@ void jackbridge_free_description(jack_description_t* desc, bool free_description #elif defined(JACKBRIDGE_DIRECT) jack_free_description(desc, free_description_itself); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().free_description_ptr != nullptr) getBridgeInstance().free_description_ptr(desc, free_description_itself); #endif @@ -2144,7 +2183,7 @@ bool jackbridge_get_properties(jack_uuid_t subject, jack_description_t* desc) #elif defined(JACKBRIDGE_DIRECT) return (jack_get_properties(subject, desc) == 0); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().get_properties_ptr != nullptr) return (getBridgeInstance().get_properties_ptr(subject, desc) == 0); #endif @@ -2157,7 +2196,7 @@ bool jackbridge_get_all_properties(jack_description_t** descs) #elif defined(JACKBRIDGE_DIRECT) return (jack_get_all_properties(descs) == 0); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().get_all_properties_ptr != nullptr) return (getBridgeInstance().get_all_properties_ptr(descs) == 0); #endif @@ -2170,7 +2209,7 @@ bool jackbridge_remove_property(jack_client_t* client, jack_uuid_t subject, cons #elif defined(JACKBRIDGE_DIRECT) return (jack_remove_property(client, subject, key) == 0); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().remove_property_ptr != nullptr) return (getBridgeInstance().remove_property_ptr(client, subject, key) == 0); #endif @@ -2183,7 +2222,7 @@ int jackbridge_remove_properties(jack_client_t* client, jack_uuid_t subject) #elif defined(JACKBRIDGE_DIRECT) return jack_remove_properties(client, subject); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().remove_properties_ptr != nullptr) return getBridgeInstance().remove_properties_ptr(client, subject); #endif @@ -2196,7 +2235,7 @@ bool jackbridge_remove_all_properties(jack_client_t* client) #elif defined(JACKBRIDGE_DIRECT) return (jack_remove_all_properties(client) == 0); #else - if (! JackBridge::usingRtAudio) + if (usingRealJACK) if (getBridgeInstance().remove_all_properties_ptr != nullptr) return (getBridgeInstance().remove_all_properties_ptr(client) == 0); #endif @@ -2209,7 +2248,7 @@ bool jackbridge_set_property_change_callback(jack_client_t* client, JackProperty #elif defined(JACKBRIDGE_DIRECT) return (jack_set_property_change_callback(client, callback, arg) == 0); #else - if (! JackBridge::usingRtAudio && getBridgeInstance().set_property_change_callback_ptr != nullptr) + if (usingRealJACK && getBridgeInstance().set_property_change_callback_ptr != nullptr) { # ifdef __WINE__ WineBridge::getInstance().set_prop_change(callback); @@ -2223,3 +2262,98 @@ bool jackbridge_set_property_change_callback(jack_client_t* client, JackProperty } // ----------------------------------------------------------------------------- + +START_NAMESPACE_DISTRHO + +bool supportsAudioInput() +{ +#if defined(JACKBRIDGE_DUMMY) + return false; +#elif !defined(JACKBRIDGE_DIRECT) + if (usingNativeBridge) + return nativeBridge->supportsAudioInput(); +#endif + return true; +} + +bool supportsBufferSizeChanges() +{ +#if !(defined(JACKBRIDGE_DUMMY) || defined(JACKBRIDGE_DIRECT)) + if (usingNativeBridge) + return nativeBridge->supportsBufferSizeChanges(); +#endif + return false; +} + +bool supportsMIDI() +{ +#if defined(JACKBRIDGE_DUMMY) + return false; +#elif !defined(JACKBRIDGE_DIRECT) + if (usingNativeBridge) + return nativeBridge->supportsMIDI(); +#endif + return true; +} + +bool isAudioInputEnabled() +{ +#if defined(JACKBRIDGE_DUMMY) + return false; +#elif !defined(JACKBRIDGE_DIRECT) + if (usingNativeBridge) + return nativeBridge->isAudioInputEnabled(); +#endif + return true; +} + +bool isMIDIEnabled() +{ +#if defined(JACKBRIDGE_DUMMY) + return false; +#elif !defined(JACKBRIDGE_DIRECT) + if (usingNativeBridge) + return nativeBridge->isMIDIEnabled(); +#endif + return true; +} + +uint32_t getBufferSize() +{ +#if !(defined(JACKBRIDGE_DUMMY) || defined(JACKBRIDGE_DIRECT)) + if (usingNativeBridge) + return nativeBridge->getBufferSize(); +#endif + return 0; +} + +bool requestAudioInput() +{ +#if !(defined(JACKBRIDGE_DUMMY) || defined(JACKBRIDGE_DIRECT)) + if (usingNativeBridge) + return nativeBridge->requestAudioInput(); +#endif + return false; +} + +bool requestBufferSizeChange(const uint32_t newBufferSize) +{ +#if !(defined(JACKBRIDGE_DUMMY) || defined(JACKBRIDGE_DIRECT)) + if (usingNativeBridge) + return nativeBridge->requestBufferSizeChange(newBufferSize); +#endif + return false; +} + +bool requestMIDI() +{ +#if !(defined(JACKBRIDGE_DUMMY) || defined(JACKBRIDGE_DIRECT)) + if (usingNativeBridge) + return nativeBridge->requestMIDI(); +#endif + return false; +} + +END_NAMESPACE_DISTRHO + +// ----------------------------------------------------------------------------- diff --git a/dpf/distrho/src/jackbridge/JackBridge.hpp b/dpf/distrho/src/jackbridge/JackBridge.hpp index f96bf16..0788093 100644 --- a/dpf/distrho/src/jackbridge/JackBridge.hpp +++ b/dpf/distrho/src/jackbridge/JackBridge.hpp @@ -300,8 +300,8 @@ JACKBRIDGE_API const char* jackbridge_get_version_string(); JACKBRIDGE_API jack_client_t* jackbridge_client_open(const char* client_name, uint32_t options, jack_status_t* status); JACKBRIDGE_API bool jackbridge_client_close(jack_client_t* client); -JACKBRIDGE_API int jackbridge_client_name_size(); -JACKBRIDGE_API char* jackbridge_get_client_name(jack_client_t* client); +JACKBRIDGE_API int jackbridge_client_name_size(); +JACKBRIDGE_API const char* jackbridge_get_client_name(jack_client_t* client); JACKBRIDGE_API char* jackbridge_client_get_uuid(jack_client_t* client); JACKBRIDGE_API char* jackbridge_get_uuid_for_client_name(jack_client_t* client, const char* name); @@ -408,19 +408,4 @@ JACKBRIDGE_API int jackbridge_remove_properties(jack_client_t* client, jack_uui JACKBRIDGE_API bool jackbridge_remove_all_properties(jack_client_t* client); JACKBRIDGE_API bool jackbridge_set_property_change_callback(jack_client_t* client, JackPropertyChangeCallback callback, void* arg); -JACKBRIDGE_API bool jackbridge_sem_init(void* sem) noexcept; -JACKBRIDGE_API void jackbridge_sem_destroy(void* sem) noexcept; -JACKBRIDGE_API bool jackbridge_sem_connect(void* sem) noexcept; -JACKBRIDGE_API void jackbridge_sem_post(void* sem, bool server) noexcept; -JACKBRIDGE_API bool jackbridge_sem_timedwait(void* sem, uint msecs, bool server) noexcept; - -JACKBRIDGE_API bool jackbridge_shm_is_valid(const void* shm) noexcept; -JACKBRIDGE_API void jackbridge_shm_init(void* shm) noexcept; -JACKBRIDGE_API void jackbridge_shm_attach(void* shm, const char* name) noexcept; -JACKBRIDGE_API void jackbridge_shm_close(void* shm) noexcept; -JACKBRIDGE_API void* jackbridge_shm_map(void* shm, uint64_t size) noexcept; -JACKBRIDGE_API void jackbridge_shm_unmap(void* shm, void* ptr) noexcept; - -JACKBRIDGE_API void jackbridge_parent_deathsig(bool kill) noexcept; - #endif // JACKBRIDGE_HPP_INCLUDED diff --git a/dpf/distrho/src/jackbridge/NativeBridge.hpp b/dpf/distrho/src/jackbridge/NativeBridge.hpp new file mode 100644 index 0000000..30e26db --- /dev/null +++ b/dpf/distrho/src/jackbridge/NativeBridge.hpp @@ -0,0 +1,294 @@ +/* + * Native Bridge for DPF + * Copyright (C) 2021-2022 Filipe Coelho + * + * Permission to use, copy, modify, and/or distribute this software for any purpose with + * or without fee is hereby granted, provided that the above copyright notice and this + * permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD + * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef NATIVE_BRIDGE_HPP_INCLUDED +#define NATIVE_BRIDGE_HPP_INCLUDED + +#include "JackBridge.hpp" + +#include "../../extra/RingBuffer.hpp" + +using DISTRHO_NAMESPACE::HeapRingBuffer; + +struct NativeBridge { + // Current status information + uint bufferSize; + uint sampleRate; + + // Port caching information + uint numAudioIns; + uint numAudioOuts; + uint numMidiIns; + uint numMidiOuts; + + // JACK callbacks + JackProcessCallback jackProcessCallback = nullptr; + JackBufferSizeCallback bufferSizeCallback = nullptr; + void* jackProcessArg = nullptr; + void* jackBufferSizeArg = nullptr; + + // Runtime buffers + enum PortMask { + kPortMaskAudio = 0x1000, + kPortMaskMIDI = 0x2000, + kPortMaskInput = 0x4000, + kPortMaskOutput = 0x8000, + kPortMaskInputMIDI = kPortMaskInput|kPortMaskMIDI, + kPortMaskOutputMIDI = kPortMaskOutput|kPortMaskMIDI, + }; +#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + float* audioBuffers[DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS]; + float* audioBufferStorage; +#endif +#if DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + bool midiAvailable; +#endif +#if DISTRHO_PLUGIN_WANT_MIDI_INPUT + static constexpr const uint32_t kMaxMIDIInputMessageSize = 3; + uint8_t midiDataStorage[kMaxMIDIInputMessageSize]; + HeapRingBuffer midiInBufferCurrent; + HeapRingBuffer midiInBufferPending; +#endif +#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + HeapRingBuffer midiOutBuffer; +#endif + + NativeBridge() + : bufferSize(0), + sampleRate(0), + numAudioIns(0), + numAudioOuts(0), + numMidiIns(0), + numMidiOuts(0), + jackProcessCallback(nullptr), + bufferSizeCallback(nullptr), + jackProcessArg(nullptr), + jackBufferSizeArg(nullptr) + #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + , audioBuffers() + , audioBufferStorage(nullptr) + #endif + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + , midiAvailable(false) + #endif + { + #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + std::memset(audioBuffers, 0, sizeof(audioBuffers)); + #endif + } + + virtual ~NativeBridge() {} + virtual bool open(const char* const clientName) = 0; + virtual bool close() = 0; + virtual bool activate() = 0; + virtual bool deactivate() = 0; + + virtual bool supportsAudioInput() const + { + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 + return true; + #else + return false; + #endif + } + + virtual bool isAudioInputEnabled() const + { + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 + return true; + #else + return false; + #endif + } + + virtual bool supportsBufferSizeChanges() const { return false; } + virtual bool isMIDIEnabled() const { return false; } + virtual bool requestAudioInput() { return false; } + virtual bool requestBufferSizeChange(uint32_t) { return false; } + virtual bool requestMIDI() { return false; } + + uint32_t getBufferSize() const noexcept + { + return bufferSize; + } + + bool supportsMIDI() const noexcept + { + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + return midiAvailable; + #else + return false; + #endif + } + + uint32_t getEventCount() + { + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT + if (midiAvailable) + { + // NOTE: this function is only called once per run + midiInBufferCurrent.copyFromAndClearOther(midiInBufferPending); + return midiInBufferCurrent.getReadableDataSize() / (kMaxMIDIInputMessageSize + 1u); + } + #endif + + return 0; + } + + bool getEvent(jack_midi_event_t* const event) + { + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT + // NOTE: this function is called for all events in index succession + if (midiAvailable && midiInBufferCurrent.getReadableDataSize() >= (kMaxMIDIInputMessageSize + 1u)) + { + event->time = 0; // TODO + event->size = midiInBufferCurrent.readByte(); + event->buffer = midiDataStorage; + return midiInBufferCurrent.readCustomData(midiDataStorage, kMaxMIDIInputMessageSize); + } + #endif + return false; + // maybe unused + (void)event; + } + + void clearEventBuffer() + { + #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + if (midiAvailable) + midiOutBuffer.clearData(); + #endif + } + + bool writeEvent(const jack_nframes_t time, const jack_midi_data_t* const data, const uint32_t size) + { + if (size > 3) + return false; + + #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + if (midiAvailable) + { + if (midiOutBuffer.writeByte(size) && midiOutBuffer.writeCustomData(data, size)) + { + bool fail = false; + // align + switch (size) + { + case 1: fail |= !midiOutBuffer.writeByte(0); + // fall-through + case 2: fail |= !midiOutBuffer.writeByte(0); + } + fail |= !midiOutBuffer.writeUInt(time); + midiOutBuffer.commitWrite(); + return !fail; + } + midiOutBuffer.commitWrite(); + } + #endif + + return false; + // maybe unused + (void)data; + (void)time; + } + + void allocBuffers() + { + DISTRHO_SAFE_ASSERT_RETURN(bufferSize != 0,); + + #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + audioBufferStorage = new float[bufferSize*(DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS)]; + + for (uint i=0; i 0 + std::memset(audioBufferStorage, 0, sizeof(float)*bufferSize*DISTRHO_PLUGIN_NUM_INPUTS); + #endif + + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT + midiInBufferCurrent.createBuffer(kMaxMIDIInputMessageSize * 512); + midiInBufferPending.createBuffer(kMaxMIDIInputMessageSize * 512); + #endif + #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + midiOutBuffer.createBuffer(2048); + #endif + } + + void freeBuffers() + { + #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + delete[] audioBufferStorage; + audioBufferStorage = nullptr; + #endif + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT + midiInBufferCurrent.deleteBuffer(); + midiInBufferPending.deleteBuffer(); + #endif + #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + midiOutBuffer.deleteBuffer(); + #endif + } + + jack_port_t* registerPort(const char* const type, const ulong flags) + { + bool isAudio, isInput; + + /**/ if (std::strcmp(type, JACK_DEFAULT_AUDIO_TYPE) == 0) + isAudio = true; + else if (std::strcmp(type, JACK_DEFAULT_MIDI_TYPE) == 0) + isAudio = false; + else + return nullptr; + + /**/ if (flags & JackPortIsInput) + isInput = true; + else if (flags & JackPortIsOutput) + isInput = false; + else + return nullptr; + + const uintptr_t ret = (isAudio ? kPortMaskAudio : kPortMaskMIDI) + | (isInput ? kPortMaskInput : kPortMaskOutput); + + return (jack_port_t*)(ret + (isAudio ? (isInput ? numAudioIns++ : numAudioOuts++) + : (isInput ? numMidiIns++ : numMidiOuts++))); + } + + void* getPortBuffer(jack_port_t* const port) + { + const uintptr_t portMask = (uintptr_t)port; + DISTRHO_SAFE_ASSERT_RETURN(portMask != 0x0, nullptr); + + #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + if (portMask & kPortMaskAudio) + return audioBuffers[(portMask & kPortMaskInput ? 0 : DISTRHO_PLUGIN_NUM_INPUTS) + (portMask & 0x0fff)]; + #endif + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT + if ((portMask & kPortMaskInputMIDI) == kPortMaskInputMIDI) + return (void*)0x1; + #endif + #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + if ((portMask & kPortMaskOutputMIDI) == kPortMaskOutputMIDI) + return (void*)0x2; + #endif + + return nullptr; + } +}; + +#endif // NATIVE_BRIDGE_HPP_INCLUDED diff --git a/dpf/distrho/src/jackbridge/RtAudioBridge.hpp b/dpf/distrho/src/jackbridge/RtAudioBridge.hpp index 78f2fdd..146ed14 100644 --- a/dpf/distrho/src/jackbridge/RtAudioBridge.hpp +++ b/dpf/distrho/src/jackbridge/RtAudioBridge.hpp @@ -1,6 +1,6 @@ /* - * RtAudioBridge for DPF - * Copyright (C) 2021 Filipe Coelho + * RtAudio Bridge for DPF + * Copyright (C) 2021-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -14,10 +14,14 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef RTAUDIOBRIDGE_HPP_INCLUDED -#define RTAUDIOBRIDGE_HPP_INCLUDED +#ifndef RTAUDIO_BRIDGE_HPP_INCLUDED +#define RTAUDIO_BRIDGE_HPP_INCLUDED -#include "JackBridge.hpp" +#include "NativeBridge.hpp" + +#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS == 0 +# error RtAudio without audio does not make sense +#endif #if defined(DISTRHO_OS_MAC) # define __MACOSX_CORE__ @@ -37,50 +41,20 @@ # define Point CorePoint /* fix conflict between DGL and macOS Point name */ # include "rtaudio/RtAudio.h" # undef Point -# include "../../extra/RingBuffer.hpp" # include "../../extra/ScopedPointer.hpp" -using DISTRHO_NAMESPACE::HeapRingBuffer; using DISTRHO_NAMESPACE::ScopedPointer; -struct RtAudioBridge { +struct RtAudioBridge : NativeBridge { // pointer to RtAudio instance ScopedPointer handle; - // RtAudio information - uint bufferSize = 0; - uint sampleRate = 0; - - // Port caching information - uint numAudioIns = 0; - uint numAudioOuts = 0; - uint numMidiIns = 0; - uint numMidiOuts = 0; - - // JACK callbacks - JackProcessCallback jackProcessCallback = nullptr; - void* jackProcessArg = nullptr; - - // Runtime buffers - enum PortMask { - kPortMaskAudio = 0x1000, - kPortMaskMIDI = 0x2000, - kPortMaskInput = 0x4000, - kPortMaskOutput = 0x8000, - kPortMaskInputMIDI = kPortMaskInput|kPortMaskMIDI, - kPortMaskOutputMIDI = kPortMaskOutput|kPortMaskMIDI, - }; -#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 - float* audioBuffers[DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS]; -#endif -#if DISTRHO_PLUGIN_WANT_MIDI_INPUT - HeapRingBuffer midiInBuffer; -#endif -#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT - HeapRingBuffer midiOutBuffer; -#endif + const char* getVersion() const noexcept + { + return RTAUDIO_VERSION; + } - bool open() + bool open(const char* const clientName) override { ScopedPointer rtAudio; @@ -90,24 +64,31 @@ struct RtAudioBridge { uint rtAudioBufferFrames = 512; -#if DISTRHO_PLUGIN_NUM_INPUTS > 0 + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 RtAudio::StreamParameters inParams; - RtAudio::StreamParameters* const inParamsPtr = &inParams; inParams.deviceId = rtAudio->getDefaultInputDevice(); inParams.nChannels = DISTRHO_PLUGIN_NUM_INPUTS; -#else + RtAudio::StreamParameters* const inParamsPtr = &inParams; + #else RtAudio::StreamParameters* const inParamsPtr = nullptr; -#endif + #endif + #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 RtAudio::StreamParameters outParams; outParams.deviceId = rtAudio->getDefaultOutputDevice(); outParams.nChannels = DISTRHO_PLUGIN_NUM_OUTPUTS; + RtAudio::StreamParameters* const outParamsPtr = &outParams; + #else + RtAudio::StreamParameters* const outParamsPtr = nullptr; + #endif RtAudio::StreamOptions opts; opts.flags = RTAUDIO_NONINTERLEAVED | RTAUDIO_MINIMIZE_LATENCY | RTAUDIO_ALSA_USE_DEFAULT; + opts.streamName = clientName; try { - rtAudio->openStream(&outParams, inParamsPtr, RTAUDIO_FLOAT32, 48000, &rtAudioBufferFrames, RtAudioCallback, this, &opts, nullptr); + rtAudio->openStream(outParamsPtr, inParamsPtr, RTAUDIO_FLOAT32, 48000, &rtAudioBufferFrames, + RtAudioCallback, this, &opts, nullptr); } catch (const RtAudioError& err) { d_safe_exception(err.getMessage().c_str(), __FILE__, __LINE__); return false; @@ -116,17 +97,10 @@ struct RtAudioBridge { handle = rtAudio; bufferSize = rtAudioBufferFrames; sampleRate = handle->getStreamSampleRate(); - -#if DISTRHO_PLUGIN_WANT_MIDI_INPUT - midiInBuffer.createBuffer(128); -#endif -#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT - midiOutBuffer.createBuffer(128); -#endif return true; } - bool close() + bool close() override { DISTRHO_SAFE_ASSERT_RETURN(handle != nullptr, false); @@ -141,82 +115,40 @@ struct RtAudioBridge { return true; } - bool activate() + bool activate() override { DISTRHO_SAFE_ASSERT_RETURN(handle != nullptr, false); try { handle->startStream(); - } DISTRHO_SAFE_EXCEPTION("handle->startStream()"); + } DISTRHO_SAFE_EXCEPTION_RETURN("handle->startStream()", false); return true; } - bool deactivate() + bool deactivate() override { DISTRHO_SAFE_ASSERT_RETURN(handle != nullptr, false); try { handle->stopStream(); - } DISTRHO_SAFE_EXCEPTION("handle->stopStream()"); + } DISTRHO_SAFE_EXCEPTION_RETURN("handle->stopStream()", false); return true; } - jack_port_t* registerPort(const char* const type, const ulong flags) - { - bool isAudio, isInput; - - if (std::strcmp(type, JACK_DEFAULT_AUDIO_TYPE) == 0) - isAudio = true; - else if (std::strcmp(type, JACK_DEFAULT_MIDI_TYPE) == 0) - isAudio = false; - else - return nullptr; - - if (flags & JackPortIsInput) - isInput = true; - else if (flags & JackPortIsOutput) - isInput = false; - else - return nullptr; - - const uintptr_t ret = (isAudio ? kPortMaskAudio : kPortMaskMIDI) - | (isInput ? kPortMaskInput : kPortMaskOutput); - - return (jack_port_t*)(ret + (isAudio ? (isInput ? numAudioIns++ : numAudioOuts++) - : (isInput ? numMidiIns++ : numMidiOuts++))); - } - - void* getPortBuffer(jack_port_t* const port) - { - const uintptr_t portMask = (uintptr_t)port; - DISTRHO_SAFE_ASSERT_RETURN(portMask != 0x0, nullptr); - -#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 - if (portMask & kPortMaskAudio) - return audioBuffers[(portMask & kPortMaskInput ? 0 : DISTRHO_PLUGIN_NUM_INPUTS) + (portMask & 0x0fff)]; -#endif -#if DISTRHO_PLUGIN_WANT_MIDI_INPUT - if ((portMask & kPortMaskInputMIDI) == kPortMaskInputMIDI) - return &midiInBuffer; -#endif -#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT - if ((portMask & kPortMaskOutputMIDI) == kPortMaskOutputMIDI) - return &midiOutBuffer; -#endif - - return nullptr; - } - static int RtAudioCallback(void* const outputBuffer, + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 void* const inputBuffer, + #else + void*, + #endif const uint numFrames, const double /* streamTime */, const RtAudioStreamStatus /* status */, void* const userData) { - RtAudioBridge* const self = (RtAudioBridge*)userData; + RtAudioBridge* const self = static_cast(userData); if (self->jackProcessCallback == nullptr) { @@ -225,35 +157,27 @@ struct RtAudioBridge { return 0; } -#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 - float** const selfAudioBuffers = self->audioBuffers; - - uint i = 0; -# if DISTRHO_PLUGIN_NUM_INPUTS > 0 - if (float* const insPtr = (float*)inputBuffer) + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 + if (float* const insPtr = static_cast(inputBuffer)) { - for (uint j=0; jaudioBuffers[i] = insPtr + (i * numFrames); } -# endif -# if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 - if (float* const outsPtr = (float*)outputBuffer) + #endif + + #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + if (float* const outsPtr = static_cast(outputBuffer)) { - for (uint j=0; jaudioBuffers[DISTRHO_PLUGIN_NUM_INPUTS + i] = outsPtr + (i * numFrames); } -# endif -#endif + #endif self->jackProcessCallback(numFrames, self->jackProcessArg); - return 0; -#if DISTRHO_PLUGIN_NUM_INPUTS == 0 - // unused - (void)inputBuffer; -#endif + return 0; } }; #endif // RTAUDIO_API_TYPE -#endif // RTAUDIOBRIDGE_HPP_INCLUDED +#endif // RTAUDIO_BRIDGE_HPP_INCLUDED diff --git a/dpf/distrho/src/jackbridge/SDL2Bridge.hpp b/dpf/distrho/src/jackbridge/SDL2Bridge.hpp new file mode 100644 index 0000000..88cfd64 --- /dev/null +++ b/dpf/distrho/src/jackbridge/SDL2Bridge.hpp @@ -0,0 +1,242 @@ +/* + * SDL Bridge for DPF + * Copyright (C) 2021-2022 Filipe Coelho + * + * Permission to use, copy, modify, and/or distribute this software for any purpose with + * or without fee is hereby granted, provided that the above copyright notice and this + * permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD + * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef SDL_BRIDGE_HPP_INCLUDED +#define SDL_BRIDGE_HPP_INCLUDED + +#include "NativeBridge.hpp" + +#include + +#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS == 0 +# error SDL without audio does not make sense +#endif + +struct SDL2Bridge : NativeBridge { + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 + SDL_AudioDeviceID captureDeviceId; + #endif + #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + SDL_AudioDeviceID playbackDeviceId; + #endif + + SDL2Bridge() + : NativeBridge() + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 + , captureDeviceId(0) + #endif + #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + , playbackDeviceId(0) + #endif + {} + + bool open(const char* const clientName) override + { + SDL_InitSubSystem(SDL_INIT_AUDIO); + + SDL_AudioSpec requested; + std::memset(&requested, 0, sizeof(requested)); + requested.format = AUDIO_F32SYS; + requested.freq = 48000; + requested.samples = 512; + requested.userdata = this; + + SDL_SetHint(SDL_HINT_AUDIO_DEVICE_APP_NAME, clientName); + // SDL_SetHint(SDL_HINT_AUDIO_RESAMPLING_MODE, "1"); + + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 + SDL_SetHint(SDL_HINT_AUDIO_DEVICE_STREAM_NAME, "Capure"); + requested.channels = DISTRHO_PLUGIN_NUM_INPUTS; + requested.callback = AudioInputCallback; + + SDL_AudioSpec receivedCapture; + captureDeviceId = SDL_OpenAudioDevice(nullptr, 1, &requested, &receivedCapture, + SDL_AUDIO_ALLOW_FREQUENCY_CHANGE|SDL_AUDIO_ALLOW_SAMPLES_CHANGE); + if (captureDeviceId == 0) + { + d_stderr2("Failed to open SDL playback device, error was: %s", SDL_GetError()); + return false; + } + + if (receivedCapture.channels != DISTRHO_PLUGIN_NUM_INPUTS) + { + SDL_CloseAudioDevice(captureDeviceId); + captureDeviceId = 0; + d_stderr2("Invalid or missing audio input channels"); + return false; + } + #endif + + #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + SDL_AudioSpec receivedPlayback; + SDL_SetHint(SDL_HINT_AUDIO_DEVICE_STREAM_NAME, "Playback"); + requested.channels = DISTRHO_PLUGIN_NUM_OUTPUTS; + requested.callback = AudioOutputCallback; + + playbackDeviceId = SDL_OpenAudioDevice(nullptr, 0, &requested, &receivedPlayback, + SDL_AUDIO_ALLOW_FREQUENCY_CHANGE|SDL_AUDIO_ALLOW_SAMPLES_CHANGE); + if (playbackDeviceId == 0) + { + d_stderr2("Failed to open SDL playback device, error was: %s", SDL_GetError()); + return false; + } + + if (receivedPlayback.channels != DISTRHO_PLUGIN_NUM_OUTPUTS) + { + SDL_CloseAudioDevice(playbackDeviceId); + playbackDeviceId = 0; + d_stderr2("Invalid or missing audio output channels"); + return false; + } + #endif + + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 && DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + // if using both input and output, make sure they match + if (receivedCapture.samples != receivedPlayback.samples) + { + SDL_CloseAudioDevice(captureDeviceId); + SDL_CloseAudioDevice(playbackDeviceId); + captureDeviceId = playbackDeviceId = 0; + d_stderr2("Mismatch buffer size %u vs %u", receivedCapture.samples, receivedCapture.samples); + return false; + } + if (receivedCapture.freq != receivedPlayback.freq) + { + SDL_CloseAudioDevice(captureDeviceId); + SDL_CloseAudioDevice(playbackDeviceId); + captureDeviceId = playbackDeviceId = 0; + d_stderr2("Mismatch sample rate %u vs %u", receivedCapture.freq, receivedCapture.freq); + return false; + } + #endif + + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 + bufferSize = receivedCapture.samples; + sampleRate = receivedCapture.freq; + #else + bufferSize = receivedPlayback.samples; + sampleRate = receivedPlayback.freq; + #endif + + allocBuffers(); + return true; + } + + bool close() override + { + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 + DISTRHO_SAFE_ASSERT_RETURN(captureDeviceId != 0, false); + SDL_CloseAudioDevice(captureDeviceId); + captureDeviceId = 0; + #endif + #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + DISTRHO_SAFE_ASSERT_RETURN(playbackDeviceId != 0, false); + SDL_CloseAudioDevice(playbackDeviceId); + playbackDeviceId = 0; + #endif + + freeBuffers(); + return true; + } + + bool activate() override + { + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 + DISTRHO_SAFE_ASSERT_RETURN(captureDeviceId != 0, false); + SDL_PauseAudioDevice(captureDeviceId, 0); + #endif + #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + DISTRHO_SAFE_ASSERT_RETURN(playbackDeviceId != 0, false); + SDL_PauseAudioDevice(playbackDeviceId, 0); + #endif + return true; + } + + bool deactivate() override + { + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 + DISTRHO_SAFE_ASSERT_RETURN(captureDeviceId != 0, false); + SDL_PauseAudioDevice(captureDeviceId, 1); + #endif + #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + DISTRHO_SAFE_ASSERT_RETURN(playbackDeviceId != 0, false); + SDL_PauseAudioDevice(playbackDeviceId, 1); + #endif + return true; + } + + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 + static void AudioInputCallback(void* const userData, uchar* const stream, const int len) + { + NativeBridge* const self = static_cast(userData); + + // safety checks + DISTRHO_SAFE_ASSERT_RETURN(stream != nullptr,); + DISTRHO_SAFE_ASSERT_RETURN(len > 0,); + + if (self->jackProcessCallback == nullptr) + return; + + const uint numFrames = static_cast(len / sizeof(float) / DISTRHO_PLUGIN_NUM_INPUTS); + DISTRHO_SAFE_ASSERT_UINT2_RETURN(numFrames == self->bufferSize, numFrames, self->bufferSize,); + + const float* const fstream = (const float*)stream; + + for (uint i=0; iaudioBuffers[i][j] = fstream[j * DISTRHO_PLUGIN_NUM_INPUTS + i]; + } + + #if DISTRHO_PLUGIN_NUM_OUTPUTS == 0 + // if there are no outputs, run process callback now + self->jackProcessCallback(numFrames, self->jackProcessArg); + #endif + } + #endif + + #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + static void AudioOutputCallback(void* const userData, uchar* const stream, const int len) + { + NativeBridge* const self = static_cast(userData); + + // safety checks + DISTRHO_SAFE_ASSERT_RETURN(stream != nullptr,); + DISTRHO_SAFE_ASSERT_RETURN(len > 0,); + + if (self->jackProcessCallback == nullptr) + { + std::memset(stream, 0, len); + return; + } + + const uint numFrames = static_cast(len / sizeof(float) / DISTRHO_PLUGIN_NUM_OUTPUTS); + DISTRHO_SAFE_ASSERT_UINT2_RETURN(numFrames == self->bufferSize, numFrames, self->bufferSize,); + + self->jackProcessCallback(numFrames, self->jackProcessArg); + + float* const fstream = (float*)stream; + + for (uint i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i) + { + for (uint j=0; j < numFrames; ++j) + fstream[j * DISTRHO_PLUGIN_NUM_OUTPUTS + i] = self->audioBuffers[DISTRHO_PLUGIN_NUM_INPUTS + i][j]; + } + } + #endif +}; + +#endif // SDL_BRIDGE_HPP_INCLUDED diff --git a/dpf/distrho/src/jackbridge/WebBridge.hpp b/dpf/distrho/src/jackbridge/WebBridge.hpp new file mode 100644 index 0000000..71154bb --- /dev/null +++ b/dpf/distrho/src/jackbridge/WebBridge.hpp @@ -0,0 +1,468 @@ +/* + * Web Audio + MIDI Bridge for DPF + * Copyright (C) 2021-2022 Filipe Coelho + * + * Permission to use, copy, modify, and/or distribute this software for any purpose with + * or without fee is hereby granted, provided that the above copyright notice and this + * permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD + * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef WEB_BRIDGE_HPP_INCLUDED +#define WEB_BRIDGE_HPP_INCLUDED + +#include "NativeBridge.hpp" + +#include + +struct WebBridge : NativeBridge { +#if DISTRHO_PLUGIN_NUM_INPUTS > 0 + bool captureAvailable = false; +#endif +#if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + bool playbackAvailable = false; +#endif + bool active = false; + double timestamp = 0; + + WebBridge() + { + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 + captureAvailable = EM_ASM_INT({ + if (typeof(navigator.mediaDevices) !== 'undefined' && typeof(navigator.mediaDevices.getUserMedia) !== 'undefined') + return 1; + if (typeof(navigator.webkitGetUserMedia) !== 'undefined') + return 1; + return false; + }) != 0; + #endif + + #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + playbackAvailable = EM_ASM_INT({ + if (typeof(AudioContext) !== 'undefined') + return 1; + if (typeof(webkitAudioContext) !== 'undefined') + return 1; + return 0; + }) != 0; + #endif + + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + midiAvailable = EM_ASM_INT({ + return typeof(navigator.requestMIDIAccess) === 'function' ? 1 : 0; + }) != 0; + #endif + } + + bool open(const char*) override + { + // early bail out if required features are not supported + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 + if (!captureAvailable) + { + #if DISTRHO_PLUGIN_NUM_OUTPUTS == 0 + d_stderr2("Audio capture is not supported"); + return false; + #else + if (!playbackAvailable) + { + d_stderr2("Audio capture and playback are not supported"); + return false; + } + d_stderr2("Audio capture is not supported, but can still use playback"); + #endif + } + #endif + + #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + if (!playbackAvailable) + { + d_stderr2("Audio playback is not supported"); + return false; + } + #endif + + const bool initialized = EM_ASM_INT({ + if (typeof(Module['WebAudioBridge']) === 'undefined') { + Module['WebAudioBridge'] = {}; + } + + var WAB = Module['WebAudioBridge']; + if (!WAB.audioContext) { + if (typeof(AudioContext) !== 'undefined') { + WAB.audioContext = new AudioContext(); + } else if (typeof(webkitAudioContext) !== 'undefined') { + WAB.audioContext = new webkitAudioContext(); + } + } + + return WAB.audioContext === undefined ? 0 : 1; + }) != 0; + + if (!initialized) + { + d_stderr2("Failed to initialize web audio"); + return false; + } + + bufferSize = 2048; + sampleRate = EM_ASM_INT_V({ + var WAB = Module['WebAudioBridge']; + return WAB.audioContext.sampleRate; + }); + + allocBuffers(); + + EM_ASM({ + var numInputs = $0; + var numOutputs = $1; + var bufferSize = $2; + var WAB = Module['WebAudioBridge']; + + // main processor + WAB.processor = WAB.audioContext['createScriptProcessor'](bufferSize, numInputs, numOutputs); + WAB.processor['onaudioprocess'] = function (e) { + // var timestamp = performance.now(); + for (var i = 0; i < numInputs; ++i) { + var buffer = e['inputBuffer']['getChannelData'](i); + for (var j = 0; j < bufferSize; ++j) { + // setValue($3 + ((bufferSize * i) + j) * 4, buffer[j], 'float'); + HEAPF32[$3 + (((bufferSize * i) + j) << 2) >> 2] = buffer[j]; + } + } + dynCall('vi', $4, [$5]); + for (var i = 0; i < numOutputs; ++i) { + var buffer = e['outputBuffer']['getChannelData'](i); + var offset = bufferSize * (numInputs + i); + for (var j = 0; j < bufferSize; ++j) { + buffer[j] = HEAPF32[$3 + ((offset + j) << 2) >> 2]; + } + } + }; + + // connect to output + WAB.processor['connect'](WAB.audioContext['destination']); + + // resume/start playback on first click + document.addEventListener('click', function(e) { + var WAB = Module['WebAudioBridge']; + console.log(WAB.audioContext.state); + if (WAB.audioContext.state === 'suspended') + WAB.audioContext.resume(); + }); + }, DISTRHO_PLUGIN_NUM_INPUTS, DISTRHO_PLUGIN_NUM_OUTPUTS, bufferSize, audioBufferStorage, WebAudioCallback, this); + + return true; + } + + bool close() override + { + freeBuffers(); + return true; + } + + bool activate() override + { + active = true; + return true; + } + + bool deactivate() override + { + active = false; + return true; + } + + bool supportsAudioInput() const override + { + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 + return captureAvailable; + #else + return false; + #endif + } + + bool isAudioInputEnabled() const override + { + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 + return EM_ASM_INT({ return Module['WebAudioBridge'].captureStreamNode ? 1 : 0 }) != 0; + #else + return false; + #endif + } + + bool requestAudioInput() override + { + DISTRHO_SAFE_ASSERT_RETURN(DISTRHO_PLUGIN_NUM_INPUTS > 0, false); + + EM_ASM({ + var numInputs = $0; + var WAB = Module['WebAudioBridge']; + + var constraints = {}; + // we need to use this weird awkward way for objects, otherwise build fails + constraints['audio'] = true; + constraints['video'] = false; + constraints['autoGainControl'] = {}; + constraints['autoGainControl']['exact'] = false; + constraints['echoCancellation'] = {}; + constraints['echoCancellation']['exact'] = false; + constraints['noiseSuppression'] = {}; + constraints['noiseSuppression']['exact'] = false; + constraints['channelCount'] = {}; + constraints['channelCount']['min'] = 0; + constraints['channelCount']['ideal'] = numInputs; + constraints['latency'] = {}; + constraints['latency']['min'] = 0; + constraints['latency']['ideal'] = 0; + constraints['sampleSize'] = {}; + constraints['sampleSize']['min'] = 8; + constraints['sampleSize']['max'] = 32; + constraints['sampleSize']['ideal'] = 16; + // old property for chrome + constraints['googAutoGainControl'] = false; + + var success = function(stream) { + WAB.captureStreamNode = WAB.audioContext['createMediaStreamSource'](stream); + WAB.captureStreamNode.connect(WAB.processor); + }; + var fail = function() { + }; + + if (navigator.mediaDevices !== undefined && navigator.mediaDevices.getUserMedia !== undefined) { + navigator.mediaDevices.getUserMedia(constraints).then(success).catch(fail); + } else if (navigator.webkitGetUserMedia !== undefined) { + navigator.webkitGetUserMedia(constraints, success, fail); + } + }, DISTRHO_PLUGIN_NUM_INPUTS); + + return true; + } + + bool supportsBufferSizeChanges() const override + { + return true; + } + + bool requestBufferSizeChange(const uint32_t newBufferSize) override + { + // try to create new processor first + bool success = EM_ASM_INT({ + var numInputs = $0; + var numOutputs = $1; + var newBufferSize = $2; + var WAB = Module['WebAudioBridge']; + + try { + WAB.newProcessor = WAB.audioContext['createScriptProcessor'](newBufferSize, numInputs, numOutputs); + } catch (e) { + return 0; + } + + // got new processor, disconnect old one + WAB.processor['disconnect'](WAB.audioContext['destination']); + + if (WAB.captureStreamNode) + WAB.captureStreamNode.disconnect(WAB.processor); + + return 1; + }, DISTRHO_PLUGIN_NUM_INPUTS, DISTRHO_PLUGIN_NUM_OUTPUTS, newBufferSize) != 0; + + if (!success) + return false; + + bufferSize = newBufferSize; + freeBuffers(); + allocBuffers(); + + if (bufferSizeCallback != nullptr) + bufferSizeCallback(newBufferSize, jackBufferSizeArg); + + EM_ASM({ + var numInputs = $0; + var numOutputs = $1; + var bufferSize = $2; + var WAB = Module['WebAudioBridge']; + + // store the new processor + delete WAB.processor; + WAB.processor = WAB.newProcessor; + delete WAB.newProcessor; + + // setup new processor the same way as old one + WAB.processor['onaudioprocess'] = function (e) { + // var timestamp = performance.now(); + for (var i = 0; i < numInputs; ++i) { + var buffer = e['inputBuffer']['getChannelData'](i); + for (var j = 0; j < bufferSize; ++j) { + // setValue($3 + ((bufferSize * i) + j) * 4, buffer[j], 'float'); + HEAPF32[$3 + (((bufferSize * i) + j) << 2) >> 2] = buffer[j]; + } + } + dynCall('vi', $4, [$5]); + for (var i = 0; i < numOutputs; ++i) { + var buffer = e['outputBuffer']['getChannelData'](i); + var offset = bufferSize * (numInputs + i); + for (var j = 0; j < bufferSize; ++j) { + buffer[j] = HEAPF32[$3 + ((offset + j) << 2) >> 2]; + } + } + }; + + // connect to output + WAB.processor['connect'](WAB.audioContext['destination']); + + // and input, if available + if (WAB.captureStreamNode) + WAB.captureStreamNode.connect(WAB.processor); + + }, DISTRHO_PLUGIN_NUM_INPUTS, DISTRHO_PLUGIN_NUM_OUTPUTS, bufferSize, audioBufferStorage, WebAudioCallback, this); + + return true; + } + + bool isMIDIEnabled() const override + { + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + return EM_ASM_INT({ return Module['WebAudioBridge'].midi ? 1 : 0 }) != 0; + #else + return false; + #endif + } + + bool requestMIDI() override + { + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + if (midiAvailable) + { + EM_ASM({ + var useInput = !!$0; + var useOutput = !!$1; + var maxSize = $2; + var WAB = Module['WebAudioBridge']; + + var offset = Module._malloc(maxSize); + + var inputCallback = function(event) { + if (event.data.length > maxSize) + return; + var buffer = new Uint8Array(Module.HEAPU8.buffer, offset, maxSize); + buffer.set(event.data); + dynCall('viiif', $3, [$4, buffer.byteOffset, event.data.length, event.timeStamp]); + }; + var stateCallback = function(event) { + if (event.port.state === 'connected' && event.port.connection === 'open') { + if (useInput && event.port.type === 'input') { + if (event.port.name.indexOf('Midi Through') < 0) + event.port.onmidimessage = inputCallback; + } else if (useOutput && event.port.type === 'output') { + event.port.open(); + } + } + }; + + var success = function(midi) { + WAB.midi = midi; + midi.onstatechange = stateCallback; + if (useInput) { + midi.inputs.forEach(function(port) { + if (port.name.indexOf('Midi Through') < 0) + port.onmidimessage = inputCallback; + }); + } + if (useOutput) { + midi.outputs.forEach(function(port) { + port.open(); + }); + } + }; + var fail = function(why) { + console.log("midi access failed:", why); + }; + + navigator.requestMIDIAccess().then(success, fail); + }, DISTRHO_PLUGIN_WANT_MIDI_INPUT, DISTRHO_PLUGIN_WANT_MIDI_OUTPUT, kMaxMIDIInputMessageSize, WebMIDICallback, this); + + return true; + } + else + #endif + { + d_stderr2("MIDI is not supported"); + return false; + } + } + + static void WebAudioCallback(void* const userData /* , const double timestamp */) + { + WebBridge* const self = static_cast(userData); + // self->timestamp = timestamp; + + const uint numFrames = self->bufferSize; + + if (self->jackProcessCallback != nullptr && self->active) + { + self->jackProcessCallback(numFrames, self->jackProcessArg); + + #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + if (self->midiAvailable && self->midiOutBuffer.isDataAvailableForReading()) + { + static_assert(kMaxMIDIInputMessageSize + 1u == 4, "change code if bumping this value"); + uint32_t offset = 0; + uint8_t bytes[4] = {}; + double timestamp = EM_ASM_DOUBLE({ return performance.now(); }); + + while (self->midiOutBuffer.isDataAvailableForReading() && + self->midiOutBuffer.readCustomData(bytes, ARRAY_SIZE(bytes))) + { + offset = self->midiOutBuffer.readUInt(); + + EM_ASM({ + var WAB = Module['WebAudioBridge']; + if (WAB.midi) { + var timestamp = $5 + $0; + var size = $1; + WAB.midi.outputs.forEach(function(port) { + if (port.state !== 'disconnected') { + port.send(size == 3 ? [ $2, $3, $4 ] : + size == 2 ? [ $2, $3 ] : + [ $2 ], timestamp); + } + }); + } + }, offset, bytes[0], bytes[1], bytes[2], bytes[3], timestamp); + } + + self->midiOutBuffer.clearData(); + } + #endif + } + else + { + for (uint i=0; iaudioBuffers[DISTRHO_PLUGIN_NUM_INPUTS + i], 0, sizeof(float)*numFrames); + } + } + + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT + static void WebMIDICallback(void* const userData, uint8_t* const data, const int len, const double timestamp) + { + DISTRHO_SAFE_ASSERT_RETURN(len > 0 && len <= (int)kMaxMIDIInputMessageSize,); + + WebBridge* const self = static_cast(userData); + + // TODO timestamp handling + self->midiInBufferPending.writeByte(static_cast(len)); + self->midiInBufferPending.writeCustomData(data, kMaxMIDIInputMessageSize); + self->midiInBufferPending.commitWrite(); + } + #endif +}; + +#endif // WEB_BRIDGE_HPP_INCLUDED diff --git a/dpf/distrho/src/lv2/atom-forge.h b/dpf/distrho/src/lv2/atom-forge.h index d803d23..25087b0 100644 --- a/dpf/distrho/src/lv2/atom-forge.h +++ b/dpf/distrho/src/lv2/atom-forge.h @@ -1,5 +1,5 @@ /* - Copyright 2008-2013 David Robillard + Copyright 2008-2016 David Robillard Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -39,6 +39,12 @@ This header is non-normative, it is provided for convenience. */ +/** + @defgroup forge Forge + @ingroup atom + @{ +*/ + #ifndef LV2_ATOM_FORGE_H #define LV2_ATOM_FORGE_H @@ -48,7 +54,7 @@ #include "atom-util.h" #include "urid.h" -#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) +#if defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) # define LV2_ATOM_FORGE_DEPRECATED __attribute__((__deprecated__)) #else # define LV2_ATOM_FORGE_DEPRECATED @@ -60,6 +66,15 @@ extern "C" { # include #endif +// Disable deprecation warnings for Blank and Resource +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wdeprecated-declarations" +#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif + /** Handle for LV2_Atom_Forge_Sink. */ typedef void* LV2_Atom_Forge_Sink_Handle; @@ -119,21 +134,14 @@ static inline void lv2_atom_forge_set_buffer(LV2_Atom_Forge* forge, uint8_t* buf, size_t size); /** - Initialise @p forge. + Initialise `forge`. - URIs will be mapped using @p map and stored, a reference to @p map itself is + URIs will be mapped using `map` and stored, a reference to `map` itself is not held. */ static inline void -lv2_atom_forge_init(LV2_Atom_Forge* forge, LV2_URID_Map* map) +lv2_atom_forge_init(LV2_Atom_Forge* forge, const LV2_URID_Map* map) { -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wdeprecated-declarations" -#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#endif lv2_atom_forge_set_buffer(forge, NULL, 0); forge->Blank = map->map(map->handle, LV2_ATOM__Blank); forge->Bool = map->map(map->handle, LV2_ATOM__Bool); @@ -153,13 +161,9 @@ lv2_atom_forge_init(LV2_Atom_Forge* forge, LV2_URID_Map* map) forge->URI = map->map(map->handle, LV2_ATOM__URI); forge->URID = map->map(map->handle, LV2_ATOM__URID); forge->Vector = map->map(map->handle, LV2_ATOM__Vector); -#if defined(__clang__) -# pragma clang diagnostic pop -#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) -# pragma GCC diagnostic pop -#endif } +/** Access the Atom pointed to by a reference. */ static inline LV2_Atom* lv2_atom_forge_deref(LV2_Atom_Forge* forge, LV2_Atom_Forge_Ref ref) { @@ -208,47 +212,23 @@ lv2_atom_forge_top_is(LV2_Atom_Forge* forge, uint32_t type) (lv2_atom_forge_deref(forge, forge->stack->ref)->type == type); } -/** Return true iff @p type is an atom:Object. */ +/** Return true iff `type` is an atom:Object. */ static inline bool lv2_atom_forge_is_object_type(const LV2_Atom_Forge* forge, uint32_t type) { -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wdeprecated-declarations" -#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#endif return (type == forge->Object || type == forge->Blank || type == forge->Resource); -#if defined(__clang__) -# pragma clang diagnostic pop -#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) -# pragma GCC diagnostic pop -#endif } -/** Return true iff @p type is an atom:Object with a blank ID. */ +/** Return true iff `type` is an atom:Object with a blank ID. */ static inline bool lv2_atom_forge_is_blank(const LV2_Atom_Forge* forge, uint32_t type, const LV2_Atom_Object_Body* body) { -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wdeprecated-declarations" -#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#endif return (type == forge->Blank || (type == forge->Object && body->id == 0)); -#if defined(__clang__) -# pragma clang diagnostic pop -#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) -# pragma GCC diagnostic pop -#endif } /** @@ -257,7 +237,7 @@ lv2_atom_forge_is_blank(const LV2_Atom_Forge* forge, @{ */ -/** Set the output buffer where @p forge will write atoms. */ +/** Set the output buffer where `forge` will write atoms. */ static inline void lv2_atom_forge_set_buffer(LV2_Atom_Forge* forge, uint8_t* buf, size_t size) { @@ -271,7 +251,7 @@ lv2_atom_forge_set_buffer(LV2_Atom_Forge* forge, uint8_t* buf, size_t size) } /** - Set the sink function where @p forge will write output. + Set the sink function where `forge` will write output. The return value of forge functions is an LV2_Atom_Forge_Ref which is an integer type safe to use as a pointer but is otherwise opaque. The sink @@ -456,7 +436,7 @@ lv2_atom_forge_typed_string(LV2_Atom_Forge* forge, return out; } -/** Write an atom:String. Note that @p str need not be NULL terminated. */ +/** Write an atom:String. Note that `str` need not be NULL terminated. */ static inline LV2_Atom_Forge_Ref lv2_atom_forge_string(LV2_Atom_Forge* forge, const char* str, uint32_t len) { @@ -464,7 +444,7 @@ lv2_atom_forge_string(LV2_Atom_Forge* forge, const char* str, uint32_t len) } /** - Write an atom:URI. Note that @p uri need not be NULL terminated. + Write an atom:URI. Note that `uri` need not be NULL terminated. This does not map the URI, but writes the complete URI string. To write a mapped URI, use lv2_atom_forge_urid(). */ @@ -474,7 +454,7 @@ lv2_atom_forge_uri(LV2_Atom_Forge* forge, const char* uri, uint32_t len) return lv2_atom_forge_typed_string(forge, forge->URI, uri, len); } -/** Write an atom:Path. Note that @p path need not be NULL terminated. */ +/** Write an atom:Path. Note that `path` need not be NULL terminated. */ static inline LV2_Atom_Forge_Ref lv2_atom_forge_path(LV2_Atom_Forge* forge, const char* path, uint32_t len) { @@ -617,24 +597,12 @@ lv2_atom_forge_resource(LV2_Atom_Forge* forge, LV2_URID id, LV2_URID otype) { -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wdeprecated-declarations" -#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#endif const LV2_Atom_Object a = { { (uint32_t)sizeof(LV2_Atom_Object_Body), forge->Resource }, { id, otype } }; return lv2_atom_forge_push( forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a))); -#if defined(__clang__) -# pragma clang diagnostic pop -#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) -# pragma GCC diagnostic pop -#endif } /** @@ -650,24 +618,12 @@ lv2_atom_forge_blank(LV2_Atom_Forge* forge, uint32_t id, LV2_URID otype) { -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wdeprecated-declarations" -#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#endif const LV2_Atom_Object a = { { (uint32_t)sizeof(LV2_Atom_Object_Body), forge->Blank }, { id, otype } }; return lv2_atom_forge_push( forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a))); -#if defined(__clang__) -# pragma clang diagnostic pop -#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) -# pragma GCC diagnostic pop -#endif } /** @@ -738,8 +694,15 @@ lv2_atom_forge_beat_time(LV2_Atom_Forge* forge, double beats) /** @} + @} */ +#if defined(__clang__) +# pragma clang diagnostic pop +#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) +# pragma GCC diagnostic pop +#endif + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/dpf/distrho/src/lv2/atom-util.h b/dpf/distrho/src/lv2/atom-util.h index cad90f8..dcf23ac 100644 --- a/dpf/distrho/src/lv2/atom-util.h +++ b/dpf/distrho/src/lv2/atom-util.h @@ -1,5 +1,5 @@ /* - Copyright 2008-2013 David Robillard + Copyright 2008-2015 David Robillard Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -22,6 +22,12 @@ This header is non-normative, it is provided for convenience. */ +/** + @defgroup util Utilities + @ingroup atom + @{ +*/ + #ifndef LV2_ATOM_UTIL_H #define LV2_ATOM_UTIL_H @@ -44,21 +50,21 @@ lv2_atom_pad_size(uint32_t size) return (size + 7U) & (~7U); } -/** Return the total size of @p atom, including the header. */ +/** Return the total size of `atom`, including the header. */ static inline uint32_t lv2_atom_total_size(const LV2_Atom* atom) { return (uint32_t)sizeof(LV2_Atom) + atom->size; } -/** Return true iff @p atom is null. */ +/** Return true iff `atom` is null. */ static inline bool lv2_atom_is_null(const LV2_Atom* atom) { return !atom || (atom->type == 0 && atom->size == 0); } -/** Return true iff @p a is equal to @p b. */ +/** Return true iff `a` is equal to `b`. */ static inline bool lv2_atom_equals(const LV2_Atom* a, const LV2_Atom* b) { @@ -79,14 +85,21 @@ lv2_atom_sequence_begin(const LV2_Atom_Sequence_Body* body) return (const LV2_Atom_Event*)(body + 1); } +/** Get an iterator pointing to the end of a Sequence body. */ +static inline const LV2_Atom_Event* +lv2_atom_sequence_end(const LV2_Atom_Sequence_Body* body, uint32_t size) +{ + return (const LV2_Atom_Event*)((const uint8_t*)body + lv2_atom_pad_size(size)); +} + /** Get an iterator pointing to the end of a Sequence body. */ static inline LV2_Atom_Event* -lv2_atom_sequence_end(LV2_Atom_Sequence_Body* body, uint32_t size) +lv2_atom_sequence_end2(LV2_Atom_Sequence_Body* body, uint32_t size) { return (LV2_Atom_Event*)((uint8_t*)body + lv2_atom_pad_size(size)); } -/** Return true iff @p i has reached the end of @p body. */ +/** Return true iff `i` has reached the end of `body`. */ static inline bool lv2_atom_sequence_is_end(const LV2_Atom_Sequence_Body* body, uint32_t size, @@ -95,7 +108,7 @@ lv2_atom_sequence_is_end(const LV2_Atom_Sequence_Body* body, return (const uint8_t*)i >= ((const uint8_t*)body + size); } -/** Return an iterator to the element following @p i. */ +/** Return an iterator to the element following `i`. */ static inline const LV2_Atom_Event* lv2_atom_sequence_next(const LV2_Atom_Event* i) { @@ -119,13 +132,13 @@ lv2_atom_sequence_next(const LV2_Atom_Event* i) #define LV2_ATOM_SEQUENCE_FOREACH(seq, iter) \ for (const LV2_Atom_Event* iter = lv2_atom_sequence_begin(&(seq)->body); \ !lv2_atom_sequence_is_end(&(seq)->body, (seq)->atom.size, (iter)); \ - (iter) = lv2_atom_sequence_next(iter)) + iter = lv2_atom_sequence_next(iter)) /** Like LV2_ATOM_SEQUENCE_FOREACH but for a headerless sequence body. */ #define LV2_ATOM_SEQUENCE_BODY_FOREACH(body, size, iter) \ for (const LV2_Atom_Event* iter = lv2_atom_sequence_begin(body); \ !lv2_atom_sequence_is_end(body, size, (iter)); \ - (iter) = lv2_atom_sequence_next(iter)) + iter = lv2_atom_sequence_next(iter)) /** @} @@ -134,7 +147,7 @@ lv2_atom_sequence_next(const LV2_Atom_Event* i) */ /** - Clear all events from @p sequence. + Clear all events from `sequence`. This simply resets the size field, the other fields are left untouched. */ @@ -145,14 +158,14 @@ lv2_atom_sequence_clear(LV2_Atom_Sequence* seq) } /** - Append an event at the end of @p sequence. + Append an event at the end of `sequence`. @param seq Sequence to append to. @param capacity Total capacity of the sequence atom (e.g. as set by the host for sequence output ports). @param event Event to write. - @return A pointer to the newly written event in @p seq, + @return A pointer to the newly written event in `seq`, or NULL on failure (insufficient space). */ static inline LV2_Atom_Event* @@ -165,7 +178,7 @@ lv2_atom_sequence_append_event(LV2_Atom_Sequence* seq, return NULL; } - LV2_Atom_Event* e = lv2_atom_sequence_end(&seq->body, seq->atom.size); + LV2_Atom_Event* e = lv2_atom_sequence_end2(&seq->body, seq->atom.size); memcpy(e, event, total_size); seq->atom.size += lv2_atom_pad_size(total_size); @@ -179,21 +192,21 @@ lv2_atom_sequence_append_event(LV2_Atom_Sequence* seq, @{ */ -/** Get an iterator pointing to the first element in @p tup. */ +/** Get an iterator pointing to the first element in `tup`. */ static inline const LV2_Atom* lv2_atom_tuple_begin(const LV2_Atom_Tuple* tup) { return (const LV2_Atom*)(LV2_ATOM_BODY_CONST(tup)); } -/** Return true iff @p i has reached the end of @p body. */ +/** Return true iff `i` has reached the end of `body`. */ static inline bool lv2_atom_tuple_is_end(const void* body, uint32_t size, const LV2_Atom* i) { return (const uint8_t*)i >= ((const uint8_t*)body + size); } -/** Return an iterator to the element following @p i. */ +/** Return an iterator to the element following `i`. */ static inline const LV2_Atom* lv2_atom_tuple_next(const LV2_Atom* i) { @@ -208,21 +221,21 @@ lv2_atom_tuple_next(const LV2_Atom* i) This macro is used similarly to a for loop (which it expands to), e.g.: @code - LV2_ATOMO_TUPLE_FOREACH(tuple, elem) { + LV2_ATOM_TUPLE_FOREACH(tuple, elem) { // Do something with elem (an LV2_Atom*) here... } @endcode */ #define LV2_ATOM_TUPLE_FOREACH(tuple, iter) \ for (const LV2_Atom* iter = lv2_atom_tuple_begin(tuple); \ - !lv2_atom_tuple_is_end(LV2_ATOM_BODY_CONST(tuple), (tuple)->size, (iter)); \ - (iter) = lv2_atom_tuple_next(iter)) + !lv2_atom_tuple_is_end(LV2_ATOM_BODY_CONST(tuple), (tuple)->atom.size, (iter)); \ + iter = lv2_atom_tuple_next(iter)) /** Like LV2_ATOM_TUPLE_FOREACH but for a headerless tuple body. */ #define LV2_ATOM_TUPLE_BODY_FOREACH(body, size, iter) \ for (const LV2_Atom* iter = (const LV2_Atom*)body; \ !lv2_atom_tuple_is_end(body, size, (iter)); \ - (iter) = lv2_atom_tuple_next(iter)) + iter = lv2_atom_tuple_next(iter)) /** @} @@ -230,14 +243,14 @@ lv2_atom_tuple_next(const LV2_Atom* i) @{ */ -/** Return a pointer to the first property in @p body. */ +/** Return a pointer to the first property in `body`. */ static inline const LV2_Atom_Property_Body* lv2_atom_object_begin(const LV2_Atom_Object_Body* body) { return (const LV2_Atom_Property_Body*)(body + 1); } -/** Return true iff @p i has reached the end of @p obj. */ +/** Return true iff `i` has reached the end of `obj`. */ static inline bool lv2_atom_object_is_end(const LV2_Atom_Object_Body* body, uint32_t size, @@ -246,7 +259,7 @@ lv2_atom_object_is_end(const LV2_Atom_Object_Body* body, return (const uint8_t*)i >= ((const uint8_t*)body + size); } -/** Return an iterator to the property following @p i. */ +/** Return an iterator to the property following `i`. */ static inline const LV2_Atom_Property_Body* lv2_atom_object_next(const LV2_Atom_Property_Body* i) { @@ -272,13 +285,13 @@ lv2_atom_object_next(const LV2_Atom_Property_Body* i) #define LV2_ATOM_OBJECT_FOREACH(obj, iter) \ for (const LV2_Atom_Property_Body* iter = lv2_atom_object_begin(&(obj)->body); \ !lv2_atom_object_is_end(&(obj)->body, (obj)->atom.size, (iter)); \ - (iter) = lv2_atom_object_next(iter)) + iter = lv2_atom_object_next(iter)) /** Like LV2_ATOM_OBJECT_FOREACH but for a headerless object body. */ #define LV2_ATOM_OBJECT_BODY_FOREACH(body, size, iter) \ for (const LV2_Atom_Property_Body* iter = lv2_atom_object_begin(body); \ !lv2_atom_object_is_end(body, size, (iter)); \ - (iter) = lv2_atom_object_next(iter)) + iter = lv2_atom_object_next(iter)) /** @} @@ -297,10 +310,10 @@ static const LV2_Atom_Object_Query LV2_ATOM_OBJECT_QUERY_END = { 0, NULL }; /** Get an object's values for various keys. - The value pointer of each item in @p query will be set to the location of - the corresponding value in @p object. Every value pointer in @p query MUST - be initialised to NULL. This function reads @p object in a single linear - sweep. By allocating @p query on the stack, objects can be "queried" + The value pointer of each item in `query` will be set to the location of + the corresponding value in `object`. Every value pointer in `query` MUST + be initialised to NULL. This function reads `object` in a single linear + sweep. By allocating `query` on the stack, objects can be "queried" quickly without allocating any memory. This function is realtime safe. This function can only do "flat" queries, it is not smart enough to match @@ -359,6 +372,7 @@ lv2_atom_object_body_get(uint32_t size, const LV2_Atom_Object_Body* body, ...) va_start(args, body); for (n_queries = 0; va_arg(args, uint32_t); ++n_queries) { if (!va_arg(args, const LV2_Atom**)) { + va_end(args); return -1; } } @@ -372,6 +386,7 @@ lv2_atom_object_body_get(uint32_t size, const LV2_Atom_Object_Body* body, ...) if (qkey == prop->key && !*qval) { *qval = &prop->value; if (++matches == n_queries) { + va_end(args); return matches; } break; @@ -436,6 +451,63 @@ lv2_atom_object_get(const LV2_Atom_Object* object, ...) } /** + Variable argument version of lv2_atom_object_query() with types. + + This is like lv2_atom_object_get(), but each entry has an additional + parameter to specify the required type. Only atoms with a matching type + will be selected. + + The arguments should be a series of uint32_t key, const LV2_Atom**, uint32_t + type triples, terminated by a zero key. The value pointers MUST be + initialized to NULL. For example: + + @code + const LV2_Atom_String* name = NULL; + const LV2_Atom_Int* age = NULL; + lv2_atom_object_get(obj, + uris.name_key, &name, uris.atom_String, + uris.age_key, &age, uris.atom_Int + 0); + @endcode +*/ +static inline int +lv2_atom_object_get_typed(const LV2_Atom_Object* object, ...) +{ + int matches = 0; + int n_queries = 0; + + /* Count number of keys so we can short-circuit when done */ + va_list args; + va_start(args, object); + for (n_queries = 0; va_arg(args, uint32_t); ++n_queries) { + if (!va_arg(args, const LV2_Atom**) || + !va_arg(args, uint32_t)) { + return -1; + } + } + va_end(args); + + LV2_ATOM_OBJECT_FOREACH(object, prop) { + va_start(args, object); + for (int i = 0; i < n_queries; ++i) { + const uint32_t qkey = va_arg(args, uint32_t); + const LV2_Atom** qval = va_arg(args, const LV2_Atom**); + const uint32_t qtype = va_arg(args, uint32_t); + if (!*qval && qkey == prop->key && qtype == prop->value.type) { + *qval = &prop->value; + if (++matches == n_queries) { + return matches; + } + break; + } + } + va_end(args); + } + return matches; +} + +/** + @} @} */ diff --git a/dpf/distrho/src/lv2/atom.h b/dpf/distrho/src/lv2/atom.h index 91c4fa3..2cb07c6 100644 --- a/dpf/distrho/src/lv2/atom.h +++ b/dpf/distrho/src/lv2/atom.h @@ -1,5 +1,5 @@ /* - Copyright 2008-2012 David Robillard + Copyright 2008-2016 David Robillard Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -15,8 +15,12 @@ */ /** - @file atom.h C header for the LV2 Atom extension - . + @defgroup atom Atom + + A generic value container and several data types, see + for details. + + @{ */ #ifndef LV2_ATOM_H @@ -25,50 +29,52 @@ #include #include -#define LV2_ATOM_URI "http://lv2plug.in/ns/ext/atom" -#define LV2_ATOM_PREFIX LV2_ATOM_URI "#" - -#define LV2_ATOM__Atom LV2_ATOM_PREFIX "Atom" -#define LV2_ATOM__AtomPort LV2_ATOM_PREFIX "AtomPort" -#define LV2_ATOM__Blank LV2_ATOM_PREFIX "Blank" -#define LV2_ATOM__Bool LV2_ATOM_PREFIX "Bool" -#define LV2_ATOM__Chunk LV2_ATOM_PREFIX "Chunk" -#define LV2_ATOM__Double LV2_ATOM_PREFIX "Double" -#define LV2_ATOM__Event LV2_ATOM_PREFIX "Event" -#define LV2_ATOM__Float LV2_ATOM_PREFIX "Float" -#define LV2_ATOM__Int LV2_ATOM_PREFIX "Int" -#define LV2_ATOM__Literal LV2_ATOM_PREFIX "Literal" -#define LV2_ATOM__Long LV2_ATOM_PREFIX "Long" -#define LV2_ATOM__Number LV2_ATOM_PREFIX "Number" -#define LV2_ATOM__Object LV2_ATOM_PREFIX "Object" -#define LV2_ATOM__Path LV2_ATOM_PREFIX "Path" -#define LV2_ATOM__Property LV2_ATOM_PREFIX "Property" -#define LV2_ATOM__Resource LV2_ATOM_PREFIX "Resource" -#define LV2_ATOM__Sequence LV2_ATOM_PREFIX "Sequence" -#define LV2_ATOM__Sound LV2_ATOM_PREFIX "Sound" -#define LV2_ATOM__String LV2_ATOM_PREFIX "String" -#define LV2_ATOM__Tuple LV2_ATOM_PREFIX "Tuple" -#define LV2_ATOM__URI LV2_ATOM_PREFIX "URI" -#define LV2_ATOM__URID LV2_ATOM_PREFIX "URID" -#define LV2_ATOM__Vector LV2_ATOM_PREFIX "Vector" -#define LV2_ATOM__atomTransfer LV2_ATOM_PREFIX "atomTransfer" -#define LV2_ATOM__beatTime LV2_ATOM_PREFIX "beatTime" -#define LV2_ATOM__bufferType LV2_ATOM_PREFIX "bufferType" -#define LV2_ATOM__childType LV2_ATOM_PREFIX "childType" -#define LV2_ATOM__eventTransfer LV2_ATOM_PREFIX "eventTransfer" -#define LV2_ATOM__frameTime LV2_ATOM_PREFIX "frameTime" -#define LV2_ATOM__supports LV2_ATOM_PREFIX "supports" -#define LV2_ATOM__timeUnit LV2_ATOM_PREFIX "timeUnit" - -#define LV2_ATOM_REFERENCE_TYPE 0 +#define LV2_ATOM_URI "http://lv2plug.in/ns/ext/atom" ///< http://lv2plug.in/ns/ext/atom +#define LV2_ATOM_PREFIX LV2_ATOM_URI "#" ///< http://lv2plug.in/ns/ext/atom# + +#define LV2_ATOM__Atom LV2_ATOM_PREFIX "Atom" ///< http://lv2plug.in/ns/ext/atom#Atom +#define LV2_ATOM__AtomPort LV2_ATOM_PREFIX "AtomPort" ///< http://lv2plug.in/ns/ext/atom#AtomPort +#define LV2_ATOM__Blank LV2_ATOM_PREFIX "Blank" ///< http://lv2plug.in/ns/ext/atom#Blank +#define LV2_ATOM__Bool LV2_ATOM_PREFIX "Bool" ///< http://lv2plug.in/ns/ext/atom#Bool +#define LV2_ATOM__Chunk LV2_ATOM_PREFIX "Chunk" ///< http://lv2plug.in/ns/ext/atom#Chunk +#define LV2_ATOM__Double LV2_ATOM_PREFIX "Double" ///< http://lv2plug.in/ns/ext/atom#Double +#define LV2_ATOM__Event LV2_ATOM_PREFIX "Event" ///< http://lv2plug.in/ns/ext/atom#Event +#define LV2_ATOM__Float LV2_ATOM_PREFIX "Float" ///< http://lv2plug.in/ns/ext/atom#Float +#define LV2_ATOM__Int LV2_ATOM_PREFIX "Int" ///< http://lv2plug.in/ns/ext/atom#Int +#define LV2_ATOM__Literal LV2_ATOM_PREFIX "Literal" ///< http://lv2plug.in/ns/ext/atom#Literal +#define LV2_ATOM__Long LV2_ATOM_PREFIX "Long" ///< http://lv2plug.in/ns/ext/atom#Long +#define LV2_ATOM__Number LV2_ATOM_PREFIX "Number" ///< http://lv2plug.in/ns/ext/atom#Number +#define LV2_ATOM__Object LV2_ATOM_PREFIX "Object" ///< http://lv2plug.in/ns/ext/atom#Object +#define LV2_ATOM__Path LV2_ATOM_PREFIX "Path" ///< http://lv2plug.in/ns/ext/atom#Path +#define LV2_ATOM__Property LV2_ATOM_PREFIX "Property" ///< http://lv2plug.in/ns/ext/atom#Property +#define LV2_ATOM__Resource LV2_ATOM_PREFIX "Resource" ///< http://lv2plug.in/ns/ext/atom#Resource +#define LV2_ATOM__Sequence LV2_ATOM_PREFIX "Sequence" ///< http://lv2plug.in/ns/ext/atom#Sequence +#define LV2_ATOM__Sound LV2_ATOM_PREFIX "Sound" ///< http://lv2plug.in/ns/ext/atom#Sound +#define LV2_ATOM__String LV2_ATOM_PREFIX "String" ///< http://lv2plug.in/ns/ext/atom#String +#define LV2_ATOM__Tuple LV2_ATOM_PREFIX "Tuple" ///< http://lv2plug.in/ns/ext/atom#Tuple +#define LV2_ATOM__URI LV2_ATOM_PREFIX "URI" ///< http://lv2plug.in/ns/ext/atom#URI +#define LV2_ATOM__URID LV2_ATOM_PREFIX "URID" ///< http://lv2plug.in/ns/ext/atom#URID +#define LV2_ATOM__Vector LV2_ATOM_PREFIX "Vector" ///< http://lv2plug.in/ns/ext/atom#Vector +#define LV2_ATOM__atomTransfer LV2_ATOM_PREFIX "atomTransfer" ///< http://lv2plug.in/ns/ext/atom#atomTransfer +#define LV2_ATOM__beatTime LV2_ATOM_PREFIX "beatTime" ///< http://lv2plug.in/ns/ext/atom#beatTime +#define LV2_ATOM__bufferType LV2_ATOM_PREFIX "bufferType" ///< http://lv2plug.in/ns/ext/atom#bufferType +#define LV2_ATOM__childType LV2_ATOM_PREFIX "childType" ///< http://lv2plug.in/ns/ext/atom#childType +#define LV2_ATOM__eventTransfer LV2_ATOM_PREFIX "eventTransfer" ///< http://lv2plug.in/ns/ext/atom#eventTransfer +#define LV2_ATOM__frameTime LV2_ATOM_PREFIX "frameTime" ///< http://lv2plug.in/ns/ext/atom#frameTime +#define LV2_ATOM__supports LV2_ATOM_PREFIX "supports" ///< http://lv2plug.in/ns/ext/atom#supports +#define LV2_ATOM__timeUnit LV2_ATOM_PREFIX "timeUnit" ///< http://lv2plug.in/ns/ext/atom#timeUnit + +#define LV2_ATOM_REFERENCE_TYPE 0 ///< The special type for a reference atom #ifdef __cplusplus extern "C" { #endif +/** @cond */ /** This expression will fail to compile if double does not fit in 64 bits. */ typedef char lv2_atom_assert_double_fits_in_64_bits[ ((sizeof(double) <= sizeof(uint64_t)) * 2) - 1]; +/** @endcond */ /** Return a pointer to the contents of an Atom. The "contents" of an atom @@ -239,6 +245,10 @@ typedef struct { LV2_Atom_Sequence_Body body; /**< Body. */ } LV2_Atom_Sequence; +/** + @} +*/ + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/dpf/distrho/src/lv2/buf-size.h b/dpf/distrho/src/lv2/buf-size.h index 3987e31..900f8fa 100644 --- a/dpf/distrho/src/lv2/buf-size.h +++ b/dpf/distrho/src/lv2/buf-size.h @@ -1,5 +1,5 @@ /* - Copyright 2007-2012 David Robillard + Copyright 2007-2016 David Robillard Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -17,15 +17,28 @@ #ifndef LV2_BUF_SIZE_H #define LV2_BUF_SIZE_H -#define LV2_BUF_SIZE_URI "http://lv2plug.in/ns/ext/buf-size" -#define LV2_BUF_SIZE_PREFIX LV2_BUF_SIZE_URI "#" +/** + @defgroup buf-size Buffer Size -#define LV2_BUF_SIZE__boundedBlockLength LV2_BUF_SIZE_PREFIX "boundedBlockLength" -#define LV2_BUF_SIZE__fixedBlockLength LV2_BUF_SIZE_PREFIX "fixedBlockLength" -#define LV2_BUF_SIZE__maxBlockLength LV2_BUF_SIZE_PREFIX "maxBlockLength" -#define LV2_BUF_SIZE__minBlockLength LV2_BUF_SIZE_PREFIX "minBlockLength" -#define LV2_BUF_SIZE__nominalBlockLength LV2_BUF_SIZE_PREFIX "nominalBlockLength" -#define LV2_BUF_SIZE__powerOf2BlockLength LV2_BUF_SIZE_PREFIX "powerOf2BlockLength" -#define LV2_BUF_SIZE__sequenceSize LV2_BUF_SIZE_PREFIX "sequenceSize" + Access to, and restrictions on, buffer sizes; see + for details. + + @{ +*/ + +#define LV2_BUF_SIZE_URI "http://lv2plug.in/ns/ext/buf-size" ///< http://lv2plug.in/ns/ext/buf-size +#define LV2_BUF_SIZE_PREFIX LV2_BUF_SIZE_URI "#" ///< http://lv2plug.in/ns/ext/buf-size# + +#define LV2_BUF_SIZE__boundedBlockLength LV2_BUF_SIZE_PREFIX "boundedBlockLength" ///< http://lv2plug.in/ns/ext/buf-size#boundedBlockLength +#define LV2_BUF_SIZE__fixedBlockLength LV2_BUF_SIZE_PREFIX "fixedBlockLength" ///< http://lv2plug.in/ns/ext/buf-size#fixedBlockLength +#define LV2_BUF_SIZE__maxBlockLength LV2_BUF_SIZE_PREFIX "maxBlockLength" ///< http://lv2plug.in/ns/ext/buf-size#maxBlockLength +#define LV2_BUF_SIZE__minBlockLength LV2_BUF_SIZE_PREFIX "minBlockLength" ///< http://lv2plug.in/ns/ext/buf-size#minBlockLength +#define LV2_BUF_SIZE__nominalBlockLength LV2_BUF_SIZE_PREFIX "nominalBlockLength" ///< http://lv2plug.in/ns/ext/buf-size#nominalBlockLength +#define LV2_BUF_SIZE__powerOf2BlockLength LV2_BUF_SIZE_PREFIX "powerOf2BlockLength" ///< http://lv2plug.in/ns/ext/buf-size#powerOf2BlockLength +#define LV2_BUF_SIZE__sequenceSize LV2_BUF_SIZE_PREFIX "sequenceSize" ///< http://lv2plug.in/ns/ext/buf-size#sequenceSize + +/** + @} +*/ #endif /* LV2_BUF_SIZE_H */ diff --git a/dpf/distrho/src/lv2/data-access.h b/dpf/distrho/src/lv2/data-access.h index 68aaf62..2f4fd28 100644 --- a/dpf/distrho/src/lv2/data-access.h +++ b/dpf/distrho/src/lv2/data-access.h @@ -1,6 +1,6 @@ /* LV2 Data Access Extension - Copyright 2008-2011 David Robillard + Copyright 2008-2016 David Robillard Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -16,18 +16,19 @@ */ /** - @file data-access.h - C header for the LV2 Extension Data extension - . + @defgroup data-access Data Access - This extension defines a method for (e.g.) plugin UIs to have (possibly - marshalled) access to the extension_data function on a plugin instance. + Access to plugin extension_data() for UIs, see + for details. + + @{ */ #ifndef LV2_DATA_ACCESS_H #define LV2_DATA_ACCESS_H -#define LV2_DATA_ACCESS_URI "http://lv2plug.in/ns/ext/data-access" +#define LV2_DATA_ACCESS_URI "http://lv2plug.in/ns/ext/data-access" ///< http://lv2plug.in/ns/ext/data-access +#define LV2_DATA_ACCESS_PREFIX LV2_DATA_ACCESS_URI "#" ///< http://lv2plug.in/ns/ext/data-access# #ifdef __cplusplus extern "C" { @@ -61,3 +62,7 @@ typedef struct { #endif #endif /* LV2_DATA_ACCESS_H */ + +/** + @} +*/ diff --git a/dpf/distrho/src/lv2/dynmanifest.h b/dpf/distrho/src/lv2/dynmanifest.h index fad33c8..afe32ae 100644 --- a/dpf/distrho/src/lv2/dynmanifest.h +++ b/dpf/distrho/src/lv2/dynmanifest.h @@ -16,10 +16,12 @@ */ /** - @file dynmanifest.h - C header for the LV2 Dynamic Manifest extension - . - Revision: 1.2 + @defgroup dynmanifest Dynamic Manifest + + Support for dynamic data generation, see + for details. + + @{ */ #ifndef LV2_DYN_MANIFEST_H_INCLUDED @@ -29,7 +31,8 @@ #include "lv2.h" -#define LV2_DYN_MANIFEST_URI "http://lv2plug.in/ns/ext/dynmanifest" +#define LV2_DYN_MANIFEST_URI "http://lv2plug.in/ns/ext/dynmanifest" ///< http://lv2plug.in/ns/ext/dynmanifest +#define LV2_DYN_MANIFEST_PREFIX LV2_DYN_MANIFEST_URI "#" ///< http://lv2plug.in/ns/ext/dynmanifest# #ifdef __cplusplus extern "C" { @@ -142,3 +145,7 @@ void lv2_dyn_manifest_close(LV2_Dyn_Manifest_Handle handle); #endif #endif /* LV2_DYN_MANIFEST_H_INCLUDED */ + +/** + @} +*/ diff --git a/dpf/distrho/src/lv2/event-helpers.h b/dpf/distrho/src/lv2/event-helpers.h index 5caaab5..2c627f7 100644 --- a/dpf/distrho/src/lv2/event-helpers.h +++ b/dpf/distrho/src/lv2/event-helpers.h @@ -1,5 +1,5 @@ /* - Copyright 2008-2012 David Robillard + Copyright 2008-2015 David Robillard Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -96,8 +96,8 @@ typedef struct { } LV2_Event_Iterator; -/** Reset an iterator to point to the start of @a buf. - * @return True if @a iter is valid, otherwise false (buffer is empty) */ +/** Reset an iterator to point to the start of `buf`. + * @return True if `iter` is valid, otherwise false (buffer is empty) */ static inline bool lv2_event_begin(LV2_Event_Iterator* iter, LV2_Event_Buffer* buf) @@ -108,8 +108,8 @@ lv2_event_begin(LV2_Event_Iterator* iter, } -/** Check if @a iter is valid. - * @return True if @a iter is valid, otherwise false (past end of buffer) */ +/** Check if `iter` is valid. + * @return True if `iter` is valid, otherwise false (past end of buffer) */ static inline bool lv2_event_is_valid(LV2_Event_Iterator* iter) { @@ -117,9 +117,9 @@ lv2_event_is_valid(LV2_Event_Iterator* iter) } -/** Advance @a iter forward one event. - * @a iter must be valid. - * @return True if @a iter is valid, otherwise false (reached end of buffer) */ +/** Advance `iter` forward one event. + * `iter` must be valid. + * @return True if `iter` is valid, otherwise false (reached end of buffer) */ static inline bool lv2_event_increment(LV2_Event_Iterator* iter) { @@ -138,11 +138,11 @@ lv2_event_increment(LV2_Event_Iterator* iter) /** Dereference an event iterator (get the event currently pointed at). - * @a iter must be valid. - * @a data if non-NULL, will be set to point to the contents of the event + * `iter` must be valid. + * `data` if non-NULL, will be set to point to the contents of the event * returned. - * @return A Pointer to the event @a iter is currently pointing at, or NULL - * if the end of the buffer is reached (in which case @a data is + * @return A Pointer to the event `iter` is currently pointing at, or NULL + * if the end of the buffer is reached (in which case `data` is * also set to NULL). */ static inline LV2_Event* lv2_event_get(LV2_Event_Iterator* iter, @@ -162,8 +162,8 @@ lv2_event_get(LV2_Event_Iterator* iter, } -/** Write an event at @a iter. - * The event (if any) pointed to by @a iter will be overwritten, and @a iter +/** Write an event at `iter`. + * The event (if any) pointed to by `iter` will be overwritten, and `iter` * incremented to point to the following event (i.e. several calls to this * function can be done in sequence without twiddling iter in-between). * @return True if event was written, otherwise false (buffer is full). */ @@ -230,8 +230,8 @@ lv2_event_reserve(LV2_Event_Iterator* iter, } -/** Write an event at @a iter. - * The event (if any) pointed to by @a iter will be overwritten, and @a iter +/** Write an event at `iter`. + * The event (if any) pointed to by `iter` will be overwritten, and `iter` * incremented to point to the following event (i.e. several calls to this * function can be done in sequence without twiddling iter in-between). * @return True if event was written, otherwise false (buffer is full). */ @@ -263,4 +263,3 @@ lv2_event_write_event(LV2_Event_Iterator* iter, #endif #endif /* LV2_EVENT_HELPERS_H */ - diff --git a/dpf/distrho/src/lv2/event.h b/dpf/distrho/src/lv2/event.h index e33d862..8b850d1 100644 --- a/dpf/distrho/src/lv2/event.h +++ b/dpf/distrho/src/lv2/event.h @@ -1,5 +1,5 @@ /* - Copyright 2008-2011 David Robillard + Copyright 2008-2016 David Robillard Copyright 2006-2007 Lars Luthman Permission to use, copy, modify, and/or distribute this software for any @@ -16,38 +16,32 @@ */ /** - @file event.h - C API for the LV2 Event extension . - - This extension is a generic transport mechanism for time stamped events - of any type (e.g. MIDI, OSC, ramps, etc). Each port can transport mixed - events of any type; the type of events and timestamps are defined by a URI - which is mapped to an integer by the host for performance reasons. - - This extension requires the host to support the LV2 URI Map extension. - Any host which supports this extension MUST guarantee that any call to - the LV2 URI Map uri_to_id function with the URI of this extension as the - 'map' argument returns a value within the range of uint16_t. + @defgroup event Event + + Generic time-stamped events, see for + details. + + @{ */ #ifndef LV2_EVENT_H #define LV2_EVENT_H -#define LV2_EVENT_URI "http://lv2plug.in/ns/ext/event" -#define LV2_EVENT_PREFIX LV2_EVENT_URI "#" +#define LV2_EVENT_URI "http://lv2plug.in/ns/ext/event" ///< http://lv2plug.in/ns/ext/event +#define LV2_EVENT_PREFIX LV2_EVENT_URI "#" ///< http://lv2plug.in/ns/ext/event# -#define LV2_EVENT__Event LV2_EVENT_PREFIX "Event" -#define LV2_EVENT__EventPort LV2_EVENT_PREFIX "EventPort" -#define LV2_EVENT__FrameStamp LV2_EVENT_PREFIX "FrameStamp" -#define LV2_EVENT__TimeStamp LV2_EVENT_PREFIX "TimeStamp" -#define LV2_EVENT__generatesTimeStamp LV2_EVENT_PREFIX "generatesTimeStamp" -#define LV2_EVENT__generic LV2_EVENT_PREFIX "generic" -#define LV2_EVENT__inheritsEvent LV2_EVENT_PREFIX "inheritsEvent" -#define LV2_EVENT__inheritsTimeStamp LV2_EVENT_PREFIX "inheritsTimeStamp" -#define LV2_EVENT__supportsEvent LV2_EVENT_PREFIX "supportsEvent" -#define LV2_EVENT__supportsTimeStamp LV2_EVENT_PREFIX "supportsTimeStamp" +#define LV2_EVENT__Event LV2_EVENT_PREFIX "Event" ///< http://lv2plug.in/ns/ext/event#Event +#define LV2_EVENT__EventPort LV2_EVENT_PREFIX "EventPort" ///< http://lv2plug.in/ns/ext/event#EventPort +#define LV2_EVENT__FrameStamp LV2_EVENT_PREFIX "FrameStamp" ///< http://lv2plug.in/ns/ext/event#FrameStamp +#define LV2_EVENT__TimeStamp LV2_EVENT_PREFIX "TimeStamp" ///< http://lv2plug.in/ns/ext/event#TimeStamp +#define LV2_EVENT__generatesTimeStamp LV2_EVENT_PREFIX "generatesTimeStamp" ///< http://lv2plug.in/ns/ext/event#generatesTimeStamp +#define LV2_EVENT__generic LV2_EVENT_PREFIX "generic" ///< http://lv2plug.in/ns/ext/event#generic +#define LV2_EVENT__inheritsEvent LV2_EVENT_PREFIX "inheritsEvent" ///< http://lv2plug.in/ns/ext/event#inheritsEvent +#define LV2_EVENT__inheritsTimeStamp LV2_EVENT_PREFIX "inheritsTimeStamp" ///< http://lv2plug.in/ns/ext/event#inheritsTimeStamp +#define LV2_EVENT__supportsEvent LV2_EVENT_PREFIX "supportsEvent" ///< http://lv2plug.in/ns/ext/event#supportsEvent +#define LV2_EVENT__supportsTimeStamp LV2_EVENT_PREFIX "supportsTimeStamp" ///< http://lv2plug.in/ns/ext/event#supportsTimeStamp -#define LV2_EVENT_AUDIO_STAMP 0 +#define LV2_EVENT_AUDIO_STAMP 0 ///< Special timestamp type for audio frames #include @@ -255,7 +249,7 @@ typedef struct { @param context The calling context. Like event types, this is a mapped URI, see lv2_context.h. Simple plugin with just a run() method should pass 0 here (the ID of the 'standard' LV2 run context). The host - guarantees that this function is realtime safe iff @a context is + guarantees that this function is realtime safe iff the context is realtime safe. PLUGINS THAT VIOLATE THESE RULES MAY CAUSE CRASHES AND MEMORY LEAKS. @@ -278,7 +272,7 @@ typedef struct { @param context The calling context. Like event types, this is a mapped URI, see lv2_context.h. Simple plugin with just a run() method should pass 0 here (the ID of the 'standard' LV2 run context). The host - guarantees that this function is realtime safe iff @a context is + guarantees that this function is realtime safe iff the context is realtime safe. PLUGINS THAT VIOLATE THESE RULES MAY CAUSE CRASHES AND MEMORY LEAKS. @@ -292,3 +286,7 @@ typedef struct { #endif #endif /* LV2_EVENT_H */ + +/** + @} +*/ diff --git a/dpf/distrho/src/lv2/instance-access.h b/dpf/distrho/src/lv2/instance-access.h index 06d8dde..7e328fd 100644 --- a/dpf/distrho/src/lv2/instance-access.h +++ b/dpf/distrho/src/lv2/instance-access.h @@ -1,6 +1,6 @@ /* LV2 Instance Access Extension - Copyright 2008-2012 David Robillard + Copyright 2008-2016 David Robillard Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -15,23 +15,22 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef LV2_INSTANCE_ACCESS_H -#define LV2_INSTANCE_ACCESS_H +/** + @defgroup instance-access Instance Access -#define LV2_INSTANCE_ACCESS_URI "http://lv2plug.in/ns/ext/instance-access" + Access to the LV2_Handle of a plugin for UIs; see + for details. -/** - @file instance-access.h - C header for the LV2 Instance Access extension - . - - This extension defines a method for (e.g.) plugin UIs to get a direct - handle to an LV2 plugin instance (LV2_Handle), if possible. - - To support this feature the host must pass an LV2_Feature struct to the - UI instantiate method with URI "http://lv2plug.in/ns/ext/instance-access" - and data pointed directly to the LV2_Handle of the plugin instance. + @{ */ +#ifndef LV2_INSTANCE_ACCESS_H +#define LV2_INSTANCE_ACCESS_H + +#define LV2_INSTANCE_ACCESS_URI "http://lv2plug.in/ns/ext/instance-access" ///< http://lv2plug.in/ns/ext/instance-access + #endif /* LV2_INSTANCE_ACCESS_H */ +/** + @} +*/ diff --git a/dpf/distrho/src/lv2/log.h b/dpf/distrho/src/lv2/log.h index 4b7b0f4..047316d 100644 --- a/dpf/distrho/src/lv2/log.h +++ b/dpf/distrho/src/lv2/log.h @@ -1,5 +1,5 @@ /* - Copyright 2012 David Robillard + Copyright 2012-2016 David Robillard Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -15,22 +15,26 @@ */ /** - @file log.h C header for the LV2 Log extension - . + @defgroup log Log + + Interface for plugins to log via the host; see + for details. + + @{ */ #ifndef LV2_LOG_H #define LV2_LOG_H -#define LV2_LOG_URI "http://lv2plug.in/ns/ext/log" -#define LV2_LOG_PREFIX LV2_LOG_URI "#" +#define LV2_LOG_URI "http://lv2plug.in/ns/ext/log" ///< http://lv2plug.in/ns/ext/log +#define LV2_LOG_PREFIX LV2_LOG_URI "#" ///< http://lv2plug.in/ns/ext/log# -#define LV2_LOG__Entry LV2_LOG_PREFIX "Entry" -#define LV2_LOG__Error LV2_LOG_PREFIX "Error" -#define LV2_LOG__Note LV2_LOG_PREFIX "Note" -#define LV2_LOG__Trace LV2_LOG_PREFIX "Trace" -#define LV2_LOG__Warning LV2_LOG_PREFIX "Warning" -#define LV2_LOG__log LV2_LOG_PREFIX "log" +#define LV2_LOG__Entry LV2_LOG_PREFIX "Entry" ///< http://lv2plug.in/ns/ext/log#Entry +#define LV2_LOG__Error LV2_LOG_PREFIX "Error" ///< http://lv2plug.in/ns/ext/log#Error +#define LV2_LOG__Note LV2_LOG_PREFIX "Note" ///< http://lv2plug.in/ns/ext/log#Note +#define LV2_LOG__Trace LV2_LOG_PREFIX "Trace" ///< http://lv2plug.in/ns/ext/log#Trace +#define LV2_LOG__Warning LV2_LOG_PREFIX "Warning" ///< http://lv2plug.in/ns/ext/log#Warning +#define LV2_LOG__log LV2_LOG_PREFIX "log" ///< http://lv2plug.in/ns/ext/log#log #include @@ -40,12 +44,14 @@ extern "C" { #endif +/** @cond */ #ifdef __GNUC__ /** Allow type checking of printf-like functions. */ # define LV2_LOG_FUNC(fmt, arg1) __attribute__((format(printf, fmt, arg1))) #else # define LV2_LOG_FUNC(fmt, arg1) #endif +/** @endcond */ /** Opaque data to host data for LV2_Log_Log. @@ -69,7 +75,7 @@ typedef struct _LV2_Log { The API of this function matches that of the standard C printf function, except for the addition of the first two parameters. This function may - be called from any non-realtime context, or from any context if @p type + be called from any non-realtime context, or from any context if `type` is @ref LV2_LOG__Trace. */ LV2_LOG_FUNC(3, 4) @@ -83,7 +89,7 @@ typedef struct _LV2_Log { The API of this function matches that of the standard C vprintf function, except for the addition of the first two parameters. This function may be called from any non-realtime context, or from any - context if @p type is @ref LV2_LOG__Trace. + context if `type` is @ref LV2_LOG__Trace. */ LV2_LOG_FUNC(3, 0) int (*vprintf)(LV2_Log_Handle handle, @@ -97,3 +103,7 @@ typedef struct _LV2_Log { #endif #endif /* LV2_LOG_H */ + +/** + @} +*/ diff --git a/dpf/distrho/src/lv2/logger.h b/dpf/distrho/src/lv2/logger.h index 9143544..138b96d 100644 --- a/dpf/distrho/src/lv2/logger.h +++ b/dpf/distrho/src/lv2/logger.h @@ -1,5 +1,5 @@ /* - Copyright 2012-2013 David Robillard + Copyright 2012-2016 David Robillard Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -15,13 +15,14 @@ */ /** - @file logger.h Convenience API for easy logging in plugin code. + @defgroup logger Logger + @ingroup log - This file provides simple wrappers for the most common log operations for - use in plugin implementations. If host support for logging is not - available, then these functions will print to stderr instead. + Convenience API for easy logging in plugin code. This API provides simple + wrappers for logging from a plugin, which automatically fall back to + printing to stderr if host support is unavailabe. - This header is non-normative, it is provided for convenience. + @{ */ #ifndef LV2_ATOM_LOGGER_H @@ -49,27 +50,40 @@ typedef struct { } LV2_Log_Logger; /** - Initialise @p logger. + Set `map` as the URI map for `logger`. - URIs will be mapped using @p map and stored, a reference to @p map itself is - not held. Both @p map and @p log may be NULL when unsupported by the host, - in which case the implementation will fall back to printing to stderr. + This affects the message type URIDs (Error, Warning, etc) which are passed + to the log's print functions. */ static inline void -lv2_log_logger_init(LV2_Log_Logger* logger, - LV2_URID_Map* map, - LV2_Log_Log* log) +lv2_log_logger_set_map(LV2_Log_Logger* logger, LV2_URID_Map* map) { - memset(logger, 0, sizeof(LV2_Log_Logger)); - logger->log = log; if (map) { logger->Error = map->map(map->handle, LV2_LOG__Error); logger->Note = map->map(map->handle, LV2_LOG__Note); logger->Trace = map->map(map->handle, LV2_LOG__Trace); logger->Warning = map->map(map->handle, LV2_LOG__Warning); + } else { + logger->Error = logger->Note = logger->Trace = logger->Warning = 0; } } +/** + Initialise `logger`. + + URIs will be mapped using `map` and stored, a reference to `map` itself is + not held. Both `map` and `log` may be NULL when unsupported by the host, + in which case the implementation will fall back to printing to stderr. +*/ +static inline void +lv2_log_logger_init(LV2_Log_Logger* logger, + LV2_URID_Map* map, + LV2_Log_Log* log) +{ + logger->log = log; + lv2_log_logger_set_map(logger, map); +} + /** Log a message to the host, or stderr if support is unavailable. */ @@ -80,7 +94,7 @@ lv2_log_vprintf(LV2_Log_Logger* logger, const char* fmt, va_list args) { - if (logger->log) { + if (logger && logger->log) { return logger->log->vprintf(logger->log->handle, type, fmt, args); } else { return vfprintf(stderr, fmt, args); @@ -135,12 +149,12 @@ lv2_log_warning(LV2_Log_Logger* logger, const char* fmt, ...) return ret; } -/** - @} -*/ - #ifdef __cplusplus } /* extern "C" */ #endif #endif /* LV2_LOG_LOGGER_H */ + +/** + @} +*/ diff --git a/dpf/distrho/src/lv2/lv2.h b/dpf/distrho/src/lv2/lv2.h index 6e0edaa..eaca514 100644 --- a/dpf/distrho/src/lv2/lv2.h +++ b/dpf/distrho/src/lv2/lv2.h @@ -19,9 +19,11 @@ */ /** - @file lv2.h - API for the LV2 specification . - Revision: 12.0 + @defgroup lv2core LV2 Core + + Core LV2 specification, see for details. + + @{ */ #ifndef LV2_H_INCLUDED @@ -29,93 +31,93 @@ #include -#define LV2_CORE_URI "http://lv2plug.in/ns/lv2core" -#define LV2_CORE_PREFIX LV2_CORE_URI "#" - -#define LV2_CORE__AllpassPlugin LV2_CORE_PREFIX "AllpassPlugin" -#define LV2_CORE__AmplifierPlugin LV2_CORE_PREFIX "AmplifierPlugin" -#define LV2_CORE__AnalyserPlugin LV2_CORE_PREFIX "AnalyserPlugin" -#define LV2_CORE__AudioPort LV2_CORE_PREFIX "AudioPort" -#define LV2_CORE__BandpassPlugin LV2_CORE_PREFIX "BandpassPlugin" -#define LV2_CORE__CVPort LV2_CORE_PREFIX "CVPort" -#define LV2_CORE__ChorusPlugin LV2_CORE_PREFIX "ChorusPlugin" -#define LV2_CORE__CombPlugin LV2_CORE_PREFIX "CombPlugin" -#define LV2_CORE__CompressorPlugin LV2_CORE_PREFIX "CompressorPlugin" -#define LV2_CORE__ConstantPlugin LV2_CORE_PREFIX "ConstantPlugin" -#define LV2_CORE__ControlPort LV2_CORE_PREFIX "ControlPort" -#define LV2_CORE__ConverterPlugin LV2_CORE_PREFIX "ConverterPlugin" -#define LV2_CORE__DelayPlugin LV2_CORE_PREFIX "DelayPlugin" -#define LV2_CORE__DistortionPlugin LV2_CORE_PREFIX "DistortionPlugin" -#define LV2_CORE__DynamicsPlugin LV2_CORE_PREFIX "DynamicsPlugin" -#define LV2_CORE__EQPlugin LV2_CORE_PREFIX "EQPlugin" -#define LV2_CORE__EnvelopePlugin LV2_CORE_PREFIX "EnvelopePlugin" -#define LV2_CORE__ExpanderPlugin LV2_CORE_PREFIX "ExpanderPlugin" -#define LV2_CORE__ExtensionData LV2_CORE_PREFIX "ExtensionData" -#define LV2_CORE__Feature LV2_CORE_PREFIX "Feature" -#define LV2_CORE__FilterPlugin LV2_CORE_PREFIX "FilterPlugin" -#define LV2_CORE__FlangerPlugin LV2_CORE_PREFIX "FlangerPlugin" -#define LV2_CORE__FunctionPlugin LV2_CORE_PREFIX "FunctionPlugin" -#define LV2_CORE__GatePlugin LV2_CORE_PREFIX "GatePlugin" -#define LV2_CORE__GeneratorPlugin LV2_CORE_PREFIX "GeneratorPlugin" -#define LV2_CORE__HighpassPlugin LV2_CORE_PREFIX "HighpassPlugin" -#define LV2_CORE__InputPort LV2_CORE_PREFIX "InputPort" -#define LV2_CORE__InstrumentPlugin LV2_CORE_PREFIX "InstrumentPlugin" -#define LV2_CORE__LimiterPlugin LV2_CORE_PREFIX "LimiterPlugin" -#define LV2_CORE__LowpassPlugin LV2_CORE_PREFIX "LowpassPlugin" -#define LV2_CORE__MixerPlugin LV2_CORE_PREFIX "MixerPlugin" -#define LV2_CORE__ModulatorPlugin LV2_CORE_PREFIX "ModulatorPlugin" -#define LV2_CORE__MultiEQPlugin LV2_CORE_PREFIX "MultiEQPlugin" -#define LV2_CORE__OscillatorPlugin LV2_CORE_PREFIX "OscillatorPlugin" -#define LV2_CORE__OutputPort LV2_CORE_PREFIX "OutputPort" -#define LV2_CORE__ParaEQPlugin LV2_CORE_PREFIX "ParaEQPlugin" -#define LV2_CORE__PhaserPlugin LV2_CORE_PREFIX "PhaserPlugin" -#define LV2_CORE__PitchPlugin LV2_CORE_PREFIX "PitchPlugin" -#define LV2_CORE__Plugin LV2_CORE_PREFIX "Plugin" -#define LV2_CORE__PluginBase LV2_CORE_PREFIX "PluginBase" -#define LV2_CORE__Point LV2_CORE_PREFIX "Point" -#define LV2_CORE__Port LV2_CORE_PREFIX "Port" -#define LV2_CORE__PortProperty LV2_CORE_PREFIX "PortProperty" -#define LV2_CORE__Resource LV2_CORE_PREFIX "Resource" -#define LV2_CORE__ReverbPlugin LV2_CORE_PREFIX "ReverbPlugin" -#define LV2_CORE__ScalePoint LV2_CORE_PREFIX "ScalePoint" -#define LV2_CORE__SimulatorPlugin LV2_CORE_PREFIX "SimulatorPlugin" -#define LV2_CORE__SpatialPlugin LV2_CORE_PREFIX "SpatialPlugin" -#define LV2_CORE__Specification LV2_CORE_PREFIX "Specification" -#define LV2_CORE__SpectralPlugin LV2_CORE_PREFIX "SpectralPlugin" -#define LV2_CORE__UtilityPlugin LV2_CORE_PREFIX "UtilityPlugin" -#define LV2_CORE__WaveshaperPlugin LV2_CORE_PREFIX "WaveshaperPlugin" -#define LV2_CORE__appliesTo LV2_CORE_PREFIX "appliesTo" -#define LV2_CORE__binary LV2_CORE_PREFIX "binary" -#define LV2_CORE__connectionOptional LV2_CORE_PREFIX "connectionOptional" -#define LV2_CORE__control LV2_CORE_PREFIX "control" -#define LV2_CORE__default LV2_CORE_PREFIX "default" -#define LV2_CORE__designation LV2_CORE_PREFIX "designation" -#define LV2_CORE__documentation LV2_CORE_PREFIX "documentation" -#define LV2_CORE__enumeration LV2_CORE_PREFIX "enumeration" -#define LV2_CORE__extensionData LV2_CORE_PREFIX "extensionData" -#define LV2_CORE__freeWheeling LV2_CORE_PREFIX "freeWheeling" -#define LV2_CORE__hardRTCapable LV2_CORE_PREFIX "hardRTCapable" -#define LV2_CORE__inPlaceBroken LV2_CORE_PREFIX "inPlaceBroken" -#define LV2_CORE__index LV2_CORE_PREFIX "index" -#define LV2_CORE__integer LV2_CORE_PREFIX "integer" -#define LV2_CORE__isLive LV2_CORE_PREFIX "isLive" -#define LV2_CORE__latency LV2_CORE_PREFIX "latency" -#define LV2_CORE__maximum LV2_CORE_PREFIX "maximum" -#define LV2_CORE__microVersion LV2_CORE_PREFIX "microVersion" -#define LV2_CORE__minimum LV2_CORE_PREFIX "minimum" -#define LV2_CORE__minorVersion LV2_CORE_PREFIX "minorVersion" -#define LV2_CORE__name LV2_CORE_PREFIX "name" -#define LV2_CORE__optionalFeature LV2_CORE_PREFIX "optionalFeature" -#define LV2_CORE__port LV2_CORE_PREFIX "port" -#define LV2_CORE__portProperty LV2_CORE_PREFIX "portProperty" -#define LV2_CORE__project LV2_CORE_PREFIX "project" -#define LV2_CORE__prototype LV2_CORE_PREFIX "prototype" -#define LV2_CORE__reportsLatency LV2_CORE_PREFIX "reportsLatency" -#define LV2_CORE__requiredFeature LV2_CORE_PREFIX "requiredFeature" -#define LV2_CORE__sampleRate LV2_CORE_PREFIX "sampleRate" -#define LV2_CORE__scalePoint LV2_CORE_PREFIX "scalePoint" -#define LV2_CORE__symbol LV2_CORE_PREFIX "symbol" -#define LV2_CORE__toggled LV2_CORE_PREFIX "toggled" +#define LV2_CORE_URI "http://lv2plug.in/ns/lv2core" ///< http://lv2plug.in/ns/lv2core +#define LV2_CORE_PREFIX LV2_CORE_URI "#" ///< http://lv2plug.in/ns/lv2core# + +#define LV2_CORE__AllpassPlugin LV2_CORE_PREFIX "AllpassPlugin" ///< http://lv2plug.in/ns/lv2core#AllpassPlugin +#define LV2_CORE__AmplifierPlugin LV2_CORE_PREFIX "AmplifierPlugin" ///< http://lv2plug.in/ns/lv2core#AmplifierPlugin +#define LV2_CORE__AnalyserPlugin LV2_CORE_PREFIX "AnalyserPlugin" ///< http://lv2plug.in/ns/lv2core#AnalyserPlugin +#define LV2_CORE__AudioPort LV2_CORE_PREFIX "AudioPort" ///< http://lv2plug.in/ns/lv2core#AudioPort +#define LV2_CORE__BandpassPlugin LV2_CORE_PREFIX "BandpassPlugin" ///< http://lv2plug.in/ns/lv2core#BandpassPlugin +#define LV2_CORE__CVPort LV2_CORE_PREFIX "CVPort" ///< http://lv2plug.in/ns/lv2core#CVPort +#define LV2_CORE__ChorusPlugin LV2_CORE_PREFIX "ChorusPlugin" ///< http://lv2plug.in/ns/lv2core#ChorusPlugin +#define LV2_CORE__CombPlugin LV2_CORE_PREFIX "CombPlugin" ///< http://lv2plug.in/ns/lv2core#CombPlugin +#define LV2_CORE__CompressorPlugin LV2_CORE_PREFIX "CompressorPlugin" ///< http://lv2plug.in/ns/lv2core#CompressorPlugin +#define LV2_CORE__ConstantPlugin LV2_CORE_PREFIX "ConstantPlugin" ///< http://lv2plug.in/ns/lv2core#ConstantPlugin +#define LV2_CORE__ControlPort LV2_CORE_PREFIX "ControlPort" ///< http://lv2plug.in/ns/lv2core#ControlPort +#define LV2_CORE__ConverterPlugin LV2_CORE_PREFIX "ConverterPlugin" ///< http://lv2plug.in/ns/lv2core#ConverterPlugin +#define LV2_CORE__DelayPlugin LV2_CORE_PREFIX "DelayPlugin" ///< http://lv2plug.in/ns/lv2core#DelayPlugin +#define LV2_CORE__DistortionPlugin LV2_CORE_PREFIX "DistortionPlugin" ///< http://lv2plug.in/ns/lv2core#DistortionPlugin +#define LV2_CORE__DynamicsPlugin LV2_CORE_PREFIX "DynamicsPlugin" ///< http://lv2plug.in/ns/lv2core#DynamicsPlugin +#define LV2_CORE__EQPlugin LV2_CORE_PREFIX "EQPlugin" ///< http://lv2plug.in/ns/lv2core#EQPlugin +#define LV2_CORE__EnvelopePlugin LV2_CORE_PREFIX "EnvelopePlugin" ///< http://lv2plug.in/ns/lv2core#EnvelopePlugin +#define LV2_CORE__ExpanderPlugin LV2_CORE_PREFIX "ExpanderPlugin" ///< http://lv2plug.in/ns/lv2core#ExpanderPlugin +#define LV2_CORE__ExtensionData LV2_CORE_PREFIX "ExtensionData" ///< http://lv2plug.in/ns/lv2core#ExtensionData +#define LV2_CORE__Feature LV2_CORE_PREFIX "Feature" ///< http://lv2plug.in/ns/lv2core#Feature +#define LV2_CORE__FilterPlugin LV2_CORE_PREFIX "FilterPlugin" ///< http://lv2plug.in/ns/lv2core#FilterPlugin +#define LV2_CORE__FlangerPlugin LV2_CORE_PREFIX "FlangerPlugin" ///< http://lv2plug.in/ns/lv2core#FlangerPlugin +#define LV2_CORE__FunctionPlugin LV2_CORE_PREFIX "FunctionPlugin" ///< http://lv2plug.in/ns/lv2core#FunctionPlugin +#define LV2_CORE__GatePlugin LV2_CORE_PREFIX "GatePlugin" ///< http://lv2plug.in/ns/lv2core#GatePlugin +#define LV2_CORE__GeneratorPlugin LV2_CORE_PREFIX "GeneratorPlugin" ///< http://lv2plug.in/ns/lv2core#GeneratorPlugin +#define LV2_CORE__HighpassPlugin LV2_CORE_PREFIX "HighpassPlugin" ///< http://lv2plug.in/ns/lv2core#HighpassPlugin +#define LV2_CORE__InputPort LV2_CORE_PREFIX "InputPort" ///< http://lv2plug.in/ns/lv2core#InputPort +#define LV2_CORE__InstrumentPlugin LV2_CORE_PREFIX "InstrumentPlugin" ///< http://lv2plug.in/ns/lv2core#InstrumentPlugin +#define LV2_CORE__LimiterPlugin LV2_CORE_PREFIX "LimiterPlugin" ///< http://lv2plug.in/ns/lv2core#LimiterPlugin +#define LV2_CORE__LowpassPlugin LV2_CORE_PREFIX "LowpassPlugin" ///< http://lv2plug.in/ns/lv2core#LowpassPlugin +#define LV2_CORE__MixerPlugin LV2_CORE_PREFIX "MixerPlugin" ///< http://lv2plug.in/ns/lv2core#MixerPlugin +#define LV2_CORE__ModulatorPlugin LV2_CORE_PREFIX "ModulatorPlugin" ///< http://lv2plug.in/ns/lv2core#ModulatorPlugin +#define LV2_CORE__MultiEQPlugin LV2_CORE_PREFIX "MultiEQPlugin" ///< http://lv2plug.in/ns/lv2core#MultiEQPlugin +#define LV2_CORE__OscillatorPlugin LV2_CORE_PREFIX "OscillatorPlugin" ///< http://lv2plug.in/ns/lv2core#OscillatorPlugin +#define LV2_CORE__OutputPort LV2_CORE_PREFIX "OutputPort" ///< http://lv2plug.in/ns/lv2core#OutputPort +#define LV2_CORE__ParaEQPlugin LV2_CORE_PREFIX "ParaEQPlugin" ///< http://lv2plug.in/ns/lv2core#ParaEQPlugin +#define LV2_CORE__PhaserPlugin LV2_CORE_PREFIX "PhaserPlugin" ///< http://lv2plug.in/ns/lv2core#PhaserPlugin +#define LV2_CORE__PitchPlugin LV2_CORE_PREFIX "PitchPlugin" ///< http://lv2plug.in/ns/lv2core#PitchPlugin +#define LV2_CORE__Plugin LV2_CORE_PREFIX "Plugin" ///< http://lv2plug.in/ns/lv2core#Plugin +#define LV2_CORE__PluginBase LV2_CORE_PREFIX "PluginBase" ///< http://lv2plug.in/ns/lv2core#PluginBase +#define LV2_CORE__Point LV2_CORE_PREFIX "Point" ///< http://lv2plug.in/ns/lv2core#Point +#define LV2_CORE__Port LV2_CORE_PREFIX "Port" ///< http://lv2plug.in/ns/lv2core#Port +#define LV2_CORE__PortProperty LV2_CORE_PREFIX "PortProperty" ///< http://lv2plug.in/ns/lv2core#PortProperty +#define LV2_CORE__Resource LV2_CORE_PREFIX "Resource" ///< http://lv2plug.in/ns/lv2core#Resource +#define LV2_CORE__ReverbPlugin LV2_CORE_PREFIX "ReverbPlugin" ///< http://lv2plug.in/ns/lv2core#ReverbPlugin +#define LV2_CORE__ScalePoint LV2_CORE_PREFIX "ScalePoint" ///< http://lv2plug.in/ns/lv2core#ScalePoint +#define LV2_CORE__SimulatorPlugin LV2_CORE_PREFIX "SimulatorPlugin" ///< http://lv2plug.in/ns/lv2core#SimulatorPlugin +#define LV2_CORE__SpatialPlugin LV2_CORE_PREFIX "SpatialPlugin" ///< http://lv2plug.in/ns/lv2core#SpatialPlugin +#define LV2_CORE__Specification LV2_CORE_PREFIX "Specification" ///< http://lv2plug.in/ns/lv2core#Specification +#define LV2_CORE__SpectralPlugin LV2_CORE_PREFIX "SpectralPlugin" ///< http://lv2plug.in/ns/lv2core#SpectralPlugin +#define LV2_CORE__UtilityPlugin LV2_CORE_PREFIX "UtilityPlugin" ///< http://lv2plug.in/ns/lv2core#UtilityPlugin +#define LV2_CORE__WaveshaperPlugin LV2_CORE_PREFIX "WaveshaperPlugin" ///< http://lv2plug.in/ns/lv2core#WaveshaperPlugin +#define LV2_CORE__appliesTo LV2_CORE_PREFIX "appliesTo" ///< http://lv2plug.in/ns/lv2core#appliesTo +#define LV2_CORE__binary LV2_CORE_PREFIX "binary" ///< http://lv2plug.in/ns/lv2core#binary +#define LV2_CORE__connectionOptional LV2_CORE_PREFIX "connectionOptional" ///< http://lv2plug.in/ns/lv2core#connectionOptional +#define LV2_CORE__control LV2_CORE_PREFIX "control" ///< http://lv2plug.in/ns/lv2core#control +#define LV2_CORE__default LV2_CORE_PREFIX "default" ///< http://lv2plug.in/ns/lv2core#default +#define LV2_CORE__designation LV2_CORE_PREFIX "designation" ///< http://lv2plug.in/ns/lv2core#designation +#define LV2_CORE__documentation LV2_CORE_PREFIX "documentation" ///< http://lv2plug.in/ns/lv2core#documentation +#define LV2_CORE__enumeration LV2_CORE_PREFIX "enumeration" ///< http://lv2plug.in/ns/lv2core#enumeration +#define LV2_CORE__extensionData LV2_CORE_PREFIX "extensionData" ///< http://lv2plug.in/ns/lv2core#extensionData +#define LV2_CORE__freeWheeling LV2_CORE_PREFIX "freeWheeling" ///< http://lv2plug.in/ns/lv2core#freeWheeling +#define LV2_CORE__hardRTCapable LV2_CORE_PREFIX "hardRTCapable" ///< http://lv2plug.in/ns/lv2core#hardRTCapable +#define LV2_CORE__inPlaceBroken LV2_CORE_PREFIX "inPlaceBroken" ///< http://lv2plug.in/ns/lv2core#inPlaceBroken +#define LV2_CORE__index LV2_CORE_PREFIX "index" ///< http://lv2plug.in/ns/lv2core#index +#define LV2_CORE__integer LV2_CORE_PREFIX "integer" ///< http://lv2plug.in/ns/lv2core#integer +#define LV2_CORE__isLive LV2_CORE_PREFIX "isLive" ///< http://lv2plug.in/ns/lv2core#isLive +#define LV2_CORE__latency LV2_CORE_PREFIX "latency" ///< http://lv2plug.in/ns/lv2core#latency +#define LV2_CORE__maximum LV2_CORE_PREFIX "maximum" ///< http://lv2plug.in/ns/lv2core#maximum +#define LV2_CORE__microVersion LV2_CORE_PREFIX "microVersion" ///< http://lv2plug.in/ns/lv2core#microVersion +#define LV2_CORE__minimum LV2_CORE_PREFIX "minimum" ///< http://lv2plug.in/ns/lv2core#minimum +#define LV2_CORE__minorVersion LV2_CORE_PREFIX "minorVersion" ///< http://lv2plug.in/ns/lv2core#minorVersion +#define LV2_CORE__name LV2_CORE_PREFIX "name" ///< http://lv2plug.in/ns/lv2core#name +#define LV2_CORE__optionalFeature LV2_CORE_PREFIX "optionalFeature" ///< http://lv2plug.in/ns/lv2core#optionalFeature +#define LV2_CORE__port LV2_CORE_PREFIX "port" ///< http://lv2plug.in/ns/lv2core#port +#define LV2_CORE__portProperty LV2_CORE_PREFIX "portProperty" ///< http://lv2plug.in/ns/lv2core#portProperty +#define LV2_CORE__project LV2_CORE_PREFIX "project" ///< http://lv2plug.in/ns/lv2core#project +#define LV2_CORE__prototype LV2_CORE_PREFIX "prototype" ///< http://lv2plug.in/ns/lv2core#prototype +#define LV2_CORE__reportsLatency LV2_CORE_PREFIX "reportsLatency" ///< http://lv2plug.in/ns/lv2core#reportsLatency +#define LV2_CORE__requiredFeature LV2_CORE_PREFIX "requiredFeature" ///< http://lv2plug.in/ns/lv2core#requiredFeature +#define LV2_CORE__sampleRate LV2_CORE_PREFIX "sampleRate" ///< http://lv2plug.in/ns/lv2core#sampleRate +#define LV2_CORE__scalePoint LV2_CORE_PREFIX "scalePoint" ///< http://lv2plug.in/ns/lv2core#scalePoint +#define LV2_CORE__symbol LV2_CORE_PREFIX "symbol" ///< http://lv2plug.in/ns/lv2core#symbol +#define LV2_CORE__toggled LV2_CORE_PREFIX "toggled" ///< http://lv2plug.in/ns/lv2core#toggled #ifdef __cplusplus extern "C" { @@ -135,7 +137,7 @@ typedef void * LV2_Handle; Features allow hosts to make additional functionality available to plugins without requiring modification to the LV2 API. Extensions may define new - features and specify the @ref URI and @ref data to be used if necessary. + features and specify the `URI` and `data` to be used if necessary. Some features, such as lv2:isLive, do not require the host to pass data. */ typedef struct _LV2_Feature { @@ -150,7 +152,7 @@ typedef struct _LV2_Feature { Pointer to arbitrary data. The format of this data is defined by the extension which describes the - feature with the given @ref URI. + feature with the given `URI`. */ void * data; } LV2_Feature; @@ -276,12 +278,12 @@ typedef struct _LV2_Descriptor { things that the plugin MUST NOT do within the run() function (see lv2core.ttl for details). - As a special case, when @p sample_count == 0, the plugin should update + As a special case, when `sample_count` is 0, the plugin should update any output ports that represent a single instant in time (e.g. control ports, but not audio ports). This is particularly useful for latent plugins, which should update their latency output port so hosts can pre-roll plugins to compute latency. Plugins MUST NOT crash when - @p sample_count == 0. + `sample_count` is 0. @param instance Instance to be run. @@ -340,14 +342,23 @@ typedef struct _LV2_Descriptor { const void * (*extension_data)(const char * uri); } LV2_Descriptor; +/** + Helper macro needed for LV2_SYMBOL_EXPORT when using C++. +*/ +#ifdef __cplusplus +# define LV2_SYMBOL_EXTERN extern "C" +#else +# define LV2_SYMBOL_EXTERN +#endif + /** Put this (LV2_SYMBOL_EXPORT) before any functions that are to be loaded by the host as a symbol from the dynamic library. */ #ifdef _WIN32 -# define LV2_SYMBOL_EXPORT __declspec(dllexport) +# define LV2_SYMBOL_EXPORT LV2_SYMBOL_EXTERN __declspec(dllexport) #else -# define LV2_SYMBOL_EXPORT +# define LV2_SYMBOL_EXPORT LV2_SYMBOL_EXTERN __attribute__((visibility("default"))) #endif /** @@ -368,9 +379,9 @@ typedef struct _LV2_Descriptor { function to find the LV2_Descriptor for the desired plugin. Plugins are accessed by index using values from 0 upwards. This function MUST return NULL for out of range indices, so the host can enumerate plugins by - increasing @p index until NULL is returned. + increasing `index` until NULL is returned. - Note that @p index has no meaning, hosts MUST NOT depend on it remaining + Note that `index` has no meaning, hosts MUST NOT depend on it remaining consistent between loads of the plugin library. */ LV2_SYMBOL_EXPORT @@ -418,7 +429,7 @@ typedef struct { Plugins are accessed by index using values from 0 upwards. Out of range indices MUST result in this function returning NULL, so the host can - enumerate plugins by increasing @a index until NULL is returned. + enumerate plugins by increasing `index` until NULL is returned. */ const LV2_Descriptor * (*get_plugin)(LV2_Lib_Handle handle, uint32_t index); @@ -440,6 +451,7 @@ typedef struct { be destroyed (using LV2_Lib_Descriptor::cleanup()) until all plugins loaded from that library have been destroyed. */ +LV2_SYMBOL_EXPORT const LV2_Lib_Descriptor * lv2_lib_descriptor(const char * bundle_path, const LV2_Feature *const * features); @@ -456,3 +468,7 @@ typedef const LV2_Lib_Descriptor * #endif #endif /* LV2_H_INCLUDED */ + +/** + @} +*/ diff --git a/dpf/distrho/src/lv2/midi.h b/dpf/distrho/src/lv2/midi.h index 2c53c49..79e3a83 100644 --- a/dpf/distrho/src/lv2/midi.h +++ b/dpf/distrho/src/lv2/midi.h @@ -1,5 +1,5 @@ /* - Copyright 2012 David Robillard + Copyright 2012-2016 David Robillard Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -15,8 +15,12 @@ */ /** - @file midi.h - C definitions for the LV2 MIDI extension . + @defgroup midi MIDI + + Definitions of standard MIDI messages, see + for details. + + @{ */ #ifndef LV2_MIDI_H @@ -30,50 +34,50 @@ extern "C" { # include #endif -#define LV2_MIDI_URI "http://lv2plug.in/ns/ext/midi" -#define LV2_MIDI_PREFIX LV2_MIDI_URI "#" - -#define LV2_MIDI__ActiveSense LV2_MIDI_PREFIX "ActiveSense" -#define LV2_MIDI__Aftertouch LV2_MIDI_PREFIX "Aftertouch" -#define LV2_MIDI__Bender LV2_MIDI_PREFIX "Bender" -#define LV2_MIDI__ChannelPressure LV2_MIDI_PREFIX "ChannelPressure" -#define LV2_MIDI__Chunk LV2_MIDI_PREFIX "Chunk" -#define LV2_MIDI__Clock LV2_MIDI_PREFIX "Clock" -#define LV2_MIDI__Continue LV2_MIDI_PREFIX "Continue" -#define LV2_MIDI__Controller LV2_MIDI_PREFIX "Controller" -#define LV2_MIDI__MidiEvent LV2_MIDI_PREFIX "MidiEvent" -#define LV2_MIDI__NoteOff LV2_MIDI_PREFIX "NoteOff" -#define LV2_MIDI__NoteOn LV2_MIDI_PREFIX "NoteOn" -#define LV2_MIDI__ProgramChange LV2_MIDI_PREFIX "ProgramChange" -#define LV2_MIDI__QuarterFrame LV2_MIDI_PREFIX "QuarterFrame" -#define LV2_MIDI__Reset LV2_MIDI_PREFIX "Reset" -#define LV2_MIDI__SongPosition LV2_MIDI_PREFIX "SongPosition" -#define LV2_MIDI__SongSelect LV2_MIDI_PREFIX "SongSelect" -#define LV2_MIDI__Start LV2_MIDI_PREFIX "Start" -#define LV2_MIDI__Stop LV2_MIDI_PREFIX "Stop" -#define LV2_MIDI__SystemCommon LV2_MIDI_PREFIX "SystemCommon" -#define LV2_MIDI__SystemExclusive LV2_MIDI_PREFIX "SystemExclusive" -#define LV2_MIDI__SystemMessage LV2_MIDI_PREFIX "SystemMessage" -#define LV2_MIDI__SystemRealtime LV2_MIDI_PREFIX "SystemRealtime" -#define LV2_MIDI__Tick LV2_MIDI_PREFIX "Tick" -#define LV2_MIDI__TuneRequest LV2_MIDI_PREFIX "TuneRequest" -#define LV2_MIDI__VoiceMessage LV2_MIDI_PREFIX "VoiceMessage" -#define LV2_MIDI__benderValue LV2_MIDI_PREFIX "benderValue" -#define LV2_MIDI__binding LV2_MIDI_PREFIX "binding" -#define LV2_MIDI__byteNumber LV2_MIDI_PREFIX "byteNumber" -#define LV2_MIDI__channel LV2_MIDI_PREFIX "channel" -#define LV2_MIDI__chunk LV2_MIDI_PREFIX "chunk" -#define LV2_MIDI__controllerNumber LV2_MIDI_PREFIX "controllerNumber" -#define LV2_MIDI__controllerValue LV2_MIDI_PREFIX "controllerValue" -#define LV2_MIDI__noteNumber LV2_MIDI_PREFIX "noteNumber" -#define LV2_MIDI__pressure LV2_MIDI_PREFIX "pressure" -#define LV2_MIDI__programNumber LV2_MIDI_PREFIX "programNumber" -#define LV2_MIDI__property LV2_MIDI_PREFIX "property" -#define LV2_MIDI__songNumber LV2_MIDI_PREFIX "songNumber" -#define LV2_MIDI__songPosition LV2_MIDI_PREFIX "songPosition" -#define LV2_MIDI__status LV2_MIDI_PREFIX "status" -#define LV2_MIDI__statusMask LV2_MIDI_PREFIX "statusMask" -#define LV2_MIDI__velocity LV2_MIDI_PREFIX "velocity" +#define LV2_MIDI_URI "http://lv2plug.in/ns/ext/midi" ///< http://lv2plug.in/ns/ext/midi +#define LV2_MIDI_PREFIX LV2_MIDI_URI "#" ///< http://lv2plug.in/ns/ext/midi# + +#define LV2_MIDI__ActiveSense LV2_MIDI_PREFIX "ActiveSense" ///< http://lv2plug.in/ns/ext/midi#ActiveSense +#define LV2_MIDI__Aftertouch LV2_MIDI_PREFIX "Aftertouch" ///< http://lv2plug.in/ns/ext/midi#Aftertouch +#define LV2_MIDI__Bender LV2_MIDI_PREFIX "Bender" ///< http://lv2plug.in/ns/ext/midi#Bender +#define LV2_MIDI__ChannelPressure LV2_MIDI_PREFIX "ChannelPressure" ///< http://lv2plug.in/ns/ext/midi#ChannelPressure +#define LV2_MIDI__Chunk LV2_MIDI_PREFIX "Chunk" ///< http://lv2plug.in/ns/ext/midi#Chunk +#define LV2_MIDI__Clock LV2_MIDI_PREFIX "Clock" ///< http://lv2plug.in/ns/ext/midi#Clock +#define LV2_MIDI__Continue LV2_MIDI_PREFIX "Continue" ///< http://lv2plug.in/ns/ext/midi#Continue +#define LV2_MIDI__Controller LV2_MIDI_PREFIX "Controller" ///< http://lv2plug.in/ns/ext/midi#Controller +#define LV2_MIDI__MidiEvent LV2_MIDI_PREFIX "MidiEvent" ///< http://lv2plug.in/ns/ext/midi#MidiEvent +#define LV2_MIDI__NoteOff LV2_MIDI_PREFIX "NoteOff" ///< http://lv2plug.in/ns/ext/midi#NoteOff +#define LV2_MIDI__NoteOn LV2_MIDI_PREFIX "NoteOn" ///< http://lv2plug.in/ns/ext/midi#NoteOn +#define LV2_MIDI__ProgramChange LV2_MIDI_PREFIX "ProgramChange" ///< http://lv2plug.in/ns/ext/midi#ProgramChange +#define LV2_MIDI__QuarterFrame LV2_MIDI_PREFIX "QuarterFrame" ///< http://lv2plug.in/ns/ext/midi#QuarterFrame +#define LV2_MIDI__Reset LV2_MIDI_PREFIX "Reset" ///< http://lv2plug.in/ns/ext/midi#Reset +#define LV2_MIDI__SongPosition LV2_MIDI_PREFIX "SongPosition" ///< http://lv2plug.in/ns/ext/midi#SongPosition +#define LV2_MIDI__SongSelect LV2_MIDI_PREFIX "SongSelect" ///< http://lv2plug.in/ns/ext/midi#SongSelect +#define LV2_MIDI__Start LV2_MIDI_PREFIX "Start" ///< http://lv2plug.in/ns/ext/midi#Start +#define LV2_MIDI__Stop LV2_MIDI_PREFIX "Stop" ///< http://lv2plug.in/ns/ext/midi#Stop +#define LV2_MIDI__SystemCommon LV2_MIDI_PREFIX "SystemCommon" ///< http://lv2plug.in/ns/ext/midi#SystemCommon +#define LV2_MIDI__SystemExclusive LV2_MIDI_PREFIX "SystemExclusive" ///< http://lv2plug.in/ns/ext/midi#SystemExclusive +#define LV2_MIDI__SystemMessage LV2_MIDI_PREFIX "SystemMessage" ///< http://lv2plug.in/ns/ext/midi#SystemMessage +#define LV2_MIDI__SystemRealtime LV2_MIDI_PREFIX "SystemRealtime" ///< http://lv2plug.in/ns/ext/midi#SystemRealtime +#define LV2_MIDI__Tick LV2_MIDI_PREFIX "Tick" ///< http://lv2plug.in/ns/ext/midi#Tick +#define LV2_MIDI__TuneRequest LV2_MIDI_PREFIX "TuneRequest" ///< http://lv2plug.in/ns/ext/midi#TuneRequest +#define LV2_MIDI__VoiceMessage LV2_MIDI_PREFIX "VoiceMessage" ///< http://lv2plug.in/ns/ext/midi#VoiceMessage +#define LV2_MIDI__benderValue LV2_MIDI_PREFIX "benderValue" ///< http://lv2plug.in/ns/ext/midi#benderValue +#define LV2_MIDI__binding LV2_MIDI_PREFIX "binding" ///< http://lv2plug.in/ns/ext/midi#binding +#define LV2_MIDI__byteNumber LV2_MIDI_PREFIX "byteNumber" ///< http://lv2plug.in/ns/ext/midi#byteNumber +#define LV2_MIDI__channel LV2_MIDI_PREFIX "channel" ///< http://lv2plug.in/ns/ext/midi#channel +#define LV2_MIDI__chunk LV2_MIDI_PREFIX "chunk" ///< http://lv2plug.in/ns/ext/midi#chunk +#define LV2_MIDI__controllerNumber LV2_MIDI_PREFIX "controllerNumber" ///< http://lv2plug.in/ns/ext/midi#controllerNumber +#define LV2_MIDI__controllerValue LV2_MIDI_PREFIX "controllerValue" ///< http://lv2plug.in/ns/ext/midi#controllerValue +#define LV2_MIDI__noteNumber LV2_MIDI_PREFIX "noteNumber" ///< http://lv2plug.in/ns/ext/midi#noteNumber +#define LV2_MIDI__pressure LV2_MIDI_PREFIX "pressure" ///< http://lv2plug.in/ns/ext/midi#pressure +#define LV2_MIDI__programNumber LV2_MIDI_PREFIX "programNumber" ///< http://lv2plug.in/ns/ext/midi#programNumber +#define LV2_MIDI__property LV2_MIDI_PREFIX "property" ///< http://lv2plug.in/ns/ext/midi#property +#define LV2_MIDI__songNumber LV2_MIDI_PREFIX "songNumber" ///< http://lv2plug.in/ns/ext/midi#songNumber +#define LV2_MIDI__songPosition LV2_MIDI_PREFIX "songPosition" ///< http://lv2plug.in/ns/ext/midi#songPosition +#define LV2_MIDI__status LV2_MIDI_PREFIX "status" ///< http://lv2plug.in/ns/ext/midi#status +#define LV2_MIDI__statusMask LV2_MIDI_PREFIX "statusMask" ///< http://lv2plug.in/ns/ext/midi#statusMask +#define LV2_MIDI__velocity LV2_MIDI_PREFIX "velocity" ///< http://lv2plug.in/ns/ext/midi#velocity /** MIDI Message Type. @@ -184,7 +188,7 @@ typedef enum { } LV2_Midi_Controller; /** - Return true iff @p msg is a MIDI voice message (which has a channel). + Return true iff `msg` is a MIDI voice message (which has a channel). */ static inline bool lv2_midi_is_voice_message(const uint8_t* msg) { @@ -192,7 +196,7 @@ lv2_midi_is_voice_message(const uint8_t* msg) { } /** - Return true iff @p msg is a MIDI system message (which has no channel). + Return true iff `msg` is a MIDI system message (which has no channel). */ static inline bool lv2_midi_is_system_message(const uint8_t* msg) { @@ -224,3 +228,7 @@ lv2_midi_message_type(const uint8_t* msg) { #endif #endif /* LV2_MIDI_H */ + +/** + @} +*/ diff --git a/dpf/distrho/src/lv2/morph.h b/dpf/distrho/src/lv2/morph.h index df888df..884af74 100644 --- a/dpf/distrho/src/lv2/morph.h +++ b/dpf/distrho/src/lv2/morph.h @@ -1,5 +1,5 @@ /* - Copyright 2012 David Robillard + Copyright 2012-2016 David Robillard Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -14,21 +14,29 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef LV2_MORPH_H -#define LV2_MORPH_H +/** + @defgroup morph Morph -#include + Ports that can dynamically change type, see + for details. + + @{ +*/ -#include "lv2.h" -#include "urid.h" +#ifndef LV2_MORPH_H +#define LV2_MORPH_H -#define LV2_MORPH_URI "http://lv2plug.in/ns/ext/morph" -#define LV2_MORPH_PREFIX LV2_MORPH_URI "#" +#define LV2_MORPH_URI "http://lv2plug.in/ns/ext/morph" ///< http://lv2plug.in/ns/ext/morph +#define LV2_MORPH_PREFIX LV2_MORPH_URI "#" ///< http://lv2plug.in/ns/ext/morph# -#define LV2_MORPH__AutoMorphPort LV2_MORPH_PREFIX "AutoMorphPort" -#define LV2_MORPH__MorphPort LV2_MORPH_PREFIX "MorphPort" -#define LV2_MORPH__interface LV2_MORPH_PREFIX "interface" -#define LV2_MORPH__supportsType LV2_MORPH_PREFIX "supportsType" -#define LV2_MORPH__currentType LV2_MORPH_PREFIX "currentType" +#define LV2_MORPH__AutoMorphPort LV2_MORPH_PREFIX "AutoMorphPort" ///< http://lv2plug.in/ns/ext/morph#AutoMorphPort +#define LV2_MORPH__MorphPort LV2_MORPH_PREFIX "MorphPort" ///< http://lv2plug.in/ns/ext/morph#MorphPort +#define LV2_MORPH__interface LV2_MORPH_PREFIX "interface" ///< http://lv2plug.in/ns/ext/morph#interface +#define LV2_MORPH__supportsType LV2_MORPH_PREFIX "supportsType" ///< http://lv2plug.in/ns/ext/morph#supportsType +#define LV2_MORPH__currentType LV2_MORPH_PREFIX "currentType" ///< http://lv2plug.in/ns/ext/morph#currentType #endif /* LV2_MORPH_H */ + +/** + @} +*/ diff --git a/dpf/distrho/src/lv2/options.h b/dpf/distrho/src/lv2/options.h index 5437db5..70fb5b7 100644 --- a/dpf/distrho/src/lv2/options.h +++ b/dpf/distrho/src/lv2/options.h @@ -1,5 +1,5 @@ /* - Copyright 2012 David Robillard + Copyright 2012-2016 David Robillard Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -14,6 +14,15 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +/** + @defgroup options Options + + Instantiation time options, see for + details. + + @{ +*/ + #ifndef LV2_OPTIONS_H #define LV2_OPTIONS_H @@ -22,14 +31,14 @@ #include "urid.h" #include "lv2.h" -#define LV2_OPTIONS_URI "http://lv2plug.in/ns/ext/options" -#define LV2_OPTIONS_PREFIX LV2_OPTIONS_URI "#" +#define LV2_OPTIONS_URI "http://lv2plug.in/ns/ext/options" ///< http://lv2plug.in/ns/ext/options +#define LV2_OPTIONS_PREFIX LV2_OPTIONS_URI "#" ///< http://lv2plug.in/ns/ext/options# -#define LV2_OPTIONS__Option LV2_OPTIONS_PREFIX "Option" -#define LV2_OPTIONS__interface LV2_OPTIONS_PREFIX "interface" -#define LV2_OPTIONS__options LV2_OPTIONS_PREFIX "options" -#define LV2_OPTIONS__requiredOption LV2_OPTIONS_PREFIX "requiredOption" -#define LV2_OPTIONS__supportedOption LV2_OPTIONS_PREFIX "supportedOption" +#define LV2_OPTIONS__Option LV2_OPTIONS_PREFIX "Option" ///< http://lv2plug.in/ns/ext/options#Option +#define LV2_OPTIONS__interface LV2_OPTIONS_PREFIX "interface" ///< http://lv2plug.in/ns/ext/options#interface +#define LV2_OPTIONS__options LV2_OPTIONS_PREFIX "options" ///< http://lv2plug.in/ns/ext/options#options +#define LV2_OPTIONS__requiredOption LV2_OPTIONS_PREFIX "requiredOption" ///< http://lv2plug.in/ns/ext/options#requiredOption +#define LV2_OPTIONS__supportedOption LV2_OPTIONS_PREFIX "supportedOption" ///< http://lv2plug.in/ns/ext/options#supportedOption #ifdef __cplusplus extern "C" { @@ -130,3 +139,7 @@ typedef struct _LV2_Options_Interface { #endif #endif /* LV2_OPTIONS_H */ + +/** + @} +*/ diff --git a/dpf/distrho/src/lv2/parameters.h b/dpf/distrho/src/lv2/parameters.h index 9c06bab..f81e78b 100644 --- a/dpf/distrho/src/lv2/parameters.h +++ b/dpf/distrho/src/lv2/parameters.h @@ -1,5 +1,5 @@ /* - Copyright 2012 David Robillard + Copyright 2012-2016 David Robillard Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -14,36 +14,49 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +/** + @defgroup parameters Parameters + + Common parameters for audio processing, see + . + + @{ +*/ + #ifndef LV2_PARAMETERS_H #define LV2_PARAMETERS_H -#define LV2_PARAMETERS_URI "http://lv2plug.in/ns/ext/parameters" -#define LV2_PARAMETERS_PREFIX LV2_PARAMETERS_URI "#" - -#define LV2_PARAMETERS__CompressorControls LV2_PARAMETERS_PREFIX "CompressorControls" -#define LV2_PARAMETERS__ControlGroup LV2_PARAMETERS_PREFIX "ControlGroup" -#define LV2_PARAMETERS__EnvelopeControls LV2_PARAMETERS_PREFIX "EnvelopeControls" -#define LV2_PARAMETERS__FilterControls LV2_PARAMETERS_PREFIX "FilterControls" -#define LV2_PARAMETERS__OscillatorControls LV2_PARAMETERS_PREFIX "OscillatorControls" -#define LV2_PARAMETERS__amplitude LV2_PARAMETERS_PREFIX "amplitude" -#define LV2_PARAMETERS__attack LV2_PARAMETERS_PREFIX "attack" -#define LV2_PARAMETERS__bypass LV2_PARAMETERS_PREFIX "bypass" -#define LV2_PARAMETERS__cutoffFrequency LV2_PARAMETERS_PREFIX "cutoffFrequency" -#define LV2_PARAMETERS__decay LV2_PARAMETERS_PREFIX "decay" -#define LV2_PARAMETERS__delay LV2_PARAMETERS_PREFIX "delay" -#define LV2_PARAMETERS__dryLevel LV2_PARAMETERS_PREFIX "dryLevel" -#define LV2_PARAMETERS__frequency LV2_PARAMETERS_PREFIX "frequency" -#define LV2_PARAMETERS__gain LV2_PARAMETERS_PREFIX "gain" -#define LV2_PARAMETERS__hold LV2_PARAMETERS_PREFIX "hold" -#define LV2_PARAMETERS__pulseWidth LV2_PARAMETERS_PREFIX "pulseWidth" -#define LV2_PARAMETERS__ratio LV2_PARAMETERS_PREFIX "ratio" -#define LV2_PARAMETERS__release LV2_PARAMETERS_PREFIX "release" -#define LV2_PARAMETERS__resonance LV2_PARAMETERS_PREFIX "resonance" -#define LV2_PARAMETERS__sampleRate LV2_PARAMETERS_PREFIX "sampleRate" -#define LV2_PARAMETERS__sustain LV2_PARAMETERS_PREFIX "sustain" -#define LV2_PARAMETERS__threshold LV2_PARAMETERS_PREFIX "threshold" -#define LV2_PARAMETERS__waveform LV2_PARAMETERS_PREFIX "waveform" -#define LV2_PARAMETERS__wetDryRatio LV2_PARAMETERS_PREFIX "wetDryRatio" -#define LV2_PARAMETERS__wetLevel LV2_PARAMETERS_PREFIX "wetLevel" +#define LV2_PARAMETERS_URI "http://lv2plug.in/ns/ext/parameters" ///< http://lv2plug.in/ns/ext/parameters +#define LV2_PARAMETERS_PREFIX LV2_PARAMETERS_URI "#" ///< http://lv2plug.in/ns/ext/parameters# + +#define LV2_PARAMETERS__CompressorControls LV2_PARAMETERS_PREFIX "CompressorControls" ///< http://lv2plug.in/ns/ext/parameters#CompressorControls +#define LV2_PARAMETERS__ControlGroup LV2_PARAMETERS_PREFIX "ControlGroup" ///< http://lv2plug.in/ns/ext/parameters#ControlGroup +#define LV2_PARAMETERS__EnvelopeControls LV2_PARAMETERS_PREFIX "EnvelopeControls" ///< http://lv2plug.in/ns/ext/parameters#EnvelopeControls +#define LV2_PARAMETERS__FilterControls LV2_PARAMETERS_PREFIX "FilterControls" ///< http://lv2plug.in/ns/ext/parameters#FilterControls +#define LV2_PARAMETERS__OscillatorControls LV2_PARAMETERS_PREFIX "OscillatorControls" ///< http://lv2plug.in/ns/ext/parameters#OscillatorControls +#define LV2_PARAMETERS__amplitude LV2_PARAMETERS_PREFIX "amplitude" ///< http://lv2plug.in/ns/ext/parameters#amplitude +#define LV2_PARAMETERS__attack LV2_PARAMETERS_PREFIX "attack" ///< http://lv2plug.in/ns/ext/parameters#attack +#define LV2_PARAMETERS__bypass LV2_PARAMETERS_PREFIX "bypass" ///< http://lv2plug.in/ns/ext/parameters#bypass +#define LV2_PARAMETERS__cutoffFrequency LV2_PARAMETERS_PREFIX "cutoffFrequency" ///< http://lv2plug.in/ns/ext/parameters#cutoffFrequency +#define LV2_PARAMETERS__decay LV2_PARAMETERS_PREFIX "decay" ///< http://lv2plug.in/ns/ext/parameters#decay +#define LV2_PARAMETERS__delay LV2_PARAMETERS_PREFIX "delay" ///< http://lv2plug.in/ns/ext/parameters#delay +#define LV2_PARAMETERS__dryLevel LV2_PARAMETERS_PREFIX "dryLevel" ///< http://lv2plug.in/ns/ext/parameters#dryLevel +#define LV2_PARAMETERS__frequency LV2_PARAMETERS_PREFIX "frequency" ///< http://lv2plug.in/ns/ext/parameters#frequency +#define LV2_PARAMETERS__gain LV2_PARAMETERS_PREFIX "gain" ///< http://lv2plug.in/ns/ext/parameters#gain +#define LV2_PARAMETERS__hold LV2_PARAMETERS_PREFIX "hold" ///< http://lv2plug.in/ns/ext/parameters#hold +#define LV2_PARAMETERS__pulseWidth LV2_PARAMETERS_PREFIX "pulseWidth" ///< http://lv2plug.in/ns/ext/parameters#pulseWidth +#define LV2_PARAMETERS__ratio LV2_PARAMETERS_PREFIX "ratio" ///< http://lv2plug.in/ns/ext/parameters#ratio +#define LV2_PARAMETERS__release LV2_PARAMETERS_PREFIX "release" ///< http://lv2plug.in/ns/ext/parameters#release +#define LV2_PARAMETERS__resonance LV2_PARAMETERS_PREFIX "resonance" ///< http://lv2plug.in/ns/ext/parameters#resonance +#define LV2_PARAMETERS__sampleRate LV2_PARAMETERS_PREFIX "sampleRate" ///< http://lv2plug.in/ns/ext/parameters#sampleRate +#define LV2_PARAMETERS__sustain LV2_PARAMETERS_PREFIX "sustain" ///< http://lv2plug.in/ns/ext/parameters#sustain +#define LV2_PARAMETERS__threshold LV2_PARAMETERS_PREFIX "threshold" ///< http://lv2plug.in/ns/ext/parameters#threshold +#define LV2_PARAMETERS__waveform LV2_PARAMETERS_PREFIX "waveform" ///< http://lv2plug.in/ns/ext/parameters#waveform +#define LV2_PARAMETERS__wetDryRatio LV2_PARAMETERS_PREFIX "wetDryRatio" ///< http://lv2plug.in/ns/ext/parameters#wetDryRatio +#define LV2_PARAMETERS__wetLevel LV2_PARAMETERS_PREFIX "wetLevel" ///< http://lv2plug.in/ns/ext/parameters#wetLevel #endif /* LV2_PARAMETERS_H */ + +/** + @} +*/ diff --git a/dpf/distrho/src/lv2/patch.h b/dpf/distrho/src/lv2/patch.h index 3224264..e78164d 100644 --- a/dpf/distrho/src/lv2/patch.h +++ b/dpf/distrho/src/lv2/patch.h @@ -1,5 +1,5 @@ /* - Copyright 2012 David Robillard + Copyright 2012-2016 David Robillard Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -15,42 +15,52 @@ */ /** - @file patch.h C header for the LV2 Patch extension - . + @defgroup patch Patch - The patch extension is purely data, this header merely defines URIs - for convenience. + Messages for accessing and manipulating properties, see + for details. + + Note the patch extension is purely data, this header merely defines URIs for + convenience. + + @{ */ #ifndef LV2_PATCH_H #define LV2_PATCH_H -#define LV2_PATCH_URI "http://lv2plug.in/ns/ext/patch" -#define LV2_PATCH_PREFIX LV2_PATCH_URI "#" - -#define LV2_PATCH__Ack LV2_PATCH_PREFIX "Ack" -#define LV2_PATCH__Delete LV2_PATCH_PREFIX "Delete" -#define LV2_PATCH__Error LV2_PATCH_PREFIX "Error" -#define LV2_PATCH__Get LV2_PATCH_PREFIX "Get" -#define LV2_PATCH__Message LV2_PATCH_PREFIX "Message" -#define LV2_PATCH__Move LV2_PATCH_PREFIX "Move" -#define LV2_PATCH__Patch LV2_PATCH_PREFIX "Patch" -#define LV2_PATCH__Post LV2_PATCH_PREFIX "Post" -#define LV2_PATCH__Put LV2_PATCH_PREFIX "Put" -#define LV2_PATCH__Request LV2_PATCH_PREFIX "Request" -#define LV2_PATCH__Response LV2_PATCH_PREFIX "Response" -#define LV2_PATCH__Set LV2_PATCH_PREFIX "Set" -#define LV2_PATCH__add LV2_PATCH_PREFIX "add" -#define LV2_PATCH__body LV2_PATCH_PREFIX "body" -#define LV2_PATCH__destination LV2_PATCH_PREFIX "destination" -#define LV2_PATCH__property LV2_PATCH_PREFIX "property" -#define LV2_PATCH__readable LV2_PATCH_PREFIX "readable" -#define LV2_PATCH__remove LV2_PATCH_PREFIX "remove" -#define LV2_PATCH__request LV2_PATCH_PREFIX "request" -#define LV2_PATCH__subject LV2_PATCH_PREFIX "subject" -#define LV2_PATCH__sequenceNumber LV2_PATCH_PREFIX "sequenceNumber" -#define LV2_PATCH__value LV2_PATCH_PREFIX "value" -#define LV2_PATCH__wildcard LV2_PATCH_PREFIX "wildcard" -#define LV2_PATCH__writable LV2_PATCH_PREFIX "writable" +#define LV2_PATCH_URI "http://lv2plug.in/ns/ext/patch" ///< http://lv2plug.in/ns/ext/patch +#define LV2_PATCH_PREFIX LV2_PATCH_URI "#" ///< http://lv2plug.in/ns/ext/patch# + +#define LV2_PATCH__Ack LV2_PATCH_PREFIX "Ack" ///< http://lv2plug.in/ns/ext/patch#Ack +#define LV2_PATCH__Delete LV2_PATCH_PREFIX "Delete" ///< http://lv2plug.in/ns/ext/patch#Delete +#define LV2_PATCH__Copy LV2_PATCH_PREFIX "Copy" ///< http://lv2plug.in/ns/ext/patch#Copy +#define LV2_PATCH__Error LV2_PATCH_PREFIX "Error" ///< http://lv2plug.in/ns/ext/patch#Error +#define LV2_PATCH__Get LV2_PATCH_PREFIX "Get" ///< http://lv2plug.in/ns/ext/patch#Get +#define LV2_PATCH__Message LV2_PATCH_PREFIX "Message" ///< http://lv2plug.in/ns/ext/patch#Message +#define LV2_PATCH__Move LV2_PATCH_PREFIX "Move" ///< http://lv2plug.in/ns/ext/patch#Move +#define LV2_PATCH__Patch LV2_PATCH_PREFIX "Patch" ///< http://lv2plug.in/ns/ext/patch#Patch +#define LV2_PATCH__Post LV2_PATCH_PREFIX "Post" ///< http://lv2plug.in/ns/ext/patch#Post +#define LV2_PATCH__Put LV2_PATCH_PREFIX "Put" ///< http://lv2plug.in/ns/ext/patch#Put +#define LV2_PATCH__Request LV2_PATCH_PREFIX "Request" ///< http://lv2plug.in/ns/ext/patch#Request +#define LV2_PATCH__Response LV2_PATCH_PREFIX "Response" ///< http://lv2plug.in/ns/ext/patch#Response +#define LV2_PATCH__Set LV2_PATCH_PREFIX "Set" ///< http://lv2plug.in/ns/ext/patch#Set +#define LV2_PATCH__accept LV2_PATCH_PREFIX "accept" ///< http://lv2plug.in/ns/ext/patch#accept +#define LV2_PATCH__add LV2_PATCH_PREFIX "add" ///< http://lv2plug.in/ns/ext/patch#add +#define LV2_PATCH__body LV2_PATCH_PREFIX "body" ///< http://lv2plug.in/ns/ext/patch#body +#define LV2_PATCH__destination LV2_PATCH_PREFIX "destination" ///< http://lv2plug.in/ns/ext/patch#destination +#define LV2_PATCH__property LV2_PATCH_PREFIX "property" ///< http://lv2plug.in/ns/ext/patch#property +#define LV2_PATCH__readable LV2_PATCH_PREFIX "readable" ///< http://lv2plug.in/ns/ext/patch#readable +#define LV2_PATCH__remove LV2_PATCH_PREFIX "remove" ///< http://lv2plug.in/ns/ext/patch#remove +#define LV2_PATCH__request LV2_PATCH_PREFIX "request" ///< http://lv2plug.in/ns/ext/patch#request +#define LV2_PATCH__subject LV2_PATCH_PREFIX "subject" ///< http://lv2plug.in/ns/ext/patch#subject +#define LV2_PATCH__sequenceNumber LV2_PATCH_PREFIX "sequenceNumber" ///< http://lv2plug.in/ns/ext/patch#sequenceNumber +#define LV2_PATCH__value LV2_PATCH_PREFIX "value" ///< http://lv2plug.in/ns/ext/patch#value +#define LV2_PATCH__wildcard LV2_PATCH_PREFIX "wildcard" ///< http://lv2plug.in/ns/ext/patch#wildcard +#define LV2_PATCH__writable LV2_PATCH_PREFIX "writable" ///< http://lv2plug.in/ns/ext/patch#writable #endif /* LV2_PATCH_H */ + +/** + @} +*/ diff --git a/dpf/distrho/src/lv2/port-groups.h b/dpf/distrho/src/lv2/port-groups.h index 4dd8cf4..a1bcd12 100644 --- a/dpf/distrho/src/lv2/port-groups.h +++ b/dpf/distrho/src/lv2/port-groups.h @@ -1,5 +1,5 @@ /* - Copyright 2012 David Robillard + Copyright 2012-2016 David Robillard Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -15,50 +15,57 @@ */ /** - @file port-groups.h - C definitions for the LV2 Port Groups extension - . + @defgroup port-groups Port Groups + + Multi-channel groups of LV2 ports, see + for details. + + @{ */ #ifndef LV2_PORT_GROUPS_H #define LV2_PORT_GROUPS_H -#define LV2_PORT_GROUPS_URI "http://lv2plug.in/ns/ext/port-groups" -#define LV2_PORT_GROUPS_PREFIX LV2_PORT_GROUPS_URI "#" +#define LV2_PORT_GROUPS_URI "http://lv2plug.in/ns/ext/port-groups" ///< http://lv2plug.in/ns/ext/port-groups +#define LV2_PORT_GROUPS_PREFIX LV2_PORT_GROUPS_URI "#" ///< http://lv2plug.in/ns/ext/port-groups# -#define LV2_PORT_GROUPS__DiscreteGroup LV2_PORT_GROUPS_PREFIX "DiscreteGroup" -#define LV2_PORT_GROUPS__Element LV2_PORT_GROUPS_PREFIX "Element" -#define LV2_PORT_GROUPS__FivePointOneGroup LV2_PORT_GROUPS_PREFIX "FivePointOneGroup" -#define LV2_PORT_GROUPS__FivePointZeroGroup LV2_PORT_GROUPS_PREFIX "FivePointZeroGroup" -#define LV2_PORT_GROUPS__FourPointZeroGroup LV2_PORT_GROUPS_PREFIX "FourPointZeroGroup" -#define LV2_PORT_GROUPS__Group LV2_PORT_GROUPS_PREFIX "Group" -#define LV2_PORT_GROUPS__InputGroup LV2_PORT_GROUPS_PREFIX "InputGroup" -#define LV2_PORT_GROUPS__MidSideGroup LV2_PORT_GROUPS_PREFIX "MidSideGroup" -#define LV2_PORT_GROUPS__MonoGroup LV2_PORT_GROUPS_PREFIX "MonoGroup" -#define LV2_PORT_GROUPS__OutputGroup LV2_PORT_GROUPS_PREFIX "OutputGroup" -#define LV2_PORT_GROUPS__SevenPointOneGroup LV2_PORT_GROUPS_PREFIX "SevenPointOneGroup" -#define LV2_PORT_GROUPS__SevenPointOneWideGroup LV2_PORT_GROUPS_PREFIX "SevenPointOneWideGroup" -#define LV2_PORT_GROUPS__SixPointOneGroup LV2_PORT_GROUPS_PREFIX "SixPointOneGroup" -#define LV2_PORT_GROUPS__StereoGroup LV2_PORT_GROUPS_PREFIX "StereoGroup" -#define LV2_PORT_GROUPS__ThreePointZeroGroup LV2_PORT_GROUPS_PREFIX "ThreePointZeroGroup" -#define LV2_PORT_GROUPS__center LV2_PORT_GROUPS_PREFIX "center" -#define LV2_PORT_GROUPS__centerLeft LV2_PORT_GROUPS_PREFIX "centerLeft" -#define LV2_PORT_GROUPS__centerRight LV2_PORT_GROUPS_PREFIX "centerRight" -#define LV2_PORT_GROUPS__element LV2_PORT_GROUPS_PREFIX "element" -#define LV2_PORT_GROUPS__group LV2_PORT_GROUPS_PREFIX "group" -#define LV2_PORT_GROUPS__left LV2_PORT_GROUPS_PREFIX "left" -#define LV2_PORT_GROUPS__lowFrequencyEffects LV2_PORT_GROUPS_PREFIX "lowFrequencyEffects" -#define LV2_PORT_GROUPS__mainInput LV2_PORT_GROUPS_PREFIX "mainInput" -#define LV2_PORT_GROUPS__mainOutput LV2_PORT_GROUPS_PREFIX "mainOutput" -#define LV2_PORT_GROUPS__rearCenter LV2_PORT_GROUPS_PREFIX "rearCenter" -#define LV2_PORT_GROUPS__rearLeft LV2_PORT_GROUPS_PREFIX "rearLeft" -#define LV2_PORT_GROUPS__rearRight LV2_PORT_GROUPS_PREFIX "rearRight" -#define LV2_PORT_GROUPS__right LV2_PORT_GROUPS_PREFIX "right" -#define LV2_PORT_GROUPS__side LV2_PORT_GROUPS_PREFIX "side" -#define LV2_PORT_GROUPS__sideChainOf LV2_PORT_GROUPS_PREFIX "sideChainOf" -#define LV2_PORT_GROUPS__sideLeft LV2_PORT_GROUPS_PREFIX "sideLeft" -#define LV2_PORT_GROUPS__sideRight LV2_PORT_GROUPS_PREFIX "sideRight" -#define LV2_PORT_GROUPS__source LV2_PORT_GROUPS_PREFIX "source" -#define LV2_PORT_GROUPS__subGroupOf LV2_PORT_GROUPS_PREFIX "subGroupOf" +#define LV2_PORT_GROUPS__DiscreteGroup LV2_PORT_GROUPS_PREFIX "DiscreteGroup" ///< http://lv2plug.in/ns/ext/port-groups#DiscreteGroup +#define LV2_PORT_GROUPS__Element LV2_PORT_GROUPS_PREFIX "Element" ///< http://lv2plug.in/ns/ext/port-groups#Element +#define LV2_PORT_GROUPS__FivePointOneGroup LV2_PORT_GROUPS_PREFIX "FivePointOneGroup" ///< http://lv2plug.in/ns/ext/port-groups#FivePointOneGroup +#define LV2_PORT_GROUPS__FivePointZeroGroup LV2_PORT_GROUPS_PREFIX "FivePointZeroGroup" ///< http://lv2plug.in/ns/ext/port-groups#FivePointZeroGroup +#define LV2_PORT_GROUPS__FourPointZeroGroup LV2_PORT_GROUPS_PREFIX "FourPointZeroGroup" ///< http://lv2plug.in/ns/ext/port-groups#FourPointZeroGroup +#define LV2_PORT_GROUPS__Group LV2_PORT_GROUPS_PREFIX "Group" ///< http://lv2plug.in/ns/ext/port-groups#Group +#define LV2_PORT_GROUPS__InputGroup LV2_PORT_GROUPS_PREFIX "InputGroup" ///< http://lv2plug.in/ns/ext/port-groups#InputGroup +#define LV2_PORT_GROUPS__MidSideGroup LV2_PORT_GROUPS_PREFIX "MidSideGroup" ///< http://lv2plug.in/ns/ext/port-groups#MidSideGroup +#define LV2_PORT_GROUPS__MonoGroup LV2_PORT_GROUPS_PREFIX "MonoGroup" ///< http://lv2plug.in/ns/ext/port-groups#MonoGroup +#define LV2_PORT_GROUPS__OutputGroup LV2_PORT_GROUPS_PREFIX "OutputGroup" ///< http://lv2plug.in/ns/ext/port-groups#OutputGroup +#define LV2_PORT_GROUPS__SevenPointOneGroup LV2_PORT_GROUPS_PREFIX "SevenPointOneGroup" ///< http://lv2plug.in/ns/ext/port-groups#SevenPointOneGroup +#define LV2_PORT_GROUPS__SevenPointOneWideGroup LV2_PORT_GROUPS_PREFIX "SevenPointOneWideGroup" ///< http://lv2plug.in/ns/ext/port-groups#SevenPointOneWideGroup +#define LV2_PORT_GROUPS__SixPointOneGroup LV2_PORT_GROUPS_PREFIX "SixPointOneGroup" ///< http://lv2plug.in/ns/ext/port-groups#SixPointOneGroup +#define LV2_PORT_GROUPS__StereoGroup LV2_PORT_GROUPS_PREFIX "StereoGroup" ///< http://lv2plug.in/ns/ext/port-groups#StereoGroup +#define LV2_PORT_GROUPS__ThreePointZeroGroup LV2_PORT_GROUPS_PREFIX "ThreePointZeroGroup" ///< http://lv2plug.in/ns/ext/port-groups#ThreePointZeroGroup +#define LV2_PORT_GROUPS__center LV2_PORT_GROUPS_PREFIX "center" ///< http://lv2plug.in/ns/ext/port-groups#center +#define LV2_PORT_GROUPS__centerLeft LV2_PORT_GROUPS_PREFIX "centerLeft" ///< http://lv2plug.in/ns/ext/port-groups#centerLeft +#define LV2_PORT_GROUPS__centerRight LV2_PORT_GROUPS_PREFIX "centerRight" ///< http://lv2plug.in/ns/ext/port-groups#centerRight +#define LV2_PORT_GROUPS__element LV2_PORT_GROUPS_PREFIX "element" ///< http://lv2plug.in/ns/ext/port-groups#element +#define LV2_PORT_GROUPS__group LV2_PORT_GROUPS_PREFIX "group" ///< http://lv2plug.in/ns/ext/port-groups#group +#define LV2_PORT_GROUPS__left LV2_PORT_GROUPS_PREFIX "left" ///< http://lv2plug.in/ns/ext/port-groups#left +#define LV2_PORT_GROUPS__lowFrequencyEffects LV2_PORT_GROUPS_PREFIX "lowFrequencyEffects" ///< http://lv2plug.in/ns/ext/port-groups#lowFrequencyEffects +#define LV2_PORT_GROUPS__mainInput LV2_PORT_GROUPS_PREFIX "mainInput" ///< http://lv2plug.in/ns/ext/port-groups#mainInput +#define LV2_PORT_GROUPS__mainOutput LV2_PORT_GROUPS_PREFIX "mainOutput" ///< http://lv2plug.in/ns/ext/port-groups#mainOutput +#define LV2_PORT_GROUPS__rearCenter LV2_PORT_GROUPS_PREFIX "rearCenter" ///< http://lv2plug.in/ns/ext/port-groups#rearCenter +#define LV2_PORT_GROUPS__rearLeft LV2_PORT_GROUPS_PREFIX "rearLeft" ///< http://lv2plug.in/ns/ext/port-groups#rearLeft +#define LV2_PORT_GROUPS__rearRight LV2_PORT_GROUPS_PREFIX "rearRight" ///< http://lv2plug.in/ns/ext/port-groups#rearRight +#define LV2_PORT_GROUPS__right LV2_PORT_GROUPS_PREFIX "right" ///< http://lv2plug.in/ns/ext/port-groups#right +#define LV2_PORT_GROUPS__side LV2_PORT_GROUPS_PREFIX "side" ///< http://lv2plug.in/ns/ext/port-groups#side +#define LV2_PORT_GROUPS__sideChainOf LV2_PORT_GROUPS_PREFIX "sideChainOf" ///< http://lv2plug.in/ns/ext/port-groups#sideChainOf +#define LV2_PORT_GROUPS__sideLeft LV2_PORT_GROUPS_PREFIX "sideLeft" ///< http://lv2plug.in/ns/ext/port-groups#sideLeft +#define LV2_PORT_GROUPS__sideRight LV2_PORT_GROUPS_PREFIX "sideRight" ///< http://lv2plug.in/ns/ext/port-groups#sideRight +#define LV2_PORT_GROUPS__source LV2_PORT_GROUPS_PREFIX "source" ///< http://lv2plug.in/ns/ext/port-groups#source +#define LV2_PORT_GROUPS__subGroupOf LV2_PORT_GROUPS_PREFIX "subGroupOf" ///< http://lv2plug.in/ns/ext/port-groups#subGroupOf #endif /* LV2_PORT_GROUPS_H */ + +/** + @} +*/ diff --git a/dpf/distrho/src/lv2/port-props.h b/dpf/distrho/src/lv2/port-props.h index 11274cc..ef2b64d 100644 --- a/dpf/distrho/src/lv2/port-props.h +++ b/dpf/distrho/src/lv2/port-props.h @@ -1,5 +1,5 @@ /* - Copyright 2012 David Robillard + Copyright 2012-2016 David Robillard Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -15,28 +15,34 @@ */ /** - @file port-props.h - C definitions for the LV2 Port Props extension - . + @defgroup port-props Port Properties + + Various port properties. + + @{ */ #ifndef LV2_PORT_PROPS_H #define LV2_PORT_PROPS_H -#define LV2_PORT_PROPS_URI "http://lv2plug.in/ns/ext/port-props" -#define LV2_PORT_PROPS_PREFIX LV2_PORT_PROPS_URI "#" - -#define LV2_PORT_PROPS__causesArtifacts LV2_PORT_PROPS_PREFIX "causesArtifacts" -#define LV2_PORT_PROPS__continuousCV LV2_PORT_PROPS_PREFIX "continuousCV" -#define LV2_PORT_PROPS__discreteCV LV2_PORT_PROPS_PREFIX "discreteCV" -#define LV2_PORT_PROPS__displayPriority LV2_PORT_PROPS_PREFIX "displayPriority" -#define LV2_PORT_PROPS__expensive LV2_PORT_PROPS_PREFIX "expensive" -#define LV2_PORT_PROPS__hasStrictBounds LV2_PORT_PROPS_PREFIX "hasStrictBounds" -#define LV2_PORT_PROPS__logarithmic LV2_PORT_PROPS_PREFIX "logarithmic" -#define LV2_PORT_PROPS__notAutomatic LV2_PORT_PROPS_PREFIX "notAutomatic" -#define LV2_PORT_PROPS__notOnGUI LV2_PORT_PROPS_PREFIX "notOnGUI" -#define LV2_PORT_PROPS__rangeSteps LV2_PORT_PROPS_PREFIX "rangeSteps" -#define LV2_PORT_PROPS__supportsStrictBounds LV2_PORT_PROPS_PREFIX "supportsStrictBounds" -#define LV2_PORT_PROPS__trigger LV2_PORT_PROPS_PREFIX "trigger" +#define LV2_PORT_PROPS_URI "http://lv2plug.in/ns/ext/port-props" ///< http://lv2plug.in/ns/ext/port-props +#define LV2_PORT_PROPS_PREFIX LV2_PORT_PROPS_URI "#" ///< http://lv2plug.in/ns/ext/port-props# + +#define LV2_PORT_PROPS__causesArtifacts LV2_PORT_PROPS_PREFIX "causesArtifacts" ///< http://lv2plug.in/ns/ext/port-props#causesArtifacts +#define LV2_PORT_PROPS__continuousCV LV2_PORT_PROPS_PREFIX "continuousCV" ///< http://lv2plug.in/ns/ext/port-props#continuousCV +#define LV2_PORT_PROPS__discreteCV LV2_PORT_PROPS_PREFIX "discreteCV" ///< http://lv2plug.in/ns/ext/port-props#discreteCV +#define LV2_PORT_PROPS__displayPriority LV2_PORT_PROPS_PREFIX "displayPriority" ///< http://lv2plug.in/ns/ext/port-props#displayPriority +#define LV2_PORT_PROPS__expensive LV2_PORT_PROPS_PREFIX "expensive" ///< http://lv2plug.in/ns/ext/port-props#expensive +#define LV2_PORT_PROPS__hasStrictBounds LV2_PORT_PROPS_PREFIX "hasStrictBounds" ///< http://lv2plug.in/ns/ext/port-props#hasStrictBounds +#define LV2_PORT_PROPS__logarithmic LV2_PORT_PROPS_PREFIX "logarithmic" ///< http://lv2plug.in/ns/ext/port-props#logarithmic +#define LV2_PORT_PROPS__notAutomatic LV2_PORT_PROPS_PREFIX "notAutomatic" ///< http://lv2plug.in/ns/ext/port-props#notAutomatic +#define LV2_PORT_PROPS__notOnGUI LV2_PORT_PROPS_PREFIX "notOnGUI" ///< http://lv2plug.in/ns/ext/port-props#notOnGUI +#define LV2_PORT_PROPS__rangeSteps LV2_PORT_PROPS_PREFIX "rangeSteps" ///< http://lv2plug.in/ns/ext/port-props#rangeSteps +#define LV2_PORT_PROPS__supportsStrictBounds LV2_PORT_PROPS_PREFIX "supportsStrictBounds" ///< http://lv2plug.in/ns/ext/port-props#supportsStrictBounds +#define LV2_PORT_PROPS__trigger LV2_PORT_PROPS_PREFIX "trigger" ///< http://lv2plug.in/ns/ext/port-props#trigger #endif /* LV2_PORT_PROPS_H */ + +/** + @} +*/ diff --git a/dpf/distrho/src/lv2/presets.h b/dpf/distrho/src/lv2/presets.h index 4851feb..7c51b1c 100644 --- a/dpf/distrho/src/lv2/presets.h +++ b/dpf/distrho/src/lv2/presets.h @@ -1,5 +1,5 @@ /* - Copyright 2012 David Robillard + Copyright 2012-2016 David Robillard Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -15,20 +15,27 @@ */ /** - @file presets.h + @defgroup presets Presets - C definitions for the LV2 Presets extension - . + Presets for plugins, see for details. + + @{ */ #ifndef LV2_PRESETS_H #define LV2_PRESETS_H -#define LV2_PRESETS_URI "http://lv2plug.in/ns/ext/presets" -#define LV2_PRESETS_PREFIX LV2_PRESETS_URI "#" +#define LV2_PRESETS_URI "http://lv2plug.in/ns/ext/presets" ///< http://lv2plug.in/ns/ext/presets +#define LV2_PRESETS_PREFIX LV2_PRESETS_URI "#" ///< http://lv2plug.in/ns/ext/presets# -#define LV2_PRESETS__Preset LV2_PRESETS_PREFIX "Preset" -#define LV2_PRESETS__preset LV2_PRESETS_PREFIX "preset" -#define LV2_PRESETS__value LV2_PRESETS_PREFIX "value" +#define LV2_PRESETS__Bank LV2_PRESETS_PREFIX "Bank" ///< http://lv2plug.in/ns/ext/presets#Bank +#define LV2_PRESETS__Preset LV2_PRESETS_PREFIX "Preset" ///< http://lv2plug.in/ns/ext/presets#Preset +#define LV2_PRESETS__bank LV2_PRESETS_PREFIX "bank" ///< http://lv2plug.in/ns/ext/presets#bank +#define LV2_PRESETS__preset LV2_PRESETS_PREFIX "preset" ///< http://lv2plug.in/ns/ext/presets#preset +#define LV2_PRESETS__value LV2_PRESETS_PREFIX "value" ///< http://lv2plug.in/ns/ext/presets#value #endif /* LV2_PRESETS_H */ + +/** + @} +*/ diff --git a/dpf/distrho/src/lv2/resize-port.h b/dpf/distrho/src/lv2/resize-port.h index fa3abd7..5eb47f2 100644 --- a/dpf/distrho/src/lv2/resize-port.h +++ b/dpf/distrho/src/lv2/resize-port.h @@ -1,5 +1,5 @@ /* - Copyright 2007-2012 David Robillard + Copyright 2007-2016 David Robillard Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -14,18 +14,26 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +/** + @defgroup resize-port Resize Port + + Dynamically sized LV2 port buffers. + + @{ +*/ + #ifndef LV2_RESIZE_PORT_H #define LV2_RESIZE_PORT_H #include #include -#define LV2_RESIZE_PORT_URI "http://lv2plug.in/ns/ext/resize-port" -#define LV2_RESIZE_PORT_PREFIX LV2_RESIZE_PORT_URI "#" +#define LV2_RESIZE_PORT_URI "http://lv2plug.in/ns/ext/resize-port" ///< http://lv2plug.in/ns/ext/resize-port +#define LV2_RESIZE_PORT_PREFIX LV2_RESIZE_PORT_URI "#" ///< http://lv2plug.in/ns/ext/resize-port# -#define LV2_RESIZE_PORT__asLargeAs LV2_RESIZE_PORT_PREFIX "asLargeAs" -#define LV2_RESIZE_PORT__minimumSize LV2_RESIZE_PORT_PREFIX "minimumSize" -#define LV2_RESIZE_PORT__resize LV2_RESIZE_PORT_PREFIX "resize" +#define LV2_RESIZE_PORT__asLargeAs LV2_RESIZE_PORT_PREFIX "asLargeAs" ///< http://lv2plug.in/ns/ext/port#asLargeAs +#define LV2_RESIZE_PORT__minimumSize LV2_RESIZE_PORT_PREFIX "minimumSize" ///< http://lv2plug.in/ns/ext/port#minimumSize +#define LV2_RESIZE_PORT__resize LV2_RESIZE_PORT_PREFIX "resize" ///< http://lv2plug.in/ns/ext/port#resize #ifdef __cplusplus extern "C" { @@ -40,22 +48,25 @@ typedef enum { LV2_RESIZE_PORT_ERR_NO_SPACE = 2 /**< Insufficient space. */ } LV2_Resize_Port_Status; +/** Opaque data for resize method. */ typedef void* LV2_Resize_Port_Feature_Data; +/** Host feature to allow plugins to resize their port buffers. */ typedef struct { + /** Opaque data for resize method. */ LV2_Resize_Port_Feature_Data data; /** - Resize a port buffer to at least @a size bytes. - + Resize a port buffer to at least `size` bytes. + This function MAY return an error, in which case the port buffer was not resized and the port is still connected to the same location. Plugins MUST gracefully handle this situation. - + This function is in the audio threading class. - + The host MUST preserve the contents of the port buffer when resizing. - + Plugins MAY resize a port many times in a single run callback. Hosts SHOULD make this as inexpensive as possible. */ @@ -70,3 +81,6 @@ typedef struct { #endif /* LV2_RESIZE_PORT_H */ +/** + @} +*/ diff --git a/dpf/distrho/src/lv2/state.h b/dpf/distrho/src/lv2/state.h index 7e162cb..fe89141 100644 --- a/dpf/distrho/src/lv2/state.h +++ b/dpf/distrho/src/lv2/state.h @@ -1,5 +1,5 @@ /* - Copyright 2010-2012 David Robillard + Copyright 2010-2016 David Robillard Copyright 2010 Leonard Ritter Permission to use, copy, modify, and/or distribute this software for any @@ -16,37 +16,45 @@ */ /** - @file state.h - C API for the LV2 State extension . + @defgroup state State + @ingroup lv2 + + An interface for LV2 plugins to save and restore state, see + for details. + + @{ */ #ifndef LV2_STATE_H #define LV2_STATE_H +#include "lv2.h" + +#include #include #include -#include "lv2.h" - -#define LV2_STATE_URI "http://lv2plug.in/ns/ext/state" -#define LV2_STATE_PREFIX LV2_STATE_URI "#" +#define LV2_STATE_URI "http://lv2plug.in/ns/ext/state" ///< http://lv2plug.in/ns/ext/state +#define LV2_STATE_PREFIX LV2_STATE_URI "#" ///< http://lv2plug.in/ns/ext/state# -#define LV2_STATE__State LV2_STATE_PREFIX "State" -#define LV2_STATE__interface LV2_STATE_PREFIX "interface" -#define LV2_STATE__loadDefaultState LV2_STATE_PREFIX "loadDefaultState" -#define LV2_STATE__makePath LV2_STATE_PREFIX "makePath" -#define LV2_STATE__mapPath LV2_STATE_PREFIX "mapPath" -#define LV2_STATE__state LV2_STATE_PREFIX "state" +#define LV2_STATE__State LV2_STATE_PREFIX "State" ///< http://lv2plug.in/ns/ext/state#State +#define LV2_STATE__interface LV2_STATE_PREFIX "interface" ///< http://lv2plug.in/ns/ext/state#interface +#define LV2_STATE__loadDefaultState LV2_STATE_PREFIX "loadDefaultState" ///< http://lv2plug.in/ns/ext/state#loadDefaultState +#define LV2_STATE__freePath LV2_STATE_PREFIX "freePath" ///< http://lv2plug.in/ns/ext/state#freePath +#define LV2_STATE__makePath LV2_STATE_PREFIX "makePath" ///< http://lv2plug.in/ns/ext/state#makePath +#define LV2_STATE__mapPath LV2_STATE_PREFIX "mapPath" ///< http://lv2plug.in/ns/ext/state#mapPath +#define LV2_STATE__state LV2_STATE_PREFIX "state" ///< http://lv2plug.in/ns/ext/state#state +#define LV2_STATE__threadSafeRestore LV2_STATE_PREFIX "threadSafeRestore" ///< http://lv2plug.in/ns/ext/state#threadSafeRestore +#define LV2_STATE__StateChanged LV2_STATE_PREFIX "StateChanged" ///< http://lv2plug.in/ns/ext/state#StateChanged #ifdef __cplusplus extern "C" { -#else -# include #endif -typedef void* LV2_State_Handle; -typedef void* LV2_State_Map_Path_Handle; -typedef void* LV2_State_Make_Path_Handle; +typedef void* LV2_State_Handle; ///< Opaque handle for state save/restore +typedef void* LV2_State_Free_Path_Handle; ///< Opaque handle for state:freePath feature +typedef void* LV2_State_Map_Path_Handle; ///< Opaque handle for state:mapPath feature +typedef void* LV2_State_Make_Path_Handle; ///< Opaque handle for state:makePath feature /** Flags describing value characteristics. @@ -61,8 +69,8 @@ typedef enum { Values with this flag contain no pointers or references to other areas of memory. It is safe to copy POD values with a simple memcpy and store them for the duration of the process. A POD value is not necessarily - safe to trasmit between processes or machines (e.g. filenames are POD), - see LV2_STATE_IS_PORTABLE for details. + safe to trasmit between processes or machines (for example, filenames + are POD), see LV2_STATE_IS_PORTABLE for details. Implementations MUST NOT attempt to copy or serialise a non-POD value if they do not understand its type (and thus know how to correctly do so). @@ -84,9 +92,9 @@ typedef enum { Native data. This flag is used by the host to indicate that the saved data is only - going to be used locally in the currently running process (e.g. for - instance duplication or snapshots), so the plugin should use the most - efficient representation possible and not worry about serialisation + going to be used locally in the currently running process (for things + like instance duplication or snapshots), so the plugin should use the + most efficient representation possible and not worry about serialisation and portability. */ LV2_STATE_IS_NATIVE = 1 << 2 @@ -106,11 +114,11 @@ typedef enum { /** A host-provided function to store a property. @param handle Must be the handle passed to LV2_State_Interface.save(). - @param key The key to store @p value under (URID). + @param key The key to store `value` under (URID). @param value Pointer to the value to be stored. - @param size The size of @p value in bytes. - @param type The type of @p value (URID). - @param flags LV2_State_Flags for @p value. + @param size The size of `value` in bytes. + @param type The type of `value` (URID). + @param flags LV2_State_Flags for `value`. @return 0 on success, otherwise a non-zero error code. The host passes a callback of this type to LV2_State_Interface.save(). This @@ -120,7 +128,7 @@ typedef enum { DO NOT INVENT NONSENSE URI SCHEMES FOR THE KEY. Best is to use keys from existing vocabularies. If nothing appropriate is available, use http URIs that point to somewhere you can host documents so documentation can be made - resolvable (e.g. a child of the plugin or project URI). If this is not + resolvable (typically a child of the plugin or project URI). If this is not possible, invent a URN scheme, e.g. urn:myproj:whatever. The plugin MUST NOT pass an invalid URI key. @@ -130,8 +138,8 @@ typedef enum { (http://lv2plug.in/ns/ext/atom) wherever possible. The plugin SHOULD attempt to fall-back and avoid the error if possible. - Note that @p size MUST be > 0, and @p value MUST point to a valid region of - memory @p size bytes long (this is required to make restore unambiguous). + Note that `size` MUST be > 0, and `value` MUST point to a valid region of + memory `size` bytes long (this is required to make restore unambiguous). The plugin MUST NOT attempt to use this function outside of the LV2_State_Interface.restore() context. @@ -152,7 +160,7 @@ typedef LV2_State_Status (*LV2_State_Store_Function)( @param type (Output) If non-NULL, set to the type of the restored value. @param flags (Output) If non-NULL, set to the flags for the restored value. @return A pointer to the restored value (object), or NULL if no value - has been stored under @p key. + has been stored under `key`. A callback of this type is passed by the host to LV2_State_Interface.restore(). This callback is called repeatedly by the @@ -187,14 +195,14 @@ typedef const void* (*LV2_State_Retrieve_Function)( authors should consider this possibility, and always store sensible data with meaningful types to avoid such problems in the future. */ -typedef struct _LV2_State_Interface { +typedef struct { /** - Save plugin state using a host-provided @p store callback. + Save plugin state using a host-provided `store` callback. @param instance The instance handle of the plugin. @param store The host-provided store callback. @param handle An opaque pointer to host data which MUST be passed as the - handle parameter to @p store if it is called. + handle parameter to `store` if it is called. @param flags Flags describing desired properties of this save. These flags may be used to determine the most appropriate values to store. @param features Extensible parameter for passing any additional @@ -205,16 +213,16 @@ typedef struct _LV2_State_Interface { possible, and consider the possibility of state being restored much later on a different machine. - The @p handle pointer and @p store function MUST NOT be used + The `handle` pointer and `store` function MUST NOT be used beyond the scope of save(). This function has its own special threading class: it may not be called concurrently with any "Instantiation" function, but it may be called concurrently with functions in any other class, unless the definition of - that class prohibits it (e.g. it may not be called concurrently with a - "Discovery" function, but it may be called concurrently with an "Audio" - function. The plugin is responsible for any locking or lock-free - techniques necessary to make this possible. + that class prohibits it (for example, it may not be called concurrently + with a "Discovery" function, but it may be called concurrently with an + "Audio" function. The plugin is responsible for any locking or + lock-free techniques necessary to make this possible. Note that in the simple case where state is only modified by restore(), there are no synchronization issues since save() is never called @@ -231,12 +239,12 @@ typedef struct _LV2_State_Interface { const LV2_Feature *const * features); /** - Restore plugin state using a host-provided @p retrieve callback. + Restore plugin state using a host-provided `retrieve` callback. @param instance The instance handle of the plugin. @param retrieve The host-provided retrieve callback. @param handle An opaque pointer to host data which MUST be passed as the - handle parameter to @p retrieve if it is called. + handle parameter to `retrieve` if it is called. @param flags Currently unused. @param features Extensible parameter for passing any additional features to be used for this restore. @@ -248,7 +256,7 @@ typedef struct _LV2_State_Interface { not be retrieved. This allows the host to reset the plugin state with an empty map. - The @p handle pointer and @p store function MUST NOT be used + The `handle` pointer and `store` function MUST NOT be used beyond the scope of restore(). This function is in the "Instantiation" threading class as defined by @@ -263,7 +271,7 @@ typedef struct _LV2_State_Interface { } LV2_State_Interface; /** - Feature data for state:mapPath (LV2_STATE__mapPath). + Feature data for state:mapPath (@ref LV2_STATE__mapPath). */ typedef struct { /** @@ -273,38 +281,38 @@ typedef struct { /** Map an absolute path to an abstract path for use in plugin state. - @param handle MUST be the @p handle member of this struct. + @param handle MUST be the `handle` member of this struct. @param absolute_path The absolute path of a file. @return An abstract path suitable for use in plugin state. The plugin MUST use this function to map any paths that will be stored in plugin state. The returned value is an abstract path which MAY not - be an actual file system path; @ref absolute_path() MUST be used to map + be an actual file system path; absolute_path() MUST be used to map it to an actual path in order to use the file. Plugins MUST NOT make any assumptions about abstract paths except that they can be mapped back to the absolute path of the "same" file (though - not necessarily the same original path) using @ref absolute_path(). + not necessarily the same original path) using absolute_path(). This function may only be called within the context of - LV2_State_Interface methods. The caller is responsible for freeing the - returned value with free(). + LV2_State_Interface methods. The caller must free the returned value + with LV2_State_Free_Path.free_path(). */ char* (*abstract_path)(LV2_State_Map_Path_Handle handle, const char* absolute_path); /** Map an abstract path from plugin state to an absolute path. - @param handle MUST be the @p handle member of this struct. - @param abstract_path An abstract path (e.g. a path from plugin state). + @param handle MUST be the `handle` member of this struct. + @param abstract_path An abstract path (typically from plugin state). @return An absolute file system path. The plugin MUST use this function in order to actually open or otherwise use any paths loaded from plugin state. This function may only be called within the context of - LV2_State_Interface methods. The caller is responsible for freeing the - returned value with free(). + LV2_State_Interface methods. The caller must free the returned value + with LV2_State_Free_Path.free_path(). */ char* (*absolute_path)(LV2_State_Map_Path_Handle handle, const char* abstract_path); @@ -321,7 +329,7 @@ typedef struct { /** Return a path the plugin may use to create a new file. - @param handle MUST be the @p handle member of this struct. + @param handle MUST be the `handle` member of this struct. @param path The path of the new file within a namespace unique to this plugin instance. @return The absolute path to use for the new file. @@ -332,22 +340,50 @@ typedef struct { LV2_Descriptor.instantiate()). The host MUST do whatever is necessary for the plugin to be able to - create a file at the returned path (e.g. using fopen), including - creating any leading directories. + create a file at the returned path (for example, using fopen()), + including creating any leading directories. If this function is passed to LV2_Descriptor.instantiate(), it may be called from any non-realtime context. If it is passed to LV2_State_Interface.save(), it may only be called within the dynamic scope of that function call. - The caller is responsible for freeing the returned value with free(). + The caller must free the returned value with + LV2_State_Free_Path.free_path(). */ char* (*path)(LV2_State_Make_Path_Handle handle, const char* path); } LV2_State_Make_Path; +/** + Feature data for state:freePath (@ref LV2_STATE__freePath). +*/ +typedef struct { + /** + Opaque host data. + */ + LV2_State_Free_Path_Handle handle; + + /** + Free a path returned by a state feature. + + @param handle MUST be the `handle` member of this struct. + @param path The path previously returned by a state feature. + + This function can be used by plugins to free paths allocated by the host + and returned by state features (LV2_State_Map_Path.abstract_path(), + LV2_State_Map_Path.absolute_path(), and LV2_State_Make_Path.path()). + */ + void (*free_path)(LV2_State_Free_Path_Handle handle, + char* path); +} LV2_State_Free_Path; + #ifdef __cplusplus } /* extern "C" */ #endif #endif /* LV2_STATE_H */ + +/** + @} +*/ diff --git a/dpf/distrho/src/lv2/time.h b/dpf/distrho/src/lv2/time.h index 3bb0614..ec5007c 100644 --- a/dpf/distrho/src/lv2/time.h +++ b/dpf/distrho/src/lv2/time.h @@ -1,5 +1,5 @@ /* - Copyright 2011 David Robillard + Copyright 2011-2016 David Robillard Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -15,35 +15,39 @@ */ /** - @file time.h C header for the LV2 Time extension - . + @defgroup time Time + + Properties for describing time, see for + details. + + Note the time extension is purely data, this header merely defines URIs for + convenience. + + @{ */ #ifndef LV2_TIME_H #define LV2_TIME_H -#ifdef __cplusplus -extern "C" { -#endif - -#define LV2_TIME_URI "http://lv2plug.in/ns/ext/time" - -#define LV2_TIME__Time LV2_TIME_URI "#Time" -#define LV2_TIME__Position LV2_TIME_URI "#Position" -#define LV2_TIME__Rate LV2_TIME_URI "#Rate" -#define LV2_TIME__position LV2_TIME_URI "#position" -#define LV2_TIME__barBeat LV2_TIME_URI "#barBeat" -#define LV2_TIME__bar LV2_TIME_URI "#bar" -#define LV2_TIME__beat LV2_TIME_URI "#beat" -#define LV2_TIME__beatUnit LV2_TIME_URI "#beatUnit" -#define LV2_TIME__beatsPerBar LV2_TIME_URI "#beatsPerBar" -#define LV2_TIME__beatsPerMinute LV2_TIME_URI "#beatsPerMinute" -#define LV2_TIME__frame LV2_TIME_URI "#frame" -#define LV2_TIME__framesPerSecond LV2_TIME_URI "#framesPerSecond" -#define LV2_TIME__speed LV2_TIME_URI "#speed" - -#ifdef __cplusplus -} /* extern "C" */ -#endif +#define LV2_TIME_URI "http://lv2plug.in/ns/ext/time" ///< http://lv2plug.in/ns/ext/time +#define LV2_TIME_PREFIX LV2_TIME_URI "#" ///< http://lv2plug.in/ns/ext/time# + +#define LV2_TIME__Time LV2_TIME_PREFIX "Time" ///< http://lv2plug.in/ns/ext/time#Time +#define LV2_TIME__Position LV2_TIME_PREFIX "Position" ///< http://lv2plug.in/ns/ext/time#Position +#define LV2_TIME__Rate LV2_TIME_PREFIX "Rate" ///< http://lv2plug.in/ns/ext/time#Rate +#define LV2_TIME__position LV2_TIME_PREFIX "position" ///< http://lv2plug.in/ns/ext/time#position +#define LV2_TIME__barBeat LV2_TIME_PREFIX "barBeat" ///< http://lv2plug.in/ns/ext/time#barBeat +#define LV2_TIME__bar LV2_TIME_PREFIX "bar" ///< http://lv2plug.in/ns/ext/time#bar +#define LV2_TIME__beat LV2_TIME_PREFIX "beat" ///< http://lv2plug.in/ns/ext/time#beat +#define LV2_TIME__beatUnit LV2_TIME_PREFIX "beatUnit" ///< http://lv2plug.in/ns/ext/time#beatUnit +#define LV2_TIME__beatsPerBar LV2_TIME_PREFIX "beatsPerBar" ///< http://lv2plug.in/ns/ext/time#beatsPerBar +#define LV2_TIME__beatsPerMinute LV2_TIME_PREFIX "beatsPerMinute" ///< http://lv2plug.in/ns/ext/time#beatsPerMinute +#define LV2_TIME__frame LV2_TIME_PREFIX "frame" ///< http://lv2plug.in/ns/ext/time#frame +#define LV2_TIME__framesPerSecond LV2_TIME_PREFIX "framesPerSecond" ///< http://lv2plug.in/ns/ext/time#framesPerSecond +#define LV2_TIME__speed LV2_TIME_PREFIX "speed" ///< http://lv2plug.in/ns/ext/time#speed + +/** + @} +*/ #endif /* LV2_TIME_H */ diff --git a/dpf/distrho/src/lv2/units.h b/dpf/distrho/src/lv2/units.h index a40f097..1debf60 100644 --- a/dpf/distrho/src/lv2/units.h +++ b/dpf/distrho/src/lv2/units.h @@ -1,5 +1,5 @@ /* - Copyright 2012 David Robillard + Copyright 2012-2016 David Robillard Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -15,48 +15,55 @@ */ /** - @file units.h - C definitions for the LV2 Units extension - . + @defgroup units Units + + Units for LV2 values, see for + details. + + @{ */ #ifndef LV2_UNITS_H #define LV2_UNITS_H -#define LV2_UNITS_URI "http://lv2plug.in/ns/extensions/units" -#define LV2_UNITS_PREFIX LV2_UNITS_URI "#" - -#define LV2_UNITS__Conversion LV2_UNITS_PREFIX "Conversion" -#define LV2_UNITS__Unit LV2_UNITS_PREFIX "Unit" -#define LV2_UNITS__bar LV2_UNITS_PREFIX "bar" -#define LV2_UNITS__beat LV2_UNITS_PREFIX "beat" -#define LV2_UNITS__bpm LV2_UNITS_PREFIX "bpm" -#define LV2_UNITS__cent LV2_UNITS_PREFIX "cent" -#define LV2_UNITS__cm LV2_UNITS_PREFIX "cm" -#define LV2_UNITS__coef LV2_UNITS_PREFIX "coef" -#define LV2_UNITS__conversion LV2_UNITS_PREFIX "conversion" -#define LV2_UNITS__db LV2_UNITS_PREFIX "db" -#define LV2_UNITS__degree LV2_UNITS_PREFIX "degree" -#define LV2_UNITS__frame LV2_UNITS_PREFIX "frame" -#define LV2_UNITS__hz LV2_UNITS_PREFIX "hz" -#define LV2_UNITS__inch LV2_UNITS_PREFIX "inch" -#define LV2_UNITS__khz LV2_UNITS_PREFIX "khz" -#define LV2_UNITS__km LV2_UNITS_PREFIX "km" -#define LV2_UNITS__m LV2_UNITS_PREFIX "m" -#define LV2_UNITS__mhz LV2_UNITS_PREFIX "mhz" -#define LV2_UNITS__midiNote LV2_UNITS_PREFIX "midiNote" -#define LV2_UNITS__mile LV2_UNITS_PREFIX "mile" -#define LV2_UNITS__min LV2_UNITS_PREFIX "min" -#define LV2_UNITS__mm LV2_UNITS_PREFIX "mm" -#define LV2_UNITS__ms LV2_UNITS_PREFIX "ms" -#define LV2_UNITS__name LV2_UNITS_PREFIX "name" -#define LV2_UNITS__oct LV2_UNITS_PREFIX "oct" -#define LV2_UNITS__pc LV2_UNITS_PREFIX "pc" -#define LV2_UNITS__prefixConversion LV2_UNITS_PREFIX "prefixConversion" -#define LV2_UNITS__render LV2_UNITS_PREFIX "render" -#define LV2_UNITS__s LV2_UNITS_PREFIX "s" -#define LV2_UNITS__semitone12TET LV2_UNITS_PREFIX "semitone12TET" -#define LV2_UNITS__symbol LV2_UNITS_PREFIX "symbol" -#define LV2_UNITS__unit LV2_UNITS_PREFIX "unit" +#define LV2_UNITS_URI "http://lv2plug.in/ns/extensions/units" ///< http://lv2plug.in/ns/extensions/units +#define LV2_UNITS_PREFIX LV2_UNITS_URI "#" ///< http://lv2plug.in/ns/extensions/units# + +#define LV2_UNITS__Conversion LV2_UNITS_PREFIX "Conversion" ///< http://lv2plug.in/ns/ext/units#Conversion +#define LV2_UNITS__Unit LV2_UNITS_PREFIX "Unit" ///< http://lv2plug.in/ns/ext/units#Unit +#define LV2_UNITS__bar LV2_UNITS_PREFIX "bar" ///< http://lv2plug.in/ns/ext/units#bar +#define LV2_UNITS__beat LV2_UNITS_PREFIX "beat" ///< http://lv2plug.in/ns/ext/units#beat +#define LV2_UNITS__bpm LV2_UNITS_PREFIX "bpm" ///< http://lv2plug.in/ns/ext/units#bpm +#define LV2_UNITS__cent LV2_UNITS_PREFIX "cent" ///< http://lv2plug.in/ns/ext/units#cent +#define LV2_UNITS__cm LV2_UNITS_PREFIX "cm" ///< http://lv2plug.in/ns/ext/units#cm +#define LV2_UNITS__coef LV2_UNITS_PREFIX "coef" ///< http://lv2plug.in/ns/ext/units#coef +#define LV2_UNITS__conversion LV2_UNITS_PREFIX "conversion" ///< http://lv2plug.in/ns/ext/units#conversion +#define LV2_UNITS__db LV2_UNITS_PREFIX "db" ///< http://lv2plug.in/ns/ext/units#db +#define LV2_UNITS__degree LV2_UNITS_PREFIX "degree" ///< http://lv2plug.in/ns/ext/units#degree +#define LV2_UNITS__frame LV2_UNITS_PREFIX "frame" ///< http://lv2plug.in/ns/ext/units#frame +#define LV2_UNITS__hz LV2_UNITS_PREFIX "hz" ///< http://lv2plug.in/ns/ext/units#hz +#define LV2_UNITS__inch LV2_UNITS_PREFIX "inch" ///< http://lv2plug.in/ns/ext/units#inch +#define LV2_UNITS__khz LV2_UNITS_PREFIX "khz" ///< http://lv2plug.in/ns/ext/units#khz +#define LV2_UNITS__km LV2_UNITS_PREFIX "km" ///< http://lv2plug.in/ns/ext/units#km +#define LV2_UNITS__m LV2_UNITS_PREFIX "m" ///< http://lv2plug.in/ns/ext/units#m +#define LV2_UNITS__mhz LV2_UNITS_PREFIX "mhz" ///< http://lv2plug.in/ns/ext/units#mhz +#define LV2_UNITS__midiNote LV2_UNITS_PREFIX "midiNote" ///< http://lv2plug.in/ns/ext/units#midiNote +#define LV2_UNITS__mile LV2_UNITS_PREFIX "mile" ///< http://lv2plug.in/ns/ext/units#mile +#define LV2_UNITS__min LV2_UNITS_PREFIX "min" ///< http://lv2plug.in/ns/ext/units#min +#define LV2_UNITS__mm LV2_UNITS_PREFIX "mm" ///< http://lv2plug.in/ns/ext/units#mm +#define LV2_UNITS__ms LV2_UNITS_PREFIX "ms" ///< http://lv2plug.in/ns/ext/units#ms +#define LV2_UNITS__name LV2_UNITS_PREFIX "name" ///< http://lv2plug.in/ns/ext/units#name +#define LV2_UNITS__oct LV2_UNITS_PREFIX "oct" ///< http://lv2plug.in/ns/ext/units#oct +#define LV2_UNITS__pc LV2_UNITS_PREFIX "pc" ///< http://lv2plug.in/ns/ext/units#pc +#define LV2_UNITS__prefixConversion LV2_UNITS_PREFIX "prefixConversion" ///< http://lv2plug.in/ns/ext/units#prefixConversion +#define LV2_UNITS__render LV2_UNITS_PREFIX "render" ///< http://lv2plug.in/ns/ext/units#render +#define LV2_UNITS__s LV2_UNITS_PREFIX "s" ///< http://lv2plug.in/ns/ext/units#s +#define LV2_UNITS__semitone12TET LV2_UNITS_PREFIX "semitone12TET" ///< http://lv2plug.in/ns/ext/units#semitone12TET +#define LV2_UNITS__symbol LV2_UNITS_PREFIX "symbol" ///< http://lv2plug.in/ns/ext/units#symbol +#define LV2_UNITS__unit LV2_UNITS_PREFIX "unit" ///< http://lv2plug.in/ns/ext/units#unit #endif /* LV2_UNITS_H */ + +/** + @} +*/ diff --git a/dpf/distrho/src/lv2/uri-map.h b/dpf/distrho/src/lv2/uri-map.h index 2062af3..12d52be 100644 --- a/dpf/distrho/src/lv2/uri-map.h +++ b/dpf/distrho/src/lv2/uri-map.h @@ -1,5 +1,5 @@ /* - Copyright 2008-2011 David Robillard + Copyright 2008-2016 David Robillard Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -15,8 +15,9 @@ */ /** - @file - C header for the LV2 URI Map extension . + @defgroup uri-map URI Map + + C API for the LV2 URI Map extension . This extension defines a simple mechanism for plugins to map URIs to integers, usually for performance reasons (e.g. processing events typed by @@ -25,12 +26,15 @@ values for use in the audio thread without doing any string comparison. This allows the extensibility of RDF with the performance of integers (or centrally defined enumerations). + + @{ */ #ifndef LV2_URI_MAP_H #define LV2_URI_MAP_H -#define LV2_URI_MAP_URI "http://lv2plug.in/ns/ext/uri-map" +#define LV2_URI_MAP_URI "http://lv2plug.in/ns/ext/uri-map" ///< http://lv2plug.in/ns/ext/uri-map +#define LV2_URI_MAP_PREFIX LV2_URI_MAP_URI "#" ///< http://lv2plug.in/ns/ext/uri-map# #include @@ -96,3 +100,7 @@ typedef struct { #endif #endif /* LV2_URI_MAP_H */ + +/** + @} +*/ diff --git a/dpf/distrho/src/lv2/urid.h b/dpf/distrho/src/lv2/urid.h index c317f7f..c9ee2e0 100644 --- a/dpf/distrho/src/lv2/urid.h +++ b/dpf/distrho/src/lv2/urid.h @@ -1,5 +1,5 @@ /* - Copyright 2008-2012 David Robillard + Copyright 2008-2016 David Robillard Copyright 2011 Gabriel M. Beddingfield Permission to use, copy, modify, and/or distribute this software for any @@ -16,22 +16,25 @@ */ /** - @file urid.h - C header for the LV2 URID extension + @defgroup urid URID + + Features for mapping URIs to and from integers, see + for details. + + @{ */ #ifndef LV2_URID_H #define LV2_URID_H -#define LV2_URID_URI "http://lv2plug.in/ns/ext/urid" -#define LV2_URID_PREFIX LV2_URID_URI "#" +#define LV2_URID_URI "http://lv2plug.in/ns/ext/urid" ///< http://lv2plug.in/ns/ext/urid +#define LV2_URID_PREFIX LV2_URID_URI "#" ///< http://lv2plug.in/ns/ext/urid# -#define LV2_URID__map LV2_URID_PREFIX "map" -#define LV2_URID__unmap LV2_URID_PREFIX "unmap" +#define LV2_URID__map LV2_URID_PREFIX "map" ///< http://lv2plug.in/ns/ext/urid#map +#define LV2_URID__unmap LV2_URID_PREFIX "unmap" ///< http://lv2plug.in/ns/ext/urid#unmap -/* Legacy defines */ -#define LV2_URID_MAP_URI LV2_URID__map -#define LV2_URID_UNMAP_URI LV2_URID__unmap +#define LV2_URID_MAP_URI LV2_URID__map ///< Legacy +#define LV2_URID_UNMAP_URI LV2_URID__unmap ///< Legacy #include @@ -106,11 +109,11 @@ typedef struct _LV2_URID_Unmap { /** Get the URI for a previously mapped numeric ID. - Returns NULL if @p urid is not yet mapped. Otherwise, the corresponding + Returns NULL if `urid` is not yet mapped. Otherwise, the corresponding URI is returned in a canonical form. This MAY not be the exact same string that was originally passed to LV2_URID_Map::map(), but it MUST be an identical URI according to the URI syntax specification (RFC3986). A - non-NULL return for a given @p urid will always be the same for the life + non-NULL return for a given `urid` will always be the same for the life of the plugin. Plugins that intend to perform string comparison on unmapped URIs SHOULD first canonicalise URI strings with a call to map_uri() followed by a call to unmap_uri(). @@ -127,3 +130,7 @@ typedef struct _LV2_URID_Unmap { #endif #endif /* LV2_URID_H */ + +/** + @} +*/ diff --git a/dpf/distrho/src/lv2/worker.h b/dpf/distrho/src/lv2/worker.h index fc09d55..6c01057 100644 --- a/dpf/distrho/src/lv2/worker.h +++ b/dpf/distrho/src/lv2/worker.h @@ -1,5 +1,5 @@ /* - Copyright 2012 David Robillard + Copyright 2012-2016 David Robillard Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -15,8 +15,12 @@ */ /** - @file worker.h C header for the LV2 Worker extension - . + @defgroup worker Worker + + Support for non-realtime plugin operations, see + for details. + + @{ */ #ifndef LV2_WORKER_H @@ -26,18 +30,18 @@ #include "lv2.h" -#define LV2_WORKER_URI "http://lv2plug.in/ns/ext/worker" -#define LV2_WORKER_PREFIX LV2_WORKER_URI "#" +#define LV2_WORKER_URI "http://lv2plug.in/ns/ext/worker" ///< http://lv2plug.in/ns/ext/worker +#define LV2_WORKER_PREFIX LV2_WORKER_URI "#" ///< http://lv2plug.in/ns/ext/worker# -#define LV2_WORKER__interface LV2_WORKER_PREFIX "interface" -#define LV2_WORKER__schedule LV2_WORKER_PREFIX "schedule" +#define LV2_WORKER__interface LV2_WORKER_PREFIX "interface" ///< http://lv2plug.in/ns/ext/worker#interface +#define LV2_WORKER__schedule LV2_WORKER_PREFIX "schedule" ///< http://lv2plug.in/ns/ext/worker#schedule #ifdef __cplusplus extern "C" { #endif /** - A status code for worker functions. + Status code for worker functions. */ typedef enum { LV2_WORKER_SUCCESS = 0, /**< Completed successfully. */ @@ -45,12 +49,13 @@ typedef enum { LV2_WORKER_ERR_NO_SPACE = 2 /**< Failed due to lack of space. */ } LV2_Worker_Status; +/** Opaque handle for LV2_Worker_Interface::work(). */ typedef void* LV2_Worker_Respond_Handle; /** A function to respond to run() from the worker method. - The @p data MUST be safe for the host to copy and later pass to + The `data` MUST be safe for the host to copy and later pass to work_response(), and the host MUST guarantee that it will be eventually passed to work_response() if this function returns LV2_WORKER_SUCCESS. */ @@ -60,7 +65,7 @@ typedef LV2_Worker_Status (*LV2_Worker_Respond_Function)( const void* data); /** - LV2 Plugin Worker Interface. + Plugin Worker Interface. This is the interface provided by the plugin to implement a worker method. The plugin's extension_data() method should return an LV2_Worker_Interface @@ -71,14 +76,17 @@ typedef struct _LV2_Worker_Interface { The worker method. This is called by the host in a non-realtime context as requested, possibly with an arbitrary message to handle. - A response can be sent to run() using @p respond. The plugin MUST NOT - make any assumptions about which thread calls this method, other than - the fact that there are no real-time requirements. + A response can be sent to run() using `respond`. The plugin MUST NOT + make any assumptions about which thread calls this method, except that + there are no real-time requirements and only one call may be executed at + a time. That is, the host MAY call this method from any non-real-time + thread, but MUST NOT make concurrent calls to this method from several + threads. @param instance The LV2 instance this is a method on. @param respond A function for sending a response to run(). - @param handle Must be passed to @p respond if it is called. - @param size The size of @p data. + @param handle Must be passed to `respond` if it is called. + @param size The size of `data`. @param data Data from run(), or NULL. */ LV2_Worker_Status (*work)(LV2_Handle instance, @@ -92,7 +100,7 @@ typedef struct _LV2_Worker_Interface { run() context when a response from the worker is ready. @param instance The LV2 instance this is a method on. - @param size The size of @p body. + @param size The size of `body`. @param body Message body, or NULL. */ LV2_Worker_Status (*work_response)(LV2_Handle instance, @@ -112,8 +120,15 @@ typedef struct _LV2_Worker_Interface { LV2_Worker_Status (*end_run)(LV2_Handle instance); } LV2_Worker_Interface; +/** Opaque handle for LV2_Worker_Schedule. */ typedef void* LV2_Worker_Schedule_Handle; +/** + Schedule Worker Host Feature. + + The host passes this feature to provide a schedule_work() function, which + the plugin can use to schedule a worker call from run(). +*/ typedef struct _LV2_Worker_Schedule { /** Opaque host data. @@ -138,12 +153,12 @@ typedef struct _LV2_Worker_Schedule { immediately, and responses from the worker are delivered immediately, the effect of the work takes place immediately with sample accuracy. - The @p data MUST be safe for the host to copy and later pass to work(), + The `data` MUST be safe for the host to copy and later pass to work(), and the host MUST guarantee that it will be eventually passed to work() if this function returns LV2_WORKER_SUCCESS. @param handle The handle field of this struct. - @param size The size of @p data. + @param size The size of `data`. @param data Message to pass to work(), or NULL. */ LV2_Worker_Status (*schedule_work)(LV2_Worker_Schedule_Handle handle, @@ -156,3 +171,7 @@ typedef struct _LV2_Worker_Schedule { #endif #endif /* LV2_WORKER_H */ + +/** + @} +*/ diff --git a/dpf/distrho/src/travesty/audio_processor.h b/dpf/distrho/src/travesty/audio_processor.h index 85b2297..8783d8e 100644 --- a/dpf/distrho/src/travesty/audio_processor.h +++ b/dpf/distrho/src/travesty/audio_processor.h @@ -1,6 +1,6 @@ /* * travesty, pure C VST3-compatible interface - * Copyright (C) 2021 Filipe Coelho + * Copyright (C) 2021-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -90,8 +90,9 @@ struct v3_process_setup { */ struct v3_param_value_queue { +#ifndef __cplusplus struct v3_funknown; - +#endif v3_param_id (V3_API* get_param_id)(void* self); int32_t (V3_API* get_point_count)(void* self); v3_result (V3_API* get_point)(void* self, int32_t idx, int32_t* sample_offset, double* value); @@ -102,8 +103,9 @@ static constexpr const v3_tuid v3_param_value_queue_iid = V3_ID(0x01263A18, 0xED074F6F, 0x98C9D356, 0x4686F9BA); struct v3_param_changes { +#ifndef __cplusplus struct v3_funknown; - +#endif int32_t (V3_API* get_param_count)(void* self); struct v3_param_value_queue** (V3_API* get_param_data)(void* self, int32_t idx); struct v3_param_value_queue** (V3_API* add_param_data)(void* self, v3_param_id* id, int32_t* index); @@ -181,8 +183,9 @@ enum { }; struct v3_process_context_requirements { +#ifndef __cplusplus struct v3_funknown; - +#endif uint32_t (V3_API* get_process_context_requirements)(void* self); }; @@ -222,8 +225,9 @@ struct v3_process_data { */ struct v3_audio_processor { +#ifndef __cplusplus struct v3_funknown; - +#endif v3_result (V3_API* set_bus_arrangements)(void* self, v3_speaker_arrangement* inputs, int32_t num_inputs, v3_speaker_arrangement* outputs, int32_t num_outputs); v3_result (V3_API* get_bus_arrangement)(void* self, int32_t bus_direction, int32_t idx, v3_speaker_arrangement*); diff --git a/dpf/distrho/src/travesty/base.h b/dpf/distrho/src/travesty/base.h index c589033..ab5245d 100644 --- a/dpf/distrho/src/travesty/base.h +++ b/dpf/distrho/src/travesty/base.h @@ -1,6 +1,6 @@ /* * travesty, pure C VST3-compatible interface - * Copyright (C) 2021 Filipe Coelho + * Copyright (C) 2021-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -24,34 +24,8 @@ * deal with C vs C++ differences */ -#ifdef __cplusplus - -/** - * cast object into its proper C++ type. - * this is needed because `struct v3_funknown;` on a C++ class does not inherit `v3_funknown`'s fields. - * - * we can use this as a little helper for keeping both C and C++ compatiblity. - * specialized templated calls are defined where required - * (that is, object inherits from something other than `v3_funknown`) - * - * example usage: `v3_cpp_obj(obj)->method(obj, args...);` - */ -template static inline -constexpr T* v3_cpp_obj(T** obj) -{ - /** - * this ugly piece of code is required due to C++ assuming `reinterpret_cast` by default, - * but we need everything to be `static_cast` for it to be `constexpr` compatible. - */ - return static_cast(static_cast(static_cast(static_cast(*obj)) + sizeof(void*)*3)); -} - -#else - -# ifndef constexpr -# define constexpr -# endif - +#if !defined(__cplusplus) && !defined(constexpr) +# define constexpr #endif /** @@ -178,8 +152,9 @@ static constexpr const v3_tuid v3_funknown_iid = */ struct v3_plugin_base { +#ifndef __cplusplus struct v3_funknown; - +#endif v3_result (V3_API* initialize)(void* self, struct v3_funknown** context); v3_result (V3_API* terminate)(void* self); }; @@ -189,6 +164,27 @@ static constexpr const v3_tuid v3_plugin_base_iid = #ifdef __cplusplus +/** + * cast object into its proper C++ type. + * this is needed because `struct v3_funknown;` on a C++ class does not inherit `v3_funknown`'s fields. + * + * we can use this as a little helper for keeping both C and C++ compatiblity. + * specialized templated calls are defined where required + * (that is, object inherits from something other than `v3_funknown`) + * + * example usage: `v3_cpp_obj(obj)->method(obj, args...);` + */ + +template static inline +constexpr T* v3_cpp_obj(T** obj) +{ + /** + * this ugly piece of code is required due to C++ assuming `reinterpret_cast` by default, + * but we need everything to be `static_cast` for it to be `constexpr` compatible. + */ + return static_cast(static_cast(static_cast(static_cast(*obj)) + sizeof(void*)*3)); +} + /** * helper C++ functions to manually call v3_funknown methods on an object. */ @@ -211,4 +207,18 @@ uint32_t v3_cpp_obj_unref(T** obj) return static_cast(static_cast(*obj))->unref(obj); } +template static inline +v3_result v3_cpp_obj_initialize(T** obj, v3_funknown** context) +{ + return static_cast( + static_cast(static_cast(static_cast(*obj)) + sizeof(void*)*3))->initialize(obj, context); +} + +template static inline +v3_result v3_cpp_obj_terminate(T** obj) +{ + return static_cast( + static_cast(static_cast(static_cast(*obj)) + sizeof(void*)*3))->terminate(obj); +} + #endif diff --git a/dpf/distrho/src/travesty/bstream.h b/dpf/distrho/src/travesty/bstream.h index a1bfcd3..92bbc3b 100644 --- a/dpf/distrho/src/travesty/bstream.h +++ b/dpf/distrho/src/travesty/bstream.h @@ -1,6 +1,6 @@ /* * travesty, pure C VST3-compatible interface - * Copyright (C) 2021 Filipe Coelho + * Copyright (C) 2021-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -25,8 +25,9 @@ enum v3_seek_mode { }; struct v3_bstream { +#ifndef __cplusplus struct v3_funknown; - +#endif v3_result (V3_API *read)(void* self, void* buffer, int32_t num_bytes, int32_t* bytes_read); v3_result (V3_API *write)(void* self, void* buffer, int32_t num_bytes, int32_t* bytes_written); v3_result (V3_API *seek)(void* self, int64_t pos, int32_t seek_mode, int64_t* result); diff --git a/dpf/distrho/src/travesty/component.h b/dpf/distrho/src/travesty/component.h index 4e73c47..652da36 100644 --- a/dpf/distrho/src/travesty/component.h +++ b/dpf/distrho/src/travesty/component.h @@ -1,6 +1,6 @@ /* * travesty, pure C VST3-compatible interface - * Copyright (C) 2021 Filipe Coelho + * Copyright (C) 2021-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -89,8 +89,9 @@ struct v3_bus_info { struct v3_routing_info; struct v3_component { +#ifndef __cplusplus struct v3_plugin_base; - +#endif v3_result (V3_API *get_controller_class_id)(void* self, v3_tuid class_id); v3_result (V3_API *set_io_mode)(void* self, int32_t io_mode); int32_t (V3_API *get_bus_count)(void* self, int32_t media_type, int32_t bus_direction); diff --git a/dpf/distrho/src/travesty/edit_controller.h b/dpf/distrho/src/travesty/edit_controller.h index 9edb151..c83a285 100644 --- a/dpf/distrho/src/travesty/edit_controller.h +++ b/dpf/distrho/src/travesty/edit_controller.h @@ -1,6 +1,6 @@ /* * travesty, pure C VST3-compatible interface - * Copyright (C) 2021 Filipe Coelho + * Copyright (C) 2021-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -40,8 +40,9 @@ enum { }; struct v3_component_handler { +#ifndef __cplusplus struct v3_funknown; - +#endif v3_result (V3_API* begin_edit)(void* self, v3_param_id); v3_result (V3_API* perform_edit)(void* self, v3_param_id, double value_normalised); v3_result (V3_API* end_edit)(void* self, v3_param_id); @@ -51,6 +52,19 @@ struct v3_component_handler { static constexpr const v3_tuid v3_component_handler_iid = V3_ID(0x93A0BEA3, 0x0BD045DB, 0x8E890B0C, 0xC1E46AC6); +struct v3_component_handler2 { +#ifndef __cplusplus + struct v3_funknown; +#endif + v3_result (V3_API* set_dirty)(void* self, v3_bool state); + v3_result (V3_API* request_open_editor)(void* self, const char* name); + v3_result (V3_API* start_group_edit)(void* self); + v3_result (V3_API* finish_group_edit)(void* self); +}; + +static constexpr const v3_tuid v3_component_handler2_iid = + V3_ID(0xF040B4B3, 0xA36045EC, 0xABCDC045, 0xB4D5A2CC); + /** * edit controller */ @@ -77,8 +91,9 @@ struct v3_param_info { }; struct v3_edit_controller { +#ifndef __cplusplus struct v3_plugin_base; - +#endif v3_result (V3_API* set_component_state)(void* self, struct v3_bstream**); v3_result (V3_API* set_state)(void* self, struct v3_bstream**); v3_result (V3_API* get_state)(void* self, struct v3_bstream**); @@ -102,8 +117,9 @@ static constexpr const v3_tuid v3_edit_controller_iid = */ struct v3_midi_mapping { +#ifndef __cplusplus struct v3_funknown; - +#endif v3_result (V3_API* get_midi_controller_assignment)(void* self, int32_t bus, int16_t channel, int16_t cc, v3_param_id* id); }; diff --git a/dpf/distrho/src/travesty/events.h b/dpf/distrho/src/travesty/events.h index 72a4830..9c83bf8 100644 --- a/dpf/distrho/src/travesty/events.h +++ b/dpf/distrho/src/travesty/events.h @@ -1,6 +1,6 @@ /* * travesty, pure C VST3-compatible interface - * Copyright (C) 2021 Filipe Coelho + * Copyright (C) 2021-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -132,8 +132,9 @@ struct v3_event { */ struct v3_event_list { +#ifndef __cplusplus struct v3_funknown; - +#endif uint32_t (V3_API* get_event_count)(void* self); v3_result (V3_API* get_event)(void* self, int32_t idx, struct v3_event* event); v3_result (V3_API* add_event)(void* self, struct v3_event* event); @@ -142,4 +143,16 @@ struct v3_event_list { static constexpr const v3_tuid v3_event_list_iid = V3_ID(0x3A2C4214, 0x346349FE, 0xB2C4F397, 0xB9695A44); +#ifdef __cplusplus + +/** + * C++ variants + */ + +struct v3_event_list_cpp : v3_funknown { + v3_event_list list; +}; + +#endif + #include "align_pop.h" diff --git a/dpf/distrho/src/travesty/factory.h b/dpf/distrho/src/travesty/factory.h index adad83c..055b707 100644 --- a/dpf/distrho/src/travesty/factory.h +++ b/dpf/distrho/src/travesty/factory.h @@ -1,6 +1,6 @@ /* * travesty, pure C VST3-compatible interface - * Copyright (C) 2021 Filipe Coelho + * Copyright (C) 2021-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -37,8 +37,9 @@ struct v3_class_info { }; struct v3_plugin_factory { +#ifndef __cplusplus struct v3_funknown; - +#endif v3_result (V3_API *get_factory_info)(void* self, struct v3_factory_info*); int32_t (V3_API *num_classes)(void* self); v3_result (V3_API *get_class_info)(void* self, int32_t idx, struct v3_class_info*); @@ -70,8 +71,9 @@ struct v3_class_info_2 { }; struct v3_plugin_factory_2 { +#ifndef __cplusplus struct v3_plugin_factory; - +#endif v3_result (V3_API *get_class_info_2)(void* self, int32_t idx, struct v3_class_info_2*); }; @@ -98,8 +100,9 @@ struct v3_class_info_3 { }; struct v3_plugin_factory_3 { +#ifndef __cplusplus struct v3_plugin_factory_2; - +#endif v3_result (V3_API *get_class_info_utf16)(void* self, int32_t idx, struct v3_class_info_3*); v3_result (V3_API *set_host_context)(void* self, struct v3_funknown** host); }; @@ -119,4 +122,26 @@ struct v3_plugin_factory_cpp : v3_funknown { v3_plugin_factory_3 v3; }; +template<> inline +constexpr v3_plugin_factory_2* v3_cpp_obj(v3_plugin_factory_2** obj) +{ + /** + * this ugly piece of code is required due to C++ assuming `reinterpret_cast` by default, + * but we need everything to be `static_cast` for it to be `constexpr` compatible. + */ + return static_cast( + static_cast(static_cast(static_cast(*obj)) + sizeof(void*)*7)); +} + +template<> inline +constexpr v3_plugin_factory_3* v3_cpp_obj(v3_plugin_factory_3** obj) +{ + /** + * this ugly piece of code is required due to C++ assuming `reinterpret_cast` by default, + * but we need everything to be `static_cast` for it to be `constexpr` compatible. + */ + return static_cast( + static_cast(static_cast(static_cast(*obj)) + sizeof(void*)*8)); +} + #endif diff --git a/dpf/distrho/src/travesty/host.h b/dpf/distrho/src/travesty/host.h index 032a7ee..bb6566b 100644 --- a/dpf/distrho/src/travesty/host.h +++ b/dpf/distrho/src/travesty/host.h @@ -1,6 +1,6 @@ /* * travesty, pure C VST3-compatible interface - * Copyright (C) 2021 Filipe Coelho + * Copyright (C) 2021-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -21,12 +21,13 @@ #include "align_push.h" /** - * connection point + * host application */ struct v3_host_application { +#ifndef __cplusplus struct v3_funknown; - +#endif v3_result (V3_API* get_name)(void* self, v3_str_128 name); // wtf? v3_result (V3_API* create_instance)(void* self, v3_tuid cid, v3_tuid iid, void** obj); }; diff --git a/dpf/distrho/src/travesty/message.h b/dpf/distrho/src/travesty/message.h index 3cd77a6..3ab8f46 100644 --- a/dpf/distrho/src/travesty/message.h +++ b/dpf/distrho/src/travesty/message.h @@ -1,6 +1,6 @@ /* * travesty, pure C VST3-compatible interface - * Copyright (C) 2021 Filipe Coelho + * Copyright (C) 2021-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -25,8 +25,9 @@ */ struct v3_attribute_list { +#ifndef __cplusplus struct v3_funknown; - +#endif v3_result (V3_API* set_int)(void* self, const char* id, int64_t value); v3_result (V3_API* get_int)(void* self, const char* id, int64_t* value); v3_result (V3_API* set_float)(void* self, const char* id, double value); @@ -45,8 +46,9 @@ static constexpr const v3_tuid v3_attribute_list_iid = */ struct v3_message { +#ifndef __cplusplus struct v3_funknown; - +#endif const char* (V3_API* get_message_id)(void* self); void (V3_API* set_message_id)(void* self, const char* id); v3_attribute_list** (V3_API* get_attributes)(void* self); @@ -60,8 +62,9 @@ static constexpr const v3_tuid v3_message_iid = */ struct v3_connection_point { +#ifndef __cplusplus struct v3_funknown; - +#endif v3_result (V3_API* connect)(void* self, struct v3_connection_point** other); v3_result (V3_API* disconnect)(void* self, struct v3_connection_point** other); v3_result (V3_API* notify)(void* self, struct v3_message** message); diff --git a/dpf/distrho/src/travesty/unit.h b/dpf/distrho/src/travesty/unit.h new file mode 100644 index 0000000..77bc9ad --- /dev/null +++ b/dpf/distrho/src/travesty/unit.h @@ -0,0 +1,69 @@ +/* + * travesty, pure C VST3-compatible interface + * Copyright (C) 2021-2022 Filipe Coelho + * + * Permission to use, copy, modify, and/or distribute this software for any purpose with + * or without fee is hereby granted, provided that the above copyright notice and this + * permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD + * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#pragma once + +#include "base.h" + +#include "align_push.h" + +struct v3_unit_info { + int32_t id; // 0 for root unit + int32_t parent_unit_id; // -1 for none + v3_str_128 name; + int32_t program_list_id; // -1 for none +}; + +struct v3_program_list_info { + int32_t id; + v3_str_128 name; + int32_t programCount; +}; + +struct v3_unit_information { +#ifndef __cplusplus + struct v3_funknown; +#endif + int32_t (V3_API* get_unit_count)(void* self); + v3_result (V3_API* get_unit_info)(void* self, int32_t unit_idx, v3_unit_info* info); + int32_t (V3_API* get_program_list_count)(void* self); + v3_result (V3_API* get_program_list_info)(void* self, int32_t list_idx, v3_program_list_info* info); + v3_result (V3_API* get_program_name)(void* self, int32_t list_id, int32_t program_idx, v3_str_128 name); + v3_result (V3_API* get_program_info)(void* self, int32_t list_id, int32_t program_idx, const char *attribute_id, v3_str_128 attribute_value); + v3_result (V3_API* has_program_pitch_names)(void* self, int32_t list_id, int32_t program_idx); + v3_result (V3_API* get_program_pitch_name)(void* self, int32_t list_id, int32_t program_idx, int16_t midi_pitch, v3_str_128 name); + int32_t (V3_API* get_selected_unit)(void* self); + v3_result (V3_API* select_unit)(void* self, int32_t unit_id); + v3_result (V3_API* get_unit_by_bus)(void* self, int32_t type, int32_t bus_direction, int32_t bus_idx, int32_t channel, int32_t* unit_id); + v3_result (V3_API* set_unit_program_data)(void* self, int32_t list_or_unit_id, int32_t program_idx, struct v3_bstream** data); +}; + +static constexpr const v3_tuid v3_unit_information_iid = + V3_ID(0x3D4BD6B5, 0x913A4FD2, 0xA886E768, 0xA5EB92C1); + +#ifdef __cplusplus + +/** + * C++ variants + */ + +struct v3_unit_information_cpp : v3_funknown { + v3_unit_information unit; +}; + +#endif + +#include "align_pop.h" diff --git a/dpf/distrho/src/travesty/view.h b/dpf/distrho/src/travesty/view.h index 0abc3be..2f5c698 100644 --- a/dpf/distrho/src/travesty/view.h +++ b/dpf/distrho/src/travesty/view.h @@ -1,6 +1,6 @@ /* * travesty, pure C VST3-compatible interface - * Copyright (C) 2021 Filipe Coelho + * Copyright (C) 2021-2022 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -48,8 +48,9 @@ struct v3_view_rect { struct v3_plugin_frame; struct v3_plugin_view { +#ifndef __cplusplus struct v3_funknown; - +#endif v3_result (V3_API* is_platform_type_supported)(void* self, const char* platform_type); v3_result (V3_API* attached)(void* self, void* parent, const char* platform_type); v3_result (V3_API* removed)(void* self); @@ -72,8 +73,9 @@ static constexpr const v3_tuid v3_plugin_view_iid = */ struct v3_plugin_frame { +#ifndef __cplusplus struct v3_funknown; - +#endif v3_result (V3_API* resize_view)(void* self, struct v3_plugin_view**, struct v3_view_rect*); }; @@ -86,8 +88,9 @@ static constexpr const v3_tuid v3_plugin_frame_iid = */ struct v3_plugin_view_content_scale { +#ifndef __cplusplus struct v3_funknown; - +#endif v3_result (V3_API* set_content_scale_factor)(void* self, float factor); }; @@ -99,8 +102,9 @@ static constexpr const v3_tuid v3_plugin_view_content_scale_iid = */ struct v3_plugin_view_parameter_finder { +#ifndef __cplusplus struct v3_funknown; - +#endif v3_result (V3_API* find_parameter)(void* self, int32_t x, int32_t y, v3_param_id *); }; @@ -112,8 +116,9 @@ static constexpr const v3_tuid v3_plugin_view_parameter_finder_iid = */ struct v3_event_handler { +#ifndef __cplusplus struct v3_funknown; - +#endif void (V3_API* on_fd_is_set)(void* self, int fd); }; @@ -125,8 +130,9 @@ static constexpr const v3_tuid v3_event_handler_iid = */ struct v3_timer_handler { +#ifndef __cplusplus struct v3_funknown; - +#endif void (V3_API* on_timer)(void* self); }; @@ -138,8 +144,9 @@ static constexpr const v3_tuid v3_timer_handler_iid = */ struct v3_run_loop { +#ifndef __cplusplus struct v3_funknown; - +#endif v3_result (V3_API* register_event_handler)(void* self, v3_event_handler** handler, int fd); v3_result (V3_API* unregister_event_handler)(void* self, v3_event_handler** handler); v3_result (V3_API* register_timer)(void* self, v3_timer_handler** handler, uint64_t ms); diff --git a/dpf/tests/Application.cpp b/dpf/tests/Application.cpp deleted file mode 100644 index d523316..0000000 --- a/dpf/tests/Application.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/* - * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho - * - * Permission to use, copy, modify, and/or distribute this software for any purpose with - * or without fee is hereby granted, provided that the above copyright notice and this - * permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD - * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "tests.hpp" - -#define DPF_TEST_APPLICATION_CPP -#include "dgl/src/pugl.cpp" -#include "dgl/src/Application.cpp" -#include "dgl/src/ApplicationPrivateData.cpp" - -START_NAMESPACE_DGL - -// -------------------------------------------------------------------------------------------------------------------- - -struct IdleCallbackCounter : IdleCallback -{ - int counter; - - IdleCallbackCounter() - : counter(0) {} - - void idleCallback() override - { - ++counter; - } -}; - -// -------------------------------------------------------------------------------------------------------------------- - -END_NAMESPACE_DGL - -int main() -{ - USE_NAMESPACE_DGL; - - // regular usage - { - Application app(true); - IdleCallbackCounter idleCounter; - app.addIdleCallback(&idleCounter); - DISTRHO_ASSERT_EQUAL(app.isQuitting(), false, "app MUST NOT be set as quitting during init"); - DISTRHO_ASSERT_EQUAL(idleCounter.counter, 0, "app MUST NOT have triggered idle callbacks yet"); - app.idle(); - DISTRHO_ASSERT_EQUAL(app.isQuitting(), false, "app MUST NOT be set as quitting after idle()"); - DISTRHO_ASSERT_EQUAL(idleCounter.counter, 1, "app MUST have triggered 1 idle callback"); - app.idle(); - DISTRHO_ASSERT_EQUAL(idleCounter.counter, 2, "app MUST have triggered 2 idle callbacks"); - app.quit(); - DISTRHO_ASSERT_EQUAL(app.isQuitting(), true, "app MUST be set as quitting after quit()"); - DISTRHO_ASSERT_EQUAL(idleCounter.counter, 2, "app MUST have triggered only 2 idle callbacks in its lifetime"); - } - - // standalone exec, must not block forever due to quit() called from another thread - { - Application app(true); - ApplicationQuitter appQuitter(app); - IdleCallbackCounter idleCounter; - app.addIdleCallback(&idleCounter); - app.exec(); - DISTRHO_ASSERT_EQUAL(appQuitter.isThreadRunning(), false, "app quit triggered because we told it so"); - DISTRHO_ASSERT_NOT_EQUAL(idleCounter.counter, 0, "app idle callbacks MUST have been triggered"); - } - - // standalone exec, but with 0 as timeout - { - Application app(true); - ApplicationQuitter appQuitter(app); - IdleCallbackCounter idleCounter; - app.addIdleCallback(&idleCounter); - app.exec(0); - DISTRHO_ASSERT_EQUAL(appQuitter.isThreadRunning(), false, "app quit triggered because we told it so"); - DISTRHO_ASSERT_NOT_EQUAL(idleCounter.counter, 0, "app idle callbacks MUST have been triggered"); - } - - return 0; -} - -// -------------------------------------------------------------------------------------------------------------------- diff --git a/dpf/tests/Circle.cpp b/dpf/tests/Circle.cpp deleted file mode 100644 index e00d80b..0000000 --- a/dpf/tests/Circle.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho - * - * Permission to use, copy, modify, and/or distribute this software for any purpose with - * or without fee is hereby granted, provided that the above copyright notice and this - * permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD - * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "tests.hpp" - -// -------------------------------------------------------------------------------------------------------------------- - -int main() -{ - USE_NAMESPACE_DGL; - - // TODO - - return 0; -} - -// -------------------------------------------------------------------------------------------------------------------- diff --git a/dpf/tests/Color.cpp b/dpf/tests/Color.cpp deleted file mode 100644 index 412de3a..0000000 --- a/dpf/tests/Color.cpp +++ /dev/null @@ -1,219 +0,0 @@ -/* - * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho - * - * Permission to use, copy, modify, and/or distribute this software for any purpose with - * or without fee is hereby granted, provided that the above copyright notice and this - * permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD - * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "tests.hpp" - -#define DPF_TEST_COLOR_CPP -#include "dgl/src/Color.cpp" - -// -------------------------------------------------------------------------------------------------------------------- - -int main() -{ - USE_NAMESPACE_DGL; - - // constructor with no arguments, must give solid black - { - Color c; - DISTRHO_ASSERT_EQUAL(c.red, 0.0f, "red value is 0"); - DISTRHO_ASSERT_EQUAL(c.green, 0.0f, "green value is 0"); - DISTRHO_ASSERT_EQUAL(c.blue, 0.0f, "blue value is 0"); - DISTRHO_ASSERT_EQUAL(c.alpha, 1.0f, "alpha value is 1"); - } - - // constructor gives correct floating-point values (arguments are r, g, b, a; in order) - { - Color c(0.1f, 0.2f, 0.3f, 0.4f); - DISTRHO_ASSERT_EQUAL(c.red, 0.1f, "red value is 0.1"); - DISTRHO_ASSERT_EQUAL(c.green, 0.2f, "green value is 0.2"); - DISTRHO_ASSERT_EQUAL(c.blue, 0.3f, "blue value is 0.3"); - DISTRHO_ASSERT_EQUAL(c.alpha, 0.4f, "alpha value is 0.4"); - } - - // constructor gives correct integer values normalized to float (arguments are r, g, b, a; in order) - { - Color c(51, 102, 153); - DISTRHO_ASSERT_SAFE_EQUAL(c.red, 0.2f, "red value is 0.2 (integer 51)"); - DISTRHO_ASSERT_SAFE_EQUAL(c.green, 0.4f, "green value is 0.4 (integer 102)"); - DISTRHO_ASSERT_SAFE_EQUAL(c.blue, 0.6f, "blue value is 0.6 (integer 153)"); - DISTRHO_ASSERT_SAFE_EQUAL(c.alpha, 1.0f, "alpha value is 1"); - - Color white(255, 255, 255); - DISTRHO_ASSERT_EQUAL(white.red, 1.0f, "white's red value is 1"); - DISTRHO_ASSERT_EQUAL(white.green, 1.0f, "white's green value is 1"); - DISTRHO_ASSERT_EQUAL(white.blue, 1.0f, "white's blue value is 1"); - DISTRHO_ASSERT_EQUAL(white.alpha, 1.0f, "white alpha value is 1"); - } - - // copy colors around - { - Color black; - Color halfTransparentWhite(1.0f, 1.0f, 1.0f, 0.5f); - - // constructor copy - Color test(halfTransparentWhite); - DISTRHO_ASSERT_EQUAL(test.red, 1.0f, "copied white's red value is 1.0"); - DISTRHO_ASSERT_EQUAL(test.green, 1.0f, "copied white's green value is 1"); - DISTRHO_ASSERT_EQUAL(test.blue, 1.0f, "copied white's blue value is 1"); - DISTRHO_ASSERT_EQUAL(test.alpha, 0.5f, "copied white's alpha value is 0.5"); - - // assign operator - test = black; - DISTRHO_ASSERT_EQUAL(test.red, 0.0f, "assigned black's red value is 0"); - DISTRHO_ASSERT_EQUAL(test.green, 0.0f, "assigned black's green value is 0"); - DISTRHO_ASSERT_EQUAL(test.blue, 0.0f, "assigned black's blue value is 0"); - DISTRHO_ASSERT_EQUAL(test.alpha, 1.0f, "assigned black's alpha value is 1"); - } - - // simple color comparisons - { - Color black1, black2; - Color white(1.0f, 1.0f, 1.0f); - Color halfTransparentWhite(1.0f, 1.0f, 1.0f, 0.5f); - - // logic operators - DISTRHO_ASSERT_EQUAL(black1, black1, "color equals itself"); - DISTRHO_ASSERT_EQUAL(black1, black2, "black equals black"); - DISTRHO_ASSERT_NOT_EQUAL(black1, white, "black is not white"); - DISTRHO_ASSERT_NOT_EQUAL(black1, halfTransparentWhite, "black is not half-transparent white"); - DISTRHO_ASSERT_NOT_EQUAL(white, halfTransparentWhite, "white is not half-transparent white"); - - // class functions (truthful) - DISTRHO_ASSERT_EQUAL(black1.isEqual(black1), true, "color equals itself"); - DISTRHO_ASSERT_EQUAL(black1.isEqual(black2), true, "black equals black"); - DISTRHO_ASSERT_EQUAL(black1.isNotEqual(white), true, "black is not white"); - DISTRHO_ASSERT_EQUAL(white.isNotEqual(halfTransparentWhite), true, "white is not half-transparent white"); - - // class functions (inverted) - DISTRHO_ASSERT_EQUAL(black1.isNotEqual(black1), false, "color equals itself"); - DISTRHO_ASSERT_EQUAL(black1.isNotEqual(black2), false, "black equals black"); - DISTRHO_ASSERT_EQUAL(black1.isEqual(white), false, "black is not white"); - DISTRHO_ASSERT_EQUAL(white.isEqual(halfTransparentWhite), false, "white is not half-transparent white"); - - // class functions ignoring alpha - DISTRHO_ASSERT_EQUAL(black1.isEqual(black1, false), true, "color equals itself"); - DISTRHO_ASSERT_EQUAL(black1.isEqual(black2, false), true, "black equals black"); - DISTRHO_ASSERT_EQUAL(black1.isNotEqual(white, false), true, "black is not white"); - DISTRHO_ASSERT_EQUAL(white.isEqual(halfTransparentWhite, false), true, - "white is half-transparent white if we ignore alpha"); - } - - // TODO advanced color comparisons - { - } - - // TODO fromHSL - { - } - - // create colors from html strings - { - Color c000 = Color::fromHTML("#000"); - DISTRHO_ASSERT_EQUAL(c000.red, 0.0f, "#000 red value is 0"); - DISTRHO_ASSERT_EQUAL(c000.green, 0.0f, "#000 green value is 0"); - DISTRHO_ASSERT_EQUAL(c000.blue, 0.0f, "#000 blue value is 0"); - DISTRHO_ASSERT_EQUAL(c000.alpha, 1.0f, "#000 alpha value is 1"); - - Color c000000 = Color::fromHTML("#000000"); - DISTRHO_ASSERT_EQUAL(c000000.red, 0.0f, "#000000 red value is 0"); - DISTRHO_ASSERT_EQUAL(c000000.green, 0.0f, "#000000 green value is 0"); - DISTRHO_ASSERT_EQUAL(c000000.blue, 0.0f, "#000000 blue value is 0"); - DISTRHO_ASSERT_EQUAL(c000000.alpha, 1.0f, "#000000 alpha value is 1"); - - Color cfff = Color::fromHTML("#fff"); - DISTRHO_ASSERT_EQUAL(cfff.red, 1.0f, "#fff red value is 1"); - DISTRHO_ASSERT_EQUAL(cfff.green, 1.0f, "#fff green value is 1"); - DISTRHO_ASSERT_EQUAL(cfff.blue, 1.0f, "#fff blue value is 1"); - DISTRHO_ASSERT_EQUAL(cfff.alpha, 1.0f, "#fff alpha value is 1"); - - Color cffffff = Color::fromHTML("#ffffff"); - DISTRHO_ASSERT_EQUAL(cffffff.red, 1.0f, "#ffffff red value is 1"); - DISTRHO_ASSERT_EQUAL(cffffff.green, 1.0f, "#ffffff green value is 1"); - DISTRHO_ASSERT_EQUAL(cffffff.blue, 1.0f, "#ffffff blue value is 1"); - DISTRHO_ASSERT_EQUAL(cffffff.alpha, 1.0f, "#ffffff alpha value is 1"); - - Color cf00 = Color::fromHTML("#f00"); - DISTRHO_ASSERT_EQUAL(cf00.red, 1.0f, "#f00 red value is 1"); - DISTRHO_ASSERT_EQUAL(cf00.green, 0.0f, "#f00 green value is 0"); - DISTRHO_ASSERT_EQUAL(cf00.blue, 0.0f, "#f00 blue value is 0"); - - Color cff0000 = Color::fromHTML("#ff0000"); - DISTRHO_ASSERT_EQUAL(cff0000.red, 1.0f, "#ff0000 red value is 1"); - DISTRHO_ASSERT_EQUAL(cff0000.green, 0.0f, "#ff0000 green value is 0"); - DISTRHO_ASSERT_EQUAL(cff0000.blue, 0.0f, "#ff0000 blue value is 0"); - - Color c0f0 = Color::fromHTML("#0f0"); - DISTRHO_ASSERT_EQUAL(c0f0.red, 0.0f, "#0f0 red value is 0"); - DISTRHO_ASSERT_EQUAL(c0f0.green, 1.0f, "#0f0 green value is 1"); - DISTRHO_ASSERT_EQUAL(c0f0.blue, 0.0f, "#0f0 blue value is 0"); - - Color c00ff00 = Color::fromHTML("#00ff00"); - DISTRHO_ASSERT_EQUAL(c00ff00.red, 0.0f, "#00ff00 red value is 0"); - DISTRHO_ASSERT_EQUAL(c00ff00.green, 1.0f, "#00ff00 green value is 1"); - DISTRHO_ASSERT_EQUAL(c00ff00.blue, 0.0f, "#00ff00 blue value is 0"); - - Color c00f = Color::fromHTML("#00f"); - DISTRHO_ASSERT_EQUAL(c00f.red, 0.0f, "#00f red value is 0"); - DISTRHO_ASSERT_EQUAL(c00f.green, 0.0f, "#00f green value is 0"); - DISTRHO_ASSERT_EQUAL(c00f.blue, 1.0f, "#00f blue value is 1"); - - Color c0000ff = Color::fromHTML("#0000ff"); - DISTRHO_ASSERT_EQUAL(c0000ff.red, 0.0f, "#0000ff red value is 0"); - DISTRHO_ASSERT_EQUAL(c0000ff.green, 0.0f, "#0000ff green value is 0"); - DISTRHO_ASSERT_EQUAL(c0000ff.blue, 1.0f, "#0000ff blue value is 1"); - - // half point, round to 1 decimal point due to precision loss - Color grey = Color::fromHTML("#7b7b7b"); - DISTRHO_ASSERT_SAFE_EQUAL(std::round(grey.red*10)/10, 0.5f, "grey's rounded red value is 0.5"); - DISTRHO_ASSERT_SAFE_EQUAL(std::round(grey.green*10)/10, 0.5f, "grey's rounded green value is 0.5"); - DISTRHO_ASSERT_SAFE_EQUAL(std::round(grey.blue*10)/10, 0.5f, "grey's rounded blue value is 0.5"); - } - - // check bounds - { - Color negativeInteger(-1, -1, -1, -1.0f); - DISTRHO_ASSERT_EQUAL(negativeInteger.red, 0.0f, "red value is 0"); - DISTRHO_ASSERT_EQUAL(negativeInteger.green, 0.0f, "green value is 0"); - DISTRHO_ASSERT_EQUAL(negativeInteger.blue, 0.0f, "blue value is 0"); - DISTRHO_ASSERT_EQUAL(negativeInteger.alpha, 0.0f, "alpha value is 0"); - - Color negativeFloat(-1.0f, -1.0f, -1.0f, -1.0f); - DISTRHO_ASSERT_EQUAL(negativeFloat.red, 0.0f, "red value is 0"); - DISTRHO_ASSERT_EQUAL(negativeFloat.green, 0.0f, "green value is 0"); - DISTRHO_ASSERT_EQUAL(negativeFloat.blue, 0.0f, "blue value is 0"); - DISTRHO_ASSERT_EQUAL(negativeFloat.alpha, 0.0f, "alpha value is 0"); - - Color overflowInteger(0xfff, 0xfff, 0xfff, 0xfff); - DISTRHO_ASSERT_EQUAL(overflowInteger.red, 1.0f, "red value is 1"); - DISTRHO_ASSERT_EQUAL(overflowInteger.green, 1.0f, "green value is 1"); - DISTRHO_ASSERT_EQUAL(overflowInteger.blue, 1.0f, "blue value is 1"); - DISTRHO_ASSERT_EQUAL(overflowInteger.alpha, 1.0f, "alpha value is 1"); - - Color overflowFloat(2.0f, 2.0f, 2.0f, 2.0f); - DISTRHO_ASSERT_EQUAL(overflowFloat.red, 1.0f, "red value is 1"); - DISTRHO_ASSERT_EQUAL(overflowFloat.green, 1.0f, "green value is 1"); - DISTRHO_ASSERT_EQUAL(overflowFloat.blue, 1.0f, "blue value is 1"); - DISTRHO_ASSERT_EQUAL(overflowFloat.alpha, 1.0f, "alpha value is 1"); - } - - // TODO interpolation - { - } - - return 0; -} - -// -------------------------------------------------------------------------------------------------------------------- diff --git a/dpf/tests/Demo.cpp b/dpf/tests/Demo.cpp deleted file mode 100644 index 41759d2..0000000 --- a/dpf/tests/Demo.cpp +++ /dev/null @@ -1,581 +0,0 @@ -/* - * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho - * - * Permission to use, copy, modify, and/or distribute this software for any purpose with - * or without fee is hereby granted, provided that the above copyright notice and this - * permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD - * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "tests.hpp" - -#include "widgets/ExampleColorWidget.hpp" -#include "widgets/ExampleImagesWidget.hpp" -#include "widgets/ExampleRectanglesWidget.hpp" -#include "widgets/ExampleShapesWidget.hpp" -#ifdef DGL_OPENGL -#include "widgets/ExampleTextWidget.hpp" -#endif - -#include "demo_res/DemoArtwork.cpp" -#include "images_res/CatPics.cpp" - -#ifdef DGL_CAIRO -#include "../dgl/Cairo.hpp" -typedef DGL_NAMESPACE::CairoImage DemoImage; -#endif -#ifdef DGL_OPENGL -#include "../dgl/OpenGL.hpp" -typedef DGL_NAMESPACE::OpenGLImage DemoImage; -#endif -#ifdef DGL_VULKAN -#include "../dgl/Vulkan.hpp" -typedef DGL_NAMESPACE::VulkanImage DemoImage; -#endif - -START_NAMESPACE_DGL - -// Partial specialization is not allowed in C++, so we need to define these here -template<> inline -ExampleImagesWidget::ExampleImagesWidget(Widget* const parentWidget) -: SubWidget(parentWidget) { init(parentWidget->getApp()); } - -template<> inline -ExampleImagesWidget::ExampleImagesWidget(Window& windowToMapTo) -: TopLevelWidget(windowToMapTo) { init(windowToMapTo.getApp()); } - -template<> -ExampleImagesWidget::ExampleImagesWidget(Application& app) -: StandaloneWindow(app) { init(app); done(); } - -typedef ExampleImagesWidget ExampleImagesSubWidget; -typedef ExampleImagesWidget ExampleImagesTopLevelWidget; -typedef ExampleImagesWidget ExampleImagesStandaloneWindow; - -// -------------------------------------------------------------------------------------------------------------------- -// Left side tab-like widget - -class LeftSideWidget : public SubWidget -{ -public: -#ifdef DGL_OPENGL - static const int kPageCount = 5; -#else - static const int kPageCount = 4; -#endif - - class Callback - { - public: - virtual ~Callback() {} - virtual void curPageChanged(int curPage) = 0; - }; - - LeftSideWidget(Widget* parent, Callback* const cb) - : SubWidget(parent), - callback(cb), - curPage(0), - curHover(-1) - { - - using namespace DemoArtwork; - img1.loadFromMemory(ico1Data, ico1Width, ico1Height, kImageFormatBGR); - img2.loadFromMemory(ico2Data, ico2Width, ico2Height, kImageFormatBGR); - img3.loadFromMemory(ico3Data, ico3Width, ico2Height, kImageFormatBGR); - img4.loadFromMemory(ico4Data, ico4Width, ico4Height, kImageFormatBGR); - -#ifdef DGL_OPENGL - img5.loadFromMemory(ico5Data, ico5Width, ico5Height, kImageFormatBGR); - - // for text - nvg.loadSharedResources(); -#endif - } - -protected: - void onDisplay() override - { - const GraphicsContext& context(getGraphicsContext()); - const double scaleFactor = getWindow().getScaleFactor(); - const int iconSize = bgIcon.getWidth(); - - Color(0.027f, 0.027f, 0.027f).setFor(context); - Rectangle(0, 0, getSize()).draw(context); - - bgIcon.setY(curPage * iconSize + curPage * 3 * scaleFactor); - - Color(0.129f, 0.129f, 0.129f).setFor(context); - bgIcon.draw(context); - - Color(0.184f, 0.184f, 0.184f).setFor(context); - bgIcon.drawOutline(context); - - if (curHover != curPage && curHover != -1) - { - Rectangle rHover(1 * scaleFactor, curHover * iconSize + curHover * 3 * scaleFactor, - iconSize - 2 * scaleFactor, iconSize - 2 * scaleFactor); - - Color(0.071f, 0.071f, 0.071f).setFor(context); - rHover.draw(context); - - Color(0.102f, 0.102f, 0.102f).setFor(context); - rHover.drawOutline(context); - } - - Color(0.184f, 0.184f, 0.184f).setFor(context); - lineSep.draw(context); - - // reset color - Color(1.0f, 1.0f, 1.0f, 1.0f).setFor(context, true); - - const int pad = iconSize/2 - DemoArtwork::ico1Width/2; - - img1.drawAt(context, pad, pad); - img2.drawAt(context, pad, pad + 3 + iconSize); - img3.drawAt(context, pad, pad + 6 + iconSize*2); - img4.drawAt(context, pad, pad + 9 + iconSize*3); - -#ifdef DGL_OPENGL - img5.drawAt(context, pad, pad + 12 + iconSize*4); - - // draw some text - nvg.beginFrame(this); - - nvg.fontSize(23.0f * scaleFactor); - nvg.textAlign(NanoVG::ALIGN_LEFT|NanoVG::ALIGN_TOP); - //nvg.textLineHeight(20.0f); - - nvg.fillColor(220,220,220,220); - nvg.textBox(10 * scaleFactor, 420 * scaleFactor, iconSize, "Haha,", nullptr); - nvg.textBox(15 * scaleFactor, 440 * scaleFactor, iconSize, "Look!", nullptr); - - nvg.endFrame(); -#endif - } - - bool onMouse(const MouseEvent& ev) override - { - if (ev.button != 1 || ! ev.press) - return false; - if (! contains(ev.pos)) - return false; - - const int iconSize = bgIcon.getWidth(); - - for (int i=0; icurPageChanged(i); - repaint(); - break; - } - } - - return true; - } - - bool onMotion(const MotionEvent& ev) override - { - if (contains(ev.pos)) - { - const int iconSize = bgIcon.getWidth(); - - for (int i=0; i bgIcon; - Line lineSep; - DemoImage img1, img2, img3, img4, img5; - -#ifdef DGL_OPENGL - // for text - NanoVG nvg; -#endif -}; - -// -------------------------------------------------------------------------------------------------------------------- -// Resize handle widget - -class ResizeHandle : public TopLevelWidget -{ - Rectangle area; - Line l1, l2, l3; - uint baseSize; - - // event handling state - bool resizing; - Point lastResizePoint; - Size resizingSize; - -public: - explicit ResizeHandle(TopLevelWidget* const tlw) - : TopLevelWidget(tlw->getWindow()), - baseSize(16), - resizing(false) - { - resetArea(); - } - - explicit ResizeHandle(Window& window) - : TopLevelWidget(window), - baseSize(16), - resizing(false) - { - resetArea(); - } - - void setBaseSize(const uint size) - { - baseSize = std::max(16u, size); - resetArea(); - } - -protected: - void onDisplay() override - { - const GraphicsContext& context(getGraphicsContext()); - const double offset = getScaleFactor(); - - // draw white lines, 1px wide - Color(1.0f, 1.0f, 1.0f).setFor(context); - l1.draw(context, 1); - l2.draw(context, 1); - l3.draw(context, 1); - - // draw black lines, offset by 1px and 2px wide - Color(0.0f, 0.0f, 0.0f).setFor(context); - Line l1b(l1), l2b(l2), l3b(l3); - l1b.moveBy(offset, offset); - l2b.moveBy(offset, offset); - l3b.moveBy(offset, offset); - l1b.draw(context, 1); - l2b.draw(context, 1); - l3b.draw(context, 1); - } - - bool onMouse(const MouseEvent& ev) override - { - if (ev.button != 1) - return false; - - if (ev.press && area.contains(ev.pos)) - { - resizing = true; - resizingSize = Size(getWidth(), getHeight()); - lastResizePoint = ev.pos; - return true; - } - - if (resizing && ! ev.press) - { - resizing = false; - return true; - } - - return false; - } - - bool onMotion(const MotionEvent& ev) override - { - if (! resizing) - return false; - - const Size offset(ev.pos.getX() - lastResizePoint.getX(), - ev.pos.getY() - lastResizePoint.getY()); - - resizingSize += offset; - lastResizePoint = ev.pos; - - // TODO min width, min height - const uint minWidth = 16; - const uint minHeight = 16; - - if (resizingSize.getWidth() < minWidth) - resizingSize.setWidth(minWidth); - if (resizingSize.getHeight() < minHeight) - resizingSize.setHeight(minHeight); - - setSize(resizingSize.getWidth(), resizingSize.getHeight()); - return true; - } - - void onResize(const ResizeEvent& ev) override - { - TopLevelWidget::onResize(ev); - resetArea(); - } - -private: - void resetArea() - { - const double scaleFactor = getScaleFactor(); - const uint margin = 0.0 * scaleFactor; - const uint size = baseSize * scaleFactor; - - area = Rectangle(getWidth() - size - margin, - getHeight() - size - margin, - size, size); - - recreateLines(area.getX(), area.getY(), size); - } - - void recreateLines(const uint x, const uint y, const uint size) - { - uint linesize = size; - uint offset = 0; - - // 1st line, full diagonal size - l1.setStartPos(x + size, y); - l1.setEndPos(x, y + size); - - // 2nd line, bit more to the right and down, cropped - offset += size / 3; - linesize -= size / 3; - l2.setStartPos(x + linesize + offset, y + offset); - l2.setEndPos(x + offset, y + linesize + offset); - - // 3rd line, even more right and down - offset += size / 3; - linesize -= size / 3; - l3.setStartPos(x + linesize + offset, y + offset); - l3.setEndPos(x + offset, y + linesize + offset); - } -}; - -// -------------------------------------------------------------------------------------------------------------------- -// Main Demo Window, having a left-side tab-like widget and main area for current widget - -class DemoWindow : public StandaloneWindow, - public LeftSideWidget::Callback -{ - static const int kSidebarWidth = 81; - -public: -#ifdef DGL_CAIRO - static constexpr const char* const kExampleWidgetName = "Demo - Cairo"; -#endif -#ifdef DGL_OPENGL - static constexpr const char* const kExampleWidgetName = "Demo - OpenGL"; -#endif -#ifdef DGL_VULKAN - static constexpr const char* const kExampleWidgetName = "Demo - Vulkan"; -#endif - - DemoWindow(Application& app) - : StandaloneWindow(app), - curWidget(nullptr) - { - const ScopedGraphicsContext sgc(*this); - const double scaleFactor = getScaleFactor(); - - wColor = new ExampleColorSubWidget(this); - wColor->hide(); - wColor->setAbsoluteX(kSidebarWidth * scaleFactor); - - wImages = new ExampleImagesSubWidget(this); - wImages->hide(); - wImages->setAbsoluteX(kSidebarWidth * scaleFactor); - - wRects = new ExampleRectanglesSubWidget(this); - wRects->hide(); - wRects->setAbsoluteX(kSidebarWidth * scaleFactor); - - wShapes = new ExampleShapesSubWidget(this); - wShapes->hide(); - wShapes->setAbsoluteX(kSidebarWidth * scaleFactor); - -#ifdef DGL_OPENGL - wText = new ExampleTextSubWidget(this), - wText->hide(); - wText->setAbsoluteX(kSidebarWidth * scaleFactor); -#endif - wLeft = new LeftSideWidget(this, this), - wLeft->setAbsolutePos(2 * scaleFactor, 2 * scaleFactor); - - resizer = new ResizeHandle(this); - - curPageChanged(0); - done(); - } - -protected: - void curPageChanged(int curPage) override - { - if (curWidget != nullptr) - curWidget->hide(); - - switch (curPage) - { - case 0: - curWidget = wColor; - break; - case 1: - curWidget = wImages; - break; - case 2: - curWidget = wRects; - break; - case 3: - curWidget = wShapes; - break; -#ifdef DGL_OPENGL - case 4: - curWidget = wText; - break; -#endif - default: - curWidget = nullptr; - break; - } - - if (curWidget != nullptr) - curWidget->show(); - } - - void onDisplay() override - { - } - - void onReshape(uint width, uint height) override - { - StandaloneWindow::onReshape(width, height); - - const double scaleFactor = getScaleFactor(); - - if (width < kSidebarWidth * scaleFactor) - return; - - const Size size(width - kSidebarWidth * scaleFactor, height); - wColor->setSize(size); - wImages->setSize(size); - wRects->setSize(size); - wShapes->setSize(size); -#ifdef DGL_OPENGL - wText->setSize(size); -#endif - wLeft->setSize((kSidebarWidth - 4) * scaleFactor, (height - 4) * scaleFactor); - } - -private: - ScopedPointer wColor; - ScopedPointer wImages; - ScopedPointer wRects; - ScopedPointer wShapes; -#ifdef DGL_OPENGL - ScopedPointer wText; -#endif - ScopedPointer wLeft; - ScopedPointer resizer; - - Widget* curWidget; -}; - -// -------------------------------------------------------------------------------------------------------------------- -// Special handy function that runs a StandaloneWindow inside the function scope - -template -void createAndShowExampleWidgetStandaloneWindow(Application& app) -{ - ExampleWidgetStandaloneWindow swin(app); - const double scaleFactor = swin.getScaleFactor(); - swin.setResizable(true); - swin.setSize(600 * scaleFactor, 500 * scaleFactor); - swin.setTitle(ExampleWidgetStandaloneWindow::kExampleWidgetName); - swin.show(); - app.exec(); -} - -// -------------------------------------------------------------------------------------------------------------------- - -END_NAMESPACE_DGL - -int main(int argc, char* argv[]) -{ - USE_NAMESPACE_DGL; - using DGL_NAMESPACE::Window; - - Application app; - - if (argc > 1) - { - /**/ if (std::strcmp(argv[1], "color") == 0) - createAndShowExampleWidgetStandaloneWindow(app); - else if (std::strcmp(argv[1], "images") == 0) - createAndShowExampleWidgetStandaloneWindow(app); - else if (std::strcmp(argv[1], "rectangles") == 0) - createAndShowExampleWidgetStandaloneWindow(app); - else if (std::strcmp(argv[1], "shapes") == 0) - createAndShowExampleWidgetStandaloneWindow(app); -#ifdef DGL_OPENGL - else if (std::strcmp(argv[1], "text") == 0) - createAndShowExampleWidgetStandaloneWindow(app); -#endif - else - d_stderr2("Invalid demo mode, must be one of: color, images, rectangles or shapes"); - } - else - { - createAndShowExampleWidgetStandaloneWindow(app); - } - - return 0; -} - -// -------------------------------------------------------------------------------------------------------------------- diff --git a/dpf/tests/FileBrowserDialog.cpp b/dpf/tests/FileBrowserDialog.cpp deleted file mode 100644 index bc4ece4..0000000 --- a/dpf/tests/FileBrowserDialog.cpp +++ /dev/null @@ -1,194 +0,0 @@ -/* - * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho - * - * Permission to use, copy, modify, and/or distribute this software for any purpose with - * or without fee is hereby granted, provided that the above copyright notice and this - * permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD - * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "tests.hpp" - -#include "dgl/NanoVG.hpp" - -START_NAMESPACE_DGL - -// -------------------------------------------------------------------------------------------------------------------- - -class NanoFilePicker : public NanoStandaloneWindow -{ - Rectangle buttonBounds; - bool buttonClick = false; - bool buttonHover = false; - String selectedFile; - -public: - NanoFilePicker(Application& app) - : NanoStandaloneWindow(app), - selectedFile("No file selected yet") - { -#ifndef DGL_NO_SHARED_RESOURCES - loadSharedResources(); -#endif - setResizable(true); - setTitle("FileBrowserDialog"); - - const double scaleFactor = getScaleFactor(); - setGeometryConstraints(500 * scaleFactor, 200 * scaleFactor, true); - setSize(500 * scaleFactor, 200 * scaleFactor); - - done(); - } - -protected: - void onNanoDisplay() override - { - const double scaleFactor = getScaleFactor(); - - // Selected file - beginPath(); - fontSize(14 * scaleFactor); - textAlign(ALIGN_LEFT | ALIGN_MIDDLE); - fillColor(255, 255, 255, 255); - text(20 * scaleFactor, getHeight()/2, selectedFile, NULL); - closePath(); - - // Button background - beginPath(); - fillColor(Color(32, buttonClick ? 128 : 32, buttonHover ? 128 : 32)); - strokeColor(Color()); - rect(buttonBounds.getX(), buttonBounds.getY(), buttonBounds.getWidth(), buttonBounds.getHeight()); - fill(); - stroke(); - closePath(); - - // Button label - beginPath(); - fontSize(14 * scaleFactor); - Rectangle buttonTextBounds; - textBounds(0, 0, "Press me", NULL, buttonTextBounds); - textAlign(ALIGN_CENTER | ALIGN_MIDDLE); - fillColor(255, 255, 255, 255); - text(buttonBounds.getX() + buttonBounds.getWidth()/2, - buttonBounds.getY() + buttonBounds.getHeight()/2, - "Press me", NULL); - closePath(); - } - - bool onMotion(const MotionEvent& ev) override - { - const bool newButtonHover = buttonBounds.contains(ev.pos); - - if (newButtonHover != buttonHover) - { - buttonHover = newButtonHover; - repaint(); - return true; - } - - return newButtonHover; - } - - bool onMouse(const MouseEvent& ev) override - { - if (ev.button != 1) - return false; - - if (! buttonBounds.contains(ev.pos)) - { - if (buttonClick) - { - buttonClick = false; - repaint(); - return true; - } - return false; - } - - const bool newButtonClick = ev.press; - - if (newButtonClick != buttonClick) - { - buttonClick = newButtonClick; - repaint(); - - if (newButtonClick) - { - selectedFile = "(in progress)"; - repaint(); - - FileBrowserOptions opts; - // opts.saving = true; - opts.title = "Look at me"; - if (! openFileBrowser(opts)) - { - selectedFile = "(Failed to start file browser)"; - repaint(); - } - } - - return true; - } - - return newButtonClick; - } - - void onResize(const ResizeEvent& ev) override - { - const uint width = ev.size.getWidth(); - const uint height = ev.size.getHeight(); - const double scaleFactor = getScaleFactor(); - - buttonBounds = Rectangle(width - 120 * scaleFactor, - height/2 - 20 * scaleFactor, - 100 * scaleFactor, - 40 * scaleFactor); - } - - void onFocus(const bool focus, CrossingMode) override - { - if (focus) - return; - - buttonClick = false; - buttonHover = false; - repaint(); - } - - void onFileSelected(const char* filename) override - { - if (filename == nullptr) - filename = "Cancelled"; - - if (selectedFile == filename) - return; - - selectedFile = filename; - repaint(); - } -}; - -// -------------------------------------------------------------------------------------------------------------------- - -END_NAMESPACE_DGL - -int main() -{ - USE_NAMESPACE_DGL; - - Application app(true); - NanoFilePicker win(app); - win.show(); - app.exec(); - - return 0; -} - -// -------------------------------------------------------------------------------------------------------------------- diff --git a/dpf/tests/Makefile b/dpf/tests/Makefile deleted file mode 100644 index 9b652ea..0000000 --- a/dpf/tests/Makefile +++ /dev/null @@ -1,159 +0,0 @@ -#!/usr/bin/make -f -# Makefile for DGL # -# ---------------- # -# Created by falkTX -# - -include ../Makefile.base.mk - -# --------------------------------------------------------------------------------------------------------------------- - -BUILD_C_FLAGS += $(DGL_FLAGS) -I.. -BUILD_CXX_FLAGS += $(DGL_FLAGS) -I.. -I../dgl/src/pugl-upstream/include -DDONT_SET_USING_DGL_NAMESPACE -LINK_FLAGS += -lpthread - -# TODO fix within pugl -BUILD_CXX_FLAGS += -Wno-extra -Wno-missing-field-initializers - -ifeq ($(MACOS),true) -BUILD_CXX_FLAGS += -ObjC++ -DGL_SILENCE_DEPRECATION -Wno-deprecated-declarations -endif - -# --------------------------------------------------------------------------------------------------------------------- - -MANUAL_TESTS = -UNIT_TESTS = Application Color Point - -ifeq ($(HAVE_CAIRO),true) -MANUAL_TESTS += Demo.cairo -UNIT_TESTS += Window.cairo -endif -ifeq ($(HAVE_OPENGL),true) -MANUAL_TESTS += Demo.opengl -MANUAL_TESTS += FileBrowserDialog -MANUAL_TESTS += NanoImage -MANUAL_TESTS += NanoSubWidgets -UNIT_TESTS += Window.opengl -endif -ifeq ($(HAVE_STUB),true) -UNIT_TESTS += Window.stub -endif -ifeq ($(HAVE_VULKAN),true) -UNIT_TESTS += Window.vulkan -endif - -MANUAL_TARGETS = $(MANUAL_TESTS:%=../build/tests/%$(APP_EXT)) -UNIT_TARGET = $(UNIT_TESTS:%=../build/tests/%$(APP_EXT)) - -ALL_OBJS = $(MANUAL_TESTS:%=../build/tests/%.cpp.o) -ALL_OBJS += $(UNIT_TESTS:%=../build/tests/%.cpp.o) - -# --------------------------------------------------------------------------------------------------------------------- - -all: $(MANUAL_TARGETS) $(UNIT_TARGET) - -# --------------------------------------------------------------------------------------------------------------------- - -define RUN_TEST - - ${1} -endef - -# valgrind --leak-check=full $@ - -run: $(UNIT_TARGET) - $(foreach TEST,$^,$(call RUN_TEST,$(TEST))) - -# --------------------------------------------------------------------------------------------------------------------- - -clean: - rm -rf ../build/tests - -# --------------------------------------------------------------------------------------------------------------------- -# building steps - -../build/tests/%.c.o: %.c - -@mkdir -p ../build/tests - @echo "Compiling $<" - $(SILENT)$(CC) $< $(BUILD_C_FLAGS) -c -o $@ - -../build/tests/%.cpp.o: %.cpp - -@mkdir -p ../build/tests - @echo "Compiling $<" - $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ - -../build/tests/%.cpp.cairo.o: %.cpp - -@mkdir -p ../build/tests - @echo "Compiling $< (Cairo)" - $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(CAIRO_FLAGS) -DDGL_CAIRO -c -o $@ - -../build/tests/%.cpp.opengl.o: %.cpp - -@mkdir -p ../build/tests - @echo "Compiling $< (OpenGL)" - $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(OPENGL_FLAGS) -DDGL_OPENGL -c -o $@ - -../build/tests/%.cpp.stub.o: %.cpp - -@mkdir -p ../build/tests - @echo "Compiling $< (Stub)" - $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ - -../build/tests/%.cpp.vulkan.o: %.cpp - -@mkdir -p ../build/tests - @echo "Compiling $< (Vulkan)" - $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(OPENGL_FLAGS) -DDGL_VULKAN -c -o $@ - -# --------------------------------------------------------------------------------------------------------------------- -# linking steps - -../build/tests/%$(APP_EXT): ../build/tests/%.cpp.o - @echo "Linking $*" - $(SILENT)$(CXX) $< $(LINK_FLAGS) $(DGL_SYSTEM_LIBS) -o $@ - -../build/tests/%.cairo$(APP_EXT): ../build/tests/%.cpp.cairo.o - @echo "Linking $*" - $(SILENT)$(CXX) $< $(LINK_FLAGS) $(DGL_SYSTEM_LIBS) $(CAIRO_LIBS) -o $@ - -../build/tests/%.opengl$(APP_EXT): ../build/tests/%.cpp.opengl.o - @echo "Linking $*" - $(SILENT)$(CXX) $< $(LINK_FLAGS) $(DGL_SYSTEM_LIBS) $(OPENGL_LIBS) -o $@ - -../build/tests/%.stub$(APP_EXT): ../build/tests/%.cpp.stub.o - @echo "Linking $*" - $(SILENT)$(CXX) $< $(LINK_FLAGS) $(DGL_SYSTEM_LIBS) -o $@ - -../build/tests/%.vulkan$(APP_EXT): ../build/tests/%.cpp.vulkan.o - @echo "Linking $*" - $(SILENT)$(CXX) $< $(LINK_FLAGS) $(DGL_SYSTEM_LIBS) $(VULKAN_LIBS) -o $@ - -# --------------------------------------------------------------------------------------------------------------------- -# linking steps (special, links against DGL static lib) - -../build/tests/Demo.cairo$(APP_EXT): ../build/tests/Demo.cpp.cairo.o ../build/libdgl-cairo.a - @echo "Linking Demo (Cairo)" - $(SILENT)$(CXX) $^ $(LINK_FLAGS) $(DGL_SYSTEM_LIBS) $(CAIRO_LIBS) -o $@ - -../build/tests/Demo.opengl$(APP_EXT): ../build/tests/Demo.cpp.opengl.o ../build/libdgl-opengl.a - @echo "Linking Demo (OpenGL)" - $(SILENT)$(CXX) $^ $(LINK_FLAGS) $(DGL_SYSTEM_LIBS) $(OPENGL_LIBS) -o $@ - -../build/tests/Demo.vulkan$(APP_EXT): ../build/tests/Demo.cpp.vulkan.o ../build/libdgl-vulkan.a - @echo "Linking Demo (OpenGL)" - $(SILENT)$(CXX) $^ $(LINK_FLAGS) $(DGL_SYSTEM_LIBS) $(VULKAN_LIBS) -o $@ - -../build/tests/FileBrowserDialog$(APP_EXT): ../build/tests/FileBrowserDialog.cpp.o ../build/libdgl-opengl.a - @echo "Linking FileBrowserDialog (OpenGL)" - $(SILENT)$(CXX) $^ $(LINK_FLAGS) $(DGL_SYSTEM_LIBS) $(OPENGL_LIBS) -o $@ - -../build/tests/NanoImage$(APP_EXT): ../build/tests/NanoImage.cpp.o ../build/libdgl-opengl.a - @echo "Linking NanoImage (OpenGL)" - $(SILENT)$(CXX) $^ $(LINK_FLAGS) $(DGL_SYSTEM_LIBS) $(OPENGL_LIBS) -o $@ - -../build/tests/NanoSubWidgets$(APP_EXT): ../build/tests/NanoSubWidgets.cpp.o ../build/libdgl-opengl.a - @echo "Linking NanoSubWidgets (OpenGL)" - $(SILENT)$(CXX) $^ $(LINK_FLAGS) $(DGL_SYSTEM_LIBS) $(OPENGL_LIBS) -o $@ - -# --------------------------------------------------------------------------------------------------------------------- - --include $(ALL_OBJS:%.o=%.d) - -# --------------------------------------------------------------------------------------------------------------------- diff --git a/dpf/tests/NanoImage.cpp b/dpf/tests/NanoImage.cpp deleted file mode 100644 index 9b719d1..0000000 --- a/dpf/tests/NanoImage.cpp +++ /dev/null @@ -1,229 +0,0 @@ -/* - * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho - * - * Permission to use, copy, modify, and/or distribute this software for any purpose with - * or without fee is hereby granted, provided that the above copyright notice and this - * permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD - * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "tests.hpp" - -#include "dgl/NanoVG.hpp" - -START_NAMESPACE_DGL - -// -------------------------------------------------------------------------------------------------------------------- -// Images - -#include "images_res/CatPics.cpp" - -// -------------------------------------------------------------------------------------------------------------------- - -class NanoImageExample : public NanoStandaloneWindow, - public IdleCallback -{ - static const int kImg1y = 0; - static const int kImg2y = 500/2-CatPics::cat2Height/2; - static const int kImg3x = 400/3-CatPics::cat3Width/3; - - static const int kImg1max = 500-CatPics::cat1Width; - static const int kImg2max = 500-CatPics::cat2Width; - static const int kImg3max = 400-CatPics::cat3Height; - - static const int kImgFlags = IMAGE_GENERATE_MIPMAPS | IMAGE_REPEAT_X; - - int imgTop1st, imgTop2nd, imgTop3rd; - int img1x, img2x, img3y; - bool img1rev, img2rev, img3rev; - NanoImage img1, img2, img3; - -public: - NanoImageExample(Application& app) - : NanoStandaloneWindow(app), - imgTop1st(1), - imgTop2nd(2), - imgTop3rd(3), - img1x(0), - img2x(kImg2max), - img3y(kImg3max), - img1rev(false), - img2rev(true), - img3rev(true), - img1(createImageFromRawMemory(CatPics::cat1Width, CatPics::cat1Height, (uchar*)CatPics::cat1Data, kImgFlags, kImageFormatBGR)), - img2(createImageFromRawMemory(CatPics::cat2Width, CatPics::cat2Height, (uchar*)CatPics::cat2Data, kImgFlags, kImageFormatBGR)), - img3(createImageFromRawMemory(CatPics::cat3Width, CatPics::cat3Height, (uchar*)CatPics::cat3Data, kImgFlags, kImageFormatBGR)) - { - DISTRHO_SAFE_ASSERT(img1.isValid()); - DISTRHO_SAFE_ASSERT(img2.isValid()); - DISTRHO_SAFE_ASSERT(img3.isValid()); - - DISTRHO_SAFE_ASSERT_UINT2(img1.getSize().getWidth() == CatPics::cat1Width, - img1.getSize().getWidth(), CatPics::cat1Width); - - DISTRHO_SAFE_ASSERT_UINT2(img1.getSize().getHeight() == CatPics::cat1Height, - img1.getSize().getHeight(), CatPics::cat1Height); - - DISTRHO_SAFE_ASSERT_UINT2(img2.getSize().getWidth() == CatPics::cat2Width, - img2.getSize().getWidth(), CatPics::cat2Width); - - DISTRHO_SAFE_ASSERT_UINT2(img2.getSize().getHeight() == CatPics::cat2Height, - img2.getSize().getHeight(), CatPics::cat2Height); - - DISTRHO_SAFE_ASSERT_UINT2(img3.getSize().getWidth() == CatPics::cat3Width, - img3.getSize().getWidth(), CatPics::cat3Width); - - DISTRHO_SAFE_ASSERT_UINT2(img3.getSize().getHeight() == CatPics::cat3Height, - img3.getSize().getHeight(), CatPics::cat3Height); - - setResizable(true); - setSize(500, 500); - setGeometryConstraints(500, 500, false, true); - setTitle("NanoImage"); - done(); - - addIdleCallback(this); - } - -protected: - void onNanoDisplay() override - { - // bottom image - beginPath(); - fillPaint(setupImagePaint(imgTop3rd)); - fill(); - - // middle image - beginPath(); - fillPaint(setupImagePaint(imgTop2nd)); - fill(); - - // top image - beginPath(); - fillPaint(setupImagePaint(imgTop1st)); - fill(); - } - - void idleCallback() noexcept override - { - if (img1rev) - { - img1x -= 2; - if (img1x <= -50) - { - img1rev = false; - setNewTopImg(1); - } - } - else - { - img1x += 2; - if (img1x >= kImg1max+50) - { - img1rev = true; - setNewTopImg(1); - } - } - - if (img2rev) - { - img2x -= 1; - if (img2x <= -50) - { - img2rev = false; - setNewTopImg(2); - } - } - else - { - img2x += 4; - if (img2x >= kImg2max+50) - { - img2rev = true; - setNewTopImg(2); - } - } - - if (img3rev) - { - img3y -= 3; - if (img3y <= -50) - { - img3rev = false; - setNewTopImg(3); - } - } - else - { - img3y += 3; - if (img3y >= kImg3max+50) - { - img3rev = true; - setNewTopImg(3); - } - } - - repaint(); - } - -private: - Paint setupImagePaint(const int imgId) noexcept - { - switch (imgId) - { - case 1: - rect(img1x, kImg1y, CatPics::cat1Width, CatPics::cat1Height); - return imagePattern(img1x, kImg1y, CatPics::cat1Width, CatPics::cat1Height, 0, img1, 1.0f); - case 2: - rect(img2x, kImg2y, CatPics::cat2Width, CatPics::cat2Height); - return imagePattern(img2x, kImg2y, CatPics::cat2Width, CatPics::cat2Height, 0, img2, 1.0f); - case 3: - rect(kImg3x, img3y, CatPics::cat3Width, CatPics::cat3Height); - return imagePattern(kImg3x, img3y, CatPics::cat3Width, CatPics::cat3Height, 0, img3, 1.0f); - }; - - return Paint(); - } - - void setNewTopImg(const int imgId) noexcept - { - if (imgTop1st == imgId) - return; - - if (imgTop2nd == imgId) - { - imgTop2nd = imgTop1st; - imgTop1st = imgId; - return; - } - - imgTop3rd = imgTop2nd; - imgTop2nd = imgTop1st; - imgTop1st = imgId; - } -}; - -// -------------------------------------------------------------------------------------------------------------------- - -END_NAMESPACE_DGL - -int main() -{ - USE_NAMESPACE_DGL; - - Application app(true); - NanoImageExample win(app); - win.show(); - app.exec(); - - return 0; -} - -// -------------------------------------------------------------------------------------------------------------------- diff --git a/dpf/tests/NanoSubWidgets.cpp b/dpf/tests/NanoSubWidgets.cpp deleted file mode 100644 index b413986..0000000 --- a/dpf/tests/NanoSubWidgets.cpp +++ /dev/null @@ -1,167 +0,0 @@ -/* - * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho - * - * Permission to use, copy, modify, and/or distribute this software for any purpose with - * or without fee is hereby granted, provided that the above copyright notice and this - * permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD - * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "tests.hpp" - -#include "../dgl/NanoVG.hpp" - -START_NAMESPACE_DGL - -// -------------------------------------------------------------------------------------------------------------------- - -class NanoRectangle : public NanoSubWidget -{ -public: - explicit NanoRectangle(Widget* const parent) - : NanoSubWidget(parent), - color() {} - - void setColor(const Color c) noexcept - { - color = c; - } - -protected: - void onNanoDisplay() override - { - beginPath(); - - fillColor(color); - rect(0, 0, getWidth(), getHeight()); - fill(); - - closePath(); - } - -private: - Color color; -}; - -// -------------------------------------------------------------------------------------------------------------------- - -class NanoRectanglesContainer : public NanoTopLevelWidget, - public IdleCallback -{ -public: - explicit NanoRectanglesContainer(Window& parent) - : NanoTopLevelWidget(parent), - rect1(this), - rect2(this), - rect3(this), - rectToHide(1) - { - rect1.setAbsolutePos(100, 100); - rect1.setSize(25, 25); - rect1.setColor(Color(255, 0, 0)); - - rect2.setAbsolutePos(200, 200); - rect2.setSize(25, 25); - rect2.setColor(Color(0, 255, 0)); - - rect3.setAbsolutePos(300, 300); - rect3.setSize(25, 25); - rect3.setColor(Color(0, 0, 255)); - - idleCallback(); - addIdleCallback(this, 500); - } - -protected: - void onNanoDisplay() override - { - beginPath(); - - fillColor(Color(0.5f, 0.5f, 0.5f)); - rect(0, 0, getWidth(), getHeight()); - fill(); - - closePath(); - } - - void idleCallback() override - { - switch (rectToHide) - { - case 1: - rect1.hide(); - rect2.show(); - rect3.show(); - rectToHide = 2; - break; - case 2: - rect1.show(); - rect2.hide(); - rect3.show(); - rectToHide = 3; - break; - case 3: - rect1.show(); - rect2.show(); - rect3.hide(); - rectToHide = 1; - break; - } - } - -private: - NanoRectangle rect1, rect2, rect3; - int rectToHide; -}; - -// -------------------------------------------------------------------------------------------------------------------- - -class NanoExampleWindow : public Window -{ -public: - explicit NanoExampleWindow(Application& app) - : Window(app) - { - { - const ScopedGraphicsContext sgc(*this); - container = new NanoRectanglesContainer(*this); - } - - const uint targetWidth = 400; - const uint targetHeight = 400; - const double scaleFactor = getScaleFactor(); - - setGeometryConstraints(targetWidth, targetHeight, true); - setResizable(true); - setSize(targetWidth * scaleFactor, targetHeight * scaleFactor); - setTitle("NanoVG SubWidgets test"); - } - -private: - ScopedPointer container; -}; - -// -------------------------------------------------------------------------------------------------------------------- - -END_NAMESPACE_DGL - -int main() -{ - USE_NAMESPACE_DGL; - - Application app; - NanoExampleWindow win(app); - win.show(); - app.exec(); - - return 0; -} - -// -------------------------------------------------------------------------------------------------------------------- diff --git a/dpf/tests/Point.cpp b/dpf/tests/Point.cpp deleted file mode 100644 index f51e555..0000000 --- a/dpf/tests/Point.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho - * - * Permission to use, copy, modify, and/or distribute this software for any purpose with - * or without fee is hereby granted, provided that the above copyright notice and this - * permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD - * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "tests.hpp" - -#define DPF_TEST_POINT_CPP -#include "dgl/src/Geometry.cpp" - -// -------------------------------------------------------------------------------------------------------------------- - -template -static int runTestsPerType() -{ - USE_NAMESPACE_DGL; - - // basic usage - { - Point p; - DISTRHO_ASSERT_EQUAL(p.getX(), 0, "point start X value is 0"); - DISTRHO_ASSERT_EQUAL(p.getY(), 0, "point start Y value is 0"); - DISTRHO_ASSERT_EQUAL(p.isZero(), true, "point start is zero"); - DISTRHO_ASSERT_EQUAL(p.isNotZero(), false, "point start is for sure zero"); - - p.setX(5); - DISTRHO_ASSERT_EQUAL(p.getX(), 5, "point X value changed to 5"); - DISTRHO_ASSERT_EQUAL(p.getY(), 0, "point start Y value remains 0"); - DISTRHO_ASSERT_EQUAL(p.isZero(), false, "point after custom X is not zero"); - DISTRHO_ASSERT_EQUAL(p.isNotZero(), true, "point after custom X is for sure not zero"); - - p.setY(7); - DISTRHO_ASSERT_EQUAL(p.getX(), 5, "point X value remains 5"); - DISTRHO_ASSERT_EQUAL(p.getY(), 7, "point Y value changed to 7"); - DISTRHO_ASSERT_EQUAL(p.isZero(), false, "point after custom X and Y is not zero"); - DISTRHO_ASSERT_EQUAL(p.isNotZero(), true, "point after custom X and Y is for sure not zero"); - - // TODO everything else - } - - return 0; -} - -int main() -{ - if (const int ret = runTestsPerType()) - return ret; - - if (const int ret = runTestsPerType()) - return ret; - - if (const int ret = runTestsPerType()) - return ret; - - if (const int ret = runTestsPerType()) - return ret; - - if (const int ret = runTestsPerType()) - return ret; - - if (const int ret = runTestsPerType()) - return ret; - - if (const int ret = runTestsPerType()) - return ret; - - if (const int ret = runTestsPerType()) - return ret; - - if (const int ret = runTestsPerType()) - return ret; - - if (const int ret = runTestsPerType()) - return ret; - - return 0; -} - -// -------------------------------------------------------------------------------------------------------------------- diff --git a/dpf/tests/README.txt b/dpf/tests/README.txt deleted file mode 100644 index 953e939..0000000 --- a/dpf/tests/README.txt +++ /dev/null @@ -1,42 +0,0 @@ -This directory contains several tests for DPF related things, from graphics to plugin stuff to utilities. -Each *.cpp file is meant to be its own test. - -In order to test DPF components individually, some of these tests do not link against DGL but import/include its files. -All test files must be self-contained, in order to prevent surprises in regards global state and initialization stuff. - -The following tests are present: - - - Application - Verifies that creating an application instance and its event loop is working correctly. - This test should automatically close itself without errors after a few seconds - - - Circle - TODO - - - Color - Runs a few unit-tests on top of the Color class. Mostly complete but still WIP. - - - Demo - A full window with widgets to verify that contents are being drawn correctly, window can be resized and events work. - Can be used in both Cairo and OpenGL modes, the Vulkan variant does not work right now. - - - Line - TODO - - - NanoSubWidgets - Verifies that NanoVG subwidgets are being drawn properly, and that hide/show calls work as intended. - There should be a grey background with 3 squares on top, one of hiding every half second in a sequence. - - - Point - Runs a few unit-tests on top of the Point class. Mostly complete but still WIP. - - - Rectangle - TODO - - - Triangle - TODO - - - Window - Runs a few basic tests with Window showing, hiding and event loop. - Will try to create a window on screen. - Should automatically close after a few seconds. diff --git a/dpf/tests/Rectangle.cpp b/dpf/tests/Rectangle.cpp deleted file mode 100644 index e00d80b..0000000 --- a/dpf/tests/Rectangle.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho - * - * Permission to use, copy, modify, and/or distribute this software for any purpose with - * or without fee is hereby granted, provided that the above copyright notice and this - * permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD - * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "tests.hpp" - -// -------------------------------------------------------------------------------------------------------------------- - -int main() -{ - USE_NAMESPACE_DGL; - - // TODO - - return 0; -} - -// -------------------------------------------------------------------------------------------------------------------- diff --git a/dpf/tests/Triangle.cpp b/dpf/tests/Triangle.cpp deleted file mode 100644 index e00d80b..0000000 --- a/dpf/tests/Triangle.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho - * - * Permission to use, copy, modify, and/or distribute this software for any purpose with - * or without fee is hereby granted, provided that the above copyright notice and this - * permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD - * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "tests.hpp" - -// -------------------------------------------------------------------------------------------------------------------- - -int main() -{ - USE_NAMESPACE_DGL; - - // TODO - - return 0; -} - -// -------------------------------------------------------------------------------------------------------------------- diff --git a/dpf/tests/Window.cpp b/dpf/tests/Window.cpp deleted file mode 100644 index 81dd37c..0000000 --- a/dpf/tests/Window.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho - * - * Permission to use, copy, modify, and/or distribute this software for any purpose with - * or without fee is hereby granted, provided that the above copyright notice and this - * permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD - * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "tests.hpp" - -#define DPF_TEST_POINT_CPP -#define DPF_TEST_WINDOW_CPP -#include "dgl/src/pugl.cpp" -#include "dgl/src/Application.cpp" -#include "dgl/src/ApplicationPrivateData.cpp" -#include "dgl/src/Geometry.cpp" -#include "dgl/src/Window.cpp" -#include "dgl/src/WindowPrivateData.cpp" - -// -------------------------------------------------------------------------------------------------------------------- - -int main() -{ - USE_NAMESPACE_DGL; - - using DGL_NAMESPACE::Window; - - // creating and destroying simple window - { - Application app(true); - Window win(app); - } - - // creating and destroying simple window, with a delay - { - Application app(true); - ApplicationQuitter appQuitter(app); - Window win(app); - app.exec(); - } - - // showing and closing simple window, MUST be visible on screen - { - Application app(true); - ApplicationQuitter appQuitter(app); - Window win(app); - win.show(); - app.exec(); - } - - // TODO - - return 0; -} - -// -------------------------------------------------------------------------------------------------------------------- diff --git a/dpf/tests/demo_res/DemoArtwork.cpp b/dpf/tests/demo_res/DemoArtwork.cpp deleted file mode 100644 index 6875a66..0000000 --- a/dpf/tests/demo_res/DemoArtwork.cpp +++ /dev/null @@ -1,569 +0,0 @@ -/* (Auto-generated binary data file). */ - -#include "DemoArtwork.hpp" - -static const unsigned char temp_ico1_1[] = { - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 2, 2, 73, 15, 15, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, - 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 15, 15, 77, 2, 2, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 15, 15, 77, 172, 172, 121, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, - 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, - 186, 186, 125, 186, 186, 125, 186, 186, 125, 172, 172, 121, 15, 15, 77, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 16, 16, 77, 186, 186, 125, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 186, 186, 125, 16, 16, 77, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 16, 16, 77, 186, 186, 125, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 186, 186, 125, 16, 16, 77, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 16, 16, 77, 186, 186, 125, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 186, 186, 125, 16, 16, 77, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 16, 16, 77, 186, 186, 125, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 186, 186, 125, 16, 16, 77, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 16, 16, 77, 186, 186, 125, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 186, 186, 125, 16, 16, 77, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 16, 16, 77, 186, 186, 125, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 186, 186, 125, 16, 16, 77, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 16, 16, 77, 186, 186, 125, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 186, 186, 125, 16, 16, 77, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 16, 16, 77, 186, 186, 125, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 186, 186, 125, 16, 16, 77, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 16, 16, 77, 186, 186, 125, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 186, 186, 125, 16, 16, 77, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 16, 16, 77, 186, 186, 125, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 186, 186, 125, 16, 16, 77, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 16, 16, 77, 186, 186, 125, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 186, 186, 125, 16, 16, 77, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 16, 16, 77, 186, 186, 125, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 186, 186, 125, 16, 16, 77, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 16, 16, 77, 186, 186, 125, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 186, 186, 125, 16, 16, 77, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 16, 16, 77, 186, 186, 125, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 186, 186, 125, 16, 16, 77, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 16, 16, 77, 186, 186, 125, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 186, 186, 125, 16, 16, 77, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 16, 16, 77, 186, 186, 125, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 186, 186, 125, 16, 16, 77, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 16, 16, 77, 186, 186, 125, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 186, 186, 125, 16, 16, 77, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 16, 16, 77, 186, 186, 125, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 186, 186, 125, 16, 16, 77, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 16, 16, 77, 186, 186, 125, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 186, 186, 125, 16, 16, 77, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 16, 16, 77, 186, 186, 125, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 186, 186, 125, 16, 16, 77, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 16, 16, 77, 186, 186, 125, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 186, 186, 125, 16, 16, 77, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 16, 16, 77, 186, 186, 125, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 186, 186, 125, 16, 16, 77, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 16, 16, 77, 186, 186, 125, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 186, 186, 125, 16, 16, 77, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 16, 16, 77, 186, 186, 125, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 186, 186, 125, 16, 16, 77, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 16, 16, 77, 186, 186, 125, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 186, 186, 125, 16, 16, 77, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 16, 16, 77, 186, 186, 125, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 186, 186, 125, 16, 16, 77, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 16, 16, 77, 186, 186, 125, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 186, 186, 125, 16, 16, 77, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 16, 16, 77, 186, 186, 125, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 186, 186, 125, 16, 16, 77, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 16, 16, 77, 186, 186, 125, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 186, 186, 125, 16, 16, 77, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 16, 16, 77, 186, 186, 125, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, - 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 201, 201, 129, 186, 186, 125, 16, 16, 77, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 15, 15, 77, 172, 172, 121, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, - 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, 186, 186, 125, - 172, 172, 121, 15, 15, 77, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 2, 2, 73, 15, 15, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, - 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, - 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 16, 16, 77, 15, 15, 77, 2, 2, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, - 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73, 1, 1, 73,}; -const char* DemoArtwork::ico1Data = (const char*)temp_ico1_1; - -static const unsigned char temp_ico2_2[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 2, 46, 12, 43, 64, 17, 57, 67, 19, 60, 72, 23, 65, 78, 26, 71, 84, 28, 78, 90, 31, 83, - 93, 35, 87, 83, 32, 78, 76, 47, 77, 49, 18, 46, 40, 9, 36, 38, 9, 34, 37, 9, 34, 38, 10, 35, 40, 11, 37, 42, 12, 40, 43, 16, 42, 56, 42, 62, 91, 96, 111, 117, 132, 149, 108, 124, 146, 87, 99, 120, 74, 83, 106, 59, 66, 91, 40, 39, 47, 40, 30, 37, 57, 54, 69, - 110, 110, 127, 114, 98, 111, 20, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 2, 45, 12, 42, - 63, 16, 57, 66, 18, 59, 71, 22, 64, 78, 25, 70, 84, 28, 78, 90, 31, 83, 90, 33, 84, 85, 49, 86, 117, 118, 134, 110, 109, 124, 61, 46, 67, 37, 14, 36, 34, 7, 32, 35, 8, 32, 35, 7, 33, 37, 11, 36, 45, 24, 46, 69, 63, 81, 95, 104, 120, 111, 127, 146, 104, 121, 143, - 88, 99, 119, 77, 87, 110, 68, 74, 101, 43, 43, 54, 28, 23, 27, 54, 56, 71, 121, 123, 144, 117, 108, 120, 19, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 2, 44, 12, 41, 61, 16, 55, 64, 18, 57, 69, 20, 62, 77, 25, 68, 85, 30, 79, 91, 33, 84, 86, 32, 79, 75, 40, 75, 80, 76, 98, 141, 154, 163, 148, 159, 168, 114, 115, 128, 80, 71, 89, 68, 54, 75, 96, 87, 104, - 117, 111, 125, 129, 128, 139, 150, 156, 166, 159, 172, 181, 148, 165, 178, 73, 90, 105, 64, 83, 99, 79, 96, 114, 106, 118, 137, 78, 86, 97, 37, 42, 50, 54, 62, 80, 116, 122, 149, 119, 112, 124, 19, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 2, 43, 11, 39, 59, 16, 54, 63, 17, 55, 68, 20, 61, 76, 24, 67, 83, 27, 76, 87, 29, 80, 78, 25, 71, 65, 25, 60, 72, 65, 89, - 85, 100, 117, 148, 164, 169, 164, 180, 186, 165, 179, 186, 176, 188, 194, 208, 217, 221, 227, 234, 236, 235, 241, 242, 237, 244, 245, 241, 250, 252, 124, 138, 146, 31, 50, 65, 45, 69, 87, 66, 91, 109, 170, 185, 193, 212, 222, 224, 177, 187, 192, 128, 143, 155, 115, 126, 154, 116, 111, 130, 20, 17, 19, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 2, 43, 11, 40, 60, 17, 55, 64, 20, 58, 69, 24, 63, - 74, 26, 68, 81, 29, 75, 86, 33, 79, 77, 28, 70, 60, 19, 55, 68, 57, 82, 85, 96, 117, 89, 107, 123, 133, 150, 157, 167, 185, 191, 206, 219, 223, 228, 236, 238, 237, 244, 245, 233, 241, 242, 210, 224, 229, 154, 173, 180, 52, 69, 81, 33, 53, 68, 39, 62, 80, 49, 78, 104, 95, 123, 142, - 202, 216, 220, 236, 244, 244, 233, 239, 240, 195, 206, 214, 145, 145, 161, 23, 21, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 2, 1, 2, 44, 12, 40, 61, 16, 55, 64, 17, 56, 68, 20, 60, 71, 22, 64, 77, 25, 69, 79, 25, 71, 74, 26, 66, 69, 31, 63, 71, 52, 79, 91, 101, 121, 108, 128, 144, 112, 134, 144, 158, 177, 182, 198, 213, 217, 207, 220, 224, 204, 218, 223, 183, 201, 208, 113, 139, 152, - 47, 63, 72, 32, 49, 58, 48, 69, 85, 50, 73, 93, 46, 68, 96, 45, 76, 104, 140, 160, 169, 225, 234, 234, 240, 246, 246, 242, 247, 246, 229, 235, 236, 37, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 2, 44, 13, 41, 61, 16, 55, 63, 18, 57, 66, 20, 59, 70, 22, 62, 77, 26, 68, 82, 29, 74, 79, 29, 72, 76, 36, 72, 83, 56, 83, 117, 120, 137, 152, 168, 178, 165, 181, 188, - 180, 196, 202, 160, 181, 189, 156, 177, 186, 149, 173, 183, 167, 187, 194, 125, 147, 156, 63, 82, 93, 45, 64, 76, 70, 92, 107, 62, 83, 103, 45, 65, 90, 31, 57, 85, 103, 124, 136, 213, 225, 227, 236, 242, 242, 242, 248, 247, 255, 255, 255, 46, 48, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 2, 43, 12, 40, 61, 17, 55, 63, 18, 56, 66, 22, 59, 70, 24, 63, 74, 24, 66, 84, 40, 78, - 95, 63, 95, 117, 100, 123, 154, 152, 165, 176, 185, 192, 183, 197, 202, 180, 194, 199, 143, 164, 172, 122, 146, 157, 118, 143, 153, 116, 143, 155, 154, 177, 185, 162, 182, 189, 133, 155, 164, 111, 133, 145, 101, 123, 134, 86, 106, 120, 64, 86, 104, 47, 68, 88, 97, 120, 132, 193, 209, 213, 222, 232, 233, - 241, 247, 246, 255, 255, 255, 46, 48, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 2, 39, 12, 37, - 57, 16, 51, 62, 19, 56, 68, 25, 60, 78, 46, 76, 100, 78, 105, 129, 122, 142, 170, 176, 188, 187, 200, 209, 195, 212, 218, 188, 205, 212, 169, 187, 195, 141, 161, 171, 94, 116, 124, 101, 122, 131, 83, 107, 118, 98, 127, 143, 151, 176, 188, 164, 184, 194, 158, 179, 188, 145, 168, 177, 144, 164, 171, - 147, 167, 175, 97, 119, 132, 57, 72, 86, 114, 136, 146, 184, 201, 207, 208, 221, 224, 235, 242, 242, 255, 255, 255, 46, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 2, 36, 13, 34, 53, 18, 49, 59, 24, 56, 83, 62, 89, 145, 151, 166, 178, 194, 203, 187, 207, 215, 184, 205, 214, 182, 203, 213, 180, 201, 211, 165, 187, 197, 128, 151, 162, 90, 111, 121, 53, 69, 77, 79, 101, 110, 62, 83, 92, - 95, 118, 133, 109, 138, 153, 164, 185, 196, 186, 202, 209, 168, 188, 196, 163, 182, 189, 157, 176, 184, 117, 140, 150, 67, 84, 93, 106, 129, 138, 181, 197, 204, 189, 207, 213, 222, 232, 233, 255, 255, 255, 46, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 2, 37, 23, 39, 84, 72, 91, 115, 111, 127, 139, 147, 161, 176, 198, 209, 177, 199, 210, 173, 195, 208, 171, 194, 206, 169, 194, 206, 168, 193, 205, - 125, 154, 167, 62, 80, 87, 54, 68, 74, 44, 55, 59, 46, 58, 64, 40, 54, 60, 37, 47, 54, 82, 99, 107, 149, 167, 176, 175, 191, 200, 181, 198, 207, 181, 200, 207, 180, 198, 204, 152, 173, 181, 91, 110, 117, 89, 110, 118, 102, 126, 138, 164, 184, 191, 220, 231, 232, 250, 255, 255, 46, 47, 47, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 3, 64, 67, 76, 166, 181, 190, 192, 211, 219, 184, 205, 215, - 168, 193, 205, 161, 187, 201, 158, 183, 198, 151, 178, 192, 145, 173, 188, 142, 171, 186, 105, 131, 143, 53, 59, 59, 21, 22, 22, 63, 75, 79, 73, 86, 90, 51, 63, 68, 27, 27, 26, 10, 10, 14, 102, 107, 108, 120, 143, 156, 125, 150, 163, 167, 189, 197, 190, 209, 215, 185, 204, 211, 174, 195, 202, - 156, 178, 187, 149, 171, 180, 168, 190, 198, 217, 229, 231, 251, 255, 255, 46, 48, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 7, 8, 8, 134, 147, 153, 192, 211, 219, 184, 205, 214, 172, 194, 206, 151, 178, 193, 144, 172, 188, 135, 164, 181, 109, 140, 158, 85, 118, 133, 96, 130, 145, 99, 124, 136, 48, 62, 67, 57, 69, 72, 111, 124, 127, 121, 134, 136, 116, 130, 140, 64, 70, 76, 53, 55, 55, 82, 96, 103, - 82, 103, 113, 97, 121, 132, 124, 149, 160, 171, 192, 200, 183, 202, 208, 178, 197, 203, 178, 197, 203, 186, 204, 210, 197, 213, 218, 222, 233, 235, 253, 255, 255, 46, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 9, 153, 167, 172, 194, 214, 221, 177, 199, 209, 162, 186, 199, 143, 171, 188, 132, 161, 178, 102, 134, 151, 81, 110, 125, 60, 88, 101, 80, 113, 125, 101, 126, 138, 48, 62, 69, 137, 151, 155, - 136, 148, 150, 119, 132, 135, 110, 123, 130, 92, 110, 119, 76, 94, 104, 67, 86, 96, 79, 98, 107, 107, 129, 138, 136, 158, 166, 140, 164, 174, 170, 189, 194, 177, 195, 199, 187, 204, 209, 196, 212, 216, 211, 224, 226, 228, 237, 237, 251, 255, 255, 46, 46, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 9, 155, 167, 173, 194, 213, 221, 176, 196, 207, 168, 189, 201, 149, 175, 188, 120, 150, 167, 96, 126, 143, - 82, 109, 124, 67, 94, 106, 87, 118, 130, 109, 136, 148, 93, 107, 113, 97, 104, 105, 110, 121, 123, 104, 119, 124, 91, 108, 114, 55, 70, 77, 59, 77, 85, 70, 89, 97, 85, 104, 111, 101, 124, 132, 125, 146, 154, 129, 152, 160, 145, 168, 177, 164, 185, 191, 173, 191, 196, 189, 205, 209, 204, 218, 220, - 222, 232, 231, 247, 253, 252, 45, 46, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 10, 158, 171, 175, - 200, 218, 225, 182, 202, 211, 170, 191, 202, 151, 176, 190, 138, 164, 179, 114, 143, 159, 84, 113, 128, 77, 103, 118, 91, 121, 133, 132, 160, 172, 96, 117, 124, 20, 23, 24, 76, 85, 88, 157, 173, 177, 159, 176, 182, 102, 122, 128, 67, 86, 91, 66, 80, 86, 66, 83, 88, 69, 88, 95, 82, 104, 110, - 118, 141, 148, 147, 169, 175, 158, 178, 184, 161, 182, 187, 187, 204, 207, 211, 223, 224, 215, 226, 225, 236, 245, 243, 43, 45, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 10, 10, 164, 175, 178, 208, 224, 229, 190, 208, 215, 176, 197, 206, 157, 180, 194, 131, 159, 174, 105, 136, 152, 88, 117, 133, 88, 114, 127, 90, 117, 127, 123, 152, 162, 108, 130, 137, 58, 67, 69, 90, 101, 104, 144, 159, 162, 166, 183, 186, - 163, 181, 187, 125, 145, 147, 91, 109, 111, 71, 85, 89, 68, 80, 85, 69, 84, 91, 89, 110, 115, 106, 131, 138, 140, 162, 168, 166, 186, 189, 193, 207, 210, 220, 229, 227, 217, 226, 224, 235, 243, 240, 37, 40, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 10, 10, 166, 176, 179, 208, 224, 229, 192, 211, 217, 178, 198, 209, 141, 168, 182, 117, 147, 163, 108, 137, 154, 96, 123, 138, 83, 107, 119, 78, 104, 114, - 115, 142, 149, 115, 137, 143, 81, 95, 99, 69, 83, 87, 102, 115, 116, 130, 146, 149, 148, 165, 169, 125, 140, 142, 96, 112, 113, 79, 94, 98, 67, 85, 91, 82, 99, 104, 84, 103, 108, 100, 121, 127, 137, 159, 163, 186, 200, 201, 204, 215, 213, 217, 225, 223, 216, 224, 222, 231, 240, 237, 119, 107, 103, - 76, 93, 110, 94, 71, 60, 116, 56, 6, 111, 54, 8, 104, 50, 8, 96, 44, 7, 85, 38, 6, 80, 37, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 10, 160, 172, 176, 199, 217, 224, 189, 207, 215, 174, 195, 204, - 140, 168, 182, 121, 149, 165, 104, 133, 150, 80, 107, 122, 76, 101, 113, 92, 117, 124, 97, 124, 131, 115, 138, 144, 100, 122, 128, 97, 118, 124, 81, 96, 100, 78, 93, 96, 109, 121, 121, 102, 116, 116, 93, 109, 109, 89, 105, 107, 98, 113, 116, 102, 121, 124, 120, 138, 140, 135, 153, 153, 165, 179, 179, - 186, 198, 198, 200, 210, 208, 212, 220, 217, 214, 222, 219, 228, 235, 230, 157, 179, 197, 136, 144, 166, 183, 114, 76, 188, 93, 11, 180, 86, 7, 163, 77, 11, 154, 71, 5, 141, 63, 9, 136, 60, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 9, 9, 9, 154, 166, 171, 193, 212, 218, 184, 203, 209, 161, 185, 194, 141, 168, 181, 114, 145, 161, 99, 128, 147, 89, 115, 129, 97, 120, 130, 80, 105, 113, 93, 117, 123, 103, 127, 133, 108, 127, 131, 101, 121, 126, 107, 127, 131, 101, 118, 121, 106, 122, 123, 121, 131, 132, 92, 107, 109, - 90, 105, 106, 99, 115, 115, 135, 146, 146, 155, 167, 165, 154, 167, 166, 157, 171, 169, 177, 188, 186, 189, 200, 197, 213, 220, 217, 211, 221, 217, 228, 234, 229, 178, 198, 216, 173, 176, 188, 183, 125, 100, 186, 93, 24, 167, 80, 18, 164, 77, 12, 167, 78, 10, 153, 70, 10, 148, 66, 5, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 9, 9, 149, 167, 172, 182, 206, 215, 176, 200, 209, 169, 195, 205, 144, 175, 191, 112, 148, 169, 88, 121, 142, 91, 121, 137, 79, 110, 123, 80, 109, 119, 97, 126, 134, 92, 121, 128, 89, 116, 123, - 90, 113, 118, 99, 117, 119, 104, 119, 119, 103, 121, 123, 108, 125, 125, 107, 121, 123, 96, 114, 113, 107, 121, 122, 126, 140, 137, 130, 147, 147, 143, 161, 161, 127, 148, 148, 157, 173, 169, 191, 200, 197, 207, 216, 212, 213, 223, 218, 222, 231, 226, 201, 218, 231, 180, 197, 214, 170, 145, 143, 176, 91, 43, - 176, 88, 24, 186, 91, 14, 186, 91, 11, 167, 79, 11, 160, 73, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 13, 6, 129, 96, 89, 152, 119, 109, 153, 118, 107, 161, 123, 109, 154, 117, 104, 135, 100, 88, 127, 90, 75, - 125, 86, 69, 121, 83, 64, 126, 88, 67, 132, 94, 72, 128, 89, 67, 120, 81, 58, 120, 78, 59, 80, 80, 97, 73, 91, 119, 124, 90, 87, 125, 92, 89, 128, 98, 99, 108, 80, 79, 73, 76, 93, 64, 72, 80, 99, 69, 65, 110, 76, 74, 114, 115, 115, 145, 162, 160, 180, 192, 190, 197, 207, 203, - 217, 225, 221, 223, 231, 227, 219, 235, 245, 185, 202, 219, 180, 174, 179, 196, 120, 67, 209, 112, 27, 203, 104, 15, 190, 92, 11, 164, 77, 10, 162, 76, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 108, 21, 2, 122, 28, 4, - 136, 36, 4, 148, 43, 4, 158, 48, 4, 165, 54, 4, 171, 58, 5, 173, 60, 5, 173, 62, 4, 173, 62, 3, 174, 63, 3, 175, 63, 3, 176, 63, 3, 179, 64, 3, 182, 64, 5, 92, 29, 14, 3, 34, 87, 15, 60, 129, 13, 59, 127, 12, 53, 119, 10, 37, 94, 3, 16, 62, 17, 4, 14, - 117, 20, 3, 102, 8, 0, 120, 93, 92, 149, 165, 163, 175, 187, 185, 186, 199, 194, 217, 224, 221, 230, 234, 231, 229, 243, 248, 205, 215, 225, 194, 161, 150, 198, 129, 88, 199, 109, 48, 184, 96, 38, 165, 81, 30, 153, 73, 18, 156, 75, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 117, 26, 2, 130, 32, 2, 141, 39, 2, 154, 46, 2, 162, 53, 2, 168, 57, 3, 171, 61, 5, 174, 65, 6, 177, 67, 4, 180, 68, 3, 183, 70, 2, 173, 65, 3, 157, 60, 14, 182, 69, 10, 181, 71, 18, 119, 48, 53, 55, 23, 75, - 41, 22, 99, 64, 18, 83, 59, 13, 60, 48, 14, 58, 50, 14, 55, 23, 10, 52, 95, 25, 25, 87, 13, 12, 104, 85, 84, 145, 160, 158, 165, 176, 172, 170, 184, 180, 193, 203, 200, 212, 218, 216, 234, 245, 246, 226, 239, 244, 186, 169, 170, 180, 118, 89, 189, 108, 59, 195, 106, 40, 193, 98, 17, - 190, 95, 13, 184, 94, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120, 28, 2, 133, 36, 2, 146, 43, 2, 158, 51, 3, 166, 57, 3, 170, 63, 11, 171, 68, 36, 174, 71, 42, 181, 74, 27, 186, 75, 13, 190, 77, 6, - 153, 57, 6, 94, 50, 75, 106, 68, 106, 64, 59, 122, 40, 48, 117, 28, 38, 107, 23, 34, 104, 29, 23, 75, 21, 18, 68, 13, 20, 84, 14, 20, 79, 11, 13, 74, 6, 20, 82, 12, 11, 63, 55, 59, 77, 112, 129, 130, 134, 151, 151, 137, 155, 155, 142, 164, 165, 142, 170, 174, 193, 215, 233, - 242, 254, 255, 212, 219, 223, 133, 107, 98, 109, 63, 33, 143, 79, 29, 137, 71, 12, 120, 59, 10, 138, 71, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 119, 31, 2, 131, 38, 2, 145, 46, 3, 158, 55, 3, 167, 62, 6, - 169, 70, 41, 177, 115, 132, 189, 150, 172, 187, 88, 79, 192, 82, 37, 195, 83, 17, 168, 67, 12, 142, 52, 28, 105, 99, 137, 38, 63, 138, 50, 46, 111, 27, 63, 137, 13, 53, 127, 18, 36, 92, 4, 21, 76, 14, 28, 81, 20, 27, 80, 32, 23, 70, 18, 18, 59, 27, 8, 41, 85, 90, 107, - 159, 174, 186, 203, 218, 223, 213, 224, 226, 194, 214, 222, 99, 156, 195, 205, 226, 245, 252, 255, 255, 239, 252, 254, 161, 177, 189, 48, 57, 65, 8, 4, 3, 8, 3, 2, 2, 0, 1, 15, 6, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 116, 31, 0, 124, 35, 0, 143, 50, 4, 158, 58, 6, 167, 66, 14, 169, 74, 58, 181, 138, 166, 204, 202, 231, 208, 147, 163, 199, 105, 88, 200, 89, 34, 185, 79, 25, 148, 53, 14, 160, 109, 107, 16, 65, 132, 24, 56, 116, 16, 83, 161, 28, 77, 153, 68, 53, 110, 12, 31, 90, - 30, 47, 103, 21, 44, 103, 18, 39, 97, 6, 29, 84, 25, 10, 39, 166, 149, 149, 225, 239, 246, 225, 239, 249, 243, 252, 254, 252, 255, 255, 222, 234, 243, 245, 251, 254, 250, 255, 255, 242, 254, 255, 224, 240, 247, 93, 104, 112, 1, 1, 2, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 88, 52, 55, 175, 153, 152, 88, 29, 24, 109, 43, 28, 118, 49, 30, 123, 65, 75, 137, 91, 112, 186, 184, 202, 221, 220, 228, 174, 111, 99, 179, 94, 67, 187, 95, 62, 135, 57, 42, 50, 88, 142, - 27, 105, 174, 16, 90, 169, 14, 92, 175, 13, 61, 133, 36, 45, 109, 14, 41, 107, 14, 32, 96, 5, 22, 91, 3, 12, 79, 5, 12, 76, 49, 8, 32, 198, 163, 152, 255, 255, 255, 231, 244, 250, 179, 197, 224, 190, 209, 237, 227, 239, 247, 242, 253, 254, 246, 254, 254, 244, 254, 254, 233, 246, 252, - 201, 214, 222, 59, 65, 71, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 94, 83, 97, 138, 129, 143, 66, 32, 58, 70, 36, 69, 130, 121, 32, 127, 118, 132, 103, 86, 122, 108, 95, 135, - 183, 186, 200, 226, 225, 208, 158, 154, 168, 155, 152, 173, 96, 98, 133, 22, 107, 180, 12, 76, 140, 12, 78, 143, 9, 56, 123, 7, 56, 127, 4, 26, 83, 5, 22, 78, 4, 18, 64, 3, 10, 50, 3, 7, 35, 3, 4, 21, 9, 0, 6, 154, 153, 155, 245, 254, 255, 238, 246, 249, 102, 124, 181, - 95, 124, 220, 187, 208, 240, 232, 245, 251, 235, 249, 253, 243, 253, 254, 232, 246, 251, 211, 224, 232, 145, 156, 164, 14, 17, 19, 0, 0, 0, 9, 11, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 82, 73, 112, 92, 76, 114, - 72, 46, 78, 66, 42, 74, 98, 87, 69, 77, 52, 75, 91, 70, 112, 124, 142, 176, 159, 190, 210, 209, 204, 173, 159, 117, 106, 142, 75, 79, 128, 82, 95, 23, 100, 176, 12, 84, 156, 12, 82, 156, 9, 49, 107, 6, 24, 75, 4, 6, 23, 8, 12, 32, 5, 7, 24, 5, 9, 29, 4, 6, 20, - 6, 9, 28, 0, 0, 15, 127, 138, 148, 221, 236, 242, 225, 239, 244, 198, 213, 234, 121, 143, 203, 219, 236, 249, 227, 240, 245, 227, 241, 248, 233, 247, 253, 225, 239, 246, 210, 224, 232, 164, 176, 184, 51, 57, 62, 6, 7, 10, 83, 96, 106, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61, 50, 87, 63, 56, 94, 47, 50, 87, 53, 50, 85, 49, 49, 89, 39, 59, 108, 81, 115, 185, 102, 148, 217, 111, 147, 207, 217, 217, 201, 179, 119, 95, 162, 83, 81, 166, 75, 55, 102, 84, 108, 39, 113, 192, 6, 46, 100, 6, 29, 76, - 8, 19, 58, 12, 24, 59, 9, 15, 42, 8, 18, 51, 8, 24, 66, 5, 14, 47, 5, 14, 44, 0, 6, 38, 104, 115, 129, 184, 202, 210, 162, 179, 190, 110, 126, 146, 148, 164, 181, 217, 231, 238, 220, 233, 239, 219, 235, 242, 221, 236, 245, 213, 229, 236, 201, 215, 222, 169, 182, 190, 127, 138, 146, - 116, 127, 135, 158, 175, 186, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70, 62, 106, 74, 69, 114, 54, 24, 49, 60, 30, 50, 65, 44, 84, 27, 82, 150, 33, 98, 173, 39, 83, 150, 58, 89, 153, 57, 69, 114, 122, 90, 140, - 140, 75, 106, 130, 74, 114, 103, 87, 143, 29, 88, 162, 6, 35, 85, 7, 22, 63, 10, 25, 67, 13, 35, 87, 11, 29, 78, 11, 35, 85, 9, 35, 84, 7, 30, 80, 5, 12, 40, 0, 8, 42, 73, 84, 102, 100, 116, 126, 133, 150, 164, 112, 130, 146, 104, 121, 135, 176, 192, 200, 215, 229, 237, - 220, 235, 244, 210, 225, 232, 200, 215, 222, 191, 205, 213, 175, 186, 194, 173, 185, 193, 181, 195, 203, 170, 187, 197, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 26, 63, 23, 19, 53, 37, 10, 44, 36, 12, 46, 30, 34, 78, - 26, 57, 114, 22, 70, 133, 22, 50, 107, 28, 51, 109, 44, 51, 105, 51, 53, 108, 61, 30, 52, 69, 23, 48, 46, 104, 174, 23, 85, 151, 6, 25, 65, 6, 20, 62, 7, 29, 77, 13, 48, 106, 10, 34, 86, 10, 37, 86, 9, 36, 83, 7, 36, 87, 3, 9, 37, 0, 3, 27, 57, 68, 80, - 102, 120, 130, 142, 160, 171, 134, 153, 165, 152, 170, 184, 185, 202, 212, 201, 217, 225, 205, 220, 228, 191, 207, 214, 182, 197, 205, 175, 188, 196, 168, 181, 189, 174, 188, 195, 178, 193, 200, 168, 185, 194, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 16, 17, 56, 24, 11, 42, 32, 16, 49, 33, 22, 62, 32, 33, 75, 30, 34, 79, 33, 41, 93, 44, 53, 112, 65, 61, 122, 56, 56, 106, 20, 18, 41, 62, 25, 33, 100, 60, 89, 30, 54, 109, 8, 45, 99, 7, 35, 77, 5, 20, 53, 4, 16, 47, 5, 22, 60, 5, 14, 45, - 5, 17, 46, 5, 25, 68, 5, 27, 72, 4, 14, 47, 0, 5, 31, 41, 49, 60, 72, 86, 95, 80, 95, 104, 104, 119, 128, 136, 149, 157, 134, 147, 155, 133, 146, 153, 132, 144, 150, 135, 147, 153, 126, 137, 143, 123, 133, 140, 124, 134, 140, 125, 135, 141, 123, 134, 140, 117, 130, 137, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 42, 94, 17, 51, 111, 22, 58, 120, 33, 71, 138, 40, 80, 149, 37, 76, 144, 40, 81, 151, 55, 91, 164, 62, 92, 165, 46, 84, 152, 37, 68, 125, 44, 78, 135, 44, 96, 169, 36, 93, 168, - 35, 88, 163, 31, 76, 143, 19, 54, 107, 10, 31, 72, 5, 19, 51, 3, 10, 29, 3, 9, 27, 3, 13, 41, 4, 16, 50, 3, 7, 31, 2, 5, 22, 4, 5, 9, 7, 8, 8, 7, 8, 9, 8, 9, 10, 9, 10, 11, 10, 11, 11, 11, 12, 12, 10, 11, 11, 10, 11, 11, 10, 10, 11, - 9, 10, 10, 10, 11, 11, 11, 11, 12, 10, 11, 11, 9, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 36, 93, 5, 45, 106, 13, 56, 122, 20, 71, 142, 29, 81, 155, 26, 79, 152, 30, 84, 158, 35, 90, 166, - 46, 101, 181, 36, 80, 149, 14, 60, 123, 7, 64, 129, 10, 63, 128, 22, 86, 159, 37, 109, 190, 36, 105, 185, 32, 91, 168, 26, 79, 151, 20, 66, 132, 12, 50, 107, 6, 34, 80, 4, 22, 61, 3, 15, 48, 3, 8, 34, 3, 6, 23, 0, 1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 27, 78, 3, 35, 90, - 4, 40, 96, 7, 49, 109, 12, 58, 123, 16, 64, 131, 16, 68, 136, 21, 73, 143, 26, 75, 145, 11, 46, 101, 4, 52, 111, 3, 43, 99, 4, 47, 105, 3, 48, 107, 5, 54, 116, 5, 56, 118, 8, 63, 127, 10, 65, 130, 13, 72, 139, 9, 61, 126, 6, 50, 110, 5, 43, 99, 4, 36, 88, - 3, 28, 76, 3, 20, 61, 1, 6, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}; -const char* DemoArtwork::ico2Data = (const char*)temp_ico2_2; - -static const unsigned char temp_ico3_3[] = { - 37, 23, 14, 88, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 88, 55, 33, 37, 23, 14, 37, 23, 14, 88, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, - 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 88, 55, 33, 38, 23, 13, 13, 23, 38, 33, 55, 88, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, - 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 88, 14, 23, 37, 88, 55, 33, 207, 130, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 207, 130, 77, - 88, 55, 33, 88, 55, 33, 207, 130, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 207, 130, 77, 90, 55, 30, 30, 55, 90, 77, 130, 207, 77, 129, 206, 77, 129, 206, - 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 130, 207, 33, 55, 88, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, - 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 87, 55, 33, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, - 206, 129, 77, 90, 55, 30, 30, 55, 90, 77, 129, 206, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, 87, 55, 33, 206, 129, 77, 204, 128, 76, - 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 87, 55, 33, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, - 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 90, 55, 30, 30, 55, 90, 77, 129, 206, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, - 76, 128, 204, 77, 129, 206, 33, 55, 87, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 87, 55, 33, 87, 55, 33, 206, 129, 77, - 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 90, 55, 30, 30, 55, 90, 77, 129, 206, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, - 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, - 204, 128, 76, 204, 128, 76, 206, 129, 77, 87, 55, 33, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 90, 55, 30, 30, 55, 90, - 77, 129, 206, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, - 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 87, 55, 33, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, - 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 90, 55, 30, 30, 55, 90, 77, 129, 206, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, - 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 87, 55, 33, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, - 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 90, 55, 30, 30, 55, 90, 77, 129, 206, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, - 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, - 87, 55, 33, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 90, 55, 30, 30, 55, 90, 77, 129, 206, 76, 128, 204, 76, 128, 204, - 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, - 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 87, 55, 33, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, - 206, 129, 77, 90, 55, 30, 30, 55, 90, 77, 129, 206, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, 87, 55, 33, 206, 129, 77, 204, 128, 76, - 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 87, 55, 33, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, - 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 90, 55, 30, 30, 55, 90, 77, 129, 206, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, - 76, 128, 204, 77, 129, 206, 33, 55, 87, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 87, 55, 33, 87, 55, 33, 206, 129, 77, - 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 90, 55, 30, 30, 55, 90, 77, 129, 206, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, - 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, - 204, 128, 76, 204, 128, 76, 206, 129, 77, 87, 55, 33, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 90, 55, 30, 30, 55, 90, - 77, 129, 206, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, - 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 87, 55, 33, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, - 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 90, 55, 30, 30, 55, 90, 77, 129, 206, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, - 88, 55, 33, 207, 130, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 207, 130, 77, 88, 55, 33, 88, 55, 33, 207, 130, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, - 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 207, 130, 77, 90, 55, 30, 30, 55, 90, 77, 130, 207, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, - 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 130, 207, 33, 55, 88, 37, 23, 14, 88, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 88, 55, 33, - 37, 23, 14, 39, 23, 13, 90, 55, 30, 90, 55, 30, 90, 55, 30, 90, 55, 30, 90, 55, 30, 90, 55, 30, 90, 55, 30, 90, 55, 30, 90, 55, 30, 90, 55, 30, 90, 55, 30, 90, 55, 30, 90, 55, 30, 90, 55, 30, 40, 23, 12, 13, 23, 39, 33, 55, 88, 33, 55, 87, 33, 55, 87, - 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 88, 14, 23, 37, 37, 23, 14, 88, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, - 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 88, 55, 33, 39, 23, 13, 12, 23, 40, 30, 55, 90, 30, 55, 90, 30, 55, 90, 30, 55, 90, 30, 55, 90, 30, 55, 90, 30, 55, 90, 30, 55, 90, 30, 55, 90, 30, 55, 90, 30, 55, 90, 30, 55, 90, 30, 55, 90, - 30, 55, 90, 13, 23, 39, 14, 23, 37, 33, 55, 88, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 88, 14, 23, 37, 88, 55, 33, 207, 130, 77, 206, 129, 77, - 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 207, 130, 77, 90, 55, 30, 30, 55, 90, 77, 130, 207, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, - 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 130, 207, 33, 55, 88, 33, 55, 88, 77, 130, 207, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, - 77, 129, 206, 77, 130, 207, 33, 55, 88, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 90, 55, 30, 30, 55, 90, 77, 129, 206, - 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, 33, 55, 87, 77, 129, 206, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, - 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, - 204, 128, 76, 204, 128, 76, 206, 129, 77, 90, 55, 30, 30, 55, 90, 77, 129, 206, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, 33, 55, 87, - 77, 129, 206, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, - 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 90, 55, 30, 30, 55, 90, 77, 129, 206, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, - 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, 33, 55, 87, 77, 129, 206, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, - 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 90, 55, 30, 30, 55, 90, 77, 129, 206, 76, 128, 204, 76, 128, 204, 76, 128, 204, - 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, 33, 55, 87, 77, 129, 206, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, - 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, - 90, 55, 30, 30, 55, 90, 77, 129, 206, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, 33, 55, 87, 77, 129, 206, 76, 128, 204, 76, 128, 204, - 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, - 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 90, 55, 30, 30, 55, 90, 77, 129, 206, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, - 77, 129, 206, 33, 55, 87, 33, 55, 87, 77, 129, 206, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, 87, 55, 33, 206, 129, 77, 204, 128, 76, - 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 90, 55, 30, 30, 55, 90, 77, 129, 206, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, - 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, 33, 55, 87, 77, 129, 206, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, - 76, 128, 204, 77, 129, 206, 33, 55, 87, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 90, 55, 30, 30, 55, 90, 77, 129, 206, - 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, 33, 55, 87, 77, 129, 206, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, - 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, - 204, 128, 76, 204, 128, 76, 206, 129, 77, 90, 55, 30, 30, 55, 90, 77, 129, 206, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, 33, 55, 87, - 77, 129, 206, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, - 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 90, 55, 30, 30, 55, 90, 77, 129, 206, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, - 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, 33, 55, 87, 77, 129, 206, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, - 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 90, 55, 30, 30, 55, 90, 77, 129, 206, 76, 128, 204, 76, 128, 204, 76, 128, 204, - 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, 33, 55, 87, 77, 129, 206, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, - 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, - 90, 55, 30, 30, 55, 90, 77, 129, 206, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, 33, 55, 87, 77, 129, 206, 76, 128, 204, 76, 128, 204, - 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, 88, 55, 33, 207, 130, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, - 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 207, 130, 77, 90, 55, 30, 30, 55, 90, 77, 130, 207, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, - 77, 130, 207, 33, 55, 88, 33, 55, 88, 77, 130, 207, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 130, 207, 33, 55, 88, 37, 23, 14, 88, 55, 33, 87, 55, 33, - 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 88, 55, 33, 39, 23, 13, 12, 23, 40, 30, 55, 90, 30, 55, 90, 30, 55, 90, 30, 55, 90, 30, 55, 90, 30, 55, 90, 30, 55, 90, - 30, 55, 90, 30, 55, 90, 30, 55, 90, 30, 55, 90, 30, 55, 90, 30, 55, 90, 30, 55, 90, 13, 23, 39, 14, 23, 37, 33, 55, 88, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, - 33, 55, 87, 33, 55, 88, 14, 23, 37, 37, 23, 14, 88, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 88, 55, 33, 37, 23, 14, 39, 23, 13, 90, 55, 30, - 90, 55, 30, 90, 55, 30, 90, 55, 30, 90, 55, 30, 90, 55, 30, 90, 55, 30, 90, 55, 30, 90, 55, 30, 90, 55, 30, 90, 55, 30, 90, 55, 30, 90, 55, 30, 90, 55, 30, 40, 23, 12, 13, 23, 39, 33, 55, 88, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, - 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 88, 14, 23, 37, 88, 55, 33, 207, 130, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, - 206, 129, 77, 206, 129, 77, 207, 130, 77, 88, 55, 33, 88, 55, 33, 207, 130, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 207, 130, 77, 90, 55, 30, 30, 55, 90, - 77, 130, 207, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 130, 207, 33, 55, 88, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, - 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 87, 55, 33, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, - 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 90, 55, 30, 30, 55, 90, 77, 129, 206, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, - 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 87, 55, 33, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, - 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 90, 55, 30, 30, 55, 90, 77, 129, 206, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, - 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, - 87, 55, 33, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 90, 55, 30, 30, 55, 90, 77, 129, 206, 76, 128, 204, 76, 128, 204, - 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, - 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 87, 55, 33, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, - 206, 129, 77, 90, 55, 30, 30, 55, 90, 77, 129, 206, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, 87, 55, 33, 206, 129, 77, 204, 128, 76, - 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 87, 55, 33, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, - 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 90, 55, 30, 30, 55, 90, 77, 129, 206, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, - 76, 128, 204, 77, 129, 206, 33, 55, 87, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 87, 55, 33, 87, 55, 33, 206, 129, 77, - 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 90, 55, 30, 30, 55, 90, 77, 129, 206, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, - 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, - 204, 128, 76, 204, 128, 76, 206, 129, 77, 87, 55, 33, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 90, 55, 30, 30, 55, 90, - 77, 129, 206, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, - 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 87, 55, 33, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, - 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 90, 55, 30, 30, 55, 90, 77, 129, 206, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, - 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 87, 55, 33, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, - 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 90, 55, 30, 30, 55, 90, 77, 129, 206, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, - 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, - 87, 55, 33, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 90, 55, 30, 30, 55, 90, 77, 129, 206, 76, 128, 204, 76, 128, 204, - 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, - 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 87, 55, 33, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, - 206, 129, 77, 90, 55, 30, 30, 55, 90, 77, 129, 206, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 77, 129, 206, 33, 55, 87, 87, 55, 33, 206, 129, 77, 204, 128, 76, - 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 87, 55, 33, 87, 55, 33, 206, 129, 77, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, - 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 204, 128, 76, 206, 129, 77, 90, 55, 30, 30, 55, 90, 77, 129, 206, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, 76, 128, 204, - 76, 128, 204, 77, 129, 206, 33, 55, 87, 88, 55, 33, 207, 130, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 207, 130, 77, 88, 55, 33, 88, 55, 33, 207, 130, 77, - 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 206, 129, 77, 207, 130, 77, 90, 55, 30, 30, 55, 90, 77, 130, 207, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, - 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 129, 206, 77, 130, 207, 33, 55, 88, 37, 23, 14, 88, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, - 87, 55, 33, 87, 55, 33, 88, 55, 33, 37, 23, 14, 37, 23, 14, 88, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 87, 55, 33, 88, 55, 33, 38, 23, 13, 13, 23, 38, - 33, 55, 88, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 87, 33, 55, 88, 14, 23, 37,}; -const char* DemoArtwork::ico3Data = (const char*)temp_ico3_3; - -static const unsigned char temp_ico4_4[] = { - 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, - 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, - 92, 86, 77, 92, 86, 77, 93, 87, 78, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 91, 85, 76, 78, 72, 63, 78, 72, 63, 78, 72, 63, 78, 72, 63, 78, 72, 63, 78, 72, 63, 78, 72, 63, 78, 72, 63, 78, 72, 63, 78, 72, 63, 78, 72, 63, 78, 72, 63, - 78, 72, 63, 78, 72, 63, 78, 72, 63, 78, 72, 63, 78, 72, 63, 78, 72, 63, 78, 72, 63, 78, 72, 63, 78, 72, 63, 78, 72, 63, 78, 72, 63, 78, 72, 63, 78, 72, 63, 78, 72, 63, 78, 72, 63, 78, 72, 63, 78, 72, 63, 78, 72, 63, 78, 72, 63, 78, 72, 63, 78, 72, 63, - 78, 72, 63, 78, 72, 63, 78, 72, 63, 78, 72, 63, 78, 72, 63, 78, 72, 63, 78, 72, 63, 78, 72, 63, 76, 70, 61, 93, 87, 78, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 89, 83, 74, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 72, 66, 57, 93, 87, 78, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 89, 83, 74, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 72, 66, 57, - 93, 87, 78, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 89, 83, 74, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 74, 68, 59, 74, 68, 59, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 72, 66, 57, 93, 87, 78, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 89, 83, 74, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 76, 70, 61, 67, 62, 55, 67, 62, 55, 76, 70, 61, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 72, 66, 57, 93, 87, 78, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 89, 83, 74, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 67, 61, 53, 126, 118, 106, 126, 118, 106, 67, 61, 53, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 72, 66, 57, 93, 87, 78, 92, 86, 77, 92, 86, 77, - 92, 86, 77, 92, 86, 77, 89, 83, 74, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 68, 63, 56, 194, 181, 162, 194, 181, 162, 68, 63, 56, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 72, 66, 57, 93, 87, 78, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 89, 83, 74, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 74, 69, 60, 140, 131, 117, 185, 172, 154, 185, 172, 154, 140, 131, 117, 74, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 72, 66, 57, 93, 87, 78, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 89, 83, 74, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 76, 70, 61, 66, 62, 55, 178, 166, 149, 184, 172, 154, 184, 172, 154, 178, 166, 149, 66, 62, 55, 76, 70, 61, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 72, 66, 57, 93, 87, 78, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 89, 83, 74, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 65, 60, 52, 132, 124, 111, 186, 174, 156, 184, 172, 154, - 184, 172, 154, 186, 174, 156, 132, 124, 111, 65, 60, 52, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 72, 66, 57, - 93, 87, 78, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 89, 83, 74, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 76, 71, 63, 191, 178, 160, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 191, 178, 160, 76, 71, 63, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 72, 66, 57, 93, 87, 78, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 89, 83, 74, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 131, 122, 109, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 131, 122, 109, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 72, 66, 57, 93, 87, 78, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 89, 83, 74, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 76, 70, 61, 59, 55, 49, 182, 171, 153, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, - 182, 171, 153, 59, 55, 49, 76, 70, 61, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 72, 66, 57, 93, 87, 78, 92, 86, 77, 92, 86, 77, - 92, 86, 77, 92, 86, 77, 89, 83, 74, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 67, 61, 53, 139, 131, 117, 186, 174, 156, - 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 186, 174, 156, 139, 131, 117, 67, 61, 53, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 72, 66, 57, 93, 87, 78, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 89, 83, 74, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 80, 75, 66, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 80, 75, 66, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 72, 66, 57, 93, 87, 78, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 89, 83, 74, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 72, 66, 58, 123, 115, 103, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 123, 115, 103, - 72, 66, 58, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 72, 66, 57, 93, 87, 78, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 89, 83, 74, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 76, 69, 60, 58, 54, 48, 189, 177, 158, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, - 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 189, 177, 158, 58, 54, 48, 76, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 72, 66, 57, - 93, 87, 78, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 89, 83, 74, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 69, 64, 56, 144, 135, 121, - 186, 174, 156, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 186, 174, 156, 144, 135, 121, 69, 64, 56, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 72, 66, 57, 93, 87, 78, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 89, 83, 74, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 76, 70, 61, 77, 72, 64, 179, 167, 150, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 179, 167, 150, 77, 72, 64, 76, 70, 61, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 72, 66, 57, 93, 87, 78, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 89, 83, 74, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 68, 63, 55, 122, 115, 103, 185, 173, 155, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, - 184, 172, 154, 184, 172, 154, 184, 172, 154, 185, 173, 155, 122, 115, 103, 68, 63, 55, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 72, 66, 57, 93, 87, 78, 92, 86, 77, 92, 86, 77, - 92, 86, 77, 92, 86, 77, 89, 83, 74, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 63, 59, 52, 194, 181, 162, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, - 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 194, 181, 162, 63, 59, 52, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 72, 66, 57, 93, 87, 78, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 89, 83, 74, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 73, 67, 59, - 143, 134, 120, 185, 173, 155, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 185, 173, 155, 143, 134, 120, 73, 67, 59, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 72, 66, 57, 93, 87, 78, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 89, 83, 74, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 76, 70, 61, 71, 66, 58, 177, 166, 148, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 186, 174, 155, 182, 170, 152, 170, 159, 143, 165, 154, 138, 165, 154, 138, 170, 159, 143, 182, 170, 152, 186, 174, 155, 184, 172, 154, 184, 172, 154, - 184, 172, 154, 184, 172, 154, 177, 166, 148, 71, 66, 58, 76, 70, 61, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 72, 66, 57, 93, 87, 78, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 89, 83, 74, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 66, 60, 52, 128, 120, 108, 186, 174, 156, 184, 172, 154, 184, 172, 154, 184, 172, 154, 190, 178, 159, 123, 116, 103, 69, 64, 56, 77, 70, 62, 72, 67, 58, - 72, 67, 58, 77, 70, 62, 69, 64, 56, 123, 116, 103, 190, 178, 159, 184, 172, 154, 184, 172, 154, 184, 172, 154, 186, 174, 156, 128, 120, 108, 66, 60, 52, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 72, 66, 57, - 93, 87, 78, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 89, 83, 74, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 72, 68, 60, 193, 180, 162, 184, 172, 154, 184, 172, 154, 184, 172, 154, - 171, 159, 143, 84, 78, 68, 66, 60, 52, 77, 70, 61, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 77, 70, 61, 66, 60, 52, 84, 78, 68, 171, 159, 143, 184, 172, 154, 184, 172, 154, 184, 172, 154, 193, 180, 162, 72, 68, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 72, 66, 57, 93, 87, 78, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 89, 83, 74, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 136, 127, 114, 184, 172, 154, 184, 172, 154, 184, 172, 154, 185, 172, 154, 67, 63, 54, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 67, 63, 54, 185, 172, 154, 184, 172, 154, 184, 172, 154, - 184, 172, 154, 136, 127, 114, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 72, 66, 57, 93, 87, 78, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 89, 83, 74, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 76, 70, 61, 62, 58, 51, 180, 168, 151, 184, 172, 154, 184, 172, 154, 180, 169, 151, 72, 67, 59, 76, 70, 61, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 76, 70, 61, 72, 67, 59, 180, 169, 151, 184, 172, 154, 184, 172, 154, 180, 168, 151, 62, 58, 51, 76, 70, 61, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 72, 66, 57, 93, 87, 78, 92, 86, 77, 92, 86, 77, - 92, 86, 77, 92, 86, 77, 89, 83, 74, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 66, 60, 53, 136, 127, 114, 186, 174, 156, 184, 172, 154, 185, 173, 155, 144, 134, 119, 72, 66, 57, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 72, 66, 57, 144, 134, 119, 185, 173, 155, 184, 172, 154, 186, 174, 156, 136, 127, 114, 66, 60, 53, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 72, 66, 57, 93, 87, 78, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 89, 83, 74, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 79, 74, 65, 188, 175, 157, 184, 172, 154, 184, 172, 154, - 191, 178, 160, 80, 74, 65, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 80, 74, 65, 191, 178, 160, 184, 172, 154, 184, 172, 154, 188, 175, 157, - 79, 74, 65, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 72, 66, 57, 93, 87, 78, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 89, 83, 74, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 74, 68, 59, 126, 118, 106, 184, 172, 154, 184, 172, 154, 184, 172, 154, 191, 179, 160, 42, 39, 33, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 42, 39, 33, 191, 179, 160, 184, 172, 154, 184, 172, 154, 184, 172, 154, 126, 118, 106, 74, 68, 59, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 72, 66, 57, 93, 87, 78, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 89, 83, 74, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 76, 70, 61, 58, 54, 48, 186, 174, 156, 184, 172, 154, 184, 172, 154, 184, 172, 154, 159, 149, 133, 57, 53, 45, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 57, 53, 45, 159, 149, 133, 184, 172, 154, 184, 172, 154, 184, 172, 154, 186, 174, 156, 58, 54, 48, 76, 70, 61, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 72, 66, 57, - 93, 87, 78, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 89, 83, 74, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 68, 62, 54, 142, 134, 120, 186, 174, 156, 184, 172, 154, 184, 172, 154, 184, 172, 154, 159, 149, 133, 57, 53, 45, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 57, 53, 45, 159, 149, 133, 184, 172, 154, 184, 172, 154, 184, 172, 154, 186, 174, 156, 142, 134, 120, 68, 62, 54, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 72, 66, 57, 93, 87, 78, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 89, 83, 74, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 76, 70, 60, 79, 74, 65, 181, 169, 152, 184, 172, 154, - 184, 172, 154, 184, 172, 154, 184, 172, 154, 191, 179, 160, 42, 39, 33, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 42, 39, 33, 191, 179, 160, - 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 181, 169, 152, 79, 74, 65, 76, 70, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 72, 66, 57, 93, 87, 78, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 89, 83, 74, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 70, 64, 56, 121, 114, 102, 185, 173, 155, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 191, 178, 160, 80, 74, 65, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 80, 74, 65, 191, 178, 160, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 185, 173, 155, 121, 114, 102, 70, 64, 56, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 72, 66, 57, 93, 87, 78, 92, 86, 77, 92, 86, 77, - 92, 86, 77, 92, 86, 77, 89, 83, 74, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 60, 56, 49, 192, 180, 161, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 185, 173, 155, 144, 134, 119, 72, 66, 57, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 72, 66, 57, 144, 134, 119, 185, 173, 155, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 192, 180, 161, 60, 56, 49, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 72, 66, 57, 93, 87, 78, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 89, 83, 74, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 71, 66, 57, 145, 135, 121, 185, 173, 155, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, - 184, 172, 154, 180, 169, 151, 72, 67, 59, 76, 70, 61, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 76, 70, 61, 72, 67, 59, 180, 169, 151, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, - 184, 172, 154, 184, 172, 154, 185, 173, 155, 145, 135, 121, 71, 66, 57, 75, 69, 60, 75, 69, 60, 75, 69, 60, 72, 66, 57, 93, 87, 78, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 89, 83, 74, 75, 69, 60, 75, 69, 60, 75, 69, 60, 76, 70, 61, 75, 69, 61, 177, 166, 149, - 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 185, 172, 154, 67, 63, 54, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 67, 63, 54, - 185, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 177, 166, 149, 75, 69, 61, 76, 70, 61, 75, 69, 60, 75, 69, 60, 72, 66, 57, 93, 87, 78, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 89, 83, 74, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 67, 61, 53, 124, 117, 105, 186, 174, 155, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 171, 159, 143, 84, 78, 68, 66, 60, 52, 77, 70, 61, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 77, 70, 61, 66, 60, 52, 84, 78, 68, 171, 159, 143, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 186, 174, 155, 124, 117, 105, 67, 61, 53, 75, 69, 60, 75, 69, 60, 72, 66, 57, - 93, 87, 78, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 89, 83, 74, 75, 69, 60, 75, 69, 60, 75, 69, 60, 68, 63, 56, 194, 181, 163, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, - 184, 172, 154, 190, 178, 159, 123, 116, 103, 69, 64, 56, 77, 70, 62, 72, 67, 58, 72, 67, 58, 77, 70, 62, 69, 64, 56, 123, 116, 103, 190, 178, 159, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, - 184, 172, 154, 194, 181, 163, 68, 63, 56, 75, 69, 60, 75, 69, 60, 72, 66, 57, 93, 87, 78, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 89, 83, 74, 75, 69, 60, 75, 69, 60, 74, 69, 60, 140, 131, 117, 185, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, - 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 186, 174, 155, 182, 170, 152, 170, 159, 143, 165, 154, 138, 165, 154, 138, 170, 159, 143, 182, 170, 152, 186, 174, 155, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, - 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 185, 172, 154, 140, 131, 117, 74, 69, 60, 75, 69, 60, 72, 66, 57, 93, 87, 78, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 89, 83, 74, 75, 69, 60, 76, 70, 61, 66, 62, 55, - 178, 166, 149, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, - 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 184, 172, 154, 178, 166, 149, 66, 62, 55, 76, 70, 61, 72, 66, 57, 93, 87, 78, 92, 86, 77, 92, 86, 77, - 92, 86, 77, 92, 86, 77, 89, 83, 74, 75, 69, 60, 65, 60, 52, 137, 129, 115, 191, 179, 160, 189, 177, 158, 189, 177, 158, 189, 177, 158, 189, 177, 158, 189, 177, 158, 189, 177, 158, 189, 177, 158, 189, 177, 158, 189, 177, 158, 189, 177, 158, 189, 177, 158, 189, 177, 158, 189, 177, 158, 189, 177, 158, - 189, 177, 158, 189, 177, 158, 189, 177, 158, 189, 177, 158, 189, 177, 158, 189, 177, 158, 189, 177, 158, 189, 177, 158, 189, 177, 158, 189, 177, 158, 189, 177, 158, 189, 177, 158, 189, 177, 158, 189, 177, 158, 189, 177, 158, 189, 177, 158, 189, 177, 158, 189, 177, 158, 189, 177, 158, 189, 177, 158, 191, 179, 160, - 137, 129, 115, 65, 60, 52, 72, 66, 57, 93, 87, 78, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 89, 83, 74, 75, 69, 60, 71, 66, 57, 58, 53, 47, 55, 51, 45, 55, 51, 45, 55, 51, 45, 55, 51, 45, 55, 51, 45, 55, 51, 45, 55, 51, 45, 55, 51, 45, 55, 51, 45, - 55, 51, 45, 55, 51, 45, 55, 51, 45, 55, 51, 45, 55, 51, 45, 55, 51, 45, 55, 51, 45, 55, 51, 45, 55, 51, 45, 55, 51, 45, 55, 51, 45, 55, 51, 45, 55, 51, 45, 55, 51, 45, 55, 51, 45, 55, 51, 45, 55, 51, 45, 55, 51, 45, 55, 51, 45, 55, 51, 45, 55, 51, 45, - 55, 51, 45, 55, 51, 45, 55, 51, 45, 55, 51, 45, 55, 51, 45, 55, 51, 45, 58, 53, 47, 72, 66, 58, 72, 66, 57, 93, 87, 78, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 89, 83, 74, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 72, 66, 57, 93, 87, 78, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 89, 83, 74, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, - 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 75, 69, 60, 72, 66, 57, - 93, 87, 78, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 91, 85, 76, 82, 76, 67, 82, 76, 67, 82, 76, 67, 82, 76, 67, 82, 76, 67, 82, 76, 67, 82, 76, 67, 82, 76, 67, 82, 76, 67, 82, 76, 67, 82, 76, 67, 82, 76, 67, 82, 76, 67, 82, 76, 67, 82, 76, 67, - 82, 76, 67, 82, 76, 67, 82, 76, 67, 82, 76, 67, 82, 76, 67, 82, 76, 67, 82, 76, 67, 82, 76, 67, 82, 76, 67, 82, 76, 67, 82, 76, 67, 82, 76, 67, 82, 76, 67, 82, 76, 67, 82, 76, 67, 82, 76, 67, 82, 76, 67, 82, 76, 67, 82, 76, 67, 82, 76, 67, 82, 76, 67, - 82, 76, 67, 82, 76, 67, 82, 76, 67, 82, 76, 67, 82, 76, 67, 81, 75, 66, 93, 87, 78, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, - 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, - 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77, 92, 86, 77,}; -const char* DemoArtwork::ico4Data = (const char*)temp_ico4_4; - -static const unsigned char temp_ico5_5[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 5, 5, 5, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 0, 0, 0, 12, 12, 12, 148, 148, 148, 161, 161, 161, - 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, - 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, - 156, 156, 156, 155, 155, 155, 10, 10, 10, 18, 18, 18, 215, 215, 215, 229, 229, 229, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, - 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, - 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 221, 221, 221, 222, 222, 222, 19, 19, 19, 17, 17, 17, 208, 208, 208, 222, 222, 222, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, - 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, - 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 215, 215, 215, 215, 215, 215, 18, 18, 18, 17, 17, 17, 208, 208, 208, 222, 222, 222, 220, 220, 220, 220, 220, 220, 220, 220, 220, - 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 219, 219, 219, 220, 220, 220, 220, 220, 220, 220, 220, 220, 219, 219, 219, 220, 220, 220, 220, 220, 220, 220, 220, 220, 219, 219, 219, 219, 219, 219, 220, 220, 220, - 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 219, 219, 219, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 215, 215, 215, 215, 215, 215, 18, 18, 18, - 17, 17, 17, 208, 208, 208, 222, 222, 222, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 223, 223, 223, 220, 220, 220, 219, 219, 219, 219, 219, 219, 226, 226, 226, - 220, 220, 220, 218, 218, 218, 221, 221, 221, 223, 223, 223, 225, 225, 225, 218, 218, 218, 217, 217, 217, 221, 221, 221, 222, 222, 222, 219, 219, 219, 226, 226, 226, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, - 220, 220, 220, 220, 220, 220, 220, 220, 220, 215, 215, 215, 215, 215, 215, 18, 18, 18, 17, 17, 17, 208, 208, 208, 222, 222, 222, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 219, 219, 219, - 225, 225, 225, 184, 184, 184, 207, 207, 207, 209, 209, 209, 215, 215, 215, 165, 165, 165, 203, 203, 203, 224, 224, 224, 210, 210, 210, 182, 182, 182, 174, 174, 174, 222, 222, 222, 223, 223, 223, 203, 203, 203, 195, 195, 195, 213, 213, 213, 166, 166, 166, 217, 217, 217, 219, 219, 219, 220, 220, 220, 220, 220, 220, - 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 215, 215, 215, 215, 215, 215, 18, 18, 18, 17, 17, 17, 208, 208, 208, 222, 222, 222, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, - 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 218, 218, 218, 232, 232, 232, 127, 127, 127, 164, 164, 164, 126, 126, 126, 145, 145, 145, 148, 148, 148, 141, 141, 141, 140, 140, 140, 218, 218, 218, 105, 105, 105, 137, 137, 137, 146, 146, 146, 129, 129, 129, 149, 149, 149, 152, 152, 152, - 142, 142, 142, 145, 145, 145, 214, 214, 214, 219, 219, 219, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 215, 215, 215, 215, 215, 215, 18, 18, 18, 17, 17, 17, 208, 208, 208, 222, 222, 222, - 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 219, 219, 219, 225, 225, 225, 187, 187, 187, 213, 213, 213, 166, 166, 166, 194, 194, 194, 182, 182, 182, 182, 182, 182, 181, 181, 181, 217, 217, 217, - 178, 178, 178, 190, 190, 190, 184, 184, 184, 176, 176, 176, 199, 199, 199, 184, 184, 184, 187, 187, 187, 192, 192, 192, 219, 219, 219, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, - 215, 215, 215, 215, 215, 215, 18, 18, 18, 17, 17, 17, 208, 208, 208, 222, 222, 222, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 221, 221, 221, 220, 220, 220, - 221, 221, 221, 221, 221, 221, 222, 222, 222, 220, 220, 220, 222, 222, 222, 220, 220, 220, 223, 223, 223, 221, 221, 221, 222, 222, 222, 221, 221, 221, 221, 221, 221, 222, 222, 222, 219, 219, 219, 221, 221, 221, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, - 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 215, 215, 215, 215, 215, 215, 18, 18, 18, 17, 17, 17, 208, 208, 208, 222, 222, 222, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, - 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, - 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 215, 215, 215, 215, 215, 215, 18, 18, 18, 17, 17, 17, 208, 208, 208, 222, 222, 222, 219, 219, 219, 219, 219, 219, 219, 219, 219, - 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, - 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 214, 214, 214, 215, 215, 215, 18, 18, 18, - 17, 17, 17, 206, 206, 206, 219, 219, 219, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, - 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, - 217, 217, 217, 217, 217, 217, 217, 217, 217, 212, 212, 212, 213, 213, 213, 19, 19, 19, 14, 14, 14, 177, 177, 177, 194, 194, 194, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, - 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, - 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 187, 187, 187, 187, 187, 187, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}; -const char* DemoArtwork::ico5Data = (const char*)temp_ico5_5; - diff --git a/dpf/tests/demo_res/DemoArtwork.hpp b/dpf/tests/demo_res/DemoArtwork.hpp deleted file mode 100644 index 2a00e2f..0000000 --- a/dpf/tests/demo_res/DemoArtwork.hpp +++ /dev/null @@ -1,35 +0,0 @@ -/* (Auto-generated binary data file). */ - -#ifndef BINARY_DEMOARTWORK_HPP -#define BINARY_DEMOARTWORK_HPP - -namespace DemoArtwork -{ - extern const char* ico1Data; - const unsigned int ico1DataSize = 6912; - const unsigned int ico1Width = 48; - const unsigned int ico1Height = 48; - - extern const char* ico2Data; - const unsigned int ico2DataSize = 6912; - const unsigned int ico2Width = 48; - const unsigned int ico2Height = 48; - - extern const char* ico3Data; - const unsigned int ico3DataSize = 6912; - const unsigned int ico3Width = 48; - const unsigned int ico3Height = 48; - - extern const char* ico4Data; - const unsigned int ico4DataSize = 6912; - const unsigned int ico4Width = 48; - const unsigned int ico4Height = 48; - - extern const char* ico5Data; - const unsigned int ico5DataSize = 6912; - const unsigned int ico5Width = 48; - const unsigned int ico5Height = 48; -} - -#endif // BINARY_DEMOARTWORK_HPP - diff --git a/dpf/tests/demo_res/ico1.png b/dpf/tests/demo_res/ico1.png deleted file mode 100644 index d8a00bf344f4886c71fc5faa8168ab6919fd699b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 259 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1SD@H&O4_(A8i#7&u~1LH1WS|^)C-6e*f@LNzKVTVh#;;?3;dVUbR%^Z(U1A(LA9- z@f1zn-+7khpG3YV-|qT7ne%DR=R1Ywy&sFOG%zqSv2X||I6xT-!Y^moE3Jw>8Lj#5 tYLSP_mV3edVG&>F3ApoeTxj3PFn_<=-F00SsX(_ec)I$ztaD0e0ss&wTVntK diff --git a/dpf/tests/demo_res/ico2.png b/dpf/tests/demo_res/ico2.png deleted file mode 100644 index 9f22da6d62eda56f353126c5d674ec27a3933c9f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3462 zcmV;14SDj3P)^wN?`y14HHR3 zK~z}7?U-3_UDtKT*B;J%&z&!MIbKmBsezO=+p-i-jq9X?oy3Jv1V)1beQv)&`vv;a zr@RzsP`iPVxM^${uB{+(Yu9#MCsHh%q8O2sD9*#3&%DPzNG+n&Y-K$ah5ru+*!yMw zu-1RAz0U&pQeW!-nb2=8Fd|32nY>XZm>ASBiD_ZeASR_Gk+Cjhx7Rk}BvGIMG(rd? zOc2HtRfqjk4? z`oDB{S1M_j@S|Tl`rM0;HKuCV&`L?Eq!3(aPHkMN`HoE`XHp6ch*IL(jzvkFg&50{ z?>R03(DxG|`de!aT7d#UN-0G&!U$o+H5W;|G{5-NbC1oQo?e){`Rlox{Z2SGFk=9?@_3Vva-F)ebgn7i(nU}#P$(f7sk-++|X8kExbPN1YzNQ+dY zQ5NST>(h@vI{V}k7oIwO;mI?$r z&$d)1d#x=iUm86y<+xt4HZ*Z~^84R^rPXeK;glhC=c_d+1y~~>gdhMgFr`+pGJNpJ zA=mfwg~IyE4Jm{anU^n9J6Ed|DN+N210qR-b|-4}Z!IleNJ8884AZPshaJy(AX94% z2s8j-Kp2#gG;fs#{n4p`V`ryECI;M`C8bp_i`YWmXhCE-E6ix?_7HQ+=a(0^#%ZckUoSEOwEq` z*`Gf@Ha;v^8i!rMGAShEncz$*xxLd|-%A!3R~|ig%=6sco!y%o+Y7I}jqK{l$u-L| z4jw*Mt`3ejCSG`9px0?(moZ`!e)`1Z$x|mC*QJ8n)-U&Z5s#YJ7MhiEL27+uhT3ipVOp#VSe9)&9;F5V zeh?2KgeuhvCYZA2JY*vyg9UbmaZ zJ&JRt?V3(*bNzO8XxuO@*KtkTvAsN|CV*1vfjo4lA1bLaF@c&Q*zjb$e~`#`SKujj2J1NlZrrmP&KZ9w=o9 z0{|wNARLC>DC}cI4Abs+11@13%j}CU)d!NqD2SLADDRT~(7>;9S5c>IimhmWN zT*_R&N^DOEskN3;Jo(ks7hl^4NP`rNXNeM$O97xU zrb38rx67FDip6%j?dQv5BNZWv+q-+e*xeo)ZE&6mDIL!(S1Ptmi>0z(C={!sQUT|J zagH(0xctu7r*AKpZmym%_6(7wH0dyw&@@nz!+t;-fHTH8V}i$VpaBVyNzN_Xv3uB(C6cWQ$I%_nBHyF&Y?}sMM+mbeyJEoM=oO*H>C<4V6kQk;Qro z{5{23zyKMR4_Yh1|A&-ugt%l8Nane=jEPNDD~oKC^rN;(k>^mxBF-h3C=&{>fwjz7 zkk1$5EV4{HVM)8WmCyU_Ru?dMxjYxlv`i^kp*pDa-b^+4`AxHBJA%0SP93pqUm!_O z{^(Nk-A{IO}h?W3jefO<~01yBIL@}zDkT=NP1CQg1yRkxttj@=UK+JR5fMz{eN$#QirPR7ASM_T5rPOHiZmvGh{go* z*yCN{4B1#8s*HqNXIF3ZyJB#MbA=)ac-q|9Fm?kYO;gPIP!Ppja+6xc0xx(2m3pme zw@}19?WC?3U`I%aHQV1qm;fa}4P;QD)Hd;u0VaVSp?zdzm_o4nSoT4~&K1LX4%=}d zl!B*GXhT}WDF?*09OtjJl$mYLtlze4Nkl2>HP;;zO7hIW;Zx^M55N81>zi}iqIi&} zOobhiEAJ0PG+>2@1`5PLLhB=kr?1b?FR!ej zyM?k3&@+#ou6T6o>eXT0>3n1I8$$@%Ya0tom9fgjXHPcx+=bE3F#FX^{_^5#7;&|< zCbSaE+nr7%b`ri3>ooy4xo)z~AAbGJ>C;E0gn$3ucfI+`*2pj|lo1Gosgg`E?&sWh z|Lwy#$$ZaYTzvlJT8P87Uwm54n}#W-Zm#_NohxxSJbI$&((UEF&U=gKr8j~b-2);+ zMH_qy-3)%YqTg@Ar!iTG(4NLUjVyyWkYv4$puNqr;M}+Wv{M;&Mh`H~d75e#^DG0< z)oNwt$dqfDfAYfb?;D{;zRI!y>83$tuC+PrZ2!TT;#3vbZp%CN=!c&qtdDPHwM^Py z8EgOZ<<>@9cQRbbnNsSqg@!#$wYCU2T20Oz9U2)}ygvWVPkv&JPYgB=Dy6g%it{9m z!zd1dpjs(C`pD_udGg}RKY0D~fu5K;l6URP%dC@G1;cx|v1P*EXAA3Fo1J(6@wG`o zMWhbuodb5j!}(8FqE3t~gVa5or%=mb$Ap3jyRjx(l?H388|x;)Nt�Zsv={a;anx z62@^DMoFAx86O-RIDB}DVDxt{zxw%Ac5UfuoB>br7;8q^(w6Ro(PlHkC=yUy>0bJH z#}%3VSKr#%X|ZMuT4~pk6`wTw8ZamgmI+d-fWvOLJ4(ka*QpE+Oqa?z*9pUZLTEqe zCvlP_8Rwa4nNmr4@7wkspe)HEW?LrrO(Zp5-l2P4tCI6vyVm8&&u%QG*0J+bjeoiF z>p1DVba0qH8I#D_RtO-GI=Unuk$LqT@DA0Fy?+kt7IN9et#8OT&&#);d6A413 zNhsF5;CkIKR_QJi+4UZ24CWexg@KYWRPbkqtX9Cby6HxjwL%qSnjk<3NiKe~m>+P) z_}mE2*~m1I?~uG>*d{e7ScZYIF}K!p%`8l`NfAccF)_yAScG8gSR{xi?ep10F6-Z3PZF&Dmd<%}2c+S$jxrEQNP4DgHgbyFKcpTRM@rC8l zV^6tx@!a9gPyQ>q-)H{y=ODj+O=#XiFX#9Dl@DK~ZdTLU*70UH?}GF1cfIZE-xm4m zQO>SfzKIgaJYB*m+YhNcSzp-Hq~Wae-S)F2TZ#h+nUpV(VG+DIp|c@I{MDb_a{|6G z4nbd)C)w_bs=SkLKc(lr=dXz&=RLxV!eXZUoEIE$<=OSAsy{ERyB!vD>zVI+^8;00 z@?PJhKPxgDDS*(dnf$81&u+0R`7mEK`RTkZzaIKCu8cLD%Fmg&#AdOWN!z4CC;469 z+oSf{U!AkoKIQ!cMoAF*c|qRJWdA<_;d=kS3|_J;{w#IT^#=wegQu&X%Q~loCIFI# BtOWo7 diff --git a/dpf/tests/demo_res/ico4.png b/dpf/tests/demo_res/ico4.png deleted file mode 100644 index 79998963f89e4162527f4669b8d82675970893fd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1355 zcmV-R1+@B!P)vW1lUPL zK~z}7&6!JY6G;%qyLujOXFMhWnb10;m-ouKtV0N^>c z=hy&nEP$wGr83!6CQB`A|96x3e+vmiW~zV?`sc4dkAsE8M4?D6i(1x1p@@)ZB@h6( zHZ@}12nmFQ5$kqsx=&Bq7m#IEGL!ibA=S$eA(_d%WmZ}Sq-k0*o#mYS*)^HYYMRzE zpi8My$FVohIF5ZOHQE9o0H~C{Cz7e1KP8f>O6hyko`jpuJ%wAdl2jvWNRnK*HQRJf zY7$6~>hZn--+Q(l-SNHwJ*poa5N9mj+h2c8ytkh>B_Emq0&}f2I+?G(Xmm1fu9Xmi zLkIF)`}&=^hP&sCUB5Hux%S}#0RSQ7j1jBpJ=;9#j1eP*>^0o>2ISbZr++|E)gX%% zRqg2?aBO;rK+JQq`C>pVCWOf5i_CKm3rKKYxH)UnJtP>LT7{dlqS5r|-UA=rzNVH%!eJr!R!8O} z9Hy4_;q7ZbD^hBuv(pC#1OQg09Pdl47j@pdS1&@L2KEny!tY+aV9fjfBJ4g|2LKd_>it6_Rqs(0b$Q{V zBuRm)5lLEJ_^2pq)sy;%Mj`t4VH58M$Zl0yZ*}DhZODN9XwJB{12tbQyMyzM^ z!G8Lzu~zyK{PAn0AE(b6n(L?_+TBRI0(p)T@4YC=TT{6}MyxwHkP++NR?14U z9Php8t>^JQ0NK>c=4ZC~pzAv6+;qU!7Go@(n|57ihXk0hskt{G#=PR~dyZ}I3_2rr z0Rw87;s5{xGGZ5YhLvO6#oPBbBDWzB0LYTub>5R>t=BEjJyBnNu5rJO2UbuWX;+Q*X;L< zPhYFAsx)1H@c3COGv+!J1LmA@&M;utp{dN+gU8P_U9Ye8#;31I7=q{_F;OU50qRcI zaYn|clIiSDf#&WWL>mIjvL*_}#rfa2l}dQ`eor7#i!s*pX#2@i?I%xZdK641|FNzx4FiQ2W1;$vZRAS6C%Vo}wu7i%Tr0G$C zP-kc7mQKDO(t3LbI`VO>JNfdu>2N3%Y8Axh3@rQc)z;S5Lc{n>{{e^BKJR0XhTH%E N002ovPDHLkV1nl&fJ^`Y diff --git a/dpf/tests/demo_res/ico5.png b/dpf/tests/demo_res/ico5.png deleted file mode 100644 index dc85b73d340df1761ae55057cbd83efafbd8982e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 539 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

*HDNGkYRZA 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 diff --git a/dpf/tests/images_res/cat2.png b/dpf/tests/images_res/cat2.png deleted file mode 100644 index c28be1ffa037aff87871009bb225b4e598646f2b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 70352 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 FV1o5oi@E>+ diff --git a/dpf/tests/images_res/cat3.png b/dpf/tests/images_res/cat3.png deleted file mode 100644 index 6fe01b3f3e02d667802322f3875e6e91e5cb8bba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 64331 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 diff --git a/dpf/tests/tests.hpp b/dpf/tests/tests.hpp deleted file mode 100644 index 334dd1f..0000000 --- a/dpf/tests/tests.hpp +++ /dev/null @@ -1,59 +0,0 @@ -/* - * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho - * - * Permission to use, copy, modify, and/or distribute this software for any purpose with - * or without fee is hereby granted, provided that the above copyright notice and this - * permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD - * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "dgl/Application.hpp" - -#include "distrho/extra/Thread.hpp" - -#define DISTRHO_ASSERT_EQUAL(v1, v2, msg) \ - if (v1 != v2) { d_stderr2("Test condition failed: %s; file:%s line:%i", msg, __FILE__, __LINE__); return 1; } - -#define DISTRHO_ASSERT_NOT_EQUAL(v1, v2, msg) \ - if (v1 == v2) { d_stderr2("Test condition failed: %s; file:%s line:%i", msg, __FILE__, __LINE__); return 1; } - -#define DISTRHO_ASSERT_SAFE_EQUAL(v1, v2, msg) \ - if (d_isNotEqual(v1, v2)) { d_stderr2("Test condition failed: %s; file:%s line:%i", msg, __FILE__, __LINE__); return 1; } - -START_NAMESPACE_DGL - -// -------------------------------------------------------------------------------------------------------------------- - -class ApplicationQuitter : public Thread -{ - Application& app; - const int numSecondsToWait; - -public: - ApplicationQuitter(Application& a, const int s = 2) - : Thread("ApplicationQuitter"), - app(a), - numSecondsToWait(s) - { - startThread(); - } - -private: - void run() override - { - d_sleep(numSecondsToWait); - d_stdout("About to quit now..."); - app.quit(); - } -}; - -// -------------------------------------------------------------------------------------------------------------------- - -END_NAMESPACE_DGL diff --git a/dpf/tests/widgets/ExampleColorWidget.hpp b/dpf/tests/widgets/ExampleColorWidget.hpp deleted file mode 100644 index ace7200..0000000 --- a/dpf/tests/widgets/ExampleColorWidget.hpp +++ /dev/null @@ -1,179 +0,0 @@ -/* - * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho - * - * Permission to use, copy, modify, and/or distribute this software for any purpose with - * or without fee is hereby granted, provided that the above copyright notice and this - * permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD - * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef EXAMPLE_COLOR_WIDGET_HPP_INCLUDED -#define EXAMPLE_COLOR_WIDGET_HPP_INCLUDED - -// ------------------------------------------------------ -// DGL Stuff - -#include "../../dgl/Color.hpp" -#include "../../dgl/StandaloneWindow.hpp" -#include "../../dgl/SubWidget.hpp" - -START_NAMESPACE_DGL - -// ------------------------------------------------------ -// our widget - -template -class ExampleColorWidget : public BaseWidget, - public IdleCallback -{ - char cur; - bool reverse; - int r, g, b; - - Rectangle bgFull, bgSmall; - -public: - static constexpr const char* kExampleWidgetName = "Color"; - - // SubWidget - explicit ExampleColorWidget(Widget* const parent); - - // TopLevelWidget - explicit ExampleColorWidget(Window& windowToMapTo); - - // StandaloneWindow - explicit ExampleColorWidget(Application& app); - -protected: - void idleCallback() noexcept override - { - switch (cur) - { - case 'r': - if (reverse) - { - if (--r == 0) - cur = 'g'; - } - else - { - if (++r == 100) - cur = 'g'; - } - break; - - case 'g': - if (reverse) - { - if (--g == 0) - cur = 'b'; - } - else - { - if (++g == 100) - cur = 'b'; - } - break; - - case 'b': - if (reverse) - { - if (--b == 0) - { - cur = 'r'; - reverse = false; - } - } - else - { - if (++b == 100) - { - cur = 'r'; - reverse = true; - } - } - break; - } - - BaseWidget::repaint(); - } - - void onDisplay() override - { - const GraphicsContext& context(BaseWidget::getGraphicsContext()); - - // paint bg color (in full size) - Color(r, g, b).setFor(context); - bgFull.draw(context); - - // paint inverted color (in 2/3 size) - Color(100-r, 100-g, 100-b).setFor(context); - bgSmall.draw(context); - } - - void onResize(const Widget::ResizeEvent& ev) override - { - const uint width = ev.size.getWidth(); - const uint height = ev.size.getHeight(); - - // full bg - bgFull = Rectangle(0, 0, width, height); - - // small bg, centered 2/3 size - bgSmall = Rectangle(width/6, height/6, width*2/3, height*2/3); - } -}; - -// SubWidget -template<> inline -ExampleColorWidget::ExampleColorWidget(Widget* const parent) - : SubWidget(parent), - cur('r'), - reverse(false), - r(0), g(0), b(0) -{ - setSize(300, 300); - parent->getApp().addIdleCallback(this); -} - -// TopLevelWidget -template<> inline -ExampleColorWidget::ExampleColorWidget(Window& windowToMapTo) - : TopLevelWidget(windowToMapTo), - cur('r'), - reverse(false), - r(0), g(0), b(0) -{ - setSize(300, 300); - addIdleCallback(this); -} - -// StandaloneWindow -template<> inline -ExampleColorWidget::ExampleColorWidget(Application& app) - : StandaloneWindow(app), - cur('r'), - reverse(false), - r(0), g(0), b(0) -{ - setSize(300, 300); - addIdleCallback(this); - done(); -} - -typedef ExampleColorWidget ExampleColorSubWidget; -typedef ExampleColorWidget ExampleColorTopLevelWidget; -typedef ExampleColorWidget ExampleColorStandaloneWindow; - -// ------------------------------------------------------ - -END_NAMESPACE_DGL - -#endif // EXAMPLE_COLOR_WIDGET_HPP_INCLUDED diff --git a/dpf/tests/widgets/ExampleImagesWidget.hpp b/dpf/tests/widgets/ExampleImagesWidget.hpp deleted file mode 100644 index 106e1a7..0000000 --- a/dpf/tests/widgets/ExampleImagesWidget.hpp +++ /dev/null @@ -1,215 +0,0 @@ -/* - * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho - * - * Permission to use, copy, modify, and/or distribute this software for any purpose with - * or without fee is hereby granted, provided that the above copyright notice and this - * permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD - * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef EXAMPLE_IMAGES_WIDGET_HPP_INCLUDED -#define EXAMPLE_IMAGES_WIDGET_HPP_INCLUDED - -// ------------------------------------------------------ -// DGL Stuff - -#include "../../dgl/ImageBase.hpp" -#include "../../dgl/StandaloneWindow.hpp" -#include "../../dgl/SubWidget.hpp" - -// ------------------------------------------------------ -// Images - -#include "../images_res/CatPics.hpp" - -START_NAMESPACE_DGL - -// ------------------------------------------------------ -// our widget - -template -class ExampleImagesWidget : public BaseWidget, - public IdleCallback -{ - static const int kImg1y = 0; - static const int kImg2y = 500/2-CatPics::cat2Height/2; - static const int kImg3x = 400/3-CatPics::cat3Width/3; - - static const int kImg1max = 500-CatPics::cat1Width; - static const int kImg2max = 500-CatPics::cat2Width; - static const int kImg3max = 400-CatPics::cat3Height; - - int imgTop1st, imgTop2nd, imgTop3rd; - int img1x, img2x, img3y; - bool img1rev, img2rev, img3rev; - BaseImage img1, img2, img3; - -public: - static constexpr const char* kExampleWidgetName = "Images"; - - // SubWidget - explicit ExampleImagesWidget(Widget* const parent); - - // TopLevelWidget - explicit ExampleImagesWidget(Window& windowToMapTo); - - // StandaloneWindow - explicit ExampleImagesWidget(Application& app); - -protected: - void init(Application& app) - { - imgTop1st = 1; - imgTop2nd = 2; - imgTop3rd = 3; - img1x = 0; - img2x = kImg2max; - img3y = kImg3max; - img1rev = false; - img2rev = true; - img3rev = true; - img1 = BaseImage(CatPics::cat1Data, CatPics::cat1Width, CatPics::cat1Height, kImageFormatBGR); - img2 = BaseImage(CatPics::cat2Data, CatPics::cat2Width, CatPics::cat2Height, kImageFormatBGR); - img3 = BaseImage(CatPics::cat3Data, CatPics::cat3Width, CatPics::cat3Height, kImageFormatBGR); - - BaseWidget::setSize(500, 400); - app.addIdleCallback(this); - } - - void idleCallback() noexcept override - { - if (img1rev) - { - img1x -= 2; - if (img1x <= -50) - { - img1rev = false; - setNewTopImg(1); - } - } - else - { - img1x += 2; - if (img1x >= kImg1max+50) - { - img1rev = true; - setNewTopImg(1); - } - } - - if (img2rev) - { - img2x -= 1; - if (img2x <= -50) - { - img2rev = false; - setNewTopImg(2); - } - } - else - { - img2x += 4; - if (img2x >= kImg2max+50) - { - img2rev = true; - setNewTopImg(2); - } - } - - if (img3rev) - { - img3y -= 3; - if (img3y <= -50) - { - img3rev = false; - setNewTopImg(3); - } - } - else - { - img3y += 3; - if (img3y >= kImg3max+50) - { - img3rev = true; - setNewTopImg(3); - } - } - - BaseWidget::repaint(); - } - - void onDisplay() override - { - const GraphicsContext& context(BaseWidget::getGraphicsContext()); - - switch (imgTop3rd) - { - case 1: - img1.drawAt(context, img1x, kImg1y); - break; - case 2: - img2.drawAt(context, img2x, kImg2y); - break; - case 3: - img3.drawAt(context, kImg3x, img3y); - break; - }; - - switch (imgTop2nd) - { - case 1: - img1.drawAt(context, img1x, kImg1y); - break; - case 2: - img2.drawAt(context, img2x, kImg2y); - break; - case 3: - img3.drawAt(context, kImg3x, img3y); - break; - }; - - switch (imgTop1st) - { - case 1: - img1.drawAt(context, img1x, kImg1y); - break; - case 2: - img2.drawAt(context, img2x, kImg2y); - break; - case 3: - img3.drawAt(context, kImg3x, img3y); - break; - }; - } - -private: - void setNewTopImg(const int imgId) noexcept - { - if (imgTop1st == imgId) - return; - - if (imgTop2nd == imgId) - { - imgTop2nd = imgTop1st; - imgTop1st = imgId; - return; - } - - imgTop3rd = imgTop2nd; - imgTop2nd = imgTop1st; - imgTop1st = imgId; - } -}; - -// ------------------------------------------------------ - -END_NAMESPACE_DGL - -#endif // EXAMPLE_IMAGES_WIDGET_HPP_INCLUDED diff --git a/dpf/tests/widgets/ExampleRectanglesWidget.hpp b/dpf/tests/widgets/ExampleRectanglesWidget.hpp deleted file mode 100644 index d9ac329..0000000 --- a/dpf/tests/widgets/ExampleRectanglesWidget.hpp +++ /dev/null @@ -1,193 +0,0 @@ -/* - * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho - * - * Permission to use, copy, modify, and/or distribute this software for any purpose with - * or without fee is hereby granted, provided that the above copyright notice and this - * permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD - * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef EXAMPLE_RECTANGLES_WIDGET_HPP_INCLUDED -#define EXAMPLE_RECTANGLES_WIDGET_HPP_INCLUDED - -// ------------------------------------------------------ -// DGL Stuff - -#include "../../dgl/Color.hpp" -#include "../../dgl/StandaloneWindow.hpp" -#include "../../dgl/SubWidget.hpp" - -START_NAMESPACE_DGL - -// ------------------------------------------------------ -// our widget - -template -class ExampleRectanglesWidget : public BaseWidget -{ - bool clicked[9]; - -public: - static constexpr const char* const kExampleWidgetName = "Rectangles"; - - // SubWidget - explicit ExampleRectanglesWidget(Widget* const parent); - - // TopLevelWidget - explicit ExampleRectanglesWidget(Window& windowToMapTo); - - // StandaloneWindow - explicit ExampleRectanglesWidget(Application& app); - - void init() - { - BaseWidget::setSize(300, 300); - - for (int i=0; i<9; ++i) - clicked[i] = false; - } - -protected: - void onDisplay() override - { - const GraphicsContext& context(BaseWidget::getGraphicsContext()); - - const uint width = BaseWidget::getWidth(); - const uint height = BaseWidget::getHeight(); - - Rectangle r; - - r.setWidth(width/3 - 6); - r.setHeight(height/3 - 6); - - // draw a 3x3 grid - for (int i=0; i<3; ++i) - { - r.setX(3 + i*width/3); - - // 1st - r.setY(3); - - if (clicked[0+i]) - Color(0.8f, 0.5f, 0.3f).setFor(context); - else - Color(0.3f, 0.5f, 0.8f).setFor(context); - - r.draw(context); - - // 2nd - r.setY(3 + height/3); - - if (clicked[3+i]) - Color(0.8f, 0.5f, 0.3f).setFor(context); - else - Color(0.3f, 0.5f, 0.8f).setFor(context); - - r.draw(context); - - // 3rd - r.setY(3 + height*2/3); - - if (clicked[6+i]) - Color(0.8f, 0.5f, 0.3f).setFor(context); - else - Color(0.3f, 0.5f, 0.8f).setFor(context); - - r.draw(context); - } - } - - bool onMouse(const Widget::MouseEvent& ev) override - { - if (ev.button != 1 || ! ev.press) - return false; - - const uint width = BaseWidget::getWidth(); - const uint height = BaseWidget::getHeight(); - - Rectangle r; - - r.setWidth(width/3 - 6); - r.setHeight(height/3 - 6); - - // draw a 3x3 grid - for (int i=0; i<3; ++i) - { - r.setX(3 + i*width/3); - - // 1st - r.setY(3); - - if (r.contains(ev.pos)) - { - clicked[0+i] = !clicked[0+i]; - BaseWidget::repaint(); - break; - } - - // 2nd - r.setY(3 + height/3); - - if (r.contains(ev.pos)) - { - clicked[3+i] = !clicked[3+i]; - BaseWidget::repaint(); - break; - } - - // 3rd - r.setY(3 + height*2/3); - - if (r.contains(ev.pos)) - { - clicked[6+i] = !clicked[6+i]; - BaseWidget::repaint(); - break; - } - } - - return true; - } -}; - -// SubWidget -template<> inline -ExampleRectanglesWidget::ExampleRectanglesWidget(Widget* const parentWidget) - : SubWidget(parentWidget) -{ - init(); -} - -// TopLevelWidget -template<> inline -ExampleRectanglesWidget::ExampleRectanglesWidget(Window& windowToMapTo) - : TopLevelWidget(windowToMapTo) -{ - init(); -} - -// StandaloneWindow -template<> inline -ExampleRectanglesWidget::ExampleRectanglesWidget(Application& app) - : StandaloneWindow(app) -{ - init(); - done(); -} - -typedef ExampleRectanglesWidget ExampleRectanglesSubWidget; -typedef ExampleRectanglesWidget ExampleRectanglesTopLevelWidget; -typedef ExampleRectanglesWidget ExampleRectanglesStandaloneWindow; - -// ------------------------------------------------------ - -END_NAMESPACE_DGL - -#endif // EXAMPLE_RECTANGLES_WIDGET_HPP_INCLUDED diff --git a/dpf/tests/widgets/ExampleShapesWidget.hpp b/dpf/tests/widgets/ExampleShapesWidget.hpp deleted file mode 100644 index c175103..0000000 --- a/dpf/tests/widgets/ExampleShapesWidget.hpp +++ /dev/null @@ -1,131 +0,0 @@ -/* - * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho - * - * Permission to use, copy, modify, and/or distribute this software for any purpose with - * or without fee is hereby granted, provided that the above copyright notice and this - * permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD - * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef EXAMPLE_SHAPES_WIDGET_HPP_INCLUDED -#define EXAMPLE_SHAPES_WIDGET_HPP_INCLUDED - -// ------------------------------------------------------ -// DGL Stuff - -#include "../../dgl/Color.hpp" -#include "../../dgl/StandaloneWindow.hpp" -#include "../../dgl/SubWidget.hpp" - -START_NAMESPACE_DGL - -// ------------------------------------------------------ -// our widget - -template -class ExampleShapesWidget : public BaseWidget -{ - Rectangle bg; - Rectangle rect; - Triangle tri; - Circle cir; - -public: - static constexpr const char* const kExampleWidgetName = "Shapes"; - - // SubWidget - explicit ExampleShapesWidget(Widget* const parent); - - // TopLevelWidget - explicit ExampleShapesWidget(Window& windowToMapTo); - - // StandaloneWindow - explicit ExampleShapesWidget(Application& app); - -protected: - void onDisplay() override - { - const GraphicsContext& context(BaseWidget::getGraphicsContext()); - - Color(0.302f, 0.337f, 0.361f).setFor(context);; - bg.draw(context); - - Color(0.235f, 0.271f, 0.294f).setFor(context); - rect.draw(context); - - Color(0.176f, 0.212f, 0.235f).setFor(context); - rect.drawOutline(context, 1); - - Color(0.302f*2, 0.337f*2, 0.361f*2).setFor(context); - tri.draw(context); - - Color(0.302f/2.0f, 0.337f/2.0f, 0.361f/2.0f).setFor(context); - tri.drawOutline(context, 3); - - Color(0.235f, 0.271f, 0.294f).setFor(context); - cir.draw(context); - - Color(0.176f/4, 0.212f/4, 0.235f/4).setFor(context); - cir.drawOutline(context, 2); - } - - void onResize(const Widget::ResizeEvent& ev) override - { - const int width = ev.size.getWidth(); - const int height = ev.size.getHeight(); - - // background - bg = Rectangle(0, 0, width, height); - - // rectangle - rect = Rectangle(20, 10, width-40, height-20); - - // center triangle - tri = Triangle(width*0.5, height*0.1, width*0.1, height*0.9, width*0.9, height*0.9); - - // circle - cir = Circle(width/2, height*2/3, height/6, 300); - } -}; - -// SubWidget -template<> inline -ExampleShapesWidget::ExampleShapesWidget(Widget* const parentWidget) - : SubWidget(parentWidget) -{ - setSize(300, 300); -} - -// TopLevelWidget -template<> inline -ExampleShapesWidget::ExampleShapesWidget(Window& windowToMapTo) - : TopLevelWidget(windowToMapTo) -{ - setSize(300, 300); -} - -// StandaloneWindow -template<> inline -ExampleShapesWidget::ExampleShapesWidget(Application& app) - : StandaloneWindow(app) -{ - setSize(300, 300); - done(); -} - -typedef ExampleShapesWidget ExampleShapesSubWidget; -typedef ExampleShapesWidget ExampleShapesTopLevelWidget; -typedef ExampleShapesWidget ExampleShapesStandaloneWindow; - -// ------------------------------------------------------ - -END_NAMESPACE_DGL - -#endif // EXAMPLE_SHAPES_WIDGET_HPP_INCLUDED diff --git a/dpf/tests/widgets/ExampleTextWidget.hpp b/dpf/tests/widgets/ExampleTextWidget.hpp deleted file mode 100644 index 60faae2..0000000 --- a/dpf/tests/widgets/ExampleTextWidget.hpp +++ /dev/null @@ -1,128 +0,0 @@ -/* - * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho - * - * Permission to use, copy, modify, and/or distribute this software for any purpose with - * or without fee is hereby granted, provided that the above copyright notice and this - * permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD - * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef EXAMPLE_TEXT_WIDGET_HPP_INCLUDED -#define EXAMPLE_TEXT_WIDGET_HPP_INCLUDED - -// ------------------------------------------------------ -// DGL Stuff - -#include "../../dgl/NanoVG.hpp" - -START_NAMESPACE_DGL - -// ------------------------------------------------------ -// our widget - -template -class ExampleTextWidget : public BaseWidget -{ -public: - static constexpr const char* kExampleWidgetName = "Text"; - - // SubWidget - explicit ExampleTextWidget(Widget* const parent); - - // TopLevelWidget - explicit ExampleTextWidget(Window& windowToMapTo); - - // StandaloneWindow - explicit ExampleTextWidget(Application& app); - - // helper - double getScaleFactor(); - -protected: - void onNanoDisplay() override - { - const int width = BaseWidget::getWidth(); - const int height = BaseWidget::getHeight(); - const double scaleFactor = getScaleFactor(); - - NanoVG::fontSize(40.0f * scaleFactor); - NanoVG::textAlign(NanoVG::Align(NanoVG::ALIGN_CENTER|NanoVG::ALIGN_MIDDLE)); - NanoVG::textLineHeight(20.0f * scaleFactor); - - NanoVG::beginPath(); - NanoVG::fillColor(220,220,220,255); - NanoVG::roundedRect(10 * scaleFactor, height/4 + 10 * scaleFactor, - width - 20 * scaleFactor, height/2 - 20 * scaleFactor, 3 * scaleFactor); - NanoVG::fill(); - - NanoVG::fillColor(0,150,0,220); - NanoVG::textBox(10 * scaleFactor, height/2, width - 20 * scaleFactor, "Hello World!", nullptr); - } -}; - -// SubWidget -template<> inline -ExampleTextWidget::ExampleTextWidget(Widget* const parent) - : NanoSubWidget(parent) -{ - loadSharedResources(); - setSize(500, 300); -} - -template<> inline -double ExampleTextWidget::getScaleFactor() -{ - return getWindow().getScaleFactor(); -} - -// TopLevelWidget -template<> inline -ExampleTextWidget::ExampleTextWidget(Window& windowToMapTo) - : NanoTopLevelWidget(windowToMapTo) -{ - loadSharedResources(); - setSize(500, 300); -} - -template<> inline -double ExampleTextWidget::getScaleFactor() -{ - return NanoTopLevelWidget::getScaleFactor(); -} - -// StandaloneWindow -template<> inline -ExampleTextWidget::ExampleTextWidget(Application& app) - : NanoStandaloneWindow(app) -{ - loadSharedResources(); - setSize(500, 300); - done(); -} - -template<> inline -double ExampleTextWidget::getScaleFactor() -{ - return Window::getScaleFactor(); -} - -template class ExampleTextWidget; -template class ExampleTextWidget; -template class ExampleTextWidget; - -typedef ExampleTextWidget ExampleTextSubWidget; -typedef ExampleTextWidget ExampleTextTopLevelWidget; -typedef ExampleTextWidget ExampleTextStandaloneWindow; - -// ------------------------------------------------------ - -END_NAMESPACE_DGL - -#endif // EXAMPLE_TEXT_WIDGET_HPP_INCLUDED diff --git a/dpf/tests/widgets/NanoPerfWidget.hpp b/dpf/tests/widgets/NanoPerfWidget.hpp deleted file mode 100644 index 6fb404a..0000000 --- a/dpf/tests/widgets/NanoPerfWidget.hpp +++ /dev/null @@ -1,240 +0,0 @@ -/* - * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2015 Filipe Coelho - * - * Permission to use, copy, modify, and/or distribute this software for any purpose with - * or without fee is hereby granted, provided that the above copyright notice and this - * permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD - * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef NANO_PERF_WIDGET_HPP_INCLUDED -#define NANO_PERF_WIDGET_HPP_INCLUDED - -// ------------------------------------------------------ -// DGL Stuff - -#include "NanoVG.hpp" -#include "../../dpf/distrho/extra/String.hpp" - -// ------------------------------------------------------ -// get time - -#include -#include - -#ifdef DISTRHO_OS_WINDOWS -#else -struct TimePOSIX { - bool monotonic; - double resolution; - uint64_t base; - - TimePOSIX() - : monotonic(false), - resolution(1e-6), - base(0) - { -#if defined(CLOCK_MONOTONIC) - struct timespec ts; - - if (::clock_gettime(CLOCK_MONOTONIC, &ts) == 0) - { - monotonic = true; - resolution = 1e-9; - } -#endif - - base = getRawTime(); - } - - uint64_t getRawTime() - { -#if defined(CLOCK_MONOTONIC) - if (monotonic) - { - struct timespec ts; - - ::clock_gettime(CLOCK_MONOTONIC, &ts); - return (uint64_t) ts.tv_sec * (uint64_t) 1000000000 + (uint64_t) ts.tv_nsec; - } - else -#endif - { - struct timeval tv; - - ::gettimeofday(&tv, NULL); - return (uint64_t) tv.tv_sec * (uint64_t) 1000000 + (uint64_t) tv.tv_usec; - } - } - - double getTime() - { - return (double)(getRawTime() - base) * resolution; - } -}; - -static TimePOSIX gTime; -#endif - -// ------------------------------------------------------ -// our widget - -class NanoPerfWidget : public NanoWidget, - public IdleCallback -{ -public: - static const int kHistoryCount = 100; - - enum RenderStyle { - RENDER_FPS, - RENDER_MS, - }; - - NanoPerfWidget(Window& parent, RenderStyle style, const char* name) - : NanoWidget(parent), - fHead(0), - fStyle(style), - fName(name) - { - parent.addIdleCallback(this); - setSize(200, 35); - - std::memset(fValues, 0, sizeof(float)*kHistoryCount); - - createFontFromFile("sans", "./nanovg_res/Roboto-Regular.ttf"); - - prevt = gTime.getTime(); - } - -protected: - void idleCallback() override - { - repaint(); - } - - void onNanoDisplay() override - { - double t, dt; - - t = gTime.getTime(); - dt = t - prevt; - prevt = t; - update(dt); - - const int w = 200; //getWidth(); - const int h = 35; //getHeight(); - - int i; - float avg; - char str[64]; - - avg = getAverage(); - - beginPath(); - rect(0, 0, w, h); - fillColor(0,0,0,128); - fill(); - - beginPath(); - moveTo(0, h); - - if (fStyle == RENDER_FPS) - { - for (i = 0; i < kHistoryCount; ++i) - { - float v = 1.0f / (0.00001f + fValues[(fHead+i) % kHistoryCount]); - float vx, vy; - if (v > 80.0f) v = 80.0f; - vx = ((float)i/(kHistoryCount-1)) * w; - vy = h - ((v / 80.0f) * h); - lineTo(vx, vy); - } - } - else - { - for (i = 0; i < kHistoryCount; ++i) - { - float v = fValues[(fHead+i) % kHistoryCount] * 1000.0f; - float vx, vy; - if (v > 20.0f) v = 20.0f; - vx = ((float)i/(kHistoryCount-1)) * w; - vy = h - ((v / 20.0f) * h); - lineTo(vx, vy); - } - } - - lineTo(w, h); - fillColor(255,192,0,128); - fill(); - - fontFace("sans"); - - if (fName.isNotEmpty()) - { - fontSize(14.0f); - textAlign(ALIGN_LEFT|ALIGN_TOP); - fillColor(240,240,240,192); - text(3, 1, fName, nullptr); - } - - if (fStyle == RENDER_FPS) - { - fontSize(18.0f); - textAlign(ALIGN_RIGHT|ALIGN_TOP); - fillColor(240,240,240,255); - std::sprintf(str, "%.2f FPS", 1.0f / avg); - text(w-3, 1, str, nullptr); - - fontSize(15.0f); - textAlign(ALIGN_RIGHT|ALIGN_BOTTOM); - fillColor(240,240,240,160); - std::sprintf(str, "%.2f ms", avg * 1000.0f); - text(w-3, h-1, str, nullptr); - } - else - { - fontSize(18.0f); - textAlign(ALIGN_RIGHT|ALIGN_TOP); - fillColor(240,240,240,255); - std::sprintf(str, "%.2f ms", avg * 1000.0f); - text(w-3, 1, str, nullptr); - } - } - -private: - int fHead; - float fValues[kHistoryCount]; - - const int fStyle; - const String fName; - - double prevt; - - void update(float frameTime) noexcept - { - fHead = (fHead+1) % kHistoryCount; - fValues[fHead] = frameTime; - } - - float getAverage() const noexcept - { - int i; - float avg = 0; - - for (i = 0; i < kHistoryCount; ++i) - avg += fValues[i]; - - return avg / (float)kHistoryCount; - } -}; - -// ------------------------------------------------------ - -#endif // NANO_PERF_WIDGET_HPP_INCLUDED diff --git a/dpf/utils/plugin.pkg/package.xml.in b/dpf/utils/plugin.pkg/package.xml.in index dc8e24f..3b4a8a6 100644 --- a/dpf/utils/plugin.pkg/package.xml.in +++ b/dpf/utils/plugin.pkg/package.xml.in @@ -2,7 +2,7 @@ @name@ - + diff --git a/get-plugins.sh b/get-plugins.sh index 84ef6ae..a003079 100755 --- a/get-plugins.sh +++ b/get-plugins.sh @@ -13,10 +13,10 @@ rm -rf repos mkdir repos cd repos -git clone --depth 1 --recursive -b develop git://github.com/DISTRHO/DPF +git clone --depth 1 --recursive -b develop https://github.com/DISTRHO/DPF.git for PLUGIN in ${PLUGINS[@]}; do - git clone --depth 1 git://github.com/DISTRHO/$PLUGIN + git clone --depth 1 https://github.com/DISTRHO/${PLUGIN}.git done # special case for ProM @@ -35,14 +35,22 @@ mkdir plugins mv repos/DPF dpf rm -rf dpf/.git* rm -rf dpf/.travis* +rm -rf dpf/dgl/src/pugl-upstream/bindings +rm -rf dpf/dgl/src/pugl-upstream/doc +rm -rf dpf/dgl/src/pugl-upstream/examples +rm -rf dpf/dgl/src/pugl-upstream/meson* +rm -rf dpf/dgl/src/pugl-upstream/resources +rm -rf dpf/dgl/src/pugl-upstream/scripts +rm -rf dpf/dgl/src/pugl-upstream/test rm -rf dpf/examples +rm -rf dpf/tests rm -f dpf/Makefile for PLUGIN in ${PLUGINS[@]}; do - for f in $(ls repos/$PLUGIN/plugins/); do - mv repos/$PLUGIN/plugins/$f plugins/$f - if [ -d plugins/$f ]; then - cp repos/$PLUGIN/LICENSE plugins/$f/LICENSE + for f in $(ls repos/${PLUGIN}/plugins/); do + mv repos/${PLUGIN}/plugins/${f} plugins/${f} + if [ -d plugins/${f} ]; then + cp repos/${PLUGIN}/LICENSE plugins/${f}/LICENSE fi done done