Browse Source

Update dpf and plugins

Signed-off-by: falkTX <falktx@falktx.com>
tags/v1.6
falkTX 2 years ago
parent
commit
1eeb49147a
Signed by: falkTX <falktx@falktx.com> GPG Key ID: CDBAA37ABC74FBA0
100 changed files with 1693 additions and 14715 deletions
  1. +188
    -86
      dpf/Makefile.base.mk
  2. +89
    -23
      dpf/Makefile.plugins.mk
  3. +17
    -24
      dpf/cmake/DPF-plugin.cmake
  4. +18
    -4
      dpf/dgl/Application.hpp
  5. +56
    -15
      dpf/dgl/Base.hpp
  6. +3
    -3
      dpf/dgl/Cairo.hpp
  7. +8
    -10
      dpf/dgl/FileBrowserDialog.hpp
  8. +24
    -12
      dpf/dgl/Makefile
  9. +1
    -1
      dpf/dgl/NanoVG.hpp
  10. +112
    -0
      dpf/dgl/OpenGL-include.hpp
  11. +8
    -95
      dpf/dgl/OpenGL.hpp
  12. +1
    -0
      dpf/dgl/StandaloneWindow.hpp
  13. +1
    -1
      dpf/dgl/SubWidget.hpp
  14. +2
    -2
      dpf/dgl/TopLevelWidget.hpp
  15. +33
    -36
      dpf/dgl/Widget.hpp
  16. +89
    -22
      dpf/dgl/Window.hpp
  17. +16
    -1
      dpf/dgl/src/Application.cpp
  18. +8
    -4
      dpf/dgl/src/ApplicationPrivateData.cpp
  19. +3
    -0
      dpf/dgl/src/ApplicationPrivateData.hpp
  20. +24
    -13
      dpf/dgl/src/NanoVG.cpp
  21. +37
    -25
      dpf/dgl/src/OpenGL.cpp
  22. +4
    -4
      dpf/dgl/src/TopLevelWidget.cpp
  23. +90
    -22
      dpf/dgl/src/Window.cpp
  24. +182
    -59
      dpf/dgl/src/WindowPrivateData.cpp
  25. +14
    -8
      dpf/dgl/src/WindowPrivateData.hpp
  26. +3
    -0
      dpf/dgl/src/nanovg/fontstash.h
  27. +59
    -2
      dpf/dgl/src/nanovg/nanovg_gl.h
  28. +1
    -0
      dpf/dgl/src/pugl-upstream/.clang-format
  29. +2
    -10
      dpf/dgl/src/pugl-upstream/.includes.imp
  30. +16
    -0
      dpf/dgl/src/pugl-upstream/.reuse/dep5
  31. +121
    -0
      dpf/dgl/src/pugl-upstream/LICENSES/CC0-1.0.txt
  32. +11
    -0
      dpf/dgl/src/pugl-upstream/LICENSES/ISC.txt
  33. +17
    -0
      dpf/dgl/src/pugl-upstream/LICENSES/MIT.txt
  34. +20
    -46
      dpf/dgl/src/pugl-upstream/README.md
  35. +0
    -15
      dpf/dgl/src/pugl-upstream/bindings/cpp/include/.clang-tidy
  36. +0
    -12
      dpf/dgl/src/pugl-upstream/bindings/cpp/include/meson.build
  37. +0
    -45
      dpf/dgl/src/pugl-upstream/bindings/cpp/include/pugl/cairo.hpp
  38. +0
    -70
      dpf/dgl/src/pugl-upstream/bindings/cpp/include/pugl/gl.hpp
  39. +0
    -734
      dpf/dgl/src/pugl-upstream/bindings/cpp/include/pugl/pugl.hpp
  40. +0
    -45
      dpf/dgl/src/pugl-upstream/bindings/cpp/include/pugl/stub.hpp
  41. +0
    -168
      dpf/dgl/src/pugl-upstream/bindings/cpp/include/pugl/vulkan.hpp
  42. +0
    -7
      dpf/dgl/src/pugl-upstream/bindings/cpp/meson.build
  43. +0
    -2
      dpf/dgl/src/pugl-upstream/doc/_static/meson.build
  44. +0
    -32
      dpf/dgl/src/pugl-upstream/doc/c/Doxyfile.in
  45. +0
    -5
      dpf/dgl/src/pugl-upstream/doc/c/api/meson.build
  46. +0
    -101
      dpf/dgl/src/pugl-upstream/doc/c/event-loop.rst
  47. +0
    -84
      dpf/dgl/src/pugl-upstream/doc/c/events.rst
  48. +0
    -11
      dpf/dgl/src/pugl-upstream/doc/c/index.rst
  49. +0
    -48
      dpf/dgl/src/pugl-upstream/doc/c/meson.build
  50. +0
    -26
      dpf/dgl/src/pugl-upstream/doc/c/overview.rst
  51. +0
    -20
      dpf/dgl/src/pugl-upstream/doc/c/shutting-down.rst
  52. +0
    -321
      dpf/dgl/src/pugl-upstream/doc/c/view.rst
  53. +0
    -65
      dpf/dgl/src/pugl-upstream/doc/c/world.rst
  54. +0
    -19
      dpf/dgl/src/pugl-upstream/doc/c/xml/meson.build
  55. +0
    -85
      dpf/dgl/src/pugl-upstream/doc/conf.py.in
  56. +0
    -37
      dpf/dgl/src/pugl-upstream/doc/cpp/Doxyfile.in
  57. +0
    -5
      dpf/dgl/src/pugl-upstream/doc/cpp/api/meson.build
  58. +0
    -37
      dpf/dgl/src/pugl-upstream/doc/cpp/event-loop.rst
  59. +0
    -43
      dpf/dgl/src/pugl-upstream/doc/cpp/events.rst
  60. +0
    -12
      dpf/dgl/src/pugl-upstream/doc/cpp/index.rst
  61. +0
    -47
      dpf/dgl/src/pugl-upstream/doc/cpp/meson.build
  62. +0
    -35
      dpf/dgl/src/pugl-upstream/doc/cpp/overview.rst
  63. +0
    -299
      dpf/dgl/src/pugl-upstream/doc/cpp/view.rst
  64. +0
    -41
      dpf/dgl/src/pugl-upstream/doc/cpp/world.rst
  65. +0
    -21
      dpf/dgl/src/pugl-upstream/doc/cpp/xml/meson.build
  66. +0
    -23
      dpf/dgl/src/pugl-upstream/doc/deployment.rst
  67. +0
    -13
      dpf/dgl/src/pugl-upstream/doc/meson.build
  68. +0
    -22
      dpf/dgl/src/pugl-upstream/doc/summary.rst
  69. +0
    -43
      dpf/dgl/src/pugl-upstream/examples/.clang-tidy
  70. +0
    -193
      dpf/dgl/src/pugl-upstream/examples/cube_view.h
  71. +0
    -124
      dpf/dgl/src/pugl-upstream/examples/demo_utils.h
  72. +0
    -68
      dpf/dgl/src/pugl-upstream/examples/file_utils.c
  73. +0
    -41
      dpf/dgl/src/pugl-upstream/examples/file_utils.h
  74. +0
    -1138
      dpf/dgl/src/pugl-upstream/examples/glad/glad.c
  75. +0
    -2127
      dpf/dgl/src/pugl-upstream/examples/glad/glad.h
  76. +0
    -290
      dpf/dgl/src/pugl-upstream/examples/glad/khrplatform.h
  77. +0
    -124
      dpf/dgl/src/pugl-upstream/examples/meson.build
  78. +0
    -261
      dpf/dgl/src/pugl-upstream/examples/pugl_cairo_demo.c
  79. +0
    -153
      dpf/dgl/src/pugl-upstream/examples/pugl_cpp_demo.cpp
  80. +0
    -169
      dpf/dgl/src/pugl-upstream/examples/pugl_cursor_demo.c
  81. +0
    -363
      dpf/dgl/src/pugl-upstream/examples/pugl_embed_demo.c
  82. +0
    -79
      dpf/dgl/src/pugl-upstream/examples/pugl_print_events.c
  83. +0
    -480
      dpf/dgl/src/pugl-upstream/examples/pugl_shader_demo.c
  84. +0
    -1826
      dpf/dgl/src/pugl-upstream/examples/pugl_vulkan_cpp_demo.cpp
  85. +0
    -1127
      dpf/dgl/src/pugl-upstream/examples/pugl_vulkan_demo.c
  86. +0
    -254
      dpf/dgl/src/pugl-upstream/examples/pugl_window_demo.c
  87. +0
    -79
      dpf/dgl/src/pugl-upstream/examples/rects.h
  88. +0
    -106
      dpf/dgl/src/pugl-upstream/examples/shader_utils.h
  89. +0
    -4
      dpf/dgl/src/pugl-upstream/examples/shaders/header_330.glsl
  90. +0
    -4
      dpf/dgl/src/pugl-upstream/examples/shaders/header_420.glsl
  91. +0
    -35
      dpf/dgl/src/pugl-upstream/examples/shaders/meson.build
  92. +0
    -33
      dpf/dgl/src/pugl-upstream/examples/shaders/rect.frag
  93. +0
    -36
      dpf/dgl/src/pugl-upstream/examples/shaders/rect.vert
  94. +0
    -2325
      dpf/dgl/src/pugl-upstream/examples/sybok.hpp
  95. +1
    -1
      dpf/dgl/src/pugl-upstream/include/.clang-tidy
  96. +3
    -0
      dpf/dgl/src/pugl-upstream/include/meson.build
  97. +2
    -15
      dpf/dgl/src/pugl-upstream/include/pugl/cairo.h
  98. +2
    -15
      dpf/dgl/src/pugl-upstream/include/pugl/gl.h
  99. +405
    -109
      dpf/dgl/src/pugl-upstream/include/pugl/pugl.h
  100. +2
    -15
      dpf/dgl/src/pugl-upstream/include/pugl/stub.h

