281 changes: 194 additions & 87 deletions dpf/Makefile.plugins.mk

Large diffs are not rendered by default.

139 changes: 90 additions & 49 deletions dpf/cmake/DPF-plugin.cmake
Expand Up @@ -75,10 +75,10 @@ include(CMakeParseArguments)
# `jack`, `ladspa`, `dssi`, `lv2`, `vst2`, `vst3`, `clap`
#
# `UI_TYPE` <type>
# the user interface type: `opengl` (default), `cairo`
# the user interface type: `opengl` (default), `cairo`, `external`
#
# `MONOLITHIC`
# build LV2 as a single binary for UI and DSP
# `FILES_COMMON` <file1>...<fileN>
# list of sources which are part of both DSP and UI
#
# `FILES_DSP` <file1>...<fileN>
# list of sources which are part of the DSP
Expand All @@ -87,32 +87,46 @@ include(CMakeParseArguments)
# list of sources which are part of the UI
# empty indicates the plugin does not have UI
#
# `FILES_COMMON` <file1>...<fileN>
# list of sources which are part of both DSP and UI
# `MODGUI_CLASS_NAME`
# class name to use for modgui builds
#
# `MONOLITHIC`
# build LV2 as a single binary for UI and DSP
#
# `NO_SHARED_RESOURCES`
# do not build DPF shared resources (fonts, etc)
#
function(dpf_add_plugin NAME)
set(options MONOLITHIC NO_SHARED_RESOURCES)
set(oneValueArgs UI_TYPE)
set(multiValueArgs TARGETS FILES_DSP FILES_UI FILES_COMMON)
set(oneValueArgs MODGUI_CLASS_NAME UI_TYPE)
set(multiValueArgs FILES_COMMON FILES_DSP FILES_UI TARGETS)
cmake_parse_arguments(_dpf_plugin "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

if("${_dpf_plugin_UI_TYPE}" STREQUAL "")
set(_dpf_plugin_UI_TYPE "opengl")
endif()

set(_dgl_library)
set(_dgl_external OFF)
if(_dpf_plugin_FILES_UI)
if(_dpf_plugin_UI_TYPE STREQUAL "cairo")
dpf__add_dgl_cairo("${_dpf_plugin_NO_SHARED_RESOURCES}")
set(_dgl_library dgl-cairo)
elseif(_dpf_plugin_UI_TYPE STREQUAL "opengl")
dpf__add_dgl_opengl("${_dpf_plugin_NO_SHARED_RESOURCES}")
set(_dgl_library dgl-opengl)
elseif(_dpf_plugin_UI_TYPE STREQUAL "external")
set(_dgl_external ON)
else()
message(FATAL_ERROR "Unrecognized UI type for plugin: ${_dpf_plugin_UI_TYPE}")
endif()
endif()

set(_dgl_has_ui OFF)
if(_dgl_library OR _dgl_external)
set(_dgl_has_ui ON)
endif()

###
dpf__ensure_sources_non_empty(_dpf_plugin_FILES_COMMON)
dpf__ensure_sources_non_empty(_dpf_plugin_FILES_DSP)
Expand All @@ -123,48 +137,61 @@ function(dpf_add_plugin NAME)
target_include_directories("${NAME}" PUBLIC
"${DPF_ROOT_DIR}/distrho")

if(_dpf_plugin_MODGUI_CLASS_NAME)
target_compile_definitions("${NAME}" PUBLIC "DISTRHO_PLUGIN_MODGUI_CLASS_NAME=\"${_dpf_plugin_MODGUI_CLASS_NAME}\"")
endif()

if((NOT WIN32) AND (NOT APPLE) AND (NOT HAIKU))
target_link_libraries("${NAME}" PRIVATE "dl")
endif()

if(_dgl_library)
if(_dgl_library AND NOT _dgl_external)
# make sure that all code will see DGL_* definitions
target_link_libraries("${NAME}" PUBLIC
"${_dgl_library}-definitions"
dgl-system-libs-definitions)
dgl-system-libs-definitions
dgl-system-libs)
endif()

dpf__add_static_library("${NAME}-dsp" ${_dpf_plugin_FILES_DSP})
target_link_libraries("${NAME}-dsp" PUBLIC "${NAME}")