+ 188
- 86
dpf/Makefile.base.mk View File

@@ -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)


+ 89
- 23
dpf/Makefile.plugins.mk View File

@@ -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

# ---------------------------------------------------------------------------------------------------------------------

+ 17
- 24
dpf/cmake/DPF-plugin.cmake View File

@@ -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)


+ 18
- 4
dpf/dgl/Application.hpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
*
* 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)
};


+ 56
- 15
dpf/dgl/Base.hpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
*
* 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;
};

// --------------------------------------------------------------------------------------------------------------------


+ 3
- 3
dpf/dgl/Cairo.hpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
*
* 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 <cairo/cairo.h>
#include <cairo.h>

START_NAMESPACE_DGL

@@ -151,7 +151,7 @@ public:
/**
Destructor.
*/
virtual ~CairoBaseWidget() {}
~CairoBaseWidget() override {}

protected:
/**


dpf/tests/Line.cpp → dpf/dgl/FileBrowserDialog.hpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
*
* 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

+ 24
- 12
dpf/dgl/Makefile View File

@@ -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 $@

# ---------------------------------------------------------------------------------------------------------------------



+ 1
- 1
dpf/dgl/NanoVG.hpp View File

@@ -940,7 +940,7 @@ public:
/**
Destructor.
*/
virtual ~NanoBaseWidget() {}
~NanoBaseWidget() override {}

protected:
/**


+ 112
- 0
dpf/dgl/OpenGL-include.hpp View File

@@ -0,0 +1,112 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
*
* 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 <GL/glu.h> 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 <OpenGL/gl3.h>
# include <OpenGL/gl3ext.h>
# else
# include <OpenGL/gl.h>
# endif
#else
# ifndef DISTRHO_OS_WINDOWS
# define GL_GLEXT_PROTOTYPES
# endif
# ifndef __GLEW_H__
# include <GL/gl.h>
# include <GL/glext.h>
# 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

+ 8
- 95
dpf/dgl/OpenGL.hpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
*
* 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 <GL/glu.h> 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 <cstddef>

#endif // DISTRHO_OS_WINDOWS

// -----------------------------------------------------------------------
// OpenGL includes

#ifdef DISTRHO_OS_MAC
# ifdef DGL_USE_OPENGL3
# include <OpenGL/gl3.h>
# include <OpenGL/gl3ext.h>
# else
# include <OpenGL/gl.h>
# endif
#else
# ifndef DISTRHO_OS_WINDOWS
# define GL_GLEXT_PROTOTYPES
# endif
# ifndef __GLEW_H__
# include <GL/gl.h>
# include <GL/glext.h>
# 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<uint>(w, h), fmt); };
{ loadFromMemory(rdata, Size<uint>(w, h), fmt); }
inline void draw(const GraphicsContext& context)
{ drawAt(context, Point<int>(0, 0)); };
{ drawAt(context, Point<int>(0, 0)); }
inline void drawAt(const GraphicsContext& context, int x, int y)
{ drawAt(context, Point<int>(x, y)); };
{ drawAt(context, Point<int>(x, y)); }

/**
Constructor using raw image data, specifying an OpenGL image format.
@@ -305,4 +218,4 @@ typedef ImageBaseSwitch<OpenGLImage> OpenGLImageSwitch;

END_NAMESPACE_DGL

#endif
#endif // DGL_OPENGL_HPP_INCLUDED

+ 1
- 0
dpf/dgl/StandaloneWindow.hpp View File

@@ -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,


+ 1
- 1
dpf/dgl/SubWidget.hpp View File

@@ -47,7 +47,7 @@ public:
/**
Destructor.
*/
virtual ~SubWidget();
~SubWidget() override;

/**
Check if this widget contains the point defined by @a x and @a y.


+ 2
- 2
dpf/dgl/TopLevelWidget.hpp View File

@@ -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<uint>& 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);


+ 33
- 36
dpf/dgl/Widget.hpp View File

@@ -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<double> pos;
/** The absolute coordinates of the pointer. */
Point<double> 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<double> pos;
/** The absolute coordinates of the pointer. */
Point<double> 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<double> pos;
/** The absolute coordinates of the pointer. */
Point<double> absolutePos;
/** The scroll distance. */
Point<double> 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<uint> size;
/** The previous size, can be null. */
Size<uint> 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<int> pos;
/** The previous absolute position of the widget. */
Point<int> oldPos;

/** Constructor */
/** Constructor for default/null values */
PositionChangedEvent() noexcept
: pos(0, 0),
oldPos(0, 0) {}


+ 89
- 22
dpf/dgl/Window.hpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
*
* 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 <vector>

#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<int> 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<int>& 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<ClipboardDataOffer> 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)
};

// -----------------------------------------------------------------------


+ 16
- 1
dpf/dgl/src/Application.cpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
*
* 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 <emscripten/emscripten.h>
#endif

START_NAMESPACE_DGL

// --------------------------------------------------------------------------------------------------------------------

#ifdef __EMSCRIPTEN__
static void app_idle(void* const app)
{
static_cast<Application*>(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()


+ 8
- 4
dpf/dgl/src/ApplicationPrivateData.cpp View File

@@ -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
}



+ 3
- 0
dpf/dgl/src/ApplicationPrivateData.hpp View File

@@ -22,6 +22,9 @@
#include <list>

#ifdef DISTRHO_OS_WINDOWS
# ifndef NOMINMAX
# define NOMINMAX
# endif
# include <winsock2.h>
# include <windows.h>
typedef HANDLE d_ThreadHandle;


+ 24
- 13
dpf/dgl/src/NanoVG.cpp View File

@@ -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);


+ 37
- 25
dpf/dgl/src/OpenGL.cpp View File

@@ -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<typename T>
static void drawLine(const Point<T>& posStart, const Point<T>& posEnd)
{
@@ -82,7 +94,7 @@ static void drawLine(const Point<T>& posStart, const Point<T>& posEnd)
template<typename T>
void Line<T>::draw(const GraphicsContext&, const T width)
{
#ifndef DGL_USE_OPENGL3
#ifdef DGL_USE_COMPAT_OPENGL
DISTRHO_SAFE_ASSERT_RETURN(width != 0,);

glLineWidth(static_cast<GLfloat>(width));
@@ -96,7 +108,7 @@ void Line<T>::draw(const GraphicsContext&, const T width)
template<typename T>
void Line<T>::draw()
{
#ifndef DGL_USE_OPENGL3
#ifdef DGL_USE_COMPAT_OPENGL
drawLine<T>(posStart, posEnd);
#else
notImplemented("Line::draw");
@@ -113,7 +125,7 @@ template class Line<ushort>;
// -----------------------------------------------------------------------
// Circle

#ifndef DGL_USE_OPENGL3
#ifdef DGL_USE_COMPAT_OPENGL
template<typename T>
static void drawCircle(const Point<T>& pos,
const uint numSegments,
@@ -146,7 +158,7 @@ static void drawCircle(const Point<T>& pos,
template<typename T>
void Circle<T>::draw(const GraphicsContext&)
{
#ifndef DGL_USE_OPENGL3
#ifdef DGL_USE_COMPAT_OPENGL
drawCircle<T>(fPos, fNumSegments, fSize, fSin, fCos, false);
#else
notImplemented("Circle::draw");
@@ -159,7 +171,7 @@ void Circle<T>::drawOutline(const GraphicsContext&, const T lineWidth)
DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,);

glLineWidth(static_cast<GLfloat>(lineWidth));
#ifndef DGL_USE_OPENGL3
#ifdef DGL_USE_COMPAT_OPENGL
drawCircle<T>(fPos, fNumSegments, fSize, fSin, fCos, true);
#else
notImplemented("Circle::drawOutline");
@@ -170,7 +182,7 @@ void Circle<T>::drawOutline(const GraphicsContext&, const T lineWidth)
template<typename T>
void Circle<T>::draw()
{
#ifndef DGL_USE_OPENGL3
#ifdef DGL_USE_COMPAT_OPENGL
drawCircle<T>(fPos, fNumSegments, fSize, fSin, fCos, false);
#else
notImplemented("Circle::draw");
@@ -180,7 +192,7 @@ void Circle<T>::draw()
template<typename T>
void Circle<T>::drawOutline()
{
#ifndef DGL_USE_OPENGL3
#ifdef DGL_USE_COMPAT_OPENGL
drawCircle<T>(fPos, fNumSegments, fSize, fSin, fCos, true);
#else
notImplemented("Circle::drawOutline");
@@ -197,7 +209,7 @@ template class Circle<ushort>;
// -----------------------------------------------------------------------
// Triangle

#ifndef DGL_USE_OPENGL3
#ifdef DGL_USE_COMPAT_OPENGL
template<typename T>
static void drawTriangle(const Point<T>& pos1,
const Point<T>& pos2,
@@ -221,7 +233,7 @@ static void drawTriangle(const Point<T>& pos1,
template<typename T>
void Triangle<T>::draw(const GraphicsContext&)
{
#ifndef DGL_USE_OPENGL3
#ifdef DGL_USE_COMPAT_OPENGL
drawTriangle<T>(pos1, pos2, pos3, false);
#else
notImplemented("Triangle::draw");
@@ -234,7 +246,7 @@ void Triangle<T>::drawOutline(const GraphicsContext&, const T lineWidth)
DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,);

glLineWidth(static_cast<GLfloat>(lineWidth));
#ifndef DGL_USE_OPENGL3
#ifdef DGL_USE_COMPAT_OPENGL
drawTriangle<T>(pos1, pos2, pos3, true);
#else
notImplemented("Triangle::drawOutline");
@@ -245,7 +257,7 @@ void Triangle<T>::drawOutline(const GraphicsContext&, const T lineWidth)
template<typename T>
void Triangle<T>::draw()
{
#ifndef DGL_USE_OPENGL3
#ifdef DGL_USE_COMPAT_OPENGL
drawTriangle<T>(pos1, pos2, pos3, false);
#else
notImplemented("Triangle::draw");
@@ -255,7 +267,7 @@ void Triangle<T>::draw()
template<typename T>
void Triangle<T>::drawOutline()
{
#ifndef DGL_USE_OPENGL3
#ifdef DGL_USE_COMPAT_OPENGL
drawTriangle<T>(pos1, pos2, pos3, true);
#else
notImplemented("Triangle::drawOutline");
@@ -272,7 +284,7 @@ template class Triangle<ushort>;
// -----------------------------------------------------------------------
// Rectangle

#ifndef DGL_USE_OPENGL3
#ifdef DGL_USE_COMPAT_OPENGL
template<typename T>
static void drawRectangle(const Rectangle<T>& rect, const bool outline)
{
@@ -306,7 +318,7 @@ static void drawRectangle(const Rectangle<T>& rect, const bool outline)
template<typename T>
void Rectangle<T>::draw(const GraphicsContext&)
{
#ifndef DGL_USE_OPENGL3
#ifdef DGL_USE_COMPAT_OPENGL
drawRectangle<T>(*this, false);
#else
notImplemented("Rectangle::draw");
@@ -319,7 +331,7 @@ void Rectangle<T>::drawOutline(const GraphicsContext&, const T lineWidth)
DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,);

glLineWidth(static_cast<GLfloat>(lineWidth));
#ifndef DGL_USE_OPENGL3
#ifdef DGL_USE_COMPAT_OPENGL
drawRectangle<T>(*this, true);
#else
notImplemented("Rectangle::drawOutline");
@@ -330,7 +342,7 @@ void Rectangle<T>::drawOutline(const GraphicsContext&, const T lineWidth)
template<typename T>
void Rectangle<T>::draw()
{
#ifndef DGL_USE_OPENGL3
#ifdef DGL_USE_COMPAT_OPENGL
drawRectangle<T>(*this, false);
#else
notImplemented("Rectangle::draw");
@@ -340,7 +352,7 @@ void Rectangle<T>::draw()
template<typename T>
void Rectangle<T>::drawOutline()
{
#ifndef DGL_USE_OPENGL3
#ifdef DGL_USE_COMPAT_OPENGL
drawRectangle<T>(*this, true);
#else
notImplemented("Rectangle::drawOutline");
@@ -395,14 +407,14 @@ static void drawOpenGLImage(const OpenGLImage& image, const Point<int>& 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<OpenGLImage>::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<float>(w2), static_cast<float>(h2), 0.0f);
glRotatef(normValue*static_cast<float>(pData->rotationAngle), 0.0f, 0.0f, 1.0f);
#endif

Rectangle<int>(-w2, -h2, w, h).draw(context);

#ifndef DGL_USE_OPENGL3
#ifdef DGL_USE_COMPAT_OPENGL
glPopMatrix();
#endif
}


+ 4
- 4
dpf/dgl/src/TopLevelWidget.cpp View File

@@ -60,14 +60,14 @@ void TopLevelWidget::setSize(const Size<uint>& 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)


+ 90
- 22
dpf/dgl/src/Window.cpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
*
* 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<int> Window::getOffset() const noexcept
{
DISTRHO_SAFE_ASSERT_RETURN(pData->view != nullptr, Point<int>());

const PuglRect rect = puglGetFrame(pData->view);
return Point<int>(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<int>& 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<uint>& rect) noexcept
return;

PuglRect prect = {
static_cast<double>(rect.getX()),
static_cast<double>(rect.getY()),
static_cast<double>(rect.getWidth()),
static_cast<double>(rect.getHeight()),
static_cast<PuglCoord>(rect.getX()),
static_cast<PuglCoord>(rect.getY()),
static_cast<PuglSpan>(rect.getWidth()),
static_cast<PuglSpan>(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<ClipboardDataOffer> Window::getClipboardDataOfferTypes()
{
std::vector<ClipboardDataOffer> offerTypes;

if (const uint32_t numTypes = puglGetNumClipboardTypes(pData->view))
{
offerTypes.reserve(numTypes);

for (uint32_t i=0; i<numTypes; ++i)
{
const ClipboardDataOffer offer = { i + 1, puglGetClipboardType(pData->view, i) };
offerTypes.push_back(offer);
}
}

return offerTypes;
}

uint32_t Window::onClipboardDataOffer()
{
std::vector<ClipboardDataOffer> offers(getClipboardDataOfferTypes());

for (std::vector<ClipboardDataOffer>::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

+ 182
- 59
dpf/dgl/src/WindowPrivateData.cpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
*
* 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<uint>(rect.width), static_cast<uint>(rect.height));
// PuglRect rect = puglGetFrame(view);
// puglSetWindowSize(view, static_cast<uint>(rect.width), static_cast<uint>(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<int>(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<int>(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<CrossingMode>(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<uint>(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<double>(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<IdleCallback*>(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;


+ 14
- 8
dpf/dgl/src/WindowPrivateData.hpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
*
* 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);



+ 3
- 0
dpf/dgl/src/nanovg/fontstash.h View File

@@ -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];



+ 59
- 2
dpf/dgl/src/nanovg/nanovg_gl.h View File

@@ -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; i<w*h; ++i)
{
tex->data[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; i<w*h; ++i)
{
tex->data[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);


+ 1
- 0
dpf/dgl/src/pugl-upstream/.clang-format View File

@@ -24,5 +24,6 @@ StatementMacros:
- PUGL_CONST_FUNC
- PUGL_DEPRECATED_BY
- PUGL_UNUSED
- PUGL_WARN_UNUSED_RESULT
- _Pragma
...

+ 2
- 10
dpf/dgl/src/pugl-upstream/.includes.imp View File

@@ -1,15 +1,7 @@
[
{ "include": [ "<ext/alloc_traits.h>", "private", "<string>", "public", ] },
{ "include": [ "<ext/alloc_traits.h>", "private", "<vector>", "public", ] },
{ "symbol": [ "bool", "private", "<stdbool.h>", "public" ] },
{ "symbol": [ "int32_t", "private", "<stdint.h>", "public" ] },
{ "symbol": [ "int64_t", "private", "<stdint.h>", "public" ] },
{ "symbol": [ "std::uintptr_t", "private", "<cstdint>", "public" ] },
{ "symbol": [ "timespec", "private", "<time.h>", "public" ] },
{ "symbol": [ "timeval", "private", "<time.h>", "public" ] },
{ "symbol": [ "uint32_t", "private", "<stdint.h>", "public" ] },
{ "symbol": [ "uint64_t", "private", "<stdint.h>", "public" ] },
{ "symbol": [ "uint8_t", "private", "<stdint.h>", "public" ] },
{ "symbol": [ "uintptr_t", "private", "<stdint.h>", "public" ] },

{ "symbol": [ "uintptr_t", "private", "<cstdint>", "public" ] }
{ "symbol": [ "timeval", "private", "<time.h>", "public" ] }
]

+ 16
- 0
dpf/dgl/src/pugl-upstream/.reuse/dep5 View File

@@ -0,0 +1,16 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: pugl
Upstream-Contact: David Robillard <d@drobilla.net>
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 <d@drobilla.net>
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 <d@drobilla.net>
License: ISC

Files: examples/glad/khrplatform.h
Copyright: 2008-2018 The Khronos Group Inc.
License: MIT

+ 121
- 0
dpf/dgl/src/pugl-upstream/LICENSES/CC0-1.0.txt View File

@@ -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.

+ 11
- 0
dpf/dgl/src/pugl-upstream/LICENSES/ISC.txt View File

@@ -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.

+ 17
- 0
dpf/dgl/src/pugl-upstream/LICENSES/MIT.txt View File

@@ -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.

+ 20
- 46
dpf/dgl/src/pugl-upstream/README.md View File

@@ -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 <d@drobilla.net>

+ 0
- 15
dpf/dgl/src/pugl-upstream/bindings/cpp/include/.clang-tidy View File

@@ -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/.*'

+ 0
- 12
dpf/dgl/src/pugl-upstream/bindings/cpp/include/meson.build View File

@@ -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')

+ 0
- 45
dpf/dgl/src/pugl-upstream/bindings/cpp/include/pugl/cairo.hpp View File

@@ -1,45 +0,0 @@
/*
Copyright 2012-2020 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#ifndef PUGL_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

+ 0
- 70
dpf/dgl/src/pugl-upstream/bindings/cpp/include/pugl/gl.hpp View File

@@ -1,70 +0,0 @@
/*
Copyright 2012-2020 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#ifndef PUGL_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<Status>(puglEnterContext(view.cobj()));
}

/// @copydoc puglLeaveContext
inline Status
leaveContext(View& view) noexcept
{
return static_cast<Status>(puglLeaveContext(view.cobj()));
}

/// @copydoc puglGlBackend
inline const PuglBackend*
glBackend() noexcept
{
return puglGlBackend();
}

/**
@}
*/

} // namespace pugl

#endif // PUGL_GL_HPP

+ 0
- 734
dpf/dgl/src/pugl-upstream/bindings/cpp/include/pugl/pugl.hpp View File

@@ -1,734 +0,0 @@
/*
Copyright 2012-2020 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#ifndef PUGL_PUGL_HPP
#define PUGL_PUGL_HPP

#include "pugl/pugl.h"

#include <cstdint>

#if defined(PUGL_HPP_THROW_FAILED_CONSTRUCTION)
# include <exception>
#elif defined(PUGL_HPP_ASSERT_CONSTRUCTION)
# include <cassert>
#endif

namespace pugl {

/**
@defgroup puglpp Pugl C++ API
Pugl C++ API wrapper.
@{
*/

namespace detail {

/// Free function for a C object
template<typename T>
using FreeFunc = void (*)(T*);

/// Generic C++ wrapper for a C object
template<class T, FreeFunc<T> 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<PuglEventType t, class Base>
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<class... Args>
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<PUGL_CREATE, PuglCreateEvent>;

/// @copydoc PuglDestroyEvent
using DestroyEvent = Event<PUGL_DESTROY, PuglDestroyEvent>;

/// @copydoc PuglConfigureEvent
using ConfigureEvent = Event<PUGL_CONFIGURE, PuglConfigureEvent>;

/// @copydoc PuglMapEvent
using MapEvent = Event<PUGL_MAP, PuglMapEvent>;

/// @copydoc PuglUnmapEvent
using UnmapEvent = Event<PUGL_UNMAP, PuglUnmapEvent>;

/// @copydoc PuglUpdateEvent
using UpdateEvent = Event<PUGL_UPDATE, PuglUpdateEvent>;

/// @copydoc PuglExposeEvent
using ExposeEvent = Event<PUGL_EXPOSE, PuglExposeEvent>;

/// @copydoc PuglCloseEvent
using CloseEvent = Event<PUGL_CLOSE, PuglCloseEvent>;

/// @copydoc PuglFocusEvent
using FocusInEvent = Event<PUGL_FOCUS_IN, PuglFocusEvent>;

/// @copydoc PuglFocusEvent
using FocusOutEvent = Event<PUGL_FOCUS_OUT, PuglFocusEvent>;

/// @copydoc PuglKeyEvent
using KeyPressEvent = Event<PUGL_KEY_PRESS, PuglKeyEvent>;

/// @copydoc PuglKeyEvent
using KeyReleaseEvent = Event<PUGL_KEY_RELEASE, PuglKeyEvent>;

/// @copydoc PuglTextEvent
using TextEvent = Event<PUGL_TEXT, PuglTextEvent>;

/// @copydoc PuglCrossingEvent
using PointerInEvent = Event<PUGL_POINTER_IN, PuglCrossingEvent>;

/// @copydoc PuglCrossingEvent
using PointerOutEvent = Event<PUGL_POINTER_OUT, PuglCrossingEvent>;

/// @copydoc PuglButtonEvent
using ButtonPressEvent = Event<PUGL_BUTTON_PRESS, PuglButtonEvent>;

/// @copydoc PuglButtonEvent
using ButtonReleaseEvent = Event<PUGL_BUTTON_RELEASE, PuglButtonEvent>;

/// @copydoc PuglMotionEvent
using MotionEvent = Event<PUGL_MOTION, PuglMotionEvent>;

/// @copydoc PuglScrollEvent
using ScrollEvent = Event<PUGL_SCROLL, PuglScrollEvent>;

/// @copydoc PuglClientEvent
using ClientEvent = Event<PUGL_CLIENT, PuglClientEvent>;

/// @copydoc PuglTimerEvent
using TimerEvent = Event<PUGL_TIMER, PuglTimerEvent>;

/// @copydoc PuglLoopEnterEvent
using LoopEnterEvent = Event<PUGL_LOOP_ENTER, PuglLoopEnterEvent>;

/// @copydoc PuglLoopLeaveEvent
using LoopLeaveEvent = Event<PUGL_LOOP_LEAVE, PuglLoopLeaveEvent>;

/**
@}
@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<PuglStatus>(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<PuglWorld, puglFreeWorld>
{
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<PuglWorldType>(type),
static_cast<PuglWorldFlags>(flag))}
{
PUGL_CHECK_CONSTRUCTION(cobj(), "Failed to create pugl::World");
}

World(WorldType type, WorldFlags flags)
: Wrapper{puglNewWorld(static_cast<PuglWorldType>(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<Status>(puglSetClassName(cobj(), name));
}

/// @copydoc puglGetTime
double time() const noexcept { return puglGetTime(cobj()); }

/// @copydoc puglUpdate
Status update(const double timeout) noexcept
{
return static_cast<Status>(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<PuglView, puglFreeView>
{
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<class Handler>
Status setEventHandler(Handler& handler)
{
puglSetHandle(cobj(), &handler);
return static_cast<Status>(puglSetEventFunc(cobj(), eventFunc<Handler>));
}

/// @copydoc puglSetBackend
Status setBackend(const PuglBackend* backend) noexcept
{
return static_cast<Status>(puglSetBackend(cobj(), backend));
}

/// @copydoc puglSetViewHint
Status setHint(ViewHint hint, int value) noexcept
{
return static_cast<Status>(
puglSetViewHint(cobj(), static_cast<PuglViewHint>(hint), value));
}

/// @copydoc puglGetViewHint
int getHint(ViewHint hint) noexcept
{
return puglGetViewHint(cobj(), static_cast<PuglViewHint>(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<Status>(puglSetFrame(cobj(), frame));
}

/// @copydoc puglSetDefaultSize
Status setDefaultSize(int width, int height) noexcept
{
return static_cast<Status>(puglSetDefaultSize(cobj(), width, height));
}

/// @copydoc puglSetMinSize
Status setMinSize(int width, int height) noexcept
{
return static_cast<Status>(puglSetMinSize(cobj(), width, height));
}

/// @copydoc puglSetMaxSize
Status setMaxSize(int width, int height) noexcept
{
return static_cast<Status>(puglSetMaxSize(cobj(), width, height));
}

/// @copydoc puglSetAspectRatio
Status setAspectRatio(int minX, int minY, int maxX, int maxY) noexcept
{
return static_cast<Status>(
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<Status>(puglSetWindowTitle(cobj(), title));
}

/// @copydoc puglSetParentWindow
Status setParentWindow(NativeView parent) noexcept
{
return static_cast<Status>(puglSetParentWindow(cobj(), parent));
}

/// @copydoc puglSetTransientFor
Status setTransientFor(NativeView parent) noexcept
{
return static_cast<Status>(puglSetTransientFor(cobj(), parent));
}

/// @copydoc puglRealize
Status realize() noexcept { return static_cast<Status>(puglRealize(cobj())); }

/// @copydoc puglShow
Status show() noexcept { return static_cast<Status>(puglShow(cobj())); }

/// @copydoc puglHide
Status hide() noexcept { return static_cast<Status>(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<Status>(puglPostRedisplay(cobj()));
}

/// @copydoc puglPostRedisplayRect
Status postRedisplayRect(const Rect rect) noexcept
{
return static_cast<Status>(puglPostRedisplayRect(cobj(), rect));
}

/**
@}
@name Interaction
Methods for interacting with the user and window system.
@{
*/

/// @copydoc puglGrabFocus
Status grabFocus() noexcept
{
return static_cast<Status>(puglGrabFocus(cobj()));
}

/// @copydoc puglHasFocus
bool hasFocus() const noexcept { return puglHasFocus(cobj()); }

/// @copydoc puglSetCursor
Status setCursor(const Cursor cursor) noexcept
{
return static_cast<Status>(
puglSetCursor(cobj(), static_cast<PuglCursor>(cursor)));
}

/// @copydoc puglRequestAttention
Status requestAttention() noexcept
{
return static_cast<Status>(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<Status>(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<Status>(puglStopTimer(cobj(), id));
}

template<PuglEventType t, class Base>
Status sendEvent(const Event<t, Base>& event) noexcept
{
PuglEvent cEvent{{t, 0}};

*reinterpret_cast<Base*>(&cEvent) = event;

return static_cast<Status>(puglSendEvent(cobj(), &cEvent));
}

/**
@}
*/

PuglView* cobj() noexcept { return Wrapper::cobj(); }
const PuglView* cobj() const noexcept { return Wrapper::cobj(); }

private:
template<class Target>
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<class Target>
static PuglStatus eventFunc(PuglView* view, const PuglEvent* event) noexcept
{
auto* target = static_cast<Target*>(puglGetHandle(view));

#ifdef __cpp_exceptions
try {
return static_cast<PuglStatus>(dispatch(*target, event));
} catch (...) {
return PUGL_UNKNOWN_ERROR;
}
#else
return static_cast<PuglStatus>(pugl::dispatch(*target, event));
#endif
}

World& _world;
};

/**
@}
@}
*/

} // namespace pugl

#endif // PUGL_PUGL_HPP

+ 0
- 45
dpf/dgl/src/pugl-upstream/bindings/cpp/include/pugl/stub.hpp View File

@@ -1,45 +0,0 @@
/*
Copyright 2012-2020 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#ifndef PUGL_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

+ 0
- 168
dpf/dgl/src/pugl-upstream/bindings/cpp/include/pugl/vulkan.hpp View File

@@ -1,168 +0,0 @@
/*
Copyright 2012-2020 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

/*
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 <vulkan/vulkan_core.h>

#include <cstdint>

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<PuglVulkanLoader, puglFreeVulkanLoader>
{
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

+ 0
- 7
dpf/dgl/src/pugl-upstream/bindings/cpp/meson.build View File

@@ -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')

+ 0
- 2
dpf/dgl/src/pugl-upstream/doc/_static/meson.build View File

@@ -1,2 +0,0 @@
configure_file(copy: true, input: '../../resources/pugl.svg', output: 'pugl.svg')


+ 0
- 32
dpf/dgl/src/pugl-upstream/doc/c/Doxyfile.in View File

@@ -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@

+ 0
- 5
dpf/dgl/src/pugl-upstream/doc/c/api/meson.build View File

@@ -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')

+ 0
- 101
dpf/dgl/src/pugl-upstream/doc/c/event-loop.rst View File

@@ -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.


+ 0
- 84
dpf/dgl/src/pugl-upstream/doc/c/events.rst View File

@@ -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 <PuglEventType.PUGL_CONFIGURE>`
and :enumerator:`PUGL_EXPOSE <PuglEventType.PUGL_EXPOSE>` to draw anything,
but there are many other :enum:`event types <PuglEventType>`.

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 <https://libsdl.org/>`_ and `GLFW <https://www.glfw.org/>`_.

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.


+ 0
- 11
dpf/dgl/src/pugl-upstream/doc/c/index.rst View File

@@ -1,11 +0,0 @@
####
Pugl
####

.. include:: summary.rst

.. toctree::

deployment
overview
api/pugl

+ 0
- 48
dpf/dgl/src/pugl-upstream/doc/c/meson.build View File

@@ -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')

+ 0
- 26
dpf/dgl/src/pugl-upstream/doc/c/overview.rst View File

@@ -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 <pugl/pugl.h>

.. toctree::

world
view
events
event-loop
shutting-down

.. _pkg-config: https://www.freedesktop.org/wiki/Software/pkg-config/

+ 0
- 20
dpf/dgl/src/pugl-upstream/doc/c/shutting-down.rst View File

@@ -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);

+ 0
- 321
dpf/dgl/src/pugl-upstream/doc/c/view.rst View File

@@ -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 <api/frame>` and :doc:`window <api/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 <PuglViewHint>` 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 <PuglNativeView>` 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 <PuglEventFunc>`,
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 <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 <api/cairo>`, :doc:`OpenGL <api/gl>`, and :doc:`Vulkan <api/vulkan>`.

Using Cairo
===========

Cairo-specific API is declared in the ``cairo.h`` header:

.. code-block:: c

#include <pugl/cairo.h>

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 <https://www.cairographics.org/manual/cairo-cairo-t.html>`_ 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 <pugl/gl.h>

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 <PuglEventType.PUGL_CREATE>` and
:enumerator:`PUGL_DESTROY <PuglEventType.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 <pugl/vulkan.h>

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 <https://developer.apple.com/documentation/appkit/nsview>`_,
which may be nested, and
`windows <https://developer.apple.com/documentation/appkit/nswindow>`_,
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

+ 0
- 65
dpf/dgl/src/pugl-upstream/doc/c/world.rst View File

@@ -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 <PuglWorldType.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.


+ 0
- 19
dpf/dgl/src/pugl-upstream/doc/c/xml/meson.build View File

@@ -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')

+ 0
- 85
dpf/dgl/src/pugl-upstream/doc/conf.py.in View File

@@ -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,
}

+ 0
- 37
dpf/dgl/src/pugl-upstream/doc/cpp/Doxyfile.in View File

@@ -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@

+ 0
- 5
dpf/dgl/src/pugl-upstream/doc/cpp/api/meson.build View File

@@ -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')

+ 0
- 37
dpf/dgl/src/pugl-upstream/doc/cpp/event-loop.rst View File

@@ -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.

+ 0
- 43
dpf/dgl/src/pugl-upstream/doc/cpp/events.rst View File

@@ -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 <pugl::EventType>`.

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 <https://libsdl.org/>`_ and `GLFW <https://www.glfw.org/>`_.

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.

+ 0
- 12
dpf/dgl/src/pugl-upstream/doc/cpp/index.rst View File

@@ -1,12 +0,0 @@
####
Pugl
####

.. include:: summary.rst

.. toctree::

deployment
overview
api/pugl
api/puglpp

+ 0
- 47
dpf/dgl/src/pugl-upstream/doc/cpp/meson.build View File

@@ -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')

+ 0
- 35
dpf/dgl/src/pugl-upstream/doc/cpp/overview.rst View File

@@ -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 <pugl/pugl.hpp>

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

+ 0
- 299
dpf/dgl/src/pugl-upstream/doc/cpp/view.rst View File

@@ -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<PuglEventType t, class Base>
pugl::Status onEvent(const pugl::Event<t, Base>&) 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 <api/frame>` and :doc:`window <api/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 <PuglViewHint>` 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 <pugl::NativeView>` 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 <api/cairo>`, :doc:`OpenGL <api/gl>`, and :doc:`Vulkan <api/vulkan>`.

Using Cairo
===========

Cairo-specific API is declared in the ``cairo.hpp`` header:

.. code-block:: cpp

#include <pugl/cairo.hpp>

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 <https://www.cairographics.org/manual/cairo-cairo-t.html>`_ can be accessed with :func:`View::context`:

.. code-block:: cpp

cairo_t* cr = static_cast<cairo_t*>(view.context());

Using OpenGL
============

OpenGL-specific API is declared in the ``gl.hpp`` header:

.. code-block:: cpp

#include <pugl/gl.hpp>

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 <pugl/vulkan.hpp>

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 <https://developer.apple.com/documentation/appkit/nsview>`_,
which may be nested, and
`windows <https://developer.apple.com/documentation/appkit/nswindow>`_,
which may not.
On Windows and X11, everything is a nestable window,
but top-level windows are configured differently.

+ 0
- 41
dpf/dgl/src/pugl-upstream/doc/cpp/world.rst View File

@@ -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");

+ 0
- 21
dpf/dgl/src/pugl-upstream/doc/cpp/xml/meson.build View File

@@ -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')


+ 0
- 23
dpf/dgl/src/pugl-upstream/doc/deployment.rst View File

@@ -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/

+ 0
- 13
dpf/dgl/src/pugl-upstream/doc/meson.build View File

@@ -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

+ 0
- 22
dpf/dgl/src/pugl-upstream/doc/summary.rst View File

@@ -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/

+ 0
- 43
dpf/dgl/src/pugl-upstream/examples/.clang-tidy View File

@@ -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/.*'

+ 0
- 193
dpf/dgl/src/pugl-upstream/examples/cube_view.h View File

@@ -1,193 +0,0 @@
/*
Copyright 2012-2020 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#ifndef 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 <stdbool.h>

// 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

+ 0
- 124
dpf/dgl/src/pugl-upstream/examples/demo_utils.h View File

@@ -1,124 +0,0 @@
/*
Copyright 2012-2019 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#ifndef EXAMPLES_DEMO_UTILS_H
#define EXAMPLES_DEMO_UTILS_H

#include "pugl/pugl.h"

#include <math.h>
#include <stdio.h>

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

+ 0
- 68
dpf/dgl/src/pugl-upstream/examples/file_utils.c View File

@@ -1,68 +0,0 @@
/*
Copyright 2019-2020 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#if !defined(__APPLE__) && !defined(_GNU_SOURCE)
# define _GNU_SOURCE
#endif

#include "file_utils.h"

#ifdef _WIN32
# include <io.h>
# include <windows.h>
# define F_OK 0
#else
# include <libgen.h>
# include <unistd.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

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;
}

+ 0
- 41
dpf/dgl/src/pugl-upstream/examples/file_utils.h View File

@@ -1,41 +0,0 @@
/*
Copyright 2019-2020 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#ifndef 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

+ 0
- 1138
dpf/dgl/src/pugl-upstream/examples/glad/glad.c
File diff suppressed because it is too large
View File


+ 0
- 2127
dpf/dgl/src/pugl-upstream/examples/glad/glad.h
File diff suppressed because it is too large
View File


+ 0
- 290
dpf/dgl/src/pugl-upstream/examples/glad/khrplatform.h View File

@@ -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 <KHR/khrplatform.h>
* by Khronos client API header files that use its types and defines.
*
* The types in khrplatform.h should only be used to define API-specific types.
*
* Types defined in khrplatform.h:
* khronos_int8_t signed 8 bit
* khronos_uint8_t unsigned 8 bit
* khronos_int16_t signed 16 bit
* khronos_uint16_t unsigned 16 bit
* khronos_int32_t signed 32 bit
* khronos_uint32_t unsigned 32 bit
* khronos_int64_t signed 64 bit
* khronos_uint64_t unsigned 64 bit
* khronos_intptr_t signed same number of bits as a pointer
* khronos_uintptr_t unsigned same number of bits as a pointer
* khronos_ssize_t signed size
* khronos_usize_t unsigned size
* khronos_float_t signed 32 bit floating point
* khronos_time_ns_t unsigned 64 bit time in nanoseconds
* khronos_utime_nanoseconds_t unsigned time interval or absolute time in
* nanoseconds
* khronos_stime_nanoseconds_t signed time interval in nanoseconds
* khronos_boolean_enum_t enumerated boolean type. This should
* only be used as a base type when a client API's boolean type is
* an enum. Client APIs which use an integer or other type for
* booleans cannot use this as the base type for their boolean.
*
* Tokens defined in khrplatform.h:
*
* KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
*
* KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
* KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
*
* Calling convention macros defined in this file:
* KHRONOS_APICALL
* KHRONOS_APIENTRY
* KHRONOS_APIATTRIBUTES
*
* These may be used in function prototypes as:
*
* KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
* int arg1,
* int arg2) KHRONOS_APIATTRIBUTES;
*/

#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC)
# define KHRONOS_STATIC 1
#endif

/*-------------------------------------------------------------------------
* Definition of KHRONOS_APICALL
*-------------------------------------------------------------------------
* This precedes the return type of the function in the function prototype.
*/
#if defined(KHRONOS_STATIC)
/* If the preprocessor constant KHRONOS_STATIC is defined, make the
* header compatible with static linking. */
# define KHRONOS_APICALL
#elif defined(_WIN32)
# define KHRONOS_APICALL __declspec(dllimport)
#elif defined (__SYMBIAN32__)
# define KHRONOS_APICALL IMPORT_C
#elif defined(__ANDROID__)
# define KHRONOS_APICALL __attribute__((visibility("default")))
#else
# define KHRONOS_APICALL
#endif

/*-------------------------------------------------------------------------
* Definition of KHRONOS_APIENTRY
*-------------------------------------------------------------------------
* This follows the return type of the function and precedes the function
* name in the function prototype.
*/
#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(KHRONOS_STATIC)
/* Win32 but not WinCE */
# define KHRONOS_APIENTRY __stdcall
#else
# define KHRONOS_APIENTRY
#endif

/*-------------------------------------------------------------------------
* Definition of KHRONOS_APIATTRIBUTES
*-------------------------------------------------------------------------
* This follows the closing parenthesis of the function prototype arguments.
*/
#if defined (__ARMCC_2__)
#define KHRONOS_APIATTRIBUTES __softfp
#else
#define KHRONOS_APIATTRIBUTES
#endif

/*-------------------------------------------------------------------------
* basic type definitions
*-----------------------------------------------------------------------*/
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)


/*
* Using <stdint.h>
*/
#include <stdint.h>
typedef int32_t khronos_int32_t;
typedef uint32_t khronos_uint32_t;
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1

#elif defined(__VMS ) || defined(__sgi)

/*
* Using <inttypes.h>
*/
#include <inttypes.h>
typedef int32_t khronos_int32_t;
typedef uint32_t khronos_uint32_t;
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1

#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)

/*
* Win32
*/
typedef __int32 khronos_int32_t;
typedef unsigned __int32 khronos_uint32_t;
typedef __int64 khronos_int64_t;
typedef unsigned __int64 khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1

#elif defined(__sun__) || defined(__digital__)

/*
* Sun or Digital
*/
typedef int khronos_int32_t;
typedef unsigned int khronos_uint32_t;
#if defined(__arch64__) || defined(_LP64)
typedef long int khronos_int64_t;
typedef unsigned long int khronos_uint64_t;
#else
typedef long long int khronos_int64_t;
typedef unsigned long long int khronos_uint64_t;
#endif /* __arch64__ */
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1

#elif 0

/*
* Hypothetical platform with no float or int64 support
*/
typedef int khronos_int32_t;
typedef unsigned int khronos_uint32_t;
#define KHRONOS_SUPPORT_INT64 0
#define KHRONOS_SUPPORT_FLOAT 0

#else

/*
* Generic fallback
*/
#include <stdint.h>
typedef int32_t khronos_int32_t;
typedef uint32_t khronos_uint32_t;
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1

#endif


/*
* Types that are (so far) the same on all platforms
*/
typedef signed char khronos_int8_t;
typedef unsigned char khronos_uint8_t;
typedef signed short int khronos_int16_t;
typedef unsigned short int khronos_uint16_t;

/*
* Types that differ between LLP64 and LP64 architectures - in LLP64,
* pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
* to be the only LLP64 architecture in current use.
*/
#ifdef _WIN64
typedef signed long long int khronos_intptr_t;
typedef unsigned long long int khronos_uintptr_t;
typedef signed long long int khronos_ssize_t;
typedef unsigned long long int khronos_usize_t;
#else
typedef signed long int khronos_intptr_t;
typedef unsigned long int khronos_uintptr_t;
typedef signed long int khronos_ssize_t;
typedef unsigned long int khronos_usize_t;
#endif

#if KHRONOS_SUPPORT_FLOAT
/*
* Float type
*/
typedef float khronos_float_t;
#endif

#if KHRONOS_SUPPORT_INT64
/* Time types
*
* These types can be used to represent a time interval in nanoseconds or
* an absolute Unadjusted System Time. Unadjusted System Time is the number
* of nanoseconds since some arbitrary system event (e.g. since the last
* time the system booted). The Unadjusted System Time is an unsigned
* 64 bit value that wraps back to 0 every 584 years. Time intervals
* may be either signed or unsigned.
*/
typedef khronos_uint64_t khronos_utime_nanoseconds_t;
typedef khronos_int64_t khronos_stime_nanoseconds_t;
#endif

/*
* Dummy value used to pad enum types to 32 bits.
*/
#ifndef KHRONOS_MAX_ENUM
#define KHRONOS_MAX_ENUM 0x7FFFFFFF
#endif

/*
* Enumerated boolean type
*
* Values other than zero should be considered to be true. Therefore
* comparisons should not be made against KHRONOS_TRUE.
*/
typedef enum {
KHRONOS_FALSE = 0,
KHRONOS_TRUE = 1,
KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
} khronos_boolean_enum_t;

#endif /* __khrplatform_h_ */

+ 0
- 124
dpf/dgl/src/pugl-upstream/examples/meson.build View File

@@ -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

+ 0
- 261
dpf/dgl/src/pugl-upstream/examples/pugl_cairo_demo.c View File

@@ -1,261 +0,0 @@
/*
Copyright 2012-2020 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#include "demo_utils.h"
#include "test/test_utils.h"

#include "pugl/cairo.h"
#include "pugl/pugl.h"

#include <cairo.h>

#include <math.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>

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;
}

+ 0
- 153
dpf/dgl/src/pugl-upstream/examples/pugl_cpp_demo.cpp View File

@@ -1,153 +0,0 @@
/*
Copyright 2012-2020 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#include "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 <cmath>

class CubeView : public pugl::View
{
public:
explicit CubeView(pugl::World& world)
: pugl::View{world}
{
setEventHandler(*this);
}

template<PuglEventType t, class Base>
pugl::Status onEvent(const pugl::Event<t, Base>&) 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<float>(event.width),
static_cast<float>(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<float>(_xAngle),
static_cast<float>(_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;
}

+ 0
- 169
dpf/dgl/src/pugl-upstream/examples/pugl_cursor_demo.c View File

@@ -1,169 +0,0 @@
/*
Copyright 2012-2020 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#include "test/test_utils.h"

#include "pugl/gl.h"
#include "pugl/pugl.h"

#include <stdbool.h>

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;
}

+ 0
- 363
dpf/dgl/src/pugl-upstream/examples/pugl_embed_demo.c View File

@@ -1,363 +0,0 @@
/*
Copyright 2012-2020 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#include "cube_view.h"
#include "demo_utils.h"
#include "test/test_utils.h"

#include "pugl/gl.h"
#include "pugl/pugl.h"

#include <math.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>

static const int borderWidth = 64;
static const uintptr_t reverseTimerId = 1u;

typedef struct {
PuglWorld* world;
PuglView* parent;
PuglView* child;
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;
}

+ 0
- 79
dpf/dgl/src/pugl-upstream/examples/pugl_print_events.c View File

@@ -1,79 +0,0 @@
/*
Copyright 2012-2020 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#include "test/test_utils.h"

#include "pugl/pugl.h"
#include "pugl/stub.h"

#include <stdbool.h>
#include <stdio.h>

typedef struct {
PuglWorld* world;
PuglView* view;
int quit;
} PuglPrintEventsApp;

static PuglStatus
onEvent(PuglView* view, const PuglEvent* event)
{
PuglPrintEventsApp* app = (PuglPrintEventsApp*)puglGetHandle(view);

printEvent(event, "Event: ", true);

switch (event->type) {
case PUGL_CLOSE:
app->quit = 1;
break;
default:
break;
}

return PUGL_SUCCESS;
}

int
main(void)
{
PuglPrintEventsApp app = {NULL, NULL, 0};

app.world = puglNewWorld(PUGL_PROGRAM, 0);
app.view = puglNewView(app.world);

puglSetClassName(app.world, "Pugl Print Events");
puglSetWindowTitle(app.view, "Pugl Event Printer");
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;
}

+ 0
- 480
dpf/dgl/src/pugl-upstream/examples/pugl_shader_demo.c View File

@@ -1,480 +0,0 @@
/*
Copyright 2012-2020 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

/*
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 <math.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

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;
}

+ 0
- 1826
dpf/dgl/src/pugl-upstream/examples/pugl_vulkan_cpp_demo.cpp
File diff suppressed because it is too large
View File


+ 0
- 1127
dpf/dgl/src/pugl-upstream/examples/pugl_vulkan_demo.c
File diff suppressed because it is too large
View File


+ 0
- 254
dpf/dgl/src/pugl-upstream/examples/pugl_window_demo.c View File

@@ -1,254 +0,0 @@
/*
Copyright 2012-2020 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

/*
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 <math.h>
#include <stdbool.h>
#include <string.h>

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;
}

+ 0
- 79
dpf/dgl/src/pugl-upstream/examples/rects.h View File

@@ -1,79 +0,0 @@
/*
Copyright 2019-2020 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#ifndef EXAMPLES_RECTS_H
#define EXAMPLES_RECTS_H

#include <math.h>
#include <stddef.h>

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

+ 0
- 106
dpf/dgl/src/pugl-upstream/examples/shader_utils.h View File

@@ -1,106 +0,0 @@
/*
Copyright 2019-2020 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#ifndef EXAMPLES_SHADER_UTILS_H
#define EXAMPLES_SHADER_UTILS_H

#include "glad/glad.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
GLuint vertexShader;
GLuint fragmentShader;
GLuint program;
} Program;

static GLuint
compileShader(const char* 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

+ 0
- 4
dpf/dgl/src/pugl-upstream/examples/shaders/header_330.glsl View File

@@ -1,4 +0,0 @@
#version 330 core

#define INTER(qualifiers)
#define UBO(qualifiers) layout(std140)

+ 0
- 4
dpf/dgl/src/pugl-upstream/examples/shaders/header_420.glsl View File

@@ -1,4 +0,0 @@
#version 420 core

#define INTER(qualifiers) layout(qualifiers)
#define UBO(qualifiers) layout(std140, qualifiers)

+ 0
- 35
dpf/dgl/src/pugl-upstream/examples/shaders/meson.build View File

@@ -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

+ 0
- 33
dpf/dgl/src/pugl-upstream/examples/shaders/rect.frag View File

@@ -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;
}

+ 0
- 36
dpf/dgl/src/pugl-upstream/examples/shaders/rect.vert View File

@@ -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);
}

+ 0
- 2325
dpf/dgl/src/pugl-upstream/examples/sybok.hpp
File diff suppressed because it is too large
View File


+ 1
- 1
dpf/dgl/src/pugl-upstream/include/.clang-tidy View File

@@ -2,7 +2,7 @@ Checks: >
*,
-*-magic-numbers,
-*-uppercase-literal-suffix,
-altera-struct-pack-align,
-altera*,
-clang-diagnostic-unused-function,
-clang-diagnostic-unused-macros,
-llvmlibc-*,


+ 3
- 0
dpf/dgl/src/pugl-upstream/include/meson.build View File

@@ -1,3 +1,6 @@
# Copyright 2021 David Robillard <d@drobilla.net>
# SPDX-License-Identifier: CC0-1.0 OR ISC

c_headers = [
'pugl/pugl.h',



+ 2
- 15
dpf/dgl/src/pugl-upstream/include/pugl/cairo.h View File

@@ -1,18 +1,5 @@
/*
Copyright 2012-2020 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
// Copyright 2012-2020 David Robillard <d@drobilla.net>
// SPDX-License-Identifier: ISC

#ifndef PUGL_CAIRO_H
#define PUGL_CAIRO_H


+ 2
- 15
dpf/dgl/src/pugl-upstream/include/pugl/gl.h View File

@@ -1,18 +1,5 @@
/*
Copyright 2012-2020 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
// Copyright 2012-2020 David Robillard <d@drobilla.net>
// SPDX-License-Identifier: ISC

#ifndef PUGL_GL_H
#define PUGL_GL_H


+ 405
- 109
dpf/dgl/src/pugl-upstream/include/pugl/pugl.h View File

@@ -1,26 +1,16 @@
/*
Copyright 2012-2020 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
// Copyright 2012-2022 David Robillard <d@drobilla.net>
// SPDX-License-Identifier: ISC

#ifndef PUGL_PUGL_H
#define PUGL_PUGL_H

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

#ifndef __cplusplus
# include <stdbool.h>
#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



+ 2
- 15
dpf/dgl/src/pugl-upstream/include/pugl/stub.h View File

@@ -1,18 +1,5 @@
/*
Copyright 2019-2020 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
// Copyright 2019-2020 David Robillard <d@drobilla.net>
// SPDX-License-Identifier: ISC

#ifndef PUGL_STUB_H
#define PUGL_STUB_H


Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save