if(_dgl_library)
if(_dgl_library AND NOT _dgl_external)
dpf__add_static_library("${NAME}-ui" ${_dpf_plugin_FILES_UI})
target_link_libraries("${NAME}-ui" PUBLIC "${NAME}" ${_dgl_library})
if((NOT WIN32) AND (NOT APPLE) AND (NOT HAIKU))
target_link_libraries("${NAME}-ui" PRIVATE "dl")
endif()
# add the files containing Objective-C classes
dpf__add_plugin_specific_ui_sources("${NAME}-ui")
elseif(_dgl_external)
dpf__add_static_library("${NAME}-ui" ${_dpf_plugin_FILES_UI})
target_link_libraries("${NAME}-ui" PUBLIC "${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
dpf__add_plugin_specific_ui_sources("${NAME}-ui")
else()
add_library("${NAME}-ui" INTERFACE)
endif()

###
foreach(_target ${_dpf_plugin_TARGETS})
if(_target STREQUAL "jack")
dpf__build_jack("${NAME}" "${_dgl_library}")
dpf__build_jack("${NAME}" "${_dgl_has_ui}")
elseif(_target STREQUAL "ladspa")
dpf__build_ladspa("${NAME}")
elseif(_target STREQUAL "dssi")
dpf__build_dssi("${NAME}" "${_dgl_library}")
dpf__build_dssi("${NAME}" "${_dgl_has_ui}")
elseif(_target STREQUAL "lv2")
dpf__build_lv2("${NAME}" "${_dgl_library}" "${_dpf_plugin_MONOLITHIC}")
dpf__build_lv2("${NAME}" "${_dgl_has_ui}" "${_dpf_plugin_MONOLITHIC}")
elseif(_target STREQUAL "vst2")
dpf__build_vst2("${NAME}" "${_dgl_library}")
dpf__build_vst2("${NAME}" "${_dgl_has_ui}")
elseif(_target STREQUAL "vst3")
dpf__build_vst3("${NAME}" "${_dgl_library}")
dpf__build_vst3("${NAME}" "${_dgl_has_ui}")
elseif(_target STREQUAL "clap")
dpf__build_clap("${NAME}" "${_dgl_library}")
dpf__build_clap("${NAME}" "${_dgl_has_ui}")
else()
message(FATAL_ERROR "Unrecognized target type for plugin: ${_target}")
endif()
Expand All @@ -184,26 +211,27 @@ endfunction()
#
# Add build rules for a JACK/Standalone program.
#
function(dpf__build_jack NAME DGL_LIBRARY)
function(dpf__build_jack NAME HAS_UI)
dpf__create_dummy_source_list(_no_srcs)

dpf__add_executable("${NAME}-jack" ${_no_srcs})
dpf__add_plugin_main("${NAME}-jack" "jack")
dpf__add_ui_main("${NAME}-jack" "jack" "${DGL_LIBRARY}")
dpf__add_ui_main("${NAME}-jack" "jack" "${HAS_UI}")
target_link_libraries("${NAME}-jack" PRIVATE "${NAME}-dsp" "${NAME}-ui")
set_target_properties("${NAME}-jack" PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/$<0:>"
OUTPUT_NAME "${NAME}")

target_compile_definitions("${NAME}" PUBLIC "HAVE_JACK")
target_compile_definitions("${NAME}-jack" PRIVATE "HAVE_GETTIMEOFDAY")

find_package(PkgConfig)
pkg_check_modules(SDL2 "sdl2")
if(SDL2_FOUND)
target_compile_definitions("${NAME}" PUBLIC "HAVE_SDL2")
target_include_directories("${NAME}-jack" PRIVATE ${SDL2_INCLUDE_DIRS})
target_link_libraries("${NAME}-jack" PRIVATE ${SDL2_LIBRARIES})
dpf__target_link_directories("${NAME}-jack" ${SDL2_LIBRARY_DIRS})
target_include_directories("${NAME}-jack" PRIVATE ${SDL2_STATIC_INCLUDE_DIRS})
target_link_libraries("${NAME}-jack" PRIVATE ${SDL2_STATIC_LIBRARIES})
dpf__target_link_directories("${NAME}-jack" "${SDL2_STATIC_LIBRARY_DIRS}")
endif()

if(APPLE OR WIN32)
Expand All @@ -216,13 +244,13 @@ function(dpf__build_jack NAME DGL_LIBRARY)
target_compile_definitions("${NAME}" PUBLIC "HAVE_ALSA")
target_include_directories("${NAME}-jack" PRIVATE ${ALSA_INCLUDE_DIRS})
target_link_libraries("${NAME}-jack" PRIVATE ${ALSA_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
dpf__target_link_directories("${NAME}-jack" ${ALSA_LIBRARY_DIRS})
dpf__target_link_directories("${NAME}-jack" "${ALSA_LIBRARY_DIRS}")
endif()
if(PULSEAUDIO_FOUND)
target_compile_definitions("${NAME}" PUBLIC "HAVE_PULSEAUDIO")
target_include_directories("${NAME}-jack" PRIVATE ${PULSEAUDIO_INCLUDE_DIRS})
target_link_libraries("${NAME}-jack" PRIVATE ${PULSEAUDIO_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
dpf__target_link_directories("${NAME}-jack" ${PULSEAUDIO_LIBRARY_DIRS})
dpf__target_link_directories("${NAME}-jack" "${PULSEAUDIO_LIBRARY_DIRS}")
endif()
if(ALSA_FOUND OR PULSEAUDIO_FOUND)
target_compile_definitions("${NAME}" PUBLIC "HAVE_RTAUDIO")
Expand All @@ -239,7 +267,10 @@ function(dpf__build_jack NAME DGL_LIBRARY)
"${APPLE_COREFOUNDATION_FRAMEWORK}"
"${APPLE_COREMIDI_FRAMEWORK}")
elseif(WIN32)
target_link_libraries("${NAME}-jack" PRIVATE "dsound" "ole32" "winmm")
target_link_libraries("${NAME}-jack" PRIVATE "ksuser" "mfplat" "mfuuid" "ole32" "winmm" "wmcodecdspuuid")
if(HAS_UI AND MINGW)
set_target_properties("${NAME}-jack" PROPERTIES WIN32_EXECUTABLE TRUE)
endif()
endif()
endfunction()

Expand Down Expand Up @@ -267,7 +298,7 @@ endfunction()
#
# Add build rules for a DSSI plugin.
#
function(dpf__build_dssi NAME DGL_LIBRARY)
function(dpf__build_dssi NAME HAS_UI)
find_package(PkgConfig)
pkg_check_modules(LIBLO "liblo")
if(NOT LIBLO_FOUND)
Expand All @@ -288,9 +319,9 @@ function(dpf__build_dssi NAME DGL_LIBRARY)
OUTPUT_NAME "${NAME}-dssi"
PREFIX "")

if(DGL_LIBRARY)
if(HAS_UI)
dpf__add_executable("${NAME}-dssi-ui" ${_no_srcs})
dpf__add_ui_main("${NAME}-dssi-ui" "dssi" "${DGL_LIBRARY}")
dpf__add_ui_main("${NAME}-dssi-ui" "dssi" "${HAS_UI}")
target_link_libraries("${NAME}-dssi-ui" PRIVATE "${NAME}-ui")
set_target_properties("${NAME}-dssi-ui" PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/${NAME}-dssi/$<0:>"
Expand All @@ -299,7 +330,7 @@ function(dpf__build_dssi NAME DGL_LIBRARY)
target_compile_definitions("${NAME}" PUBLIC "HAVE_LIBLO")
target_include_directories("${NAME}-dssi-ui" PRIVATE ${LIBLO_INCLUDE_DIRS})
target_link_libraries("${NAME}-dssi-ui" PRIVATE ${LIBLO_LIBRARIES})
dpf__target_link_directories("${NAME}-dssi-ui" ${LIBLO_LIBRARY_DIRS})
dpf__target_link_directories("${NAME}-dssi-ui" "${LIBLO_LIBRARY_DIRS}")
endif()
endfunction()

Expand All @@ -308,12 +339,12 @@ endfunction()
#
# Add build rules for an LV2 plugin.
#
function(dpf__build_lv2 NAME DGL_LIBRARY MONOLITHIC)
function(dpf__build_lv2 NAME HAS_UI MONOLITHIC)
dpf__create_dummy_source_list(_no_srcs)

dpf__add_module("${NAME}-lv2" ${_no_srcs})
dpf__add_plugin_main("${NAME}-lv2" "lv2")
if(DGL_LIBRARY AND MONOLITHIC)
if(HAS_UI AND MONOLITHIC)
dpf__set_module_export_list("${NAME}-lv2" "lv2")
else()
dpf__set_module_export_list("${NAME}-lv2" "lv2-dsp")
Expand All @@ -325,15 +356,15 @@ function(dpf__build_lv2 NAME DGL_LIBRARY MONOLITHIC)
OUTPUT_NAME "${NAME}_dsp"
PREFIX "")

if(DGL_LIBRARY)
if(HAS_UI)
if(MONOLITHIC)
dpf__add_ui_main("${NAME}-lv2" "lv2" "${DGL_LIBRARY}")
dpf__add_ui_main("${NAME}-lv2" "lv2" "${HAS_UI}")
target_link_libraries("${NAME}-lv2" PRIVATE "${NAME}-ui")
set_target_properties("${NAME}-lv2" PROPERTIES
OUTPUT_NAME "${NAME}")
else()
dpf__add_module("${NAME}-lv2-ui" ${_no_srcs})
dpf__add_ui_main("${NAME}-lv2-ui" "lv2" "${DGL_LIBRARY}")
dpf__add_ui_main("${NAME}-lv2-ui" "lv2" "${HAS_UI}")
dpf__set_module_export_list("${NAME}-lv2-ui" "lv2-ui")
target_link_libraries("${NAME}-lv2-ui" PRIVATE "${NAME}-ui")
set_target_properties("${NAME}-lv2-ui" PROPERTIES
Expand Down Expand Up @@ -361,12 +392,12 @@ endfunction()
#
# Add build rules for a VST2 plugin.
#
function(dpf__build_vst2 NAME DGL_LIBRARY)
function(dpf__build_vst2 NAME HAS_UI)
dpf__create_dummy_source_list(_no_srcs)

dpf__add_module("${NAME}-vst2" ${_no_srcs})
dpf__add_plugin_main("${NAME}-vst2" "vst2")
dpf__add_ui_main("${NAME}-vst2" "vst2" "${DGL_LIBRARY}")
dpf__add_ui_main("${NAME}-vst2" "vst2" "${HAS_UI}")
dpf__set_module_export_list("${NAME}-vst2" "vst2")
target_link_libraries("${NAME}-vst2" PRIVATE "${NAME}-dsp" "${NAME}-ui")
set_target_properties("${NAME}-vst2" PROPERTIES
Expand Down Expand Up @@ -439,14 +470,14 @@ endfunction()
#
# Add build rules for a VST3 plugin.
#
function(dpf__build_vst3 NAME DGL_LIBRARY)
function(dpf__build_vst3 NAME HAS_UI)
dpf__determine_vst3_package_architecture(vst3_arch)

dpf__create_dummy_source_list(_no_srcs)

dpf__add_module("${NAME}-vst3" ${_no_srcs})
dpf__add_plugin_main("${NAME}-vst3" "vst3")
dpf__add_ui_main("${NAME}-vst3" "vst3" "${DGL_LIBRARY}")
dpf__add_ui_main("${NAME}-vst3" "vst3" "${HAS_UI}")
dpf__set_module_export_list("${NAME}-vst3" "vst3")
target_link_libraries("${NAME}-vst3" PRIVATE "${NAME}-dsp" "${NAME}-ui")
set_target_properties("${NAME}-vst3" PROPERTIES
Expand Down Expand Up @@ -481,12 +512,12 @@ endfunction()
#
# Add build rules for a VST2 plugin.
#
function(dpf__build_clap NAME DGL_LIBRARY)
function(dpf__build_clap NAME HAS_UI)
dpf__create_dummy_source_list(_no_srcs)

dpf__add_module("${NAME}-clap" ${_no_srcs})
dpf__add_plugin_main("${NAME}-clap" "clap")
dpf__add_ui_main("${NAME}-clap" "clap" "${DGL_LIBRARY}")
dpf__add_ui_main("${NAME}-clap" "clap" "${HAS_UI}")
dpf__set_module_export_list("${NAME}-clap" "clap")
target_link_libraries("${NAME}-clap" PRIVATE "${NAME}-dsp" "${NAME}-ui")
set_target_properties("${NAME}-clap" PROPERTIES
Expand Down Expand Up @@ -532,6 +563,7 @@ function(dpf__add_dgl_cairo NO_SHARED_RESOURCES)
"${DPF_ROOT_DIR}/dgl/src/Geometry.cpp"
"${DPF_ROOT_DIR}/dgl/src/ImageBase.cpp"
"${DPF_ROOT_DIR}/dgl/src/ImageBaseWidgets.cpp"
"${DPF_ROOT_DIR}/dgl/src/Layout.cpp"
"${DPF_ROOT_DIR}/dgl/src/SubWidget.cpp"
"${DPF_ROOT_DIR}/dgl/src/SubWidgetPrivateData.cpp"
"${DPF_ROOT_DIR}/dgl/src/TopLevelWidget.cpp"
Expand Down Expand Up @@ -597,6 +629,7 @@ function(dpf__add_dgl_opengl NO_SHARED_RESOURCES)
"${DPF_ROOT_DIR}/dgl/src/Geometry.cpp"
"${DPF_ROOT_DIR}/dgl/src/ImageBase.cpp"
"${DPF_ROOT_DIR}/dgl/src/ImageBaseWidgets.cpp"
"${DPF_ROOT_DIR}/dgl/src/Layout.cpp"
"${DPF_ROOT_DIR}/dgl/src/SubWidget.cpp"
"${DPF_ROOT_DIR}/dgl/src/SubWidgetPrivateData.cpp"
"${DPF_ROOT_DIR}/dgl/src/TopLevelWidget.cpp"
Expand Down Expand Up @@ -661,34 +694,42 @@ function(dpf__add_dgl_system_libs)
endif()
add_library(dgl-system-libs INTERFACE)
add_library(dgl-system-libs-definitions INTERFACE)
if(HAIKU)
target_link_libraries(dgl-system-libs INTERFACE "be")
elseif(WIN32)
target_link_libraries(dgl-system-libs INTERFACE "gdi32" "comdlg32")
elseif(APPLE)
if(APPLE)
find_library(APPLE_COCOA_FRAMEWORK "Cocoa")
find_library(APPLE_COREVIDEO_FRAMEWORK "CoreVideo")
target_link_libraries(dgl-system-libs INTERFACE "${APPLE_COCOA_FRAMEWORK}" "${APPLE_COREVIDEO_FRAMEWORK}")
elseif(EMSCRIPTEN)
elseif(HAIKU)
target_link_libraries(dgl-system-libs INTERFACE "be")
elseif(WIN32)
target_link_libraries(dgl-system-libs INTERFACE "gdi32" "comdlg32")
else()
find_package(PkgConfig)
pkg_check_modules(DBUS "dbus-1")
if(DBUS_FOUND)
target_compile_definitions(dgl-system-libs-definitions INTERFACE "HAVE_DBUS")
target_include_directories(dgl-system-libs INTERFACE "${DBUS_INCLUDE_DIRS}")
target_link_libraries(dgl-system-libs INTERFACE "${DBUS_LIBRARIES}")
endif()
find_package(X11 REQUIRED)
target_compile_definitions(dgl-system-libs-definitions INTERFACE "HAVE_X11")
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")
target_link_libraries(dgl-system-libs INTERFACE "${X11_Xcursor_LIB}")
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")
target_link_libraries(dgl-system-libs INTERFACE "${X11_Xext_LIB}")
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")
target_link_libraries(dgl-system-libs INTERFACE "${X11_Xrandr_LIB}")
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")
target_link_libraries(dgl-system-libs INTERFACE "${X11_XSync_LIB}")
endif()
endif()

Expand Down
5 changes: 5 additions & 0 deletions dpf/dgl/Color.hpp
Expand Up @@ -94,6 +94,11 @@ struct Color {
*/
Color plus(float value) const noexcept;

/**
Create a new color based on this one but colors inverted.
*/
Color invert() const noexcept;

/**
Create a color specified by hue, saturation and lightness.
Values must in [0..1] range.
Expand Down
2 changes: 1 addition & 1 deletion dpf/dgl/EventHandlers.hpp
Expand Up @@ -156,7 +156,7 @@ class KnobEventHandler
bool scrollEvent(const Widget::ScrollEvent& ev);

protected:
State getState() const noexcept;
State getState() const noexcept;

private:
struct PrivateData;
Expand Down
170 changes: 89 additions & 81 deletions dpf/dgl/Makefile
Expand Up @@ -26,229 +26,237 @@ endif

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

ifeq ($(MODGUI_BUILD),true)
BUILD_DIR_SUFFIX = -modgui
endif

BUILD_DIR = ../build$(BUILD_DIR_SUFFIX)

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

OBJS_common = \
../build/dgl/Application.cpp.o \
../build/dgl/ApplicationPrivateData.cpp.o \
../build/dgl/Color.cpp.o \
../build/dgl/EventHandlers.cpp.o \
../build/dgl/Geometry.cpp.o \
../build/dgl/ImageBase.cpp.o \
../build/dgl/ImageBaseWidgets.cpp.o \
../build/dgl/Layout.cpp.o \
../build/dgl/Resources.cpp.o \
../build/dgl/SubWidget.cpp.o \
../build/dgl/SubWidgetPrivateData.cpp.o \
../build/dgl/TopLevelWidget.cpp.o \
../build/dgl/TopLevelWidgetPrivateData.cpp.o \
../build/dgl/Widget.cpp.o \
../build/dgl/WidgetPrivateData.cpp.o \
../build/dgl/Window.cpp.o \
../build/dgl/WindowPrivateData.cpp.o
$(BUILD_DIR)/dgl/Application.cpp.o \
$(BUILD_DIR)/dgl/ApplicationPrivateData.cpp.o \
$(BUILD_DIR)/dgl/Color.cpp.o \
$(BUILD_DIR)/dgl/EventHandlers.cpp.o \
$(BUILD_DIR)/dgl/Geometry.cpp.o \
$(BUILD_DIR)/dgl/ImageBase.cpp.o \
$(BUILD_DIR)/dgl/ImageBaseWidgets.cpp.o \
$(BUILD_DIR)/dgl/Layout.cpp.o \
$(BUILD_DIR)/dgl/Resources.cpp.o \
$(BUILD_DIR)/dgl/SubWidget.cpp.o \
$(BUILD_DIR)/dgl/SubWidgetPrivateData.cpp.o \
$(BUILD_DIR)/dgl/TopLevelWidget.cpp.o \
$(BUILD_DIR)/dgl/TopLevelWidgetPrivateData.cpp.o \
$(BUILD_DIR)/dgl/Widget.cpp.o \
$(BUILD_DIR)/dgl/WidgetPrivateData.cpp.o \
$(BUILD_DIR)/dgl/Window.cpp.o \
$(BUILD_DIR)/dgl/WindowPrivateData.cpp.o

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

OBJS_cairo = $(OBJS_common) \
../build/dgl/Cairo.cpp.cairo.o
$(BUILD_DIR)/dgl/Cairo.cpp.cairo.o

ifeq ($(MACOS),true)
OBJS_cairo += ../build/dgl/pugl.mm.cairo.o
OBJS_cairo += $(BUILD_DIR)/dgl/pugl.mm.cairo.o
else
OBJS_cairo += ../build/dgl/pugl.cpp.cairo.o
OBJS_cairo += $(BUILD_DIR)/dgl/pugl.cpp.cairo.o
endif

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

OBJS_opengl = $(OBJS_common) \
../build/dgl/OpenGL.cpp.opengl.o \
../build/dgl/NanoVG.cpp.opengl.o
$(BUILD_DIR)/dgl/OpenGL.cpp.opengl.o \
$(BUILD_DIR)/dgl/NanoVG.cpp.opengl.o

ifeq ($(MACOS),true)
OBJS_opengl += ../build/dgl/pugl.mm.opengl.o
OBJS_opengl += $(BUILD_DIR)/dgl/pugl.mm.opengl.o
else
OBJS_opengl += ../build/dgl/pugl.cpp.opengl.o
OBJS_opengl += $(BUILD_DIR)/dgl/pugl.cpp.opengl.o
endif

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

OBJS_opengl3 = $(OBJS_common) \
../build/dgl/OpenGL.cpp.opengl3.o \
../build/dgl/NanoVG.cpp.opengl3.o
$(BUILD_DIR)/dgl/OpenGL.cpp.opengl3.o \
$(BUILD_DIR)/dgl/NanoVG.cpp.opengl3.o

ifeq ($(MACOS),true)
OBJS_opengl3 += ../build/dgl/pugl.mm.opengl3.o
OBJS_opengl3 += $(BUILD_DIR)/dgl/pugl.mm.opengl3.o
else
OBJS_opengl3 += ../build/dgl/pugl.cpp.opengl3.o
OBJS_opengl3 += $(BUILD_DIR)/dgl/pugl.cpp.opengl3.o
endif

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

OBJS_stub = $(OBJS_common)

ifeq ($(MACOS),true)
OBJS_stub += ../build/dgl/pugl.mm.o
OBJS_stub += $(BUILD_DIR)/dgl/pugl.mm.o
else
OBJS_stub += ../build/dgl/pugl.cpp.o
OBJS_stub += $(BUILD_DIR)/dgl/pugl.cpp.o
endif

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

OBJS_vulkan = $(OBJS_common) \
../build/dgl/Vulkan.cpp.vulkan.o
$(BUILD_DIR)/dgl/Vulkan.cpp.vulkan.o

ifeq ($(MACOS),true)
OBJS_vulkan += ../build/dgl/pugl.mm.vulkan.o
OBJS_vulkan += $(BUILD_DIR)/dgl/pugl.mm.vulkan.o
else
OBJS_vulkan += ../build/dgl/pugl.cpp.vulkan.o
OBJS_vulkan += $(BUILD_DIR)/dgl/pugl.cpp.vulkan.o
endif

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

ifeq ($(HAVE_CAIRO),true)
TARGETS += ../build/libdgl-cairo.a
TARGETS += $(BUILD_DIR)/libdgl-cairo.a
endif

ifeq ($(HAVE_OPENGL),true)
TARGETS += ../build/libdgl-opengl.a
TARGETS += $(BUILD_DIR)/libdgl-opengl.a
# Compat name, to be removed soon
TARGETS += ../build/libdgl.a
TARGETS += $(BUILD_DIR)/libdgl.a
endif

ifeq ($(HAVE_STUB),true)
TARGETS += ../build/libdgl-stub.a
TARGETS += $(BUILD_DIR)/libdgl-stub.a
endif

ifeq ($(HAVE_VULKAN),true)
TARGETS += ../build/libdgl-vulkan.a
TARGETS += $(BUILD_DIR)/libdgl-vulkan.a
endif

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

all: $(TARGETS)

cairo: ../build/libdgl-cairo.a
opengl: ../build/libdgl-opengl.a
opengl3: ../build/libdgl-opengl3.a
stub: ../build/libdgl-stub.a
vulkan: ../build/libdgl-vulkan.a
cairo: $(BUILD_DIR)/libdgl-cairo.a
opengl: $(BUILD_DIR)/libdgl-opengl.a
opengl3: $(BUILD_DIR)/libdgl-opengl3.a
stub: $(BUILD_DIR)/libdgl-stub.a
vulkan: $(BUILD_DIR)/libdgl-vulkan.a

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

../build/libdgl-cairo.a: $(OBJS_cairo)
-@mkdir -p ../build
$(BUILD_DIR)/libdgl-cairo.a: $(OBJS_cairo)
-@mkdir -p $(BUILD_DIR)
@echo "Creating libdgl-cairo.a"
$(SILENT)rm -f $@
$(SILENT)$(AR) crs $@ $^

../build/libdgl-opengl.a: $(OBJS_opengl)
-@mkdir -p ../build
$(BUILD_DIR)/libdgl-opengl.a: $(OBJS_opengl)
-@mkdir -p $(BUILD_DIR)
@echo "Creating libdgl-opengl.a"
$(SILENT)rm -f $@
$(SILENT)$(AR) crs $@ $^

../build/libdgl-opengl3.a: $(OBJS_opengl3)
-@mkdir -p ../build
$(BUILD_DIR)/libdgl-opengl3.a: $(OBJS_opengl3)
-@mkdir -p $(BUILD_DIR)
@echo "Creating libdgl-opengl3.a"
$(SILENT)rm -f $@
$(SILENT)$(AR) crs $@ $^

../build/libdgl-stub.a: $(OBJS_stub)
-@mkdir -p ../build
$(BUILD_DIR)/libdgl-stub.a: $(OBJS_stub)
-@mkdir -p $(BUILD_DIR)
@echo "Creating libdgl-stub.a"
$(SILENT)rm -f $@
$(SILENT)$(AR) crs $@ $^

../build/libdgl-vulkan.a: $(OBJS_vulkan)
-@mkdir -p ../build
$(BUILD_DIR)/libdgl-vulkan.a: $(OBJS_vulkan)
-@mkdir -p $(BUILD_DIR)
@echo "Creating libdgl-vulkan.a"
$(SILENT)rm -f $@
$(SILENT)$(AR) crs $@ $^

# Compat name, to be removed soon
../build/libdgl.a: ../build/libdgl-opengl.a
$(BUILD_DIR)/libdgl.a: $(BUILD_DIR)/libdgl-opengl.a
@echo "Symlinking libdgl.a"
$(SILENT)ln -sf $< $@

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

../build/dgl/%.c.o: src/%.c
-@mkdir -p ../build/dgl
$(BUILD_DIR)/dgl/%.c.o: src/%.c
-@mkdir -p $(BUILD_DIR)/dgl
@echo "Compiling $<"
$(SILENT)$(CC) $< $(BUILD_C_FLAGS) -c -o $@

../build/dgl/%.cpp.o: src/%.cpp
-@mkdir -p ../build/dgl
$(BUILD_DIR)/dgl/%.cpp.o: src/%.cpp
-@mkdir -p $(BUILD_DIR)/dgl
@echo "Compiling $<"
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@

../build/dgl/%.mm.o: src/%.mm
-@mkdir -p ../build/dgl
$(BUILD_DIR)/dgl/%.mm.o: src/%.mm
-@mkdir -p $(BUILD_DIR)/dgl
@echo "Compiling $<"
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -ObjC++ -o $@

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

../build/dgl/pugl.cpp.o: src/pugl.cpp
-@mkdir -p ../build/dgl
$(BUILD_DIR)/dgl/pugl.cpp.o: src/pugl.cpp
-@mkdir -p $(BUILD_DIR)/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
$(BUILD_DIR)/dgl/pugl.mm.o: src/pugl.mm
-@mkdir -p $(BUILD_DIR)/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
$(BUILD_DIR)/dgl/%.cpp.cairo.o: src/%.cpp
-@mkdir -p $(BUILD_DIR)/dgl
@echo "Compiling $< (Cairo variant)"
$(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
$(BUILD_DIR)/dgl/%.mm.cairo.o: src/%.mm
-@mkdir -p $(BUILD_DIR)/dgl
@echo "Compiling $< (Cairo variant)"
$(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
$(BUILD_DIR)/dgl/%.cpp.opengl.o: src/%.cpp
-@mkdir -p $(BUILD_DIR)/dgl
@echo "Compiling $< (OpenGL variant)"
$(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
$(BUILD_DIR)/dgl/%.mm.opengl.o: src/%.mm
-@mkdir -p $(BUILD_DIR)/dgl
@echo "Compiling $< (OpenGL variant)"
$(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
$(BUILD_DIR)/dgl/%.cpp.opengl3.o: src/%.cpp
-@mkdir -p $(BUILD_DIR)/dgl
@echo "Compiling $< (OpenGL3 variant)"
$(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
$(BUILD_DIR)/dgl/%.mm.opengl3.o: src/%.mm
-@mkdir -p $(BUILD_DIR)/dgl
@echo "Compiling $< (OpenGL3 variant)"
$(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
$(BUILD_DIR)/dgl/%.cpp.vulkan.o: src/%.cpp
-@mkdir -p $(BUILD_DIR)/dgl
@echo "Compiling $< (Vulkan variant)"
$(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
$(BUILD_DIR)/dgl/%.mm.vulkan.o: src/%.mm
-@mkdir -p $(BUILD_DIR)/dgl
@echo "Compiling $< (Vulkan variant)"
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(PUGL_EXTRA_FLAGS) $(VULKAN_FLAGS) -DDGL_VULKAN -c -ObjC++ -o $@

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

clean:
rm -rf ../build/dgl ../build/libdgl*.*
rm -rf $(BUILD_DIR)/dgl $(BUILD_DIR)/libdgl*.*

debug:
$(MAKE) DEBUG=true
Expand Down
6 changes: 4 additions & 2 deletions dpf/dgl/src/ApplicationPrivateData.cpp
Expand Up @@ -67,9 +67,11 @@ Application::PrivateData::PrivateData(const bool standalone)
DISTRHO_SAFE_ASSERT_RETURN(world != nullptr,);

puglSetWorldHandle(world, this);
#ifndef __EMSCRIPTEN__
#ifdef __EMSCRIPTEN__
puglSetClassName(world, "canvas");
#else
puglSetClassName(world, DISTRHO_MACRO_AS_STRING(DGL_NAMESPACE));
#endif
#endif
}

Application::PrivateData::~PrivateData()
Expand Down
9 changes: 9 additions & 0 deletions dpf/dgl/src/Color.cpp
Expand Up @@ -163,6 +163,15 @@ Color Color::plus(const float value) const noexcept
return color;
}

Color Color::invert() const noexcept
{
Color color(*this);
color.red = 1.f - color.red;
color.green = 1.f - color.green;
color.blue = 1.f - color.blue;
return color;
}

Color Color::fromHSL(float hue, float saturation, float lightness, float alpha)
{
float m1, m2;
Expand Down
2 changes: 1 addition & 1 deletion dpf/dgl/src/EventHandlers.cpp
Expand Up @@ -441,7 +441,7 @@ struct KnobEventHandler::PrivateData {
}

if (d_isZero(movDiff))
return false;
return true;

const float divisor = (ev.mod & kModifierControl) ? accel * 10.f : accel;
valueTmp += (maximum - minimum) / divisor * movDiff;
Expand Down
492 changes: 0 additions & 492 deletions dpf/dgl/src/pugl-custom/pugl.h

This file was deleted.

441 changes: 0 additions & 441 deletions dpf/dgl/src/pugl-custom/pugl_haiku.cpp

This file was deleted.

263 changes: 0 additions & 263 deletions dpf/dgl/src/pugl-custom/pugl_internal.h

This file was deleted.

974 changes: 0 additions & 974 deletions dpf/dgl/src/pugl-custom/pugl_osx.m

This file was deleted.

565 changes: 0 additions & 565 deletions dpf/dgl/src/pugl-custom/pugl_win.cpp

This file was deleted.

739 changes: 0 additions & 739 deletions dpf/dgl/src/pugl-custom/pugl_x11.c

This file was deleted.

29 changes: 0 additions & 29 deletions dpf/dgl/src/pugl-extra/extras.c

This file was deleted.

50 changes: 0 additions & 50 deletions dpf/dgl/src/pugl-extra/extras.h

This file was deleted.

363 changes: 342 additions & 21 deletions dpf/dgl/src/pugl-extra/haiku.cpp
@@ -1,28 +1,348 @@
/*
Copyright 2012-2019 David Robillard <http://drobilla.net>
Copyright 2019-2020 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.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

/**
@file mac.cpp HaikuOS implementation.
*/
// Copyright 2012-2022 David Robillard <d@drobilla.net>
// Copyright 2021-2022 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: ISC

#include "haiku.h"

#include "pugl/detail/implementation.h"
#include "../pugl-upstream/src/internal.h"

class PuglHaikuView : public BView
{
PuglView* const view;

public:
PuglHaikuView(PuglView* const v)
: BView(NULL, B_FULL_UPDATE_ON_RESIZE|B_FRAME_EVENTS|B_NAVIGABLE|B_INPUT_METHOD_AWARE),
view(v) {}

protected:
void GetPreferredSize(float* width, float* height) override
{
d_stdout("%s %i", __func__, __LINE__);
if (width != nullptr)
*width = view->frame.width;
if (height != nullptr)
*height = view->frame.height;
d_stdout("%s %i", __func__, __LINE__);
}
};

class PuglHaikuWindow : public BWindow
{
PuglView* const view;

public:
PuglHaikuWindow(PuglView* const v)
: BWindow(BRect(1.0f), "DPF-Window", B_TITLED_WINDOW, 0x0),
view(v) {}

// protected:
// bool QuitRequested() override
// {
// d_stdout("%s %i", __func__, __LINE__);
// if (puglView->closeFunc) {
// puglView->closeFunc(puglView);
// puglView->redisplay = false;
// }
// needsQuit = false;
// d_stdout("%s %i", __func__, __LINE__);
// return true;
// }
};

BApplication* s_app = NULL;

PuglWorldInternals*
puglInitWorldInternals(const PuglWorldType type, const PuglWorldFlags flags)
{
if (!s_app) {
status_t status;
s_app = new BApplication("application/x-vnd.pugl-application", &status);

if (status != B_OK) {
delete s_app;
return NULL;
}
}

PuglWorldInternals* impl =
(PuglWorldInternals*)calloc(1, sizeof(PuglWorldInternals));

impl->app = s_app;
return impl;
}

void*
puglGetNativeWorld(PuglWorld* const world)
{
return world->impl->app;
}

PuglInternals*
puglInitViewInternals(PuglWorld* const world)
{
PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals));

return impl;
}

PuglStatus
puglRealize(PuglView* const view)
{
PuglInternals* const impl = view->impl;
PuglStatus st = PUGL_SUCCESS;

// Ensure that we're unrealized and that a reasonable backend has been set
if (impl->view) {
return PUGL_FAILURE;
}
if (!view->backend || !view->backend->configure) {
return PUGL_BAD_BACKEND;
}

// Set the size to the default if it has not already been set
if (view->frame.width <= 0.0 || view->frame.height <= 0.0) {
const PuglViewSize defaultSize = view->sizeHints[PUGL_DEFAULT_SIZE];
if (!defaultSize.width || !defaultSize.height) {
return PUGL_BAD_CONFIGURATION;
}

view->frame.width = defaultSize.width;
view->frame.height = defaultSize.height;
}

// Center top-level windows if a position has not been set
if (!view->parent && !view->frame.x && !view->frame.y) {
// TODO
}

if (!view->parent) {
impl->window = new PuglHaikuWindow(view);
impl->window->Lock();
}

impl->view = new PuglHaikuView(view);

if (view->parent) {
BView* const pview = (BView*)view->parent;
pview->AddChild(impl->view);
} else {
impl->window->AddChild(impl->view);
}

// Configure and create the backend
if ((st = view->backend->configure(view)) || (st = view->backend->create(view))) {
view->backend->destroy(view);
return st;
}

if (view->title) {
puglSetWindowTitle(view, view->title);
}

if (view->transientParent) {
puglSetTransientParent(view, view->transientParent);
}

puglDispatchSimpleEvent(view, PUGL_CREATE);

if (impl->window) {
impl->window->Unlock();
}

return PUGL_SUCCESS;
}

PuglStatus
puglShow(PuglView* const view)
{
PuglInternals* const impl = view->impl;
if (impl->window) {
impl->window->Show();
} else {
impl->view->Show();
}
return PUGL_SUCCESS;
}

PuglStatus
puglHide(PuglView* const view)
{
PuglInternals* const impl = view->impl;
if (impl->window) {
impl->window->Hide();
} else {
impl->view->Hide();
}
return PUGL_SUCCESS;
}

void
puglFreeViewInternals(PuglView* const view)
{
if (view && view->impl) {
PuglInternals* const impl = view->impl;
if (view->backend) {
view->backend->destroy(view);
}
if (impl->view) {
if (impl->window) {
impl->window->RemoveChild(impl->view);
}
delete impl->view;
delete impl->window;
}
free(impl);
}
}

void
puglFreeWorldInternals(PuglWorld* const world)
{
// if (world->impl->app != nullptr && world->impl->app->CountWindows() == 0) {
// delete world->impl->app;
// s_app = NULL;
// }
free(world->impl);
}

PuglStatus
puglGrabFocus(PuglView*)
{
return PUGL_UNSUPPORTED;
}

double
puglGetScaleFactor(const PuglView* const view)
{
return 1.0;
}

double
puglGetTime(const PuglWorld* const world)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return ((double)ts.tv_sec + (double)ts.tv_nsec / 1000000000.0) -
world->startTime;
}

PuglStatus
puglUpdate(PuglWorld* const world, const double timeout)
{
return PUGL_UNSUPPORTED;
}

PuglStatus
puglPostRedisplay(PuglView* const view)
{
return PUGL_UNSUPPORTED;
}

PuglStatus
puglPostRedisplayRect(PuglView* const view, const PuglRect rect)
{
return PUGL_UNSUPPORTED;
}

PuglNativeView
puglGetNativeView(PuglView* const view)
{
return 0;
}

PuglStatus
puglSetWindowTitle(PuglView* const view, const char* const title)
{
puglSetString(&view->title, title);
return PUGL_UNSUPPORTED;
}

PuglStatus
puglSetSizeHint(PuglView* const view,
const PuglSizeHint hint,
const PuglSpan width,
const PuglSpan height)
{
view->sizeHints[hint].width = width;
view->sizeHints[hint].height = height;
return PUGL_SUCCESS;
}

PuglStatus
puglStartTimer(PuglView* const view, const uintptr_t id, const double timeout)
{
return PUGL_UNSUPPORTED;
}

PuglStatus
puglStopTimer(PuglView* const view, const uintptr_t id)
{
return PUGL_UNSUPPORTED;
}

PuglStatus
puglPaste(PuglView* const view)
{
return PUGL_UNSUPPORTED;
}

PuglStatus
puglAcceptOffer(PuglView* const view,
const PuglDataOfferEvent* const offer,
const uint32_t typeIndex)
{
return PUGL_UNSUPPORTED;
}

uint32_t
puglGetNumClipboardTypes(const PuglView* const view)
{
return 0u;
}

const char*
puglGetClipboardType(const PuglView* const view, const uint32_t typeIndex)
{
return NULL;
}

const void*
puglGetClipboard(PuglView* const view,
const uint32_t typeIndex,
size_t* const len)
{
return NULL;
}

PuglStatus
puglSetClipboard(PuglView* const view,
const char* const type,
const void* const data,
const size_t len)
{
return PUGL_FAILURE;
}

PuglStatus
puglSetCursor(PuglView* const view, const PuglCursor cursor)
{
return PUGL_FAILURE;
}

PuglStatus
puglSetTransientParent(PuglView* const view, const PuglNativeView parent)
{
return PUGL_FAILURE;
}

PuglStatus
puglSetPosition(PuglView* const view, const int x, const int y)
{
return PUGL_FAILURE;
}

#if 0
PuglStatus
puglGrabFocus(PuglView* view)
{
Expand Down Expand Up @@ -79,3 +399,4 @@ void setVisible(const bool yesNo)
bView->Hide();
}
}
#endif
34 changes: 12 additions & 22 deletions dpf/dgl/src/pugl-extra/haiku.h
@@ -1,35 +1,25 @@
/*
Copyright 2012-2019 David Robillard <http://drobilla.net>
Copyright 2019-2020 Filipe Coelho <falktx@falktx.com>
// Copyright 2012-2022 David Robillard <d@drobilla.net>
// Copyright 2021-2022 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: ISC

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

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

/**
@file haiku.h Shared definitions for HaikuOS implementation.
*/
#include "../pugl-upstream/src/types.h"

#include "pugl/pugl.h"

#include <Application.h>
#include <Window.h>
// using? interface/

struct PuglWorldInternalsImpl {
BApplication* app;
BApplication* app;
};

struct PuglInternalsImpl {
BViewType* view;
BWindow* window;
PuglSurface* surface;
BView* view;
BWindow* window;
};

#endif // PUGL_SRC_HAIKU_H
87 changes: 87 additions & 0 deletions dpf/dgl/src/pugl-extra/haiku_gl.cpp
@@ -0,0 +1,87 @@
// Copyright 2012-2022 David Robillard <d@drobilla.net>
// Copyright 2021-2022 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: ISC

#include "../pugl-upstream/src/stub.h"
#include "haiku.h"

#include "pugl/pugl.h"

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

#include <GL/gl.h>
#include <opengl/GLView.h>

typedef struct {
BGLView* view;
} PuglHaikuGlSurface;

static PuglStatus
puglHaikuGlConfigure(PuglView* view)
{
PuglInternals* const impl = view->impl;

PuglHaikuGlSurface* const surface =
(PuglHaikuGlSurface*)calloc(1, sizeof(PuglHaikuGlSurface));
impl->surface = surface;

return PUGL_SUCCESS;
}

PUGL_WARN_UNUSED_RESULT
static PuglStatus
puglHaikuGlEnter(PuglView* const view, const PuglExposeEvent* PUGL_UNUSED(expose))
{
PuglHaikuGlSurface* const surface = (PuglHaikuGlSurface*)view->impl->surface;
if (!surface || !surface->view) {
return PUGL_FAILURE;
}

surface->view->LockGL();
return PUGL_SUCCESS;
}

PUGL_WARN_UNUSED_RESULT
static PuglStatus
puglHaikuGlLeave(PuglView* const view, const PuglExposeEvent* const expose)
{
PuglHaikuGlSurface* const surface = (PuglHaikuGlSurface*)view->impl->surface;
if (!surface || !surface->view) {
return PUGL_FAILURE;
}

if (expose)
surface->view->SwapBuffers();

surface->view->UnlockGL();
return PUGL_SUCCESS;
}

static PuglStatus
puglHaikuGlCreate(PuglView* view)
{
return PUGL_SUCCESS;
}

static void
puglHaikuGlDestroy(PuglView* view)
{
PuglHaikuGlSurface* surface = (PuglHaikuGlSurface*)view->impl->surface;
if (surface) {
free(surface);
view->impl->surface = NULL;
}
}

const PuglBackend*
puglGlBackend(void)
{
static const PuglBackend backend = {puglHaikuGlConfigure,
puglHaikuGlCreate,
puglHaikuGlDestroy,
puglHaikuGlEnter,
puglHaikuGlLeave,
puglStubGetContext};
return &backend;
}
24 changes: 24 additions & 0 deletions dpf/dgl/src/pugl-extra/haiku_stub.cpp
@@ -0,0 +1,24 @@
// Copyright 2012-2022 David Robillard <d@drobilla.net>
// Copyright 2021-2022 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: ISC

#include "pugl/stub.h"

#include "../pugl-upstream/src/stub.h"

#include "pugl/pugl.h"

const PuglBackend*
puglStubBackend(void)
{
static const PuglBackend backend = {
puglStubConfigure,
puglStubCreate,
puglStubDestroy,
puglStubEnter,
puglStubLeave,
puglStubGetContext,
};

return &backend;
}
48 changes: 0 additions & 48 deletions dpf/dgl/src/pugl-extra/mac.m

This file was deleted.

1,141 changes: 1,141 additions & 0 deletions dpf/dgl/src/pugl-extra/wasm.c

Large diffs are not rendered by default.

45 changes: 45 additions & 0 deletions dpf/dgl/src/pugl-extra/wasm.h
@@ -0,0 +1,45 @@
// Copyright 2012-2022 David Robillard <d@drobilla.net>
// Copyright 2021-2022 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: ISC

#ifndef PUGL_SRC_WASM_H
#define PUGL_SRC_WASM_H

#include "../pugl-upstream/src/types.h"

#include "pugl/pugl.h"

// #define PUGL_WASM_ASYNC_CLIPBOARD

struct PuglTimer {
PuglView* view;
uintptr_t id;
};

struct PuglWorldInternalsImpl {
double scaleFactor;
};

struct LastMotionValues {
double x, y, xRoot, yRoot;
};

struct PuglInternalsImpl {
PuglSurface* surface;
bool isFullscreen;
bool needsRepaint;
bool pointerLocked;
uint32_t numTimers;
LastMotionValues lastMotion;
long buttonPressTimeout;
PuglEvent nextButtonEvent;
#ifdef PUGL_WASM_ASYNC_CLIPBOARD
PuglViewHintValue supportsClipboardRead;
PuglViewHintValue supportsClipboardWrite;
#endif
PuglViewHintValue supportsTouch;
char* clipboardData;
struct PuglTimer* timers;
};

#endif // PUGL_SRC_WASM_H
228 changes: 228 additions & 0 deletions dpf/dgl/src/pugl-extra/wasm_gl.c
@@ -0,0 +1,228 @@
// Copyright 2012-2022 David Robillard <d@drobilla.net>
// Copyright 2021-2022 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: ISC

#include "../pugl-upstream/src/stub.h"
#include "wasm.h"

#include "pugl/pugl.h"

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

#include <EGL/egl.h>

// for performance reasons we can keep a single EGL context always active
#define PUGL_WASM_SINGLE_EGL_CONTEXT

typedef struct {
EGLDisplay display;
EGLConfig config;
EGLContext context;
EGLSurface surface;
} PuglWasmGlSurface;

static EGLint
puglWasmGlHintValue(const int value)
{
return value == PUGL_DONT_CARE ? EGL_DONT_CARE : value;
}

static int
puglWasmGlGetAttrib(const EGLDisplay display,
const EGLConfig config,
const EGLint attrib)
{
EGLint value = 0;
eglGetConfigAttrib(display, config, attrib, &value);
return value;
}

static PuglStatus
puglWasmGlConfigure(PuglView* view)
{
PuglInternals* const impl = view->impl;

const EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);

if (display == EGL_NO_DISPLAY) {
return PUGL_CREATE_CONTEXT_FAILED;
}

int major, minor;
if (eglInitialize(display, &major, &minor) != EGL_TRUE) {
return PUGL_CREATE_CONTEXT_FAILED;
}

EGLConfig config;
int numConfigs;

if (eglGetConfigs(display, &config, 1, &numConfigs) != EGL_TRUE || numConfigs != 1) {
eglTerminate(display);
return PUGL_CREATE_CONTEXT_FAILED;
}

// clang-format off
const EGLint attrs[] = {
/*
GLX_X_RENDERABLE, True,
GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
GLX_RENDER_TYPE, GLX_RGBA_BIT,
EGL_SAMPLE_BUFFERS, view->hints[PUGL_MULTI_SAMPLE] ? 1 : 0,
*/
EGL_SAMPLES, puglWasmGlHintValue(view->hints[PUGL_SAMPLES]),
EGL_RED_SIZE, puglWasmGlHintValue(view->hints[PUGL_RED_BITS]),
EGL_GREEN_SIZE, puglWasmGlHintValue(view->hints[PUGL_GREEN_BITS]),
EGL_BLUE_SIZE, puglWasmGlHintValue(view->hints[PUGL_BLUE_BITS]),
EGL_ALPHA_SIZE, puglWasmGlHintValue(view->hints[PUGL_ALPHA_BITS]),
EGL_DEPTH_SIZE, puglWasmGlHintValue(view->hints[PUGL_DEPTH_BITS]),
EGL_STENCIL_SIZE, puglWasmGlHintValue(view->hints[PUGL_STENCIL_BITS]),
EGL_NONE
};
// clang-format on

if (eglChooseConfig(display, attrs, &config, 1, &numConfigs) != EGL_TRUE || numConfigs != 1) {
eglTerminate(display);
return PUGL_CREATE_CONTEXT_FAILED;
}

PuglWasmGlSurface* const surface =
(PuglWasmGlSurface*)calloc(1, sizeof(PuglWasmGlSurface));
impl->surface = surface;

surface->display = display;
surface->config = config;
surface->context = EGL_NO_SURFACE;
surface->surface = EGL_NO_CONTEXT;

view->hints[PUGL_RED_BITS] =
puglWasmGlGetAttrib(display, config, EGL_RED_SIZE);
view->hints[PUGL_GREEN_BITS] =
puglWasmGlGetAttrib(display, config, EGL_GREEN_SIZE);
view->hints[PUGL_BLUE_BITS] =
puglWasmGlGetAttrib(display, config, EGL_BLUE_SIZE);
view->hints[PUGL_ALPHA_BITS] =
puglWasmGlGetAttrib(display, config, EGL_ALPHA_SIZE);
view->hints[PUGL_DEPTH_BITS] =
puglWasmGlGetAttrib(display, config, EGL_DEPTH_SIZE);
view->hints[PUGL_STENCIL_BITS] =
puglWasmGlGetAttrib(display, config, EGL_STENCIL_SIZE);
view->hints[PUGL_SAMPLES] =
puglWasmGlGetAttrib(display, config, EGL_SAMPLES);

// double-buffering is always enabled for EGL
view->hints[PUGL_DOUBLE_BUFFER] = 1;

return PUGL_SUCCESS;
}

PUGL_WARN_UNUSED_RESULT
static PuglStatus
puglWasmGlEnter(PuglView* view, const PuglExposeEvent* PUGL_UNUSED(expose))
{
PuglWasmGlSurface* const surface = (PuglWasmGlSurface*)view->impl->surface;
if (!surface || !surface->context || !surface->surface) {
return PUGL_FAILURE;
}

#ifndef PUGL_WASM_SINGLE_EGL_CONTEXT
return eglMakeCurrent(surface->display, surface->surface, surface->surface, surface->context) ? PUGL_SUCCESS : PUGL_FAILURE;
#else
return PUGL_SUCCESS;
#endif
}

PUGL_WARN_UNUSED_RESULT
static PuglStatus
puglWasmGlLeave(PuglView* view, const PuglExposeEvent* expose)
{
PuglWasmGlSurface* const surface = (PuglWasmGlSurface*)view->impl->surface;

if (expose) { // note: swap buffers always enabled for EGL
eglSwapBuffers(surface->display, surface->surface);
}

#ifndef PUGL_WASM_SINGLE_EGL_CONTEXT
return eglMakeCurrent(surface->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT) ? PUGL_SUCCESS : PUGL_FAILURE;
#else
return PUGL_SUCCESS;
#endif
}

static PuglStatus
puglWasmGlCreate(PuglView* view)
{
PuglWasmGlSurface* const surface = (PuglWasmGlSurface*)view->impl->surface;
const EGLDisplay display = surface->display;
const EGLConfig config = surface->config;

const EGLint attrs[] = {
EGL_CONTEXT_CLIENT_VERSION,
view->hints[PUGL_CONTEXT_VERSION_MAJOR],

EGL_CONTEXT_MAJOR_VERSION,
view->hints[PUGL_CONTEXT_VERSION_MAJOR],

/*
EGL_CONTEXT_MINOR_VERSION,
view->hints[PUGL_CONTEXT_VERSION_MINOR],
EGL_CONTEXT_OPENGL_DEBUG,
(view->hints[PUGL_USE_DEBUG_CONTEXT] ? EGL_TRUE : EGL_FALSE),
EGL_CONTEXT_OPENGL_PROFILE_MASK,
(view->hints[PUGL_USE_COMPAT_PROFILE]
? EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT
: EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT),
*/

EGL_NONE
};

surface->context = eglCreateContext(display, config, EGL_NO_CONTEXT, attrs);

if (surface->context == EGL_NO_CONTEXT) {
return PUGL_CREATE_CONTEXT_FAILED;
}

surface->surface = eglCreateWindowSurface(display, config, 0, NULL);

if (surface->surface == EGL_NO_SURFACE) {
return PUGL_CREATE_CONTEXT_FAILED;
}

#ifdef PUGL_WASM_SINGLE_EGL_CONTEXT
eglMakeCurrent(surface->display, surface->surface, surface->surface, surface->context);
#endif

return PUGL_SUCCESS;
}

static void
puglWasmGlDestroy(PuglView* view)
{
PuglWasmGlSurface* surface = (PuglWasmGlSurface*)view->impl->surface;
if (surface) {
const EGLDisplay display = surface->display;
if (surface->surface != EGL_NO_SURFACE)
eglDestroySurface(display, surface->surface);
if (surface->context != EGL_NO_CONTEXT)
eglDestroyContext(display, surface->context);
eglTerminate(display);
free(surface);
view->impl->surface = NULL;
}
}

const PuglBackend*
puglGlBackend(void)
{
static const PuglBackend backend = {puglWasmGlConfigure,
puglWasmGlCreate,
puglWasmGlDestroy,
puglWasmGlEnter,
puglWasmGlLeave,
puglStubGetContext};
return &backend;
}
24 changes: 24 additions & 0 deletions dpf/dgl/src/pugl-extra/wasm_stub.c
@@ -0,0 +1,24 @@
// Copyright 2012-2022 David Robillard <d@drobilla.net>
// Copyright 2021-2022 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: ISC

#include "pugl/stub.h"

#include "../pugl-upstream/src/stub.h"

#include "pugl/pugl.h"

const PuglBackend*
puglStubBackend(void)
{
static const PuglBackend backend = {
puglStubConfigure,
puglStubCreate,
puglStubDestroy,
puglStubEnter,
puglStubLeave,
puglStubGetContext,
};

return &backend;
}
118 changes: 0 additions & 118 deletions dpf/dgl/src/pugl-extra/win.c

This file was deleted.

111 changes: 0 additions & 111 deletions dpf/dgl/src/pugl-extra/x11.c

This file was deleted.

46 changes: 35 additions & 11 deletions dpf/dgl/src/pugl.cpp
Expand Up @@ -37,7 +37,14 @@
#include <cstring>
#include <ctime>

#if defined(DISTRHO_OS_MAC)
#if defined(DISTRHO_OS_HAIKU)
# include <Application.h>
# include <Window.h>
# ifdef DGL_OPENGL
# include <GL/gl.h>
# include <opengl/GLView.h>
# endif
#elif defined(DISTRHO_OS_MAC)
# import <Cocoa/Cocoa.h>
# include <dlfcn.h>
# include <mach/mach_time.h>
Expand Down Expand Up @@ -119,7 +126,13 @@ START_NAMESPACE_DGL

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

#if defined(DISTRHO_OS_MAC)
#if defined(DISTRHO_OS_HAIKU)
# include "pugl-extra/haiku.cpp"
# include "pugl-extra/haiku_stub.cpp"
# ifdef DGL_OPENGL
# include "pugl-extra/haiku_gl.cpp"
# endif
#elif defined(DISTRHO_OS_MAC)
# ifndef DISTRHO_MACOS_NAMESPACE_MACRO
# define DISTRHO_MACOS_NAMESPACE_MACRO_HELPER(NS, SEP, INTERFACE) NS ## SEP ## INTERFACE
# define DISTRHO_MACOS_NAMESPACE_MACRO(NS, INTERFACE) DISTRHO_MACOS_NAMESPACE_MACRO_HELPER(NS, _, INTERFACE)
Expand All @@ -146,10 +159,10 @@ START_NAMESPACE_DGL
# endif
# pragma clang diagnostic pop
#elif defined(DISTRHO_OS_WASM)
# include "pugl-upstream/src/wasm.c"
# include "pugl-upstream/src/wasm_stub.c"
# include "pugl-extra/wasm.c"
# include "pugl-extra/wasm_stub.c"
# ifdef DGL_OPENGL
# include "pugl-upstream/src/wasm_gl.c"
# include "pugl-extra/wasm_gl.c"
# endif
#elif defined(DISTRHO_OS_WINDOWS)
# include "pugl-upstream/src/win.c"
Expand Down Expand Up @@ -237,7 +250,8 @@ void puglSetMatchingBackendForCurrentBuild(PuglView* const view)

void puglRaiseWindow(PuglView* const view)
{
#if defined(DISTRHO_OS_MAC)
#if defined(DISTRHO_OS_HAIKU)
#elif defined(DISTRHO_OS_MAC)
if (NSWindow* const window = view->impl->window ? view->impl->window
: [view->impl->wrapperView window])
[window orderFrontRegardless];
Expand All @@ -257,7 +271,10 @@ void puglRaiseWindow(PuglView* const view)
double puglGetScaleFactorFromParent(const PuglView* const view)
{
const PuglNativeView parent = view->parent ? view->parent : view->transientParent ? view->transientParent : 0;
#if defined(DISTRHO_OS_MAC)
#if defined(DISTRHO_OS_HAIKU)
// TODO
return 1.0;
#elif defined(DISTRHO_OS_MAC)
// some of these can return 0 as backingScaleFactor, pick the most relevant valid one
const NSWindow* possibleWindows[] = {
parent != 0 ? [(NSView*)parent window] : nullptr,
Expand Down Expand Up @@ -296,7 +313,8 @@ PuglStatus puglSetGeometryConstraints(PuglView* const view, const uint width, co
view->sizeHints[PUGL_FIXED_ASPECT].height = height;
}

#if defined(DISTRHO_OS_MAC)
#if defined(DISTRHO_OS_HAIKU)
#elif defined(DISTRHO_OS_MAC)
if (view->impl->window)
{
PuglStatus status;
Expand Down Expand Up @@ -328,7 +346,8 @@ void puglSetResizable(PuglView* const view, const bool resizable)
{
puglSetViewHint(view, PUGL_RESIZABLE, resizable ? PUGL_TRUE : PUGL_FALSE);

#if defined(DISTRHO_OS_MAC)
#if defined(DISTRHO_OS_HAIKU)
#elif defined(DISTRHO_OS_MAC)
if (PuglWindow* const window = view->impl->window)
{
const uint style = (NSClosableWindowMask | NSTitledWindowMask | NSMiniaturizableWindowMask)
Expand Down Expand Up @@ -361,7 +380,8 @@ PuglStatus puglSetSizeAndDefault(PuglView* view, uint width, uint height)
view->sizeHints[PUGL_DEFAULT_SIZE].width = view->frame.width = static_cast<PuglSpan>(width);
view->sizeHints[PUGL_DEFAULT_SIZE].height = view->frame.height = static_cast<PuglSpan>(height);

#if defined(DISTRHO_OS_MAC)
#if defined(DISTRHO_OS_HAIKU)
#elif defined(DISTRHO_OS_MAC)
// mostly matches upstream pugl, simplified
PuglInternals* const impl = view->impl;

Expand Down Expand Up @@ -456,7 +476,11 @@ void puglFallbackOnResize(PuglView* const view)

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

#if defined(DISTRHO_OS_MAC)
#if defined(DISTRHO_OS_HAIKU)

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

#elif defined(DISTRHO_OS_MAC)

// --------------------------------------------------------------------------------------------------------------------
// macOS specific, add another view's window as child
Expand Down
6 changes: 5 additions & 1 deletion dpf/dgl/src/pugl.hpp
Expand Up @@ -73,7 +73,11 @@ void puglOnDisplayPrepare(PuglView* view);
// DGL specific, build-specific fallback resize
void puglFallbackOnResize(PuglView* view);

#if defined(DISTRHO_OS_MAC)
#if defined(DISTRHO_OS_HAIKU)

// nothing here yet

#elif defined(DISTRHO_OS_MAC)

// macOS specific, add another view's window as child
PuglStatus puglMacOSAddChildWindow(PuglView* view, PuglView* child);
Expand Down
1,031 changes: 1,031 additions & 0 deletions dpf/distrho/DistrhoDetails.hpp

Large diffs are not rendered by default.

936 changes: 2 additions & 934 deletions dpf/distrho/DistrhoPlugin.hpp

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion dpf/distrho/DistrhoUI.hpp
@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-2023 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
Expand All @@ -17,6 +17,7 @@
#ifndef DISTRHO_UI_HPP_INCLUDED
#define DISTRHO_UI_HPP_INCLUDED

#include "DistrhoDetails.hpp"
#include "extra/LeakDetector.hpp"
#include "src/DistrhoPluginChecks.h"

Expand Down
4 changes: 4 additions & 0 deletions dpf/distrho/DistrhoUIMain.cpp
Expand Up @@ -16,6 +16,10 @@

#include "src/DistrhoUI.cpp"

#if ! DISTRHO_PLUGIN_HAS_UI
# error Trying to build UI without DISTRHO_PLUGIN_HAS_UI set to 1
#endif

#if defined(DISTRHO_PLUGIN_TARGET_CARLA)
# define DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT 1
#elif defined(DISTRHO_PLUGIN_TARGET_CLAP)
Expand Down
1 change: 1 addition & 0 deletions dpf/distrho/DistrhoUI_macOS.mm
Expand Up @@ -16,6 +16,7 @@

// A few utils declared in DistrhoUI.cpp but defined here because they use Obj-C

#include "DistrhoDetails.hpp"
#include "src/DistrhoPluginChecks.h"
#include "src/DistrhoDefines.h"

Expand Down
21 changes: 10 additions & 11 deletions dpf/distrho/DistrhoUtils.hpp
@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-2023 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
Expand Down Expand Up @@ -58,7 +58,7 @@ inline float round(float __x)
#define DISTRHO_MACRO_AS_STRING_VALUE(MACRO) #MACRO
#define DISTRHO_MACRO_AS_STRING(MACRO) DISTRHO_MACRO_AS_STRING_VALUE(MACRO)

/* ------------------------------------------------------------------------------------------------------------
/* --------------------------------------------------------------------------------------------------------------------
* misc functions */

/**
Expand Down Expand Up @@ -94,7 +94,7 @@ void d_pass() noexcept {}

/** @} */

/* ------------------------------------------------------------------------------------------------------------
/* --------------------------------------------------------------------------------------------------------------------
* string print functions */

/**
Expand Down Expand Up @@ -240,7 +240,7 @@ void d_safe_exception(const char* const exception, const char* const file, const

/** @} */

/* ------------------------------------------------------------------------------------------------------------
/* --------------------------------------------------------------------------------------------------------------------
* math functions */

/**
Expand All @@ -254,7 +254,7 @@ void d_safe_exception(const char* const exception, const char* const file, const
Returns true if they match.
*/
template<typename T>
static inline
static inline constexpr
bool d_isEqual(const T& v1, const T& v2)
{
return std::abs(v1-v2) < std::numeric_limits<T>::epsilon();
Expand All @@ -265,7 +265,7 @@ bool d_isEqual(const T& v1, const T& v2)
Returns true if they don't match.
*/
template<typename T>
static inline
static inline constexpr
bool d_isNotEqual(const T& v1, const T& v2)
{
return std::abs(v1-v2) >= std::numeric_limits<T>::epsilon();
Expand All @@ -275,7 +275,7 @@ bool d_isNotEqual(const T& v1, const T& v2)
Safely check if a floating point number is zero.
*/
template<typename T>
static inline
static inline constexpr
bool d_isZero(const T& value)
{
return std::abs(value) < std::numeric_limits<T>::epsilon();
Expand All @@ -285,7 +285,7 @@ bool d_isZero(const T& value)
Safely check if a floating point number is not zero.
*/
template<typename T>
static inline
static inline constexpr
bool d_isNotZero(const T& value)
{
return std::abs(value) >= std::numeric_limits<T>::epsilon();
Expand All @@ -311,7 +311,8 @@ uint32_t d_nextPowerOf2(uint32_t size) noexcept

/** @} */

// -----------------------------------------------------------------------
/* --------------------------------------------------------------------------------------------------------------------
* math functions */

#ifndef DONT_SET_USING_DISTRHO_NAMESPACE
// If your code uses a lot of DISTRHO classes, then this will obviously save you
Expand All @@ -320,6 +321,4 @@ uint32_t d_nextPowerOf2(uint32_t size) noexcept
using namespace DISTRHO_NAMESPACE;
#endif

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

#endif // DISTRHO_UTILS_HPP_INCLUDED
6 changes: 3 additions & 3 deletions dpf/distrho/extra/FileBrowserDialogImpl.hpp
Expand Up @@ -92,7 +92,7 @@ struct FileBrowserOptions {
@p windowId: The native window id to attach this dialog to as transient parent (X11 Window, HWND or NSView*)
@p scaleFactor: Scale factor to use (only used on X11)
@p options: Extra options, optional
By default the file browser dialog will be work as "open file" in the current working directory.
By default the file browser dialog will work as "open file" in the current working directory.
*/
FileBrowserHandle fileBrowserCreate(bool isEmbed,
uintptr_t windowId,
Expand All @@ -102,13 +102,13 @@ FileBrowserHandle fileBrowserCreate(bool isEmbed,
/**
Idle the file browser dialog handle.@n
Returns true if dialog was closed (with or without a file selection),
in which case the handle must not be used afterwards.
in which case this idle function must not be called anymore for this handle.
You can then call fileBrowserGetPath to know the selected file (or null if cancelled).
*/
bool fileBrowserIdle(const FileBrowserHandle handle);

/**
Close the file browser dialog, handle must not be used afterwards.
Close and free the file browser dialog, handle must not be used afterwards.
*/
void fileBrowserClose(const FileBrowserHandle handle);

Expand Down
112 changes: 112 additions & 0 deletions dpf/distrho/extra/ScopedDenormalDisable.hpp
@@ -0,0 +1,112 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2023 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 DISTRHO_SCOPED_DENORMAL_DISABLE_HPP_INCLUDED
#define DISTRHO_SCOPED_DENORMAL_DISABLE_HPP_INCLUDED

#include "../DistrhoUtils.hpp"

#ifdef __SSE2_MATH__
# include <xmmintrin.h>
#endif

START_NAMESPACE_DISTRHO

// --------------------------------------------------------------------------------------------------------------------
// ScopedDenormalDisable class definition

/**
ScopedDenormalDisable is a handy class for disabling denormal numbers during a function scope.
Denormal numbers can happen in IIR or other types of filters, they are often very slow.
Use this class with care! Messing up with the global state is bound to make some hosts unhappy.
*/
class ScopedDenormalDisable {
public:
/*
* Constructor.
* Current cpu flags will saved, then denormals-as-zero and flush-to-zero set on top.
*/
inline ScopedDenormalDisable() noexcept;

/*
* Destructor.
* CPU flags will be restored to the value obtained in the constructor.
*/
inline ~ScopedDenormalDisable() noexcept
{
setFlags(oldflags);
}

private:
#if defined(__SSE2_MATH__)
typedef uint cpuflags_t;
#elif defined(__aarch64__)
typedef uint64_t cpuflags_t;
#elif defined(__arm__) && !defined(__SOFTFP__)
typedef uint32_t cpuflags_t;
#else
typedef char cpuflags_t;
#endif

// retrieved on constructor, reset to it on destructor
cpuflags_t oldflags;

// helper function to set cpu flags
inline void setFlags(cpuflags_t flags) noexcept;

DISTRHO_DECLARE_NON_COPYABLE(ScopedDenormalDisable)
DISTRHO_PREVENT_HEAP_ALLOCATION
};

// --------------------------------------------------------------------------------------------------------------------
// ScopedDenormalDisable class implementation

inline ScopedDenormalDisable::ScopedDenormalDisable() noexcept
: oldflags(0)
{
#if defined(__SSE2_MATH__)
oldflags = _mm_getcsr();
setFlags(oldflags | 0x8040);
#elif defined(__aarch64__)
__asm__ __volatile__("mrs %0, fpcr" : "=r" (oldflags));
setFlags(oldflags | 0x1000000);
__asm__ __volatile__("isb");
#elif defined(__arm__) && !defined(__SOFTFP__)
__asm__ __volatile__("vmrs %0, fpscr" : "=r" (oldflags));
setFlags(oldflags | 0x1000000);
#endif
}

inline void ScopedDenormalDisable::setFlags(const cpuflags_t flags) noexcept
{
#if defined(__SSE2_MATH__)
_mm_setcsr(flags);
#elif defined(__aarch64__)
__asm__ __volatile__("msr fpcr, %0" :: "r" (flags));
#elif defined(__arm__) && !defined(__SOFTFP__)
__asm__ __volatile__("vmsr fpscr, %0" :: "r" (flags));
#else
// unused
(void)flags;
#endif
}

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

END_NAMESPACE_DISTRHO

#endif // DISTRHO_SCOPED_DENORMAL_DISABLE_HPP_INCLUDED
16 changes: 15 additions & 1 deletion dpf/distrho/extra/String.hpp
@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-2023 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
Expand All @@ -22,6 +22,10 @@

#include <algorithm>

#if __cplusplus >= 201703L
# include <string_view>
#endif

START_NAMESPACE_DISTRHO

// -----------------------------------------------------------------------
Expand Down Expand Up @@ -87,6 +91,16 @@ class String
_dup(strBuf);
}

#if __cplusplus >= 201703L
/*
* constexpr compatible variant.
*/
explicit constexpr String(const std::string_view& strView) noexcept
: fBuffer(const_cast<char*>(strView.data())),
fBufferLen(strView.size()),
fBufferAlloc(false) {}
#endif

/*
* Integer.
*/
Expand Down
204 changes: 204 additions & 0 deletions dpf/distrho/extra/ValueSmoother.hpp
@@ -0,0 +1,204 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2021 Jean Pierre Cimalando <jp-dev@inbox.ru>
* Copyright (C) 2021-2023 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 DISTRHO_VALUE_SMOOTHER_HPP_INCLUDED
#define DISTRHO_VALUE_SMOOTHER_HPP_INCLUDED

#include "../DistrhoUtils.hpp"

START_NAMESPACE_DISTRHO

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

/**
* @brief An exponential smoother for control values
*
* This continually smooths a value towards a defined target,
* using a low-pass filter of the 1st order, which creates an exponential curve.
*
* The length of the curve is defined by a T60 constant,
* which is the time it takes for a 1-to-0 smoothing to fall to -60dB.
*
* Note that this smoother has asymptotical behavior,
* and it must not be assumed that the final target is ever reached.
*/
class ExponentialValueSmoother {
float coef;
float target;
float mem;
float tau;
float sampleRate;

public:
ExponentialValueSmoother()
: coef(0.f),
target(0.f),
mem(0.f),
tau(0.f),
sampleRate(0.f) {}

void setSampleRate(const float newSampleRate) noexcept
{
if (d_isNotEqual(sampleRate, newSampleRate))
{
sampleRate = newSampleRate;
updateCoef();
}
}

void setTimeConstant(const float newT60) noexcept
{
const float newTau = newT60 * (float)(1.0 / 6.91);

if (d_isNotEqual(tau, newTau))
{
tau = newTau;
updateCoef();
}
}

float getCurrentValue() const noexcept
{
return mem;
}

float getTargetValue() const noexcept
{
return target;
}

void setTargetValue(const float newTarget) noexcept
{
target = newTarget;
}

void clearToTargetValue() noexcept
{
mem = target;
}

inline float peek() const noexcept
{
return mem * coef + target * (1.f - coef);
}

inline float next() noexcept
{
return (mem = mem * coef + target * (1.f - coef));
}

private:
void updateCoef() noexcept
{
coef = std::exp(-1.f / (tau * sampleRate));
}
};

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

/**
* @brief A linear smoother for control values
*
* This continually smooths a value towards a defined target, using linear segments.
*
* The duration of the smoothing segment is defined by the given time constant.
* Every time the target changes, a new segment restarts for the whole duration of the time constant.
*
* Note that this smoother, unlike an exponential smoother, eventually should converge to its target value.
*/
class LinearValueSmoother {
float step;
float target;
float mem;
float tau;
float sampleRate;

public:
LinearValueSmoother()
: step(0.f),
target(0.f),
mem(0.f),
tau(0.f),
sampleRate(0.f) {}

void setSampleRate(const float newSampleRate) noexcept
{
if (d_isNotEqual(sampleRate, newSampleRate))
{
sampleRate = newSampleRate;
updateStep();
}
}

void setTimeConstant(const float newTau) noexcept
{
if (d_isNotEqual(tau, newTau))
{
tau = newTau;
updateStep();
}
}

float getCurrentValue() const noexcept
{
return mem;
}

float getTargetValue() const noexcept
{
return target;
}

void setTargetValue(const float newTarget) noexcept
{
if (d_isNotEqual(target, newTarget))
{
target = newTarget;
updateStep();
}
}

void clearToTargetValue() noexcept
{
mem = target;
}

inline float peek() const noexcept
{
const float dy = target - mem;
return mem + std::copysign(std::fmin(std::abs(dy), std::abs(step)), dy);
}

inline float next() noexcept
{
const float y0 = mem;
const float dy = target - y0;
return (mem = y0 + std::copysign(std::fmin(std::abs(dy), std::abs(step)), dy));
}

private:
void updateStep() noexcept
{
step = (target - mem) / (tau * sampleRate);
}
};

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

END_NAMESPACE_DISTRHO

#endif // DISTRHO_VALUE_SMOOTHER_HPP_INCLUDED
2 changes: 1 addition & 1 deletion dpf/distrho/src/DistrhoPlugin.cpp
@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-2023 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
Expand Down