From 0530b4309bf5f451c3ee00503acc9c997d30353c Mon Sep 17 00:00:00 2001 From: falkTX Date: Sun, 7 Jul 2019 10:30:45 +0200 Subject: [PATCH] Update DPF and plugins Fixes #14 --- Makefile | 14 +- dpf/Makefile.base.mk | 113 +++- dpf/Makefile.plugins.mk | 72 ++- dpf/README.md | 2 +- dpf/dgl/Base.hpp | 90 +-- dpf/dgl/Cairo.hpp | 40 ++ dpf/dgl/Color.hpp | 2 +- dpf/dgl/Geometry.hpp | 23 +- dpf/dgl/Image.hpp | 82 +-- dpf/dgl/ImageBase.hpp | 125 ++++ dpf/dgl/Makefile | 106 +++- dpf/dgl/NanoVG.hpp | 3 +- dpf/dgl/OpenGL.hpp | 121 ++++ dpf/dgl/Widget.hpp | 2 +- dpf/dgl/Window.hpp | 8 +- dpf/dgl/src/Cairo.cpp | 27 + dpf/dgl/src/Color.cpp | 48 +- dpf/dgl/src/Geometry.cpp | 102 +--- dpf/dgl/src/Image.cpp | 102 +--- dpf/dgl/src/ImageBase.cpp | 106 ++++ dpf/dgl/src/ImageWidgets.cpp | 6 +- dpf/dgl/src/NanoVG.cpp | 21 +- dpf/dgl/src/OpenGL.cpp | 157 ++++++ dpf/dgl/src/Widget.cpp | 2 +- dpf/dgl/src/WidgetPrivateData.cpp | 107 ++++ dpf/dgl/src/WidgetPrivateData.hpp | 59 +- dpf/dgl/src/Window.cpp | 79 ++- dpf/dgl/src/pugl/pugl.h | 83 +-- dpf/dgl/src/pugl/pugl_internal.h | 3 + dpf/dgl/src/pugl/pugl_osx.m | 626 ++++++++++++++++----- dpf/dgl/src/pugl/pugl_win.cpp | 123 +++- dpf/dgl/src/pugl/pugl_x11.c | 141 ++++- dpf/distrho/DistrhoInfo.hpp | 16 +- dpf/distrho/DistrhoPlugin.hpp | 2 +- dpf/distrho/DistrhoUI.hpp | 24 +- dpf/distrho/src/DistrhoPluginChecks.h | 4 +- dpf/distrho/src/DistrhoPluginJack.cpp | 12 +- dpf/distrho/src/DistrhoPluginLV2.cpp | 2 +- dpf/distrho/src/DistrhoPluginLV2export.cpp | 2 +- dpf/distrho/src/DistrhoPluginVST.cpp | 14 +- dpf/distrho/src/DistrhoUI.cpp | 24 +- dpf/distrho/src/DistrhoUIInternal.hpp | 37 +- dpf/distrho/src/DistrhoUILV2.cpp | 24 +- dpf/distrho/src/lv2/ui.h | 1 + dpf/dpf.doxygen | 3 +- dpf/utils/lv2-ttl-generator/GNUmakefile | 2 +- dpf/utils/{png2c.py => res2c.py} | 30 +- plugins/Kars/DistrhoPluginKars.cpp | 75 ++- plugins/Kars/DistrhoPluginKars.hpp | 4 +- plugins/bitcrush/Makefile | 1 + plugins/freeverb/Makefile | 1 + plugins/gigaverb/Makefile | 1 + plugins/glBars/DistrhoUIGLBars.cpp | 2 +- plugins/glBars/DistrhoUIGLBars.hpp | 3 +- plugins/glBars/glBars.hpp | 4 +- plugins/pitchshift/Makefile | 1 + 56 files changed, 2116 insertions(+), 768 deletions(-) create mode 100644 dpf/dgl/Cairo.hpp create mode 100644 dpf/dgl/ImageBase.hpp create mode 100644 dpf/dgl/OpenGL.hpp create mode 100644 dpf/dgl/src/Cairo.cpp create mode 100644 dpf/dgl/src/ImageBase.cpp create mode 100644 dpf/dgl/src/OpenGL.cpp create mode 100644 dpf/dgl/src/WidgetPrivateData.cpp rename dpf/utils/{png2c.py => res2c.py} (82%) diff --git a/Makefile b/Makefile index 65277771..5d6e6e9f 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,7 @@ HAVE_PROJM = $(shell pkg-config --exists libprojectM && echo true) # -------------------------------------------------------------- dgl: -ifeq ($(HAVE_DGL),true) +ifeq ($(HAVE_CAIRO_OR_OPENGL),true) $(MAKE) -C dpf/dgl endif @@ -50,7 +50,7 @@ plugins: dgl $(MAKE) all -C plugins/gigaverb $(MAKE) all -C plugins/pitchshift -ifeq ($(HAVE_DGL),true) +ifeq ($(HAVE_CAIRO_OR_OPENGL),true) # glBars (needs OpenGL) $(MAKE) all -C plugins/glBars @@ -58,7 +58,7 @@ ifeq ($(HAVE_PROJM),true) # ProM (needs OpenGL + ProjectM) $(MAKE) all -C plugins/ProM endif # HAVE_PROJM -endif # HAVE_DGL +endif # HAVE_CAIRO_OR_OPENGL ifneq ($(CROSS_COMPILING),true) gen: plugins dpf/utils/lv2_ttl_generator @@ -123,9 +123,9 @@ install: install -m 644 bin/*-dssi.* $(DESTDIR)$(PREFIX)/lib/dssi/ install -m 644 bin/*-vst.* $(DESTDIR)$(PREFIX)/lib/vst/ -ifeq ($(HAVE_DGL),true) +ifeq ($(HAVE_CAIRO_OR_OPENGL),true) cp -r bin/*-dssi $(DESTDIR)$(PREFIX)/lib/dssi/ -endif # HAVE_DGL +endif # HAVE_CAIRO_OR_OPENGL cp -r bin/*.lv2 $(DESTDIR)$(PREFIX)/lib/lv2/ ifeq ($(HAVE_JACK),true) @@ -142,12 +142,12 @@ ifeq ($(HAVE_JACK),true) install -m 755 bin/MaFreeverb $(DESTDIR)$(PREFIX)/bin/ install -m 755 bin/MaGigaverb $(DESTDIR)$(PREFIX)/bin/ install -m 755 bin/MaPitchshift $(DESTDIR)$(PREFIX)/bin/ -ifeq ($(HAVE_DGL),true) +ifeq ($(HAVE_CAIRO_OR_OPENGL),true) install -m 755 bin/glBars $(DESTDIR)$(PREFIX)/bin/ ifeq ($(HAVE_PROJM),true) install -m 755 bin/ProM $(DESTDIR)$(PREFIX)/bin/ endif # HAVE_PROJM -endif # HAVE_DGL +endif # HAVE_CAIRO_OR_OPENGL endif # HAVE_JACK # -------------------------------------------------------------- diff --git a/dpf/Makefile.base.mk b/dpf/Makefile.base.mk index 5e10d7da..83ef5c45 100644 --- a/dpf/Makefile.base.mk +++ b/dpf/Makefile.base.mk @@ -16,7 +16,7 @@ ifneq ($(HAIKU),true) ifneq ($(HURD),true) ifneq ($(LINUX),true) ifneq ($(MACOS),true) -ifneq ($(WIN32),true) +ifneq ($(WINDOWS),true) TARGET_MACHINE := $(shell $(CC) -dumpmachine) ifneq (,$(findstring bsd,$(TARGET_MACHINE))) @@ -35,7 +35,7 @@ ifneq (,$(findstring apple,$(TARGET_MACHINE))) MACOS=true endif ifneq (,$(findstring mingw,$(TARGET_MACHINE))) -WIN32=true +WINDOWS=true endif endif @@ -45,6 +45,16 @@ endif endif endif +# --------------------------------------------------------------------------------------------------------------------- +# Set PKG_CONFIG (can be overridden by environment variable) + +ifeq ($(WINDOWS),true) +# Build statically on Windows by default +PKG_CONFIG ?= pkg-config --static +else +PKG_CONFIG ?= pkg-config +endif + # --------------------------------------------------------------------------------------------------------------------- # Set LINUX_OR_MACOS @@ -57,14 +67,20 @@ LINUX_OR_MACOS=true endif # --------------------------------------------------------------------------------------------------------------------- -# Set MACOS_OR_WIN32 +# Set MACOS_OR_WINDOWS and HAIKU_OR_MACOS_OR_WINDOWS + +ifeq ($(HAIKU),true) +HAIKU_OR_MACOS_OR_WINDOWS=true +endif ifeq ($(MACOS),true) -MACOS_OR_WIN32=true +MACOS_OR_WINDOWS=true +HAIKU_OR_MACOS_OR_WINDOWS=true endif -ifeq ($(WIN32),true) -MACOS_OR_WIN32=true +ifeq ($(WINDOWS),true) +MACOS_OR_WINDOWS=true +HAIKU_OR_MACOS_OR_WINDOWS=true endif # --------------------------------------------------------------------------------------------------------------------- @@ -108,10 +124,12 @@ ifeq ($(NOOPT),true) BASE_OPTS = -O2 -ffast-math -fdata-sections -ffunction-sections endif -ifeq ($(WIN32),true) +ifeq ($(WINDOWS),true) # mingw has issues with this specific optimization # See https://github.com/falkTX/Carla/issues/696 BASE_OPTS += -fno-rerun-cse-after-loop +# See https://github.com/falkTX/Carla/issues/855 +BASE_OPTS += -mstackrealign ifeq ($(BUILDING_FOR_WINDOWS),true) BASE_FLAGS += -DBUILDING_CARLA_FOR_WINDOWS endif @@ -141,7 +159,7 @@ ifeq ($(MACOS_OLD),true) BUILD_CXX_FLAGS = $(BASE_FLAGS) $(CXXFLAGS) -DHAVE_CPP11_SUPPORT=0 endif -ifeq ($(WIN32),true) +ifeq ($(WINDOWS),true) # Always build statically on windows LINK_FLAGS += -static endif @@ -170,44 +188,81 @@ CXXFLAGS += -Weffc++ -Wnon-virtual-dtor -Woverloaded-virtual endif # --------------------------------------------------------------------------------------------------------------------- -# Check for optional libs +# Check for required libraries -ifeq ($(MACOS_OR_WIN32),true) -HAVE_DGL = true +HAVE_CAIRO = $(shell $(PKG_CONFIG) --exists cairo && echo true) + +ifeq ($(HAIKU_OR_MACOS_OR_WINDOWS),true) +HAVE_OPENGL = true else -HAVE_DGL = $(shell pkg-config --exists gl x11 && echo true) -HAVE_JACK = $(shell pkg-config --exists jack && echo true) -HAVE_LIBLO = $(shell pkg-config --exists liblo && echo true) +HAVE_OPENGL = $(shell $(PKG_CONFIG) --exists gl && echo true) +HAVE_X11 = $(shell $(PKG_CONFIG) --exists x11 && echo true) endif -ifneq ($(HAVE_DGL),true) -$(error DGL missing 22) +# --------------------------------------------------------------------------------------------------------------------- +# Check for optional libraries + +HAVE_JACK = $(shell $(PKG_CONFIG) --exists jack && echo true) +HAVE_LIBLO = $(shell $(PKG_CONFIG) --exists liblo && echo true) + +# --------------------------------------------------------------------------------------------------------------------- +# Set Generic DGL stuff + +ifeq ($(MACOS),true) +DGL_SYSTEM_LIBS += -framework Cocoa +endif + +ifeq ($(WINDOWS),true) +DGL_SYSTEM_LIBS += -lgdi32 +endif + +ifneq ($(HAIKU_OR_MACOS_OR_WINDOWS),true) +DGL_FLAGS += $(shell $(PKG_CONFIG) --cflags x11) +DGL_SYSTEM_LIBS += $(shell $(PKG_CONFIG) --libs x11) +endif + +# --------------------------------------------------------------------------------------------------------------------- +# Set Cairo specific stuff + +ifeq ($(HAVE_CAIRO),true) + +DGL_FLAGS += -DHAVE_CAIRO + +CAIRO_FLAGS = $(shell $(PKG_CONFIG) --cflags cairo) +CAIRO_LIBS = $(shell $(PKG_CONFIG) --libs cairo) + +HAVE_CAIRO_OR_OPENGL = true + endif # --------------------------------------------------------------------------------------------------------------------- -# Set libs stuff +# Set OpenGL specific stuff + +ifeq ($(HAVE_OPENGL),true) -ifeq ($(HAVE_DGL),true) +DGL_FLAGS += -DHAVE_OPENGL ifeq ($(MACOS),true) -DGL_LIBS = -framework OpenGL -framework Cocoa +OPENGL_LIBS = -framework OpenGL endif -ifeq ($(WIN32),true) -DGL_LIBS = -lopengl32 -lgdi32 +ifeq ($(WINDOWS),true) +OPENGL_LIBS = -lopengl32 endif -ifneq ($(MACOS_OR_WIN32),true) -DGL_FLAGS = $(shell pkg-config --cflags gl x11) -DGL_LIBS = $(shell pkg-config --libs gl x11) +ifneq ($(MACOS_OR_WINDOWS),true) +OPENGL_FLAGS = $(shell $(PKG_CONFIG) --cflags gl x11) +OPENGL_LIBS = $(shell $(PKG_CONFIG) --libs gl x11) endif -endif # HAVE_DGL +HAVE_CAIRO_OR_OPENGL = true + +endif # --------------------------------------------------------------------------------------------------------------------- # Set app extension -ifeq ($(WIN32),true) +ifeq ($(WINDOWS),true) APP_EXT = .exe endif @@ -220,17 +275,17 @@ ifeq ($(MACOS),true) LIB_EXT = .dylib endif -ifeq ($(WIN32),true) +ifeq ($(WINDOWS),true) LIB_EXT = .dll endif # --------------------------------------------------------------------------------------------------------------------- # Set shared library CLI arg -SHARED = -shared - ifeq ($(MACOS),true) SHARED = -dynamiclib +else +SHARED = -shared endif # --------------------------------------------------------------------------------------------------------------------- diff --git a/dpf/Makefile.plugins.mk b/dpf/Makefile.plugins.mk index aa69a91c..4afe6b40 100644 --- a/dpf/Makefile.plugins.mk +++ b/dpf/Makefile.plugins.mk @@ -15,10 +15,6 @@ endif include $(DPF_PATH)/Makefile.base.mk -ifeq ($(FILES_UI),) -HAVE_DGL = false -endif - # --------------------------------------------------------------------------------------------------------------------- # Basic setup @@ -28,8 +24,12 @@ BUILD_DIR = ../../build/$(NAME) BUILD_C_FLAGS += -I. BUILD_CXX_FLAGS += -I. -I$(DPF_PATH)/distrho -I$(DPF_PATH)/dgl -ifeq ($(HAVE_DGL),true) -BASE_FLAGS += -DHAVE_DGL +ifeq ($(HAVE_CAIRO),true) +DGL_FLAGS += -DHAVE_CAIRO +endif + +ifeq ($(HAVE_OPENGL),true) +DGL_FLAGS += -DHAVE_OPENGL endif ifeq ($(HAVE_JACK),true) @@ -59,7 +59,39 @@ lv2_ui = $(TARGET_DIR)/$(NAME).lv2/$(NAME)_ui$(LIB_EXT) vst = $(TARGET_DIR)/$(NAME)-vst$(LIB_EXT) # --------------------------------------------------------------------------------------------------------------------- -# Handle plugins without UI +# Handle UI stuff, disable UI support automatically + +ifeq ($(FILES_UI),) +UI_TYPE = none +endif + +ifeq ($(UI_TYPE),) +UI_TYPE = opengl +endif + +ifeq ($(UI_TYPE),cairo) +ifeq ($(HAVE_CAIRO),true) +DGL_FLAGS += $(CAIRO_FLAGS) -DDGL_CAIRO +DGL_LIBS += $(CAIRO_LIBS) +DGL_LIB = $(DPF_PATH)/build/libdgl-cairo.a +HAVE_DGL = true +else +HAVE_DGL = false +endif +endif + +ifeq ($(UI_TYPE),opengl) +ifeq ($(HAVE_OPENGL),true) +DGL_FLAGS += $(OPENGL_FLAGS) -DDGL_OPENGL +DGL_LIBS += $(OPENGL_LIBS) +DGL_LIB = $(DPF_PATH)/build/libdgl-opengl.a +HAVE_DGL = true +else +HAVE_DGL = false +endif +endif + +DGL_LIBS += $(DGL_SYSTEM_LIBS) ifneq ($(HAVE_DGL),true) dssi_ui = @@ -68,6 +100,9 @@ DGL_LIBS = OBJS_UI = endif +# TODO split dsp and ui object build flags +BASE_FLAGS += $(DGL_FLAGS) + # --------------------------------------------------------------------------------------------------------------------- # all needs to be first @@ -81,6 +116,11 @@ $(BUILD_DIR)/%.c.o: %.c @echo "Compiling $<" @$(CC) $< $(BUILD_C_FLAGS) -c -o $@ +$(BUILD_DIR)/%.cc.o: %.cc + -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" + @echo "Compiling $<" + @$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ + $(BUILD_DIR)/%.cpp.o: %.cpp -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" @echo "Compiling $<" @@ -105,12 +145,12 @@ $(BUILD_DIR)/DistrhoUIMain_%.cpp.o: $(DPF_PATH)/distrho/DistrhoUIMain.cpp $(BUILD_DIR)/DistrhoPluginMain_JACK.cpp.o: $(DPF_PATH)/distrho/DistrhoPluginMain.cpp -@mkdir -p $(BUILD_DIR) @echo "Compiling DistrhoPluginMain.cpp (JACK)" - @$(CXX) $< $(BUILD_CXX_FLAGS) $(shell pkg-config --cflags jack) -DDISTRHO_PLUGIN_TARGET_JACK -c -o $@ + @$(CXX) $< $(BUILD_CXX_FLAGS) $(shell $(PKG_CONFIG) --cflags jack) -DDISTRHO_PLUGIN_TARGET_JACK -c -o $@ $(BUILD_DIR)/DistrhoUIMain_DSSI.cpp.o: $(DPF_PATH)/distrho/DistrhoUIMain.cpp -@mkdir -p $(BUILD_DIR) @echo "Compiling DistrhoUIMain.cpp (DSSI)" - @$(CXX) $< $(BUILD_CXX_FLAGS) $(shell pkg-config --cflags liblo) -DDISTRHO_PLUGIN_TARGET_DSSI -c -o $@ + @$(CXX) $< $(BUILD_CXX_FLAGS) $(shell $(PKG_CONFIG) --cflags liblo) -DDISTRHO_PLUGIN_TARGET_DSSI -c -o $@ # --------------------------------------------------------------------------------------------------------------------- # JACK @@ -118,13 +158,13 @@ $(BUILD_DIR)/DistrhoUIMain_DSSI.cpp.o: $(DPF_PATH)/distrho/DistrhoUIMain.cpp jack: $(jack) ifeq ($(HAVE_DGL),true) -$(jack): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_JACK.cpp.o $(BUILD_DIR)/DistrhoUIMain_JACK.cpp.o $(DPF_PATH)/build/libdgl.a +$(jack): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_JACK.cpp.o $(BUILD_DIR)/DistrhoUIMain_JACK.cpp.o $(DGL_LIB) else $(jack): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_JACK.cpp.o endif -@mkdir -p $(shell dirname $@) @echo "Creating JACK standalone for $(NAME)" - @$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(shell pkg-config --libs jack) -o $@ + @$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(shell $(PKG_CONFIG) --libs jack) -o $@ # --------------------------------------------------------------------------------------------------------------------- # LADSPA @@ -148,10 +188,10 @@ $(dssi_dsp): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_DSSI.cpp.o @echo "Creating DSSI plugin library for $(NAME)" @$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(SHARED) -o $@ -$(dssi_ui): $(OBJS_UI) $(BUILD_DIR)/DistrhoUIMain_DSSI.cpp.o $(DPF_PATH)/build/libdgl.a +$(dssi_ui): $(OBJS_UI) $(BUILD_DIR)/DistrhoUIMain_DSSI.cpp.o $(DGL_LIB) -@mkdir -p $(shell dirname $@) @echo "Creating DSSI UI for $(NAME)" - @$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(shell pkg-config --libs liblo) -o $@ + @$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(shell $(PKG_CONFIG) --libs liblo) -o $@ # --------------------------------------------------------------------------------------------------------------------- # LV2 @@ -160,7 +200,7 @@ lv2: $(lv2) lv2_dsp: $(lv2_dsp) lv2_sep: $(lv2_dsp) $(lv2_ui) -$(lv2): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.o $(BUILD_DIR)/DistrhoUIMain_LV2.cpp.o $(DPF_PATH)/build/libdgl.a +$(lv2): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.o $(BUILD_DIR)/DistrhoUIMain_LV2.cpp.o $(DGL_LIB) -@mkdir -p $(shell dirname $@) @echo "Creating LV2 plugin for $(NAME)" @$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(SHARED) -o $@ @@ -170,7 +210,7 @@ $(lv2_dsp): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.o @echo "Creating LV2 plugin library for $(NAME)" @$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(SHARED) -o $@ -$(lv2_ui): $(OBJS_UI) $(BUILD_DIR)/DistrhoUIMain_LV2.cpp.o $(DPF_PATH)/build/libdgl.a +$(lv2_ui): $(OBJS_UI) $(BUILD_DIR)/DistrhoUIMain_LV2.cpp.o $(DGL_LIB) -@mkdir -p $(shell dirname $@) @echo "Creating LV2 plugin UI for $(NAME)" @$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(SHARED) -o $@ @@ -181,7 +221,7 @@ $(lv2_ui): $(OBJS_UI) $(BUILD_DIR)/DistrhoUIMain_LV2.cpp.o $(DPF_PATH)/build/lib vst: $(vst) ifeq ($(HAVE_DGL),true) -$(vst): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_VST.cpp.o $(BUILD_DIR)/DistrhoUIMain_VST.cpp.o $(DPF_PATH)/build/libdgl.a +$(vst): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_VST.cpp.o $(BUILD_DIR)/DistrhoUIMain_VST.cpp.o $(DGL_LIB) else $(vst): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_VST.cpp.o endif diff --git a/dpf/README.md b/dpf/README.md index b8788fc0..5dda160b 100644 --- a/dpf/README.md +++ b/dpf/README.md @@ -28,7 +28,7 @@ List of plugins made with DPF:
- [Juice Plugins](https://github.com/DISTRHO/JuicePlugins) (work in progress) - [ZamAudio Suite](https://github.com/zamaudio/zam-plugins) - [DragonFly-Reverb](https://github.com/michaelwillis/dragonfly-reverb) - - [Wolf-Shaper](https://github.com/pdesaulniers/wolf-shaper) + - [Wolf-Shaper](https://github.com/pdesaulniers/wolf-shaper) and [Wolf-Spectrum](https://github.com/pdesaulniers/wolf-spectrum) - [YK Chorus](https://github.com/SpotlightKid/ykchorus) diff --git a/dpf/dgl/Base.hpp b/dpf/dgl/Base.hpp index 30d10e0d..90377883 100644 --- a/dpf/dgl/Base.hpp +++ b/dpf/dgl/Base.hpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2016 Filipe Coelho + * Copyright (C) 2012-2019 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -31,89 +31,6 @@ #define END_NAMESPACE_DGL } #define USE_NAMESPACE_DGL using namespace DGL_NAMESPACE; -#ifdef DISTRHO_OS_WINDOWS -// ----------------------------------------------------------------------- -// Fix OpenGL includes for Windows, based on glfw code - -#ifndef APIENTRY -# define APIENTRY __stdcall -#endif // APIENTRY - -/* We need WINGDIAPI defined */ -#ifndef WINGDIAPI -# if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__POCC__) -# define WINGDIAPI __declspec(dllimport) -# elif defined(__LCC__) -# define WINGDIAPI __stdcall -# else -# define WINGDIAPI extern -# endif -# define DGL_WINGDIAPI_DEFINED -#endif // WINGDIAPI - -/* Some files also need CALLBACK defined */ -#ifndef CALLBACK -# if defined(_MSC_VER) -# if (defined(_M_MRX000) || defined(_M_IX86) || defined(_M_ALPHA) || defined(_M_PPC)) && !defined(MIDL_PASS) -# define CALLBACK __stdcall -# else -# define CALLBACK -# endif -# else -# define CALLBACK __stdcall -# endif -# define DGL_CALLBACK_DEFINED -#endif // CALLBACK - -/* Most GL/glu.h variants on Windows need wchar_t */ -#include - -#endif // DISTRHO_OS_WINDOWS - -// ----------------------------------------------------------------------- -// OpenGL includes - -#ifdef DISTRHO_OS_MAC -# include -#else -# ifndef DISTRHO_OS_WINDOWS -# define GL_GLEXT_PROTOTYPES -# endif -# include -# include -#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 - -#ifdef DISTRHO_OS_WINDOWS -// ----------------------------------------------------------------------- -// Fix OpenGL includes for Windows, based on glfw code - -#ifdef DGL_WINGDIAPI_DEFINED -# undef WINGDIAPI -# undef DGL_WINGDIAPI_DEFINED -#endif - -#ifdef DGL_CALLBACK_DEFINED -# undef CALLBACK -# undef DGL_CALLBACK_DEFINED -#endif - -#endif // DISTRHO_OS_WINDOWS - START_NAMESPACE_DGL // ----------------------------------------------------------------------- @@ -172,6 +89,11 @@ enum Key { // ----------------------------------------------------------------------- // Base DGL classes +/** + Graphics context, definition depends on build type. + */ +struct GraphicsContext; + /** Idle callback. */ diff --git a/dpf/dgl/Cairo.hpp b/dpf/dgl/Cairo.hpp new file mode 100644 index 00000000..ce0c920b --- /dev/null +++ b/dpf/dgl/Cairo.hpp @@ -0,0 +1,40 @@ +/* + * DISTRHO Plugin Framework (DPF) + * Copyright (C) 2012-2019 Filipe Coelho + * + * Permission to use, copy, modify, and/or distribute this software for any purpose with + * or without fee is hereby granted, provided that the above copyright notice and this + * permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD + * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef DGL_CAIRO_HPP_INCLUDED +#define DGL_CAIRO_HPP_INCLUDED + +#include "Base.hpp" + +#include + +START_NAMESPACE_DGL + +// ----------------------------------------------------------------------- + +/** + Graphics context. + */ +struct GraphicsContext +{ + cairo_t* cairo; // FIXME proper name.. +}; + +// ----------------------------------------------------------------------- + +END_NAMESPACE_DGL + +#endif diff --git a/dpf/dgl/Color.hpp b/dpf/dgl/Color.hpp index 2fc8c64c..a874f660 100644 --- a/dpf/dgl/Color.hpp +++ b/dpf/dgl/Color.hpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2016 Filipe Coelho + * Copyright (C) 2012-2019 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this diff --git a/dpf/dgl/Geometry.hpp b/dpf/dgl/Geometry.hpp index 3dbf7064..f7fe31ec 100644 --- a/dpf/dgl/Geometry.hpp +++ b/dpf/dgl/Geometry.hpp @@ -482,6 +482,7 @@ class Circle // cached values float fTheta, fCos, fSin; + /** @internal */ void _draw(const bool outline); }; @@ -516,16 +517,6 @@ class Triangle */ Triangle(const Triangle& tri) noexcept; - /** - Draw this triangle using the current OpenGL state. - */ - void draw(); - - /** - Draw lines (outline of this triangle) using the current OpenGL state. - */ - void drawOutline(); - /** Return true if triangle is null (all its points are equal). An null triangle is also invalid. @@ -549,6 +540,16 @@ class Triangle */ bool isInvalid() const noexcept; + /** + Draw this triangle using the current OpenGL state. + */ + void draw(); + + /** + Draw lines (outline of this triangle) using the current OpenGL state. + */ + void drawOutline(); + Triangle& operator=(const Triangle& tri) noexcept; bool operator==(const Triangle& tri) const noexcept; bool operator!=(const Triangle& tri) const noexcept; @@ -556,6 +557,7 @@ class Triangle private: Point fPos1, fPos2, fPos3; + /** @internal */ void _draw(const bool outline); }; @@ -740,6 +742,7 @@ class Rectangle Point fPos; Size fSize; + /** @internal */ void _draw(const bool outline); }; diff --git a/dpf/dgl/Image.hpp b/dpf/dgl/Image.hpp index 3df5bd84..634665ff 100644 --- a/dpf/dgl/Image.hpp +++ b/dpf/dgl/Image.hpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2016 Filipe Coelho + * Copyright (C) 2012-2019 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -17,14 +17,15 @@ #ifndef DGL_IMAGE_HPP_INCLUDED #define DGL_IMAGE_HPP_INCLUDED -#include "Geometry.hpp" +#include "ImageBase.hpp" +#include "OpenGL.hpp" START_NAMESPACE_DGL // ----------------------------------------------------------------------- /** - Base DGL Image class. + OpenGL Image class. This is an Image class that handles raw image data in pixels. You can init the image data on the contructor or later on by calling loadFromMemory(). @@ -35,7 +36,7 @@ START_NAMESPACE_DGL Images are drawn on screen via 2D textures. */ -class Image +class Image : public ImageBase { public: /** @@ -47,13 +48,20 @@ class Image Constructor using raw image data. @note @a rawData must remain valid for the lifetime of this Image. */ - Image(const char* const rawData, const uint width, const uint height, const GLenum format = GL_BGRA, const GLenum type = GL_UNSIGNED_BYTE); + Image(const char* const rawData, + const uint width, + const uint height, + const GLenum format = GL_BGRA, + const GLenum type = GL_UNSIGNED_BYTE); /** Constructor using raw image data. @note @a rawData must remain valid for the lifetime of this Image. */ - Image(const char* const rawData, const Size& size, const GLenum format = GL_BGRA, const GLenum type = GL_UNSIGNED_BYTE); + Image(const char* const rawData, + const Size& size, + const GLenum format = GL_BGRA, + const GLenum type = GL_UNSIGNED_BYTE); /** Constructor using another image data. @@ -63,44 +71,26 @@ class Image /** Destructor. */ - ~Image(); + ~Image() override; /** Load image data from memory. @note @a rawData must remain valid for the lifetime of this Image. */ - void loadFromMemory(const char* const rawData, const uint width, const uint height, const GLenum format = GL_BGRA, const GLenum type = GL_UNSIGNED_BYTE) noexcept; + void loadFromMemory(const char* const rawData, + const uint width, + const uint height, + const GLenum format = GL_BGRA, + const GLenum type = GL_UNSIGNED_BYTE) noexcept; /** Load image data from memory. @note @a rawData must remain valid for the lifetime of this Image. */ - void loadFromMemory(const char* const rawData, const Size& size, const GLenum format = GL_BGRA, const GLenum type = GL_UNSIGNED_BYTE) noexcept; - - /** - Check if this image is valid. - */ - bool isValid() const noexcept; - - /** - Get width. - */ - uint getWidth() const noexcept; - - /** - Get height. - */ - uint getHeight() const noexcept; - - /** - Get size. - */ - const Size& getSize() const noexcept; - - /** - Get the raw image data. - */ - const char* getRawData() const noexcept; + void loadFromMemory(const char* const rawData, + const Size& size, + const GLenum format = GL_BGRA, + const GLenum type = GL_UNSIGNED_BYTE) noexcept; /** Get the image format. @@ -113,27 +103,15 @@ class Image GLenum getType() const noexcept; /** - Draw this image at (0, 0) point. - */ - void draw(); - - /** - Draw this image at (x, y) point. + TODO document this. */ - void drawAt(const int x, const int y); - - /** - Draw this image at position @a pos. - */ - void drawAt(const Point& pos); - Image& operator=(const Image& image) noexcept; - bool operator==(const Image& image) const noexcept; - bool operator!=(const Image& image) const noexcept; + +protected: + /** @internal */ + void _drawAt(const Point& pos) override; private: - const char* fRawData; - Size fSize; GLenum fFormat; GLenum fType; GLuint fTextureId; @@ -144,4 +122,4 @@ class Image END_NAMESPACE_DGL -#endif // DGL_IMAGE_HPP_INCLUDED +#endif diff --git a/dpf/dgl/ImageBase.hpp b/dpf/dgl/ImageBase.hpp new file mode 100644 index 00000000..0a7ee780 --- /dev/null +++ b/dpf/dgl/ImageBase.hpp @@ -0,0 +1,125 @@ +/* + * DISTRHO Plugin Framework (DPF) + * Copyright (C) 2012-2019 Filipe Coelho + * + * Permission to use, copy, modify, and/or distribute this software for any purpose with + * or without fee is hereby granted, provided that the above copyright notice and this + * permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD + * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef DGL_IMAGE_BASE_HPP_INCLUDED +#define DGL_IMAGE_BASE_HPP_INCLUDED + +#include "Geometry.hpp" + +START_NAMESPACE_DGL + +// ----------------------------------------------------------------------- + +/** + Base DGL Image class. + + This is an Image class that handles raw image data in pixels. + It is an abstract class that provides the common methods to build on top. + Cairo and OpenGL Image classes are based upon this one. + + @see Image + */ +class ImageBase +{ +protected: + /** + Constructor for a null Image. + */ + ImageBase(); + + /** + Constructor using raw image data. + @note @a rawData must remain valid for the lifetime of this Image. + */ + ImageBase(const char* const rawData, const uint width, const uint height); + + /** + Constructor using raw image data. + @note @a rawData must remain valid for the lifetime of this Image. + */ + ImageBase(const char* const rawData, const Size& size); + + /** + Constructor using another image data. + */ + ImageBase(const ImageBase& image); + +public: + /** + Destructor. + */ + virtual ~ImageBase(); + + /** + Check if this image is valid. + */ + bool isValid() const noexcept; + + /** + Get width. + */ + uint getWidth() const noexcept; + + /** + Get height. + */ + uint getHeight() const noexcept; + + /** + Get size. + */ + const Size& getSize() const noexcept; + + /** + Get the raw image data. + */ + const char* getRawData() const noexcept; + + /** + Draw this image at (0, 0) point. + */ + void draw(); + + /** + Draw this image at (x, y) point. + */ + void drawAt(const int x, const int y); + + /** + Draw this image at position @a pos. + */ + void drawAt(const Point& pos); + + /** + TODO document this. + */ + ImageBase& operator=(const ImageBase& image) noexcept; + bool operator==(const ImageBase& image) const noexcept; + bool operator!=(const ImageBase& image) const noexcept; + +protected: + /** @internal */ + virtual void _drawAt(const Point& pos) = 0; + + const char* fRawData; + Size fSize; +}; + +// ----------------------------------------------------------------------- + +END_NAMESPACE_DGL + +#endif // DGL_IMAGE_HPP_INCLUDED diff --git a/dpf/dgl/Makefile b/dpf/dgl/Makefile index b0b4f419..9d6f31a3 100644 --- a/dpf/dgl/Makefile +++ b/dpf/dgl/Makefile @@ -9,7 +9,7 @@ include ../Makefile.base.mk # --------------------------------------------------------------------------------------------------------------------- BUILD_C_FLAGS += $(DGL_FLAGS) -I. -Isrc -BUILD_CXX_FLAGS += $(DGL_FLAGS) -I. -Isrc +BUILD_CXX_FLAGS += $(DGL_FLAGS) -I. -Isrc -DDONT_SET_USING_DGL_NAMESPACE -Wno-unused-parameter LINK_FLAGS += $(DGL_LIBS) # ifneq ($(MACOS_OLD),true) @@ -19,36 +19,78 @@ LINK_FLAGS += $(DGL_LIBS) # --------------------------------------------------------------------------------------------------------------------- -OBJS = \ +OBJS_common = \ ../build/dgl/Application.cpp.o \ ../build/dgl/Color.cpp.o \ ../build/dgl/Geometry.cpp.o \ - ../build/dgl/Image.cpp.o \ - ../build/dgl/ImageWidgets.cpp.o \ - ../build/dgl/NanoVG.cpp.o \ + ../build/dgl/ImageBase.cpp.o \ ../build/dgl/Resources.cpp.o \ ../build/dgl/Widget.cpp.o +# TODO: ImageWidgets.cpp + +# --------------------------------------------------------------------------------------------------------------------- + +OBJS_cairo = $(OBJS_common) \ + ../build/dgl/Cairo.cpp.cairo.o \ + ../build/dgl/WidgetPrivateData.cpp.cairo.o + +ifeq ($(MACOS),true) +OBJS_cairo += ../build/dgl/Window.mm.cairo.o +else +OBJS_cairo += ../build/dgl/Window.cpp.cairo.o +endif + +# --------------------------------------------------------------------------------------------------------------------- + +OBJS_opengl = $(OBJS_common) \ + ../build/dgl/OpenGL.cpp.opengl.o \ + ../build/dgl/Image.cpp.opengl.o \ + ../build/dgl/ImageWidgets.cpp.opengl.o \ + ../build/dgl/NanoVG.cpp.opengl.o \ + ../build/dgl/WidgetPrivateData.cpp.opengl.o + ifeq ($(MACOS),true) -OBJS += ../build/dgl/Window.mm.o +OBJS_opengl += ../build/dgl/Window.mm.opengl.o else -OBJS += ../build/dgl/Window.cpp.o +OBJS_opengl += ../build/dgl/Window.cpp.opengl.o endif -TARGET = ../build/libdgl.a +# --------------------------------------------------------------------------------------------------------------------- + +ifeq ($(HAVE_CAIRO),true) +TARGETS += ../build/libdgl-cairo.a +endif + +ifeq ($(HAVE_OPENGL),true) +TARGETS += ../build/libdgl-opengl.a +# Compat name, to be removed soon +TARGETS += ../build/libdgl.a +endif # --------------------------------------------------------------------------------------------------------------------- -all: $(TARGET) +all: $(TARGETS) # --------------------------------------------------------------------------------------------------------------------- -../build/libdgl.a: $(OBJS) +../build/libdgl-cairo.a: $(OBJS_cairo) + -@mkdir -p ../build + @echo "Creating libdgl-cairo.a" + @rm -f $@ + @$(AR) crs $@ $^ + +../build/libdgl-opengl.a: $(OBJS_opengl) -@mkdir -p ../build - @echo "Creating libdgl.a" + @echo "Creating libdgl-opengl.a" @rm -f $@ @$(AR) crs $@ $^ +# Compat name, to be removed soon +../build/libdgl.a: ../build/libdgl-opengl.a + @echo "Symlinking libdgl.a" + @ln -sf $< $@ + # --------------------------------------------------------------------------------------------------------------------- ../build/dgl/%.c.o: src/%.c @@ -61,26 +103,52 @@ all: $(TARGET) @echo "Compiling $<" @$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ -../build/dgl/Window.cpp.o: src/Window.cpp src/sofd/* src/pugl/* +# --------------------------------------------------------------------------------------------------------------------- + +../build/dgl/%.cpp.cairo.o: src/%.cpp -@mkdir -p ../build/dgl - @echo "Compiling $<" - @$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ + @echo "Compiling $< (Cairo variant)" + @$(CXX) $< $(BUILD_CXX_FLAGS) -DDGL_CAIRO -c -o $@ -../build/dgl/Window.mm.o: src/Window.cpp src/sofd/* src/pugl/* +../build/dgl/Window.cpp.cairo.o: src/Window.cpp src/sofd/* src/pugl/* -@mkdir -p ../build/dgl - @echo "Compiling $<" - @$(CXX) $< $(BUILD_CXX_FLAGS) -ObjC++ -c -o $@ + @echo "Compiling $< (Cairo variant)" + @$(CXX) $< $(BUILD_CXX_FLAGS) -DDGL_CAIRO -c -o $@ + +../build/dgl/Window.mm.cairo.o: src/Window.cpp src/sofd/* src/pugl/* + -@mkdir -p ../build/dgl + @echo "Compiling $< (Cairo variant)" + @$(CXX) $< $(BUILD_CXX_FLAGS) -DDGL_CAIRO -ObjC++ -c -o $@ + +# --------------------------------------------------------------------------------------------------------------------- + +../build/dgl/%.cpp.opengl.o: src/%.cpp + -@mkdir -p ../build/dgl + @echo "Compiling $< (OpenGL variant)" + @$(CXX) $< $(BUILD_CXX_FLAGS) -DDGL_OPENGL -c -o $@ + +../build/dgl/Window.cpp.opengl.o: src/Window.cpp src/sofd/* src/pugl/* + -@mkdir -p ../build/dgl + @echo "Compiling $< (OpenGL variant)" + @$(CXX) $< $(BUILD_CXX_FLAGS) -DDGL_OPENGL -c -o $@ + +../build/dgl/Window.mm.opengl.o: src/Window.cpp src/sofd/* src/pugl/* + -@mkdir -p ../build/dgl + @echo "Compiling $< (OpenGL variant)" + @$(CXX) $< $(BUILD_CXX_FLAGS) -DDGL_OPENGL -ObjC++ -c -o $@ # --------------------------------------------------------------------------------------------------------------------- clean: - rm -rf ../build/dgl ../build/libdgl.* + rm -rf ../build/dgl ../build/libdgl*.* debug: $(MAKE) DEBUG=true # --------------------------------------------------------------------------------------------------------------------- --include $(OBJS:%.o=%.d) +-include $(OBJS_common:%.o=%.d) +-include $(OBJS_cairo:%.o=%.d) +-include $(OBJS_opengl:%.o=%.d) # --------------------------------------------------------------------------------------------------------------------- diff --git a/dpf/dgl/NanoVG.hpp b/dpf/dgl/NanoVG.hpp index e94da105..ea07df28 100644 --- a/dpf/dgl/NanoVG.hpp +++ b/dpf/dgl/NanoVG.hpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2016 Filipe Coelho + * Copyright (C) 2012-2019 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -18,6 +18,7 @@ #define DGL_NANO_WIDGET_HPP_INCLUDED #include "Color.hpp" +#include "OpenGL.hpp" #include "Widget.hpp" #ifndef DGL_NO_SHARED_RESOURCES diff --git a/dpf/dgl/OpenGL.hpp b/dpf/dgl/OpenGL.hpp new file mode 100644 index 00000000..5466161c --- /dev/null +++ b/dpf/dgl/OpenGL.hpp @@ -0,0 +1,121 @@ +/* + * DISTRHO Plugin Framework (DPF) + * Copyright (C) 2012-2019 Filipe Coelho + * + * Permission to use, copy, modify, and/or distribute this software for any purpose with + * or without fee is hereby granted, provided that the above copyright notice and this + * permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD + * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef DGL_OPENGL_HPP_INCLUDED +#define DGL_OPENGL_HPP_INCLUDED + +#include "ImageBase.hpp" + +// ----------------------------------------------------------------------- +// Fix OpenGL includes for Windows, based on glfw code (part 1) + +#undef DGL_CALLBACK_DEFINED +#undef DGL_WINGDIAPI_DEFINED + +#ifdef DISTRHO_OS_WINDOWS + +#ifndef APIENTRY +# define APIENTRY __stdcall +#endif // APIENTRY + +/* We need WINGDIAPI defined */ +#ifndef WINGDIAPI +# if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__POCC__) +# define WINGDIAPI __declspec(dllimport) +# elif defined(__LCC__) +# define WINGDIAPI __stdcall +# else +# define WINGDIAPI extern +# endif +# define DGL_WINGDIAPI_DEFINED +#endif // WINGDIAPI + +/* Some files also need CALLBACK defined */ +#ifndef CALLBACK +# if defined(_MSC_VER) +# if (defined(_M_MRX000) || defined(_M_IX86) || defined(_M_ALPHA) || defined(_M_PPC)) && !defined(MIDL_PASS) +# define CALLBACK __stdcall +# else +# define CALLBACK +# endif +# else +# define CALLBACK __stdcall +# endif +# define DGL_CALLBACK_DEFINED +#endif // CALLBACK + +/* Most GL/glu.h variants on Windows need wchar_t */ +#include + +#endif // DISTRHO_OS_WINDOWS + +// ----------------------------------------------------------------------- +// OpenGL includes + +#ifdef DISTRHO_OS_MAC +# include +#else +# ifndef DISTRHO_OS_WINDOWS +# define GL_GLEXT_PROTOTYPES +# endif +# include +# include +#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 + +START_NAMESPACE_DGL + +// ----------------------------------------------------------------------- + +/** + Graphics context. + */ +struct GraphicsContext +{ +}; + +// ----------------------------------------------------------------------- + +END_NAMESPACE_DGL + +#endif diff --git a/dpf/dgl/Widget.hpp b/dpf/dgl/Widget.hpp index 73d2d6e9..f8d7139d 100644 --- a/dpf/dgl/Widget.hpp +++ b/dpf/dgl/Widget.hpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2016 Filipe Coelho + * Copyright (C) 2012-2019 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this diff --git a/dpf/dgl/Window.hpp b/dpf/dgl/Window.hpp index 465bb1cb..931177ea 100644 --- a/dpf/dgl/Window.hpp +++ b/dpf/dgl/Window.hpp @@ -77,7 +77,7 @@ class Window explicit Window(Application& app); explicit Window(Application& app, Window& parent); - explicit Window(Application& app, intptr_t parentId, bool resizable); + explicit Window(Application& app, intptr_t parentId, double scaling, bool resizable); virtual ~Window(); void show(); @@ -113,7 +113,6 @@ class Window void setTransientWinId(uintptr_t winId); double getScaling() const noexcept; - void setScaling(double scaling) noexcept; bool getIgnoringKeyRepeat() const noexcept; void setIgnoringKeyRepeat(bool ignore) noexcept; @@ -121,6 +120,8 @@ class Window Application& getApp() const noexcept; intptr_t getWindowId() const noexcept; + const GraphicsContext& getGraphicsContext() const noexcept; + void addIdleCallback(IdleCallback* const callback); void removeIdleCallback(IdleCallback* const callback); @@ -134,6 +135,9 @@ class Window virtual void fileBrowserSelected(const char* filename); #endif + // internal + void _setAutoScaling(double scaling) noexcept; + private: struct PrivateData; PrivateData* const pData; diff --git a/dpf/dgl/src/Cairo.cpp b/dpf/dgl/src/Cairo.cpp new file mode 100644 index 00000000..2c9e42ee --- /dev/null +++ b/dpf/dgl/src/Cairo.cpp @@ -0,0 +1,27 @@ +/* + * DISTRHO Plugin Framework (DPF) + * Copyright (C) 2012-2019 Filipe Coelho + * + * Permission to use, copy, modify, and/or distribute this software for any purpose with + * or without fee is hereby granted, provided that the above copyright notice and this + * permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD + * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "../Base.hpp" + +START_NAMESPACE_DGL + +// ----------------------------------------------------------------------- + +// nothing here yet + +// ----------------------------------------------------------------------- + +END_NAMESPACE_DGL diff --git a/dpf/dgl/src/Color.cpp b/dpf/dgl/src/Color.cpp index 2ea9819f..3fc570ca 100644 --- a/dpf/dgl/src/Color.cpp +++ b/dpf/dgl/src/Color.cpp @@ -16,12 +16,27 @@ #include "../Color.hpp" +#ifndef HAVE_DCAIRO #include "nanovg/nanovg.h" +#endif START_NAMESPACE_DGL // ----------------------------------------------------------------------- +static float computeHue(float h, float m1, float m2) +{ + if (h < 0) h += 1; + if (h > 1) h -= 1; + if (h < 1.0f/6.0f) + return m1 + (m2 - m1) * h * 6.0f; + if (h < 3.0f/6.0f) + return m2; + if (h < 4.0f/6.0f) + return m1 + (m2 - m1) * (2.0f/3.0f - h) * 6.0f; + return m1; +} + static void fixRange(float& value) { /**/ if (value < 0.0f) @@ -105,7 +120,20 @@ Color::Color(const Color& color1, const Color& color2, float u) noexcept Color Color::fromHSL(float hue, float saturation, float lightness, float alpha) { - return nvgHSLA(hue, saturation, lightness, static_cast(getFixedRange(alpha)*255.0f)); + float m1, m2; + Color col; + hue = fmodf(hue, 1.0f); + if (hue < 0.0f) hue += 1.0f; + fixRange(saturation); + fixRange(lightness); + m2 = lightness <= 0.5f ? (lightness * (1 + saturation)) : (lightness + saturation - lightness * saturation); + m1 = 2 * lightness - m2; + col.red = computeHue(hue + 1.0f/3.0f, m1, m2); + col.green = computeHue(hue, m1, m2); + col.blue = computeHue(hue - 1.0f/3.0f, m1, m2); + col.alpha = alpha; + col.fixBounds(); + return col; } Color Color::fromHTML(const char* rgb, float alpha) @@ -224,22 +252,4 @@ void Color::fixBounds() noexcept // ----------------------------------------------------------------------- -Color::Color(const NVGcolor& c) noexcept - : red(c.r), green(c.g), blue(c.b), alpha(c.a) -{ - fixBounds(); -} - -Color::operator NVGcolor() const noexcept -{ - NVGcolor nc; - nc.r = red; - nc.g = green; - nc.b = blue; - nc.a = alpha; - return nc; -} - -// ----------------------------------------------------------------------- - END_NAMESPACE_DGL diff --git a/dpf/dgl/src/Geometry.cpp b/dpf/dgl/src/Geometry.cpp index c76809dc..d133985f 100644 --- a/dpf/dgl/src/Geometry.cpp +++ b/dpf/dgl/src/Geometry.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2016 Filipe Coelho + * Copyright (C) 2012-2019 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -441,21 +441,6 @@ void Line::moveBy(const Point& pos) noexcept fPosEnd.moveBy(pos); } -template -void Line::draw() -{ - DISTRHO_SAFE_ASSERT_RETURN(fPosStart != fPosEnd,); - - glBegin(GL_LINES); - - { - glVertex2d(fPosStart.fX, fPosStart.fY); - glVertex2d(fPosEnd.fX, fPosEnd.fY); - } - - glEnd(); -} - template bool Line::isNull() const noexcept { @@ -650,27 +635,6 @@ bool Circle::operator!=(const Circle& cir) const noexcept return (fPos != cir.fPos || d_isNotEqual(fSize, cir.fSize) || fNumSegments != cir.fNumSegments); } -template -void Circle::_draw(const bool outline) -{ - DISTRHO_SAFE_ASSERT_RETURN(fNumSegments >= 3 && fSize > 0.0f,); - - double t, x = fSize, y = 0.0; - - glBegin(outline ? GL_LINE_LOOP : GL_POLYGON); - - for (uint i=0; i::Triangle(const Triangle& tri) noexcept fPos2(tri.fPos2), fPos3(tri.fPos3) {} -template -void Triangle::draw() -{ - _draw(false); -} - -template -void Triangle::drawOutline() -{ - _draw(true); -} - template bool Triangle::isNull() const noexcept { @@ -734,6 +686,18 @@ bool Triangle::isInvalid() const noexcept return fPos1 == fPos2 || fPos1 == fPos3; } +template +void Triangle::draw() +{ + _draw(false); +} + +template +void Triangle::drawOutline() +{ + _draw(true); +} + template Triangle& Triangle::operator=(const Triangle& tri) noexcept { @@ -755,22 +719,6 @@ bool Triangle::operator!=(const Triangle& tri) const noexcept return (fPos1 != tri.fPos1 || fPos2 != tri.fPos2 || fPos3 != tri.fPos3); } -template -void Triangle::_draw(const bool outline) -{ - DISTRHO_SAFE_ASSERT_RETURN(fPos1 != fPos2 && fPos1 != fPos3,); - - glBegin(outline ? GL_LINE_LOOP : GL_TRIANGLES); - - { - glVertex2d(fPos1.fX, fPos1.fY); - glVertex2d(fPos2.fX, fPos2.fY); - glVertex2d(fPos3.fX, fPos3.fY); - } - - glEnd(); -} - // ----------------------------------------------------------------------- // Rectangle @@ -998,30 +946,6 @@ bool Rectangle::operator!=(const Rectangle& rect) const noexcept return (fPos != rect.fPos || fSize != rect.fSize); } -template -void Rectangle::_draw(const bool outline) -{ - DISTRHO_SAFE_ASSERT_RETURN(fSize.isValid(),); - - glBegin(outline ? GL_LINE_LOOP : GL_QUADS); - - { - glTexCoord2f(0.0f, 0.0f); - glVertex2d(fPos.fX, fPos.fY); - - glTexCoord2f(1.0f, 0.0f); - glVertex2d(fPos.fX+fSize.fWidth, fPos.fY); - - glTexCoord2f(1.0f, 1.0f); - glVertex2d(fPos.fX+fSize.fWidth, fPos.fY+fSize.fHeight); - - glTexCoord2f(0.0f, 1.0f); - glVertex2d(fPos.fX, fPos.fY+fSize.fHeight); - } - - glEnd(); -} - // ----------------------------------------------------------------------- // Possible template data types diff --git a/dpf/dgl/src/Image.cpp b/dpf/dgl/src/Image.cpp index b79b8d44..90596fec 100644 --- a/dpf/dgl/src/Image.cpp +++ b/dpf/dgl/src/Image.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2016 Filipe Coelho + * Copyright (C) 2012-2019 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -21,8 +21,7 @@ START_NAMESPACE_DGL // ----------------------------------------------------------------------- Image::Image() - : fRawData(nullptr), - fSize(0, 0), + : ImageBase(), fFormat(0), fType(0), fTextureId(0), @@ -31,20 +30,18 @@ Image::Image() glGenTextures(1, &fTextureId); } -Image::Image(const char* const rawData, const uint width, const uint height, const GLenum format, const GLenum type) - : fRawData(rawData), - fSize(width, height), - fFormat(format), - fType(type), +Image::Image(const Image& image) + : ImageBase(image), + fFormat(image.fFormat), + fType(image.fType), fTextureId(0), fIsReady(false) { glGenTextures(1, &fTextureId); } -Image::Image(const char* const rawData, const Size& size, const GLenum format, const GLenum type) - : fRawData(rawData), - fSize(size), +Image::Image(const char* const rawData, const uint width, const uint height, const GLenum format, const GLenum type) + : ImageBase(rawData, width, height), fFormat(format), fType(type), fTextureId(0), @@ -53,11 +50,10 @@ Image::Image(const char* const rawData, const Size& size, const GLenum for glGenTextures(1, &fTextureId); } -Image::Image(const Image& image) - : fRawData(image.fRawData), - fSize(image.fSize), - fFormat(image.fFormat), - fType(image.fType), +Image::Image(const char* const rawData, const Size& size, const GLenum format, const GLenum type) + : ImageBase(rawData, size), + fFormat(format), + fType(type), fTextureId(0), fIsReady(false) { @@ -75,12 +71,19 @@ Image::~Image() } } -void Image::loadFromMemory(const char* const rawData, const uint width, const uint height, const GLenum format, const GLenum type) noexcept +void Image::loadFromMemory(const char* const rawData, + const uint width, + const uint height, + const GLenum format, + const GLenum type) noexcept { loadFromMemory(rawData, Size(width, height), format, type); } -void Image::loadFromMemory(const char* const rawData, const Size& size, const GLenum format, const GLenum type) noexcept +void Image::loadFromMemory(const char* const rawData, + const Size& size, + const GLenum format, + const GLenum type) noexcept { fRawData = rawData; fSize = size; @@ -89,31 +92,6 @@ void Image::loadFromMemory(const char* const rawData, const Size& size, co fIsReady = false; } -bool Image::isValid() const noexcept -{ - return (fRawData != nullptr && fSize.getWidth() > 0 && fSize.getHeight() > 0); -} - -uint Image::getWidth() const noexcept -{ - return fSize.getWidth(); -} - -uint Image::getHeight() const noexcept -{ - return fSize.getHeight(); -} - -const Size& Image::getSize() const noexcept -{ - return fSize; -} - -const char* Image::getRawData() const noexcept -{ - return fRawData; -} - GLenum Image::getFormat() const noexcept { return fFormat; @@ -124,17 +102,17 @@ GLenum Image::getType() const noexcept return fType; } -void Image::draw() -{ - drawAt(0, 0); -} - -void Image::drawAt(const int x, const int y) +Image& Image::operator=(const Image& image) noexcept { - drawAt(Point(x, y)); + fRawData = image.fRawData; + fSize = image.fSize; + fFormat = image.fFormat; + fType = image.fType; + fIsReady = false; + return *this; } -void Image::drawAt(const Point& pos) +void Image::_drawAt(const Point& pos) { if (fTextureId == 0 || ! isValid()) return; @@ -169,26 +147,4 @@ void Image::drawAt(const Point& pos) // ----------------------------------------------------------------------- -Image& Image::operator=(const Image& image) noexcept -{ - fRawData = image.fRawData; - fSize = image.fSize; - fFormat = image.fFormat; - fType = image.fType; - fIsReady = false; - return *this; -} - -bool Image::operator==(const Image& image) const noexcept -{ - return (fRawData == image.fRawData && fSize == image.fSize); -} - -bool Image::operator!=(const Image& image) const noexcept -{ - return !operator==(image); -} - -// ----------------------------------------------------------------------- - END_NAMESPACE_DGL diff --git a/dpf/dgl/src/ImageBase.cpp b/dpf/dgl/src/ImageBase.cpp new file mode 100644 index 00000000..b5dfbb96 --- /dev/null +++ b/dpf/dgl/src/ImageBase.cpp @@ -0,0 +1,106 @@ +/* + * DISTRHO Plugin Framework (DPF) + * Copyright (C) 2012-2019 Filipe Coelho + * + * Permission to use, copy, modify, and/or distribute this software for any purpose with + * or without fee is hereby granted, provided that the above copyright notice and this + * permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD + * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "../ImageBase.hpp" + +START_NAMESPACE_DGL + +// ----------------------------------------------------------------------- + +ImageBase::ImageBase() + : fRawData(nullptr), + fSize(0, 0) {} + +ImageBase::ImageBase(const char* const rawData, const uint width, const uint height) + : fRawData(rawData), + fSize(width, height) {} + +ImageBase::ImageBase(const char* const rawData, const Size& size) + : fRawData(rawData), + fSize(size) {} + +ImageBase::ImageBase(const ImageBase& image) + : fRawData(image.fRawData), + fSize(image.fSize) {} + +ImageBase::~ImageBase() {} + +// ----------------------------------------------------------------------- + +bool ImageBase::isValid() const noexcept +{ + return (fRawData != nullptr && fSize.isValid()); +} + +uint ImageBase::getWidth() const noexcept +{ + return fSize.getWidth(); +} + +uint ImageBase::getHeight() const noexcept +{ + return fSize.getHeight(); +} + +const Size& ImageBase::getSize() const noexcept +{ + return fSize; +} + +const char* ImageBase::getRawData() const noexcept +{ + return fRawData; +} + +// ----------------------------------------------------------------------- + +void ImageBase::draw() +{ + _drawAt(Point()); +} + +void ImageBase::drawAt(const int x, const int y) +{ + _drawAt(Point(x, y)); +} + +void ImageBase::drawAt(const Point& pos) +{ + _drawAt(pos); +} + +// ----------------------------------------------------------------------- + +ImageBase& ImageBase::operator=(const ImageBase& image) noexcept +{ + fRawData = image.fRawData; + fSize = image.fSize; + return *this; +} + +bool ImageBase::operator==(const ImageBase& image) const noexcept +{ + return (fRawData == image.fRawData && fSize == image.fSize); +} + +bool ImageBase::operator!=(const ImageBase& image) const noexcept +{ + return !operator==(image); +} + +// ----------------------------------------------------------------------- + +END_NAMESPACE_DGL diff --git a/dpf/dgl/src/ImageWidgets.cpp b/dpf/dgl/src/ImageWidgets.cpp index 12f952e7..71276e36 100644 --- a/dpf/dgl/src/ImageWidgets.cpp +++ b/dpf/dgl/src/ImageWidgets.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2016 Filipe Coelho + * Copyright (C) 2012-2019 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -14,9 +14,13 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "../Image.hpp" #include "Common.hpp" #include "WidgetPrivateData.hpp" +// FIXME make this code more generic and move GL specific bits to OpenGL.cpp +#include "../OpenGL.hpp" + START_NAMESPACE_DGL // ----------------------------------------------------------------------- diff --git a/dpf/dgl/src/NanoVG.cpp b/dpf/dgl/src/NanoVG.cpp index 3c29222a..06fc49f7 100644 --- a/dpf/dgl/src/NanoVG.cpp +++ b/dpf/dgl/src/NanoVG.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2018 Filipe Coelho + * Copyright (C) 2012-2019 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -124,6 +124,25 @@ DGL_EXT(PFNGLVERTEXATTRIBPOINTERPROC, glVertexAttribPointer) START_NAMESPACE_DGL +// ----------------------------------------------------------------------- +// DGL Color class conversion + +Color::Color(const NVGcolor& c) noexcept + : red(c.r), green(c.g), blue(c.b), alpha(c.a) +{ + fixBounds(); +} + +Color::operator NVGcolor() const noexcept +{ + NVGcolor nc; + nc.r = red; + nc.g = green; + nc.b = blue; + nc.a = alpha; + return nc; +} + // ----------------------------------------------------------------------- // NanoImage diff --git a/dpf/dgl/src/OpenGL.cpp b/dpf/dgl/src/OpenGL.cpp new file mode 100644 index 00000000..25a38619 --- /dev/null +++ b/dpf/dgl/src/OpenGL.cpp @@ -0,0 +1,157 @@ +/* + * DISTRHO Plugin Framework (DPF) + * Copyright (C) 2012-2019 Filipe Coelho + * + * Permission to use, copy, modify, and/or distribute this software for any purpose with + * or without fee is hereby granted, provided that the above copyright notice and this + * permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD + * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "../Geometry.hpp" +#include "../OpenGL.hpp" + +START_NAMESPACE_DGL + +// ----------------------------------------------------------------------- +// Line + +template +void Line::draw() +{ + DISTRHO_SAFE_ASSERT_RETURN(fPosStart != fPosEnd,); + + glBegin(GL_LINES); + + { + glVertex2d(fPosStart.fX, fPosStart.fY); + glVertex2d(fPosEnd.fX, fPosEnd.fY); + } + + glEnd(); +} + +// ----------------------------------------------------------------------- +// Circle + +template +void Circle::_draw(const bool outline) +{ + DISTRHO_SAFE_ASSERT_RETURN(fNumSegments >= 3 && fSize > 0.0f,); + + double t, x = fSize, y = 0.0; + + glBegin(outline ? GL_LINE_LOOP : GL_POLYGON); + + for (uint i=0; i +void Triangle::_draw(const bool outline) +{ + DISTRHO_SAFE_ASSERT_RETURN(fPos1 != fPos2 && fPos1 != fPos3,); + + glBegin(outline ? GL_LINE_LOOP : GL_TRIANGLES); + + { + glVertex2d(fPos1.fX, fPos1.fY); + glVertex2d(fPos2.fX, fPos2.fY); + glVertex2d(fPos3.fX, fPos3.fY); + } + + glEnd(); +} + +// ----------------------------------------------------------------------- +// Rectangle + +template +void Rectangle::_draw(const bool outline) +{ + DISTRHO_SAFE_ASSERT_RETURN(fSize.isValid(),); + + glBegin(outline ? GL_LINE_LOOP : GL_QUADS); + + { + glTexCoord2f(0.0f, 0.0f); + glVertex2d(fPos.fX, fPos.fY); + + glTexCoord2f(1.0f, 0.0f); + glVertex2d(fPos.fX+fSize.fWidth, fPos.fY); + + glTexCoord2f(1.0f, 1.0f); + glVertex2d(fPos.fX+fSize.fWidth, fPos.fY+fSize.fHeight); + + glTexCoord2f(0.0f, 1.0f); + glVertex2d(fPos.fX, fPos.fY+fSize.fHeight); + } + + glEnd(); +} + +// ----------------------------------------------------------------------- +// Possible template data types + +template class Point; +template class Point; +template class Point; +template class Point; +template class Point; +template class Point; + +template class Size; +template class Size; +template class Size; +template class Size; +template class Size; +template class Size; + +template class Line; +template class Line; +template class Line; +template class Line; +template class Line; +template class Line; + +template class Circle; +template class Circle; +template class Circle; +template class Circle; +template class Circle; +template class Circle; + +template class Triangle; +template class Triangle; +template class Triangle; +template class Triangle; +template class Triangle; +template class Triangle; + +template class Rectangle; +template class Rectangle; +template class Rectangle; +template class Rectangle; +template class Rectangle; +template class Rectangle; + +// ----------------------------------------------------------------------- + +END_NAMESPACE_DGL diff --git a/dpf/dgl/src/Widget.cpp b/dpf/dgl/src/Widget.cpp index d200fb40..4ef69b8e 100644 --- a/dpf/dgl/src/Widget.cpp +++ b/dpf/dgl/src/Widget.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2016 Filipe Coelho + * Copyright (C) 2012-2019 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this diff --git a/dpf/dgl/src/WidgetPrivateData.cpp b/dpf/dgl/src/WidgetPrivateData.cpp new file mode 100644 index 00000000..cef082b1 --- /dev/null +++ b/dpf/dgl/src/WidgetPrivateData.cpp @@ -0,0 +1,107 @@ +/* + * DISTRHO Plugin Framework (DPF) + * Copyright (C) 2012-2019 Filipe Coelho + * + * Permission to use, copy, modify, and/or distribute this software for any purpose with + * or without fee is hereby granted, provided that the above copyright notice and this + * permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD + * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "WidgetPrivateData.hpp" + +#ifdef DGL_CAIRO +# include "../Cairo.hpp" +#endif +#ifdef DGL_OPENGL +# include "../OpenGL.hpp" +#endif + +START_NAMESPACE_DGL + +// ----------------------------------------------------------------------- + +void Widget::PrivateData::display(const uint width, + const uint height, + const double scaling, + const bool renderingSubWidget) +{ + if ((skipDisplay && ! renderingSubWidget) || size.isInvalid() || ! visible) + return; + +#ifdef DGL_OPENGL + bool needsDisableScissor = false; + + // reset color + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + + if (needsFullViewport || (absolutePos.isZero() && size == Size(width, height))) + { + // full viewport size + glViewport(0, + -(height * scaling - height), + width * scaling, + height * scaling); + } + else if (needsScaling) + { + // limit viewport to widget bounds + glViewport(absolutePos.getX(), + height - self->getHeight() - absolutePos.getY(), + self->getWidth(), + self->getHeight()); + } + else + { + // only set viewport pos + glViewport(absolutePos.getX() * scaling, + -std::round((height * scaling - height) + (absolutePos.getY() * scaling)), + std::round(width * scaling), + std::round(height * scaling)); + + // then cut the outer bounds + glScissor(absolutePos.getX() * scaling, + height - std::round((self->getHeight() + absolutePos.getY()) * scaling), + std::round(self->getWidth() * scaling), + std::round(self->getHeight() * scaling)); + + glEnable(GL_SCISSOR_TEST); + needsDisableScissor = true; + } +#endif + +#ifdef DGL_CAIRO + cairo_t* cr = parent.getGraphicsContext().cairo; + cairo_matrix_t matrix; + cairo_get_matrix(cr, &matrix); + cairo_translate(cr, absolutePos.getX(), absolutePos.getY()); + // TODO: scaling and cropping +#endif + + // display widget + self->onDisplay(); + +#ifdef DGL_CAIRO + cairo_set_matrix(cr, &matrix); +#endif + +#ifdef DGL_OPENGL + if (needsDisableScissor) + { + glDisable(GL_SCISSOR_TEST); + needsDisableScissor = false; + } +#endif + + displaySubWidgets(width, height, scaling); +} + +// ----------------------------------------------------------------------- + +END_NAMESPACE_DGL diff --git a/dpf/dgl/src/WidgetPrivateData.hpp b/dpf/dgl/src/WidgetPrivateData.hpp index 5dbe2ace..f48a33bc 100644 --- a/dpf/dgl/src/WidgetPrivateData.hpp +++ b/dpf/dgl/src/WidgetPrivateData.hpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2018 Filipe Coelho + * Copyright (C) 2012-2019 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -63,61 +63,8 @@ struct Widget::PrivateData { subWidgets.clear(); } - void display(const uint width, const uint height, const double scaling, const bool renderingSubWidget) - { - if ((skipDisplay && ! renderingSubWidget) || size.isInvalid() || ! visible) - return; - - bool needsDisableScissor = false; - - // reset color - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - - if (needsFullViewport || (absolutePos.isZero() && size == Size(width, height))) - { - // full viewport size - glViewport(0, - -(height * scaling - height), - width * scaling, - height * scaling); - } - else if (needsScaling) - { - // limit viewport to widget bounds - glViewport(absolutePos.getX(), - height - self->getHeight() - absolutePos.getY(), - self->getWidth(), - self->getHeight()); - } - else - { - // only set viewport pos - glViewport(absolutePos.getX() * scaling, - -std::round((height * scaling - height) + (absolutePos.getY() * scaling)), - std::round(width * scaling), - std::round(height * scaling)); - - // then cut the outer bounds - glScissor(absolutePos.getX() * scaling, - height - std::round((self->getHeight() + absolutePos.getY()) * scaling), - std::round(self->getWidth() * scaling), - std::round(self->getHeight() * scaling)); - - glEnable(GL_SCISSOR_TEST); - needsDisableScissor = true; - } - - // display widget - self->onDisplay(); - - if (needsDisableScissor) - { - glDisable(GL_SCISSOR_TEST); - needsDisableScissor = false; - } - - displaySubWidgets(width, height, scaling); - } + // display function is different depending on build type + void display(const uint width, const uint height, const double scaling, const bool renderingSubWidget); void displaySubWidgets(const uint width, const uint height, const double scaling) { diff --git a/dpf/dgl/src/Window.cpp b/dpf/dgl/src/Window.cpp index 7da52c75..bb9db161 100644 --- a/dpf/dgl/src/Window.cpp +++ b/dpf/dgl/src/Window.cpp @@ -19,6 +19,15 @@ #include "../Base.hpp" +#ifdef DGL_CAIRO +# define PUGL_CAIRO +# include "../Cairo.hpp" +#endif +#ifdef DGL_OPENGL +# define PUGL_OPENGL +# include "../OpenGL.hpp" +#endif + #include "pugl/pugl.h" #if defined(__GNUC__) && (__GNUC__ >= 7) @@ -84,6 +93,7 @@ struct Window::PrivateData { fWidth(1), fHeight(1), fScaling(1.0), + fAutoScaling(1.0), fTitle(nullptr), fWidgets(), fModal(), @@ -115,6 +125,7 @@ struct Window::PrivateData { fWidth(1), fHeight(1), fScaling(1.0), + fAutoScaling(1.0), fTitle(nullptr), fWidgets(), fModal(parent.pData), @@ -147,7 +158,7 @@ struct Window::PrivateData { #endif } - PrivateData(Application& app, Window* const self, const intptr_t parentId, const bool resizable) + PrivateData(Application& app, Window* const self, const intptr_t parentId, const double scaling, const bool resizable) : fApp(app), fSelf(self), fView(puglInit()), @@ -157,7 +168,8 @@ struct Window::PrivateData { fUsingEmbed(parentId != 0), fWidth(1), fHeight(1), - fScaling(1.0), + fScaling(scaling), + fAutoScaling(1.0), fTitle(nullptr), fWidgets(), fModal(), @@ -222,11 +234,12 @@ struct Window::PrivateData { puglCreateWindow(fView, nullptr); PuglInternals* impl = fView->impl; + #if defined(DISTRHO_OS_WINDOWS) hwnd = impl->hwnd; DISTRHO_SAFE_ASSERT(hwnd != 0); #elif defined(DISTRHO_OS_MAC) - mView = impl->glview; + mView = impl->view; mWindow = impl->window; DISTRHO_SAFE_ASSERT(mView != nullptr); if (fUsingEmbed) { @@ -555,6 +568,7 @@ struct Window::PrivateData { void setGeometryConstraints(uint width, uint height, bool aspect) { + // Did you forget to set DISTRHO_UI_USER_RESIZABLE ? DISTRHO_SAFE_ASSERT_RETURN(fResizable,); fView->min_width = width; @@ -701,11 +715,11 @@ struct Window::PrivateData { return fScaling; } - void setScaling(double scaling) noexcept + void setAutoScaling(const double scaling) noexcept { DISTRHO_SAFE_ASSERT_RETURN(scaling > 0.0,); - fScaling = scaling; + fAutoScaling = scaling; } // ------------------------------------------------------------------- @@ -773,7 +787,7 @@ struct Window::PrivateData { FOR_EACH_WIDGET(it) { Widget* const widget(*it); - widget->pData->display(fWidth, fHeight, fScaling, false); + widget->pData->display(fWidth, fHeight, fAutoScaling, false); } fSelf->onDisplayAfter(); @@ -843,8 +857,8 @@ struct Window::PrivateData { if (fModal.childFocus != nullptr) return fModal.childFocus->focus(); - x /= fScaling; - y /= fScaling; + x /= fAutoScaling; + y /= fAutoScaling; Widget::MouseEvent ev; ev.button = button; @@ -870,8 +884,8 @@ struct Window::PrivateData { if (fModal.childFocus != nullptr) return; - x /= fScaling; - y /= fScaling; + x /= fAutoScaling; + y /= fAutoScaling; Widget::MotionEvent ev; ev.mod = static_cast(puglGetModifiers(fView)); @@ -895,10 +909,10 @@ struct Window::PrivateData { if (fModal.childFocus != nullptr) return; - x /= fScaling; - y /= fScaling; - dx /= fScaling; - dy /= fScaling; + x /= fAutoScaling; + y /= fAutoScaling; + dx /= fAutoScaling; + dy /= fAutoScaling; Widget::ScrollEvent ev; ev.delta = Point(dx, dy); @@ -1038,9 +1052,10 @@ struct Window::PrivateData { // ------------------------------------------------------------------- - Application& fApp; - Window* fSelf; - PuglView* fView; + Application& fApp; + Window* fSelf; + GraphicsContext fContext; + PuglView* fView; bool fFirstInit; bool fVisible; @@ -1049,6 +1064,7 @@ struct Window::PrivateData { uint fWidth; uint fHeight; double fScaling; + double fAutoScaling; char* fTitle; std::list fWidgets; @@ -1081,7 +1097,7 @@ struct Window::PrivateData { HWND hwndParent; #elif defined(DISTRHO_OS_MAC) bool fNeedsIdle; - PuglOpenGLView* mView; + NSView* mView; id mWindow; id mParentWindow; #else @@ -1155,8 +1171,8 @@ Window::Window(Application& app) Window::Window(Application& app, Window& parent) : pData(new PrivateData(app, this, parent)) {} -Window::Window(Application& app, intptr_t parentId, bool resizable) - : pData(new PrivateData(app, this, parentId, resizable)) {} +Window::Window(Application& app, intptr_t parentId, double scaling, bool resizable) + : pData(new PrivateData(app, this, parentId, scaling, resizable)) {} Window::~Window() { @@ -1347,11 +1363,6 @@ double Window::getScaling() const noexcept return pData->getScaling(); } -void Window::setScaling(double scaling) noexcept -{ - pData->setScaling(scaling); -} - bool Window::getIgnoringKeyRepeat() const noexcept { return pData->getIgnoringKeyRepeat(); @@ -1372,6 +1383,20 @@ intptr_t Window::getWindowId() const noexcept return puglGetNativeWindow(pData->fView); } +const GraphicsContext& Window::getGraphicsContext() const noexcept +{ + GraphicsContext& context = pData->fContext; +#ifdef DGL_CAIRO + context.cairo = (cairo_t*)puglGetContext(pData->fView); +#endif + return context; +} + +void Window::_setAutoScaling(double scaling) noexcept +{ + pData->setAutoScaling(scaling); +} + void Window::_addWidget(Widget* const widget) { pData->addWidget(widget); @@ -1407,8 +1432,10 @@ void Window::removeIdleCallback(IdleCallback* const callback) void Window::onDisplayBefore() { +#ifdef DGL_OPENGL glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); +#endif } void Window::onDisplayAfter() @@ -1417,6 +1444,7 @@ void Window::onDisplayAfter() void Window::onReshape(uint width, uint height) { +#ifdef DGL_OPENGL glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glMatrixMode(GL_PROJECTION); @@ -1425,6 +1453,7 @@ void Window::onReshape(uint width, uint height) glViewport(0, 0, static_cast(width), static_cast(height)); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); +#endif } void Window::onClose() diff --git a/dpf/dgl/src/pugl/pugl.h b/dpf/dgl/src/pugl/pugl.h index 32a10a2b..20a38140 100644 --- a/dpf/dgl/src/pugl/pugl.h +++ b/dpf/dgl/src/pugl/pugl.h @@ -1,5 +1,6 @@ /* Copyright 2012-2014 David Robillard + Copyright 2012-2019 Filipe Coelho Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -29,19 +30,13 @@ platforms so they are included here to allow for pure portable programs. */ #ifdef __APPLE__ -# include "OpenGL/gl.h" +# include #else # ifdef _WIN32 # include # include /* Broken Windows GL headers require this */ # endif -# include "GL/gl.h" -#endif - -#ifdef _WIN32 -# define PUGL_API -#else -# define PUGL_API __attribute__((visibility("hidden"))) +# include #endif #ifdef __cplusplus @@ -237,31 +232,31 @@ typedef void (*PuglFileSelectedFunc)(PuglView* view, const char* filename); To create a window, call the various puglInit* functions as necessary, then call puglCreateWindow(). */ -PUGL_API PuglView* +PuglView* puglInit(void); /** Set the parent window before creating a window (for embedding). */ -PUGL_API void +void puglInitWindowParent(PuglView* view, PuglNativeWindow parent); /** Set the window size before creating a window. */ -PUGL_API void +void puglInitWindowSize(PuglView* view, int width, int height); /** Set the minimum window size before creating a window. */ -PUGL_API void +void puglInitWindowMinSize(PuglView* view, int width, int height); /** Enable or disable resizing before creating a window. */ -PUGL_API void +void puglInitUserResizable(PuglView* view, bool resizable); /** @@ -270,7 +265,7 @@ puglInitUserResizable(PuglView* view, bool resizable); On X11, parent_id must be a Window. On OSX, parent_id must be an NSView*. */ -PUGL_API void +void puglInitTransientFor(PuglView* view, uintptr_t parent); /** @@ -288,7 +283,7 @@ puglInitTransientFor(PuglView* view, uintptr_t parent); @return 1 (pugl does not currently support multiple windows). */ -PUGL_API int +int puglCreateWindow(PuglView* view, const char* title); /** @@ -299,7 +294,7 @@ puglCreateWindow(PuglView* view, const char* title); @param height Window height in pixels. @param resizable Whether window should be user resizable. */ -PUGL_API PuglView* +PuglView* puglCreate(PuglNativeWindow parent, const char* title, int min_width, @@ -312,19 +307,19 @@ puglCreate(PuglNativeWindow parent, /** Show Window (external ui) */ -PUGL_API void +void puglShowWindow(PuglView* view); /** Hide Window (external ui) */ -PUGL_API void +void puglHideWindow(PuglView* view); /** Return the native window handle. */ -PUGL_API PuglNativeWindow +PuglNativeWindow puglGetNativeWindow(PuglView* view); /** @@ -340,19 +335,27 @@ puglGetNativeWindow(PuglView* view); Note the lack of this facility makes GLUT unsuitable for plugins or non-trivial programs; this mistake is largely why Pugl exists. */ -PUGL_API void +void puglSetHandle(PuglView* view, PuglHandle handle); /** Get the handle to be passed to all callbacks. */ -PUGL_API PuglHandle +PuglHandle puglGetHandle(PuglView* view); +/** + Get the drawing context. + For Cairo contexts, this returns a pointer to a cairo_t. + For everything else, this is unused and returns NULL. +*/ +void* +puglGetContext(PuglView* view); + /** Return the timestamp (if any) of the currently-processing event. */ -PUGL_API uint32_t +uint32_t puglGetEventTimestamp(PuglView* view); /** @@ -360,13 +363,13 @@ puglGetEventTimestamp(PuglView* view); This should only be called from an event handler. */ -PUGL_API int +int puglGetModifiers(PuglView* view); /** Ignore synthetic repeated key events. */ -PUGL_API void +void puglIgnoreKeyRepeat(PuglView* view, bool ignore); /** @@ -378,61 +381,61 @@ puglIgnoreKeyRepeat(PuglView* view, bool ignore); /** Set the function to call when the window is closed. */ -PUGL_API void +void puglSetCloseFunc(PuglView* view, PuglCloseFunc closeFunc); /** Set the display function which should draw the UI using GL. */ -PUGL_API void +void puglSetDisplayFunc(PuglView* view, PuglDisplayFunc displayFunc); /** Set the function to call on keyboard events. */ -PUGL_API void +void puglSetKeyboardFunc(PuglView* view, PuglKeyboardFunc keyboardFunc); /** Set the function to call on mouse motion. */ -PUGL_API void +void puglSetMotionFunc(PuglView* view, PuglMotionFunc motionFunc); /** Set the function to call on mouse button events. */ -PUGL_API void +void puglSetMouseFunc(PuglView* view, PuglMouseFunc mouseFunc); /** Set the function to call on scroll events. */ -PUGL_API void +void puglSetScrollFunc(PuglView* view, PuglScrollFunc scrollFunc); /** Set the function to call on special events. */ -PUGL_API void +void puglSetSpecialFunc(PuglView* view, PuglSpecialFunc specialFunc); /** Set the function to call when the window size changes. */ -PUGL_API void +void puglSetReshapeFunc(PuglView* view, PuglReshapeFunc reshapeFunc); /** Set callback function to change window size. */ -PUGL_API void +void puglSetResizeFunc(PuglView* view, PuglResizeFunc resizeFunc); /** Set the function to call on file-browser selections. */ -PUGL_API void +void puglSetFileSelectedFunc(PuglView* view, PuglFileSelectedFunc fileSelectedFunc); /** @@ -442,13 +445,13 @@ puglSetFileSelectedFunc(PuglView* view, PuglFileSelectedFunc fileSelectedFunc); /** TODO document this. */ -PUGL_API int +int puglUpdateGeometryConstraints(PuglView* view, int min_width, int min_height, bool aspect); /** Grab the input focus. */ -PUGL_API void +void puglGrabFocus(PuglView* view); /** @@ -457,25 +460,25 @@ puglGrabFocus(PuglView* view); This handles input events as well as rendering, so it should be called regularly and rapidly enough to keep the UI responsive. */ -PUGL_API PuglStatus +PuglStatus puglProcessEvents(PuglView* view); /** Request a redisplay on the next call to puglProcessEvents(). */ -PUGL_API void +void puglPostRedisplay(PuglView* view); /** Request a resize on the next call to puglProcessEvents(). */ -PUGL_API void +void puglPostResize(PuglView* view); /** Destroy a GL window. */ -PUGL_API void +void puglDestroy(PuglView* view); /** diff --git a/dpf/dgl/src/pugl/pugl_internal.h b/dpf/dgl/src/pugl/pugl_internal.h index fa52df40..609c97b9 100644 --- a/dpf/dgl/src/pugl/pugl_internal.h +++ b/dpf/dgl/src/pugl/pugl_internal.h @@ -1,5 +1,6 @@ /* Copyright 2012-2014 David Robillard + Copyright 2012-2019 Filipe Coelho Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -239,6 +240,7 @@ puglLeaveContext(PuglView* view, bool flush); static void puglDefaultReshape(int width, int height) { +#ifdef PUGL_OPENGL #ifdef ROBTK_HERE glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); @@ -257,4 +259,5 @@ puglDefaultReshape(int width, int height) glMatrixMode(GL_MODELVIEW); glLoadIdentity(); #endif +#endif // PUGL_OPENGL } diff --git a/dpf/dgl/src/pugl/pugl_osx.m b/dpf/dgl/src/pugl/pugl_osx.m index 738103f3..80b99304 100644 --- a/dpf/dgl/src/pugl/pugl_osx.m +++ b/dpf/dgl/src/pugl/pugl_osx.m @@ -1,5 +1,6 @@ /* Copyright 2012 David Robillard + Copyright 2012-2019 Filipe Coelho Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -20,6 +21,10 @@ #include +#ifdef PUGL_CAIRO +#import +#import +#endif #import #include "pugl_internal.h" @@ -93,7 +98,200 @@ - (BOOL)windowShouldClose:(id)sender } } -@interface PuglOpenGLView : NSOpenGLView +@protocol PuglGenericView +@required +- (PuglView *) puglview; +- (void) setPuglview:(PuglView *)pv; +- (NSTrackingArea *) puglTrackingArea; +- (void) setPuglTrackingArea:(NSTrackingArea *)area; +@end + +static unsigned +getModifiers(PuglView* view, NSEvent* ev) +{ + const unsigned modifierFlags = [ev modifierFlags]; + + view->event_timestamp_ms = fmod([ev timestamp] * 1000.0, UINT32_MAX); + + unsigned mods = 0; + mods |= (modifierFlags & NSShiftKeyMask) ? PUGL_MOD_SHIFT : 0; + mods |= (modifierFlags & NSControlKeyMask) ? PUGL_MOD_CTRL : 0; + mods |= (modifierFlags & NSAlternateKeyMask) ? PUGL_MOD_ALT : 0; + mods |= (modifierFlags & NSCommandKeyMask) ? PUGL_MOD_SUPER : 0; + return mods; +} + +static int +getFixedAppKitButton(NSInteger button) +{ + switch (button) { + case 0: return 1; + case 1: return 3; + case 2: return 2; + default: return button; + } +} + +static void +cursorUpdate(NSView *self, NSEvent* event) +{ + [[NSCursor arrowCursor] set]; + (void)self; + (void)event; +} + +static void +updateTrackingAreas(NSView *self) +{ + static const int opts = NSTrackingMouseEnteredAndExited + | NSTrackingMouseMoved + | NSTrackingEnabledDuringMouseDrag + | NSTrackingInVisibleRect + | NSTrackingActiveAlways + | NSTrackingCursorUpdate; + + NSTrackingArea *trackingArea = [self puglTrackingArea]; + if (trackingArea != nil) { + [self removeTrackingArea:trackingArea]; + [trackingArea release]; + } + + trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds] + options:opts + owner:self + userInfo:nil]; + [self setPuglTrackingArea:trackingArea]; + [self addTrackingArea:trackingArea]; +} + +static void +viewWillMoveToWindow(NSView *self, NSWindow* newWindow) +{ + if (newWindow != nil) { + [newWindow setAcceptsMouseMovedEvents:YES]; + [newWindow makeFirstResponder:self]; + } +} + +static void +reshape(NSView *self) +{ + PuglView* puglview = [self puglview]; + + NSRect bounds = [self bounds]; + int width = bounds.size.width; + int height = bounds.size.height; + + puglEnterContext(puglview); + + if (puglview->reshapeFunc) { + puglview->reshapeFunc(puglview, width, height); + } else { + puglDefaultReshape(width, height); + } + + puglLeaveContext(puglview, false); + + puglview->width = width; + puglview->height = height; +} + +static void +mouseMoved(NSView *self, NSEvent *event) +{ + PuglView* puglview = [self puglview]; + + if (puglview->motionFunc) { + NSPoint loc = [self convertPoint:[event locationInWindow] fromView:nil]; + puglview->mods = getModifiers(puglview, event); + puglview->motionFunc(puglview, loc.x, loc.y); + } +} + +static void +mouseDown(NSView *self, NSEvent *event) +{ + PuglView* puglview = [self puglview]; + + if (puglview->mouseFunc) { + NSPoint loc = [self convertPoint:[event locationInWindow] fromView:nil]; + puglview->mods = getModifiers(puglview, event); + puglview->mouseFunc(puglview, getFixedAppKitButton([event buttonNumber]), true, loc.x, loc.y); + } +} + +static void +mouseUp(NSView *self, NSEvent *event) +{ + PuglView* puglview = [self puglview]; + + if (puglview->mouseFunc) { + NSPoint loc = [self convertPoint:[event locationInWindow] fromView:nil]; + puglview->mods = getModifiers(puglview, event); + puglview->mouseFunc(puglview, getFixedAppKitButton([event buttonNumber]), false, loc.x, loc.y); + } +} + +static void +scrollWheel(NSView *self, NSEvent *event) +{ + PuglView* puglview = [self puglview]; + + if (puglview->scrollFunc) { + NSPoint loc = [self convertPoint:[event locationInWindow] fromView:nil]; + puglview->mods = getModifiers(puglview, event); + puglview->scrollFunc(puglview, + loc.x, loc.y, + [event deltaX], [event deltaY]); + } +} + +static void +keyDown(NSView *self, NSEvent *event) +{ + PuglView* puglview = [self puglview]; + + if (puglview->keyboardFunc && !(puglview->ignoreKeyRepeat && [event isARepeat])) { + NSString* chars = [event characters]; + puglview->mods = getModifiers(puglview, event); + puglview->keyboardFunc(puglview, true, [chars characterAtIndex:0]); + } +} + +static void +keyUp(NSView *self, NSEvent *event) +{ + PuglView* puglview = [self puglview]; + + if (puglview->keyboardFunc) { + NSString* chars = [event characters]; + puglview->mods = getModifiers(puglview, event); + puglview->keyboardFunc(puglview, false, [chars characterAtIndex:0]); + } +} + +static void +flagsChanged(NSView *self, NSEvent *event) +{ + PuglView* puglview = [self puglview]; + + if (puglview->specialFunc) { + const unsigned mods = getModifiers(puglview, event); + if ((mods & PUGL_MOD_SHIFT) != (puglview->mods & PUGL_MOD_SHIFT)) { + puglview->specialFunc(puglview, mods & PUGL_MOD_SHIFT, PUGL_KEY_SHIFT); + } else if ((mods & PUGL_MOD_CTRL) != (puglview->mods & PUGL_MOD_CTRL)) { + puglview->specialFunc(puglview, mods & PUGL_MOD_CTRL, PUGL_KEY_CTRL); + } else if ((mods & PUGL_MOD_ALT) != (puglview->mods & PUGL_MOD_ALT)) { + puglview->specialFunc(puglview, mods & PUGL_MOD_ALT, PUGL_KEY_ALT); + } else if ((mods & PUGL_MOD_SUPER) != (puglview->mods & PUGL_MOD_SUPER)) { + puglview->specialFunc(puglview, mods & PUGL_MOD_SUPER, PUGL_KEY_SUPER); + } + puglview->mods = mods; + } +} + +#ifdef PUGL_OPENGL +@interface PuglOpenGLView : NSOpenGLView { @public PuglView* puglview; @@ -101,6 +299,11 @@ @interface PuglOpenGLView : NSOpenGLView bool doubleBuffered; } +- (PuglView *) puglview; +- (void) setPuglview:(PuglView *)pv; +- (NSTrackingArea *) puglTrackingArea; +- (void) setPuglTrackingArea:(NSTrackingArea *)area; + - (BOOL) acceptsFirstMouse:(NSEvent*)e; - (BOOL) acceptsFirstResponder; - (BOOL) isFlipped; @@ -130,6 +333,21 @@ - (void) flagsChanged:(NSEvent*)event; @end @implementation PuglOpenGLView +- (PuglView *) puglview { + return self->puglview; +} + +- (void) setPuglview:(PuglView *)pv { + self->puglview = pv; +} + +- (NSTrackingArea *) puglTrackingArea { + return self->trackingArea; +} + +- (void) setPuglTrackingArea:(NSTrackingArea *)area { + self->trackingArea = area; +} - (BOOL) acceptsFirstMouse:(NSEvent*)e { @@ -209,22 +427,7 @@ deleting the view (?), so we must have reset puglview to NULL when [[self openGLContext] update]; - NSRect bounds = [self bounds]; - int width = bounds.size.width; - int height = bounds.size.height; - - puglEnterContext(puglview); - - if (puglview->reshapeFunc) { - puglview->reshapeFunc(puglview, width, height); - } else { - puglDefaultReshape(width, height); - } - - puglLeaveContext(puglview, false); - - puglview->width = width; - puglview->height = height; + reshape(self); } - (void) drawRect:(NSRect)r @@ -239,182 +442,326 @@ - (void) drawRect:(NSRect)r - (void) cursorUpdate:(NSEvent*)e { - [[NSCursor arrowCursor] set]; - - // unused - return; (void)e; + cursorUpdate(self, e); } - (void) updateTrackingAreas { - static const int opts = NSTrackingMouseEnteredAndExited - | NSTrackingMouseMoved - | NSTrackingEnabledDuringMouseDrag - | NSTrackingInVisibleRect - | NSTrackingActiveAlways - | NSTrackingCursorUpdate; - - if (trackingArea != nil) { - [self removeTrackingArea:trackingArea]; - [trackingArea release]; - } - - trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds] - options:opts - owner:self - userInfo:nil]; - [self addTrackingArea:trackingArea]; + updateTrackingAreas(self); [super updateTrackingAreas]; } - (void) viewWillMoveToWindow:(NSWindow*)newWindow { - if (newWindow != nil) { - [newWindow setAcceptsMouseMovedEvents:YES]; - [newWindow makeFirstResponder:self]; - } - + viewWillMoveToWindow(self, newWindow); [super viewWillMoveToWindow:newWindow]; } -static unsigned -getModifiers(PuglView* view, NSEvent* ev) +- (void) mouseMoved:(NSEvent*)event { - const unsigned modifierFlags = [ev modifierFlags]; + mouseMoved(self, event); +} - view->event_timestamp_ms = fmod([ev timestamp] * 1000.0, UINT32_MAX); +- (void) mouseDragged:(NSEvent*)event +{ + mouseMoved(self, event); +} - unsigned mods = 0; - mods |= (modifierFlags & NSShiftKeyMask) ? PUGL_MOD_SHIFT : 0; - mods |= (modifierFlags & NSControlKeyMask) ? PUGL_MOD_CTRL : 0; - mods |= (modifierFlags & NSAlternateKeyMask) ? PUGL_MOD_ALT : 0; - mods |= (modifierFlags & NSCommandKeyMask) ? PUGL_MOD_SUPER : 0; - return mods; +- (void) rightMouseDragged:(NSEvent*)event +{ + mouseMoved(self, event); } -static int -getFixedAppKitButton(NSInteger button) +- (void) otherMouseDragged:(NSEvent*)event { - switch (button) { - case 0: return 1; - case 1: return 3; - case 2: return 2; - default: return button; + mouseMoved(self, event); +} + +- (void) mouseDown:(NSEvent*)event +{ + mouseDown(self, event); +} + +- (void) rightMouseDown:(NSEvent*)event +{ + mouseDown(self, event); +} + +- (void) otherMouseDown:(NSEvent*)event +{ + mouseDown(self, event); +} + +- (void) mouseUp:(NSEvent*)event +{ + mouseUp(self, event); +} + +- (void) rightMouseUp:(NSEvent*)event +{ + mouseUp(self, event); +} + +- (void) otherMouseUp:(NSEvent*)event +{ + mouseUp(self, event); +} + +- (void) scrollWheel:(NSEvent*)event +{ + scrollWheel(self, event); +} + +- (void) keyDown:(NSEvent*)event +{ + keyDown(self, event); +} + +- (void) keyUp:(NSEvent*)event +{ + keyUp(self, event); +} + +- (void) flagsChanged:(NSEvent*)event +{ + flagsChanged(self, event); +} + +@end +#endif + +#ifdef PUGL_CAIRO +@interface PuglCairoView : NSView +{ + PuglView* puglview; + cairo_t* cr; + NSTrackingArea* trackingArea; +} + +- (PuglView *) puglview; +- (void) setPuglview:(PuglView *)pv; +- (NSTrackingArea *) puglTrackingArea; +- (void) setPuglTrackingArea:(NSTrackingArea *)area; + +- (cairo_t *) cairoContext; + +- (BOOL) acceptsFirstMouse:(NSEvent*)e; +- (BOOL) acceptsFirstResponder; +- (BOOL) isFlipped; +- (BOOL) isOpaque; +- (BOOL) preservesContentInLiveResize; +- (id) initWithFrame:(NSRect)frame; +- (void) reshape; +- (void) drawRect:(NSRect)r; +- (void) cursorUpdate:(NSEvent*)e; +- (void) updateTrackingAreas; +- (void) viewWillMoveToWindow:(NSWindow*)newWindow; +- (void) mouseMoved:(NSEvent*)event; +- (void) mouseDragged:(NSEvent*)event; +- (void) rightMouseDragged:(NSEvent*)event; +- (void) otherMouseDragged:(NSEvent*)event; +- (void) mouseDown:(NSEvent*)event; +- (void) rightMouseDown:(NSEvent*)event; +- (void) otherMouseDown:(NSEvent*)event; +- (void) mouseUp:(NSEvent*)event; +- (void) rightMouseUp:(NSEvent*)event; +- (void) otherMouseUp:(NSEvent*)event; +- (void) scrollWheel:(NSEvent*)event; +- (void) keyDown:(NSEvent*)event; +- (void) keyUp:(NSEvent*)event; +- (void) flagsChanged:(NSEvent*)event; +@end + +@implementation PuglCairoView +- (PuglView *) puglview { + return self->puglview; +} + +- (void) setPuglview:(PuglView *)pv { + self->puglview = pv; +} + +- (NSTrackingArea *) puglTrackingArea { + return self->trackingArea; +} + +- (void) setPuglTrackingArea:(NSTrackingArea *)area { + self->trackingArea = area; +} + +- (cairo_t *) cairoContext { + return cr; +} + +- (BOOL) acceptsFirstMouse:(NSEvent*)e +{ + return YES; + + // unused + (void)e; +} + +- (BOOL) acceptsFirstResponder +{ + return YES; +} + +- (BOOL) isFlipped +{ + return YES; +} + +- (BOOL) isOpaque +{ + return YES; +} + +- (BOOL) preservesContentInLiveResize +{ + return NO; +} + +- (id) initWithFrame:(NSRect)frame { + puglview = nil; + cr = NULL; + trackingArea = nil; + [super initWithFrame:frame]; + return self; +} + +- (void) reshape +{ + if (!puglview) { + /* NOTE: Apparently reshape gets called when the GC gets around to + deleting the view (?), so we must have reset puglview to NULL when + this comes around. + */ + return; } + + reshape(self); +} + +- (void) drawRect:(NSRect)r { + CGContextRef ctx = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort]; + NSRect bounds = [self bounds]; + cairo_surface_t* surface; + cairo_t* cairo; + + surface = cairo_quartz_surface_create_for_cg_context(ctx, bounds.size.width, bounds.size.height); + if (surface) { + cairo = cairo_create(surface); + if (cairo) { + self->cr = cairo; + puglEnterContext(puglview); + puglDisplay(puglview); + puglLeaveContext(puglview, true); + self->cr = NULL; + cairo_destroy(cairo); + } + cairo_surface_destroy(surface); + } +} + +- (void) cursorUpdate:(NSEvent*)e +{ + cursorUpdate(self, e); +} + +- (void) updateTrackingAreas +{ + updateTrackingAreas(self); + [super updateTrackingAreas]; +} + +- (void) viewWillMoveToWindow:(NSWindow*)newWindow +{ + viewWillMoveToWindow(self, newWindow); + [super viewWillMoveToWindow:newWindow]; } - (void) mouseMoved:(NSEvent*)event { - if (puglview->motionFunc) { - NSPoint loc = [self convertPoint:[event locationInWindow] fromView:nil]; - puglview->mods = getModifiers(puglview, event); - puglview->motionFunc(puglview, loc.x, loc.y); - } + mouseMoved(self, event); } - (void) mouseDragged:(NSEvent*)event { - [self mouseMoved:event]; + mouseMoved(self, event); } - (void) rightMouseDragged:(NSEvent*)event { - [self mouseDragged:event]; + mouseMoved(self, event); } - (void) otherMouseDragged:(NSEvent*)event { - [self mouseDragged:event]; + mouseMoved(self, event); } - (void) mouseDown:(NSEvent*)event { - if (puglview->mouseFunc) { - NSPoint loc = [self convertPoint:[event locationInWindow] fromView:nil]; - puglview->mods = getModifiers(puglview, event); - puglview->mouseFunc(puglview, getFixedAppKitButton([event buttonNumber]), true, loc.x, loc.y); - } + mouseDown(self, event); } - (void) rightMouseDown:(NSEvent*)event { - [self mouseDown:event]; + mouseDown(self, event); } - (void) otherMouseDown:(NSEvent*)event { - [self mouseDown:event]; + mouseDown(self, event); } - (void) mouseUp:(NSEvent*)event { - if (puglview->mouseFunc) { - NSPoint loc = [self convertPoint:[event locationInWindow] fromView:nil]; - puglview->mods = getModifiers(puglview, event); - puglview->mouseFunc(puglview, getFixedAppKitButton([event buttonNumber]), false, loc.x, loc.y); - } + mouseUp(self, event); } - (void) rightMouseUp:(NSEvent*)event { - [self mouseUp:event]; + mouseUp(self, event); } - (void) otherMouseUp:(NSEvent*)event { - [self mouseUp:event]; + mouseUp(self, event); } - (void) scrollWheel:(NSEvent*)event { - if (puglview->scrollFunc) { - NSPoint loc = [self convertPoint:[event locationInWindow] fromView:nil]; - puglview->mods = getModifiers(puglview, event); - puglview->scrollFunc(puglview, - loc.x, loc.y, - [event deltaX], [event deltaY]); - } + scrollWheel(self, event); } - (void) keyDown:(NSEvent*)event { - if (puglview->keyboardFunc && !(puglview->ignoreKeyRepeat && [event isARepeat])) { - NSString* chars = [event characters]; - puglview->mods = getModifiers(puglview, event); - puglview->keyboardFunc(puglview, true, [chars characterAtIndex:0]); - } + keyDown(self, event); } - (void) keyUp:(NSEvent*)event { - if (puglview->keyboardFunc) { - NSString* chars = [event characters]; - puglview->mods = getModifiers(puglview, event); - puglview->keyboardFunc(puglview, false, [chars characterAtIndex:0]); - } + keyUp(self, event); } - (void) flagsChanged:(NSEvent*)event { - if (puglview->specialFunc) { - const unsigned mods = getModifiers(puglview, event); - if ((mods & PUGL_MOD_SHIFT) != (puglview->mods & PUGL_MOD_SHIFT)) { - puglview->specialFunc(puglview, mods & PUGL_MOD_SHIFT, PUGL_KEY_SHIFT); - } else if ((mods & PUGL_MOD_CTRL) != (puglview->mods & PUGL_MOD_CTRL)) { - puglview->specialFunc(puglview, mods & PUGL_MOD_CTRL, PUGL_KEY_CTRL); - } else if ((mods & PUGL_MOD_ALT) != (puglview->mods & PUGL_MOD_ALT)) { - puglview->specialFunc(puglview, mods & PUGL_MOD_ALT, PUGL_KEY_ALT); - } else if ((mods & PUGL_MOD_SUPER) != (puglview->mods & PUGL_MOD_SUPER)) { - puglview->specialFunc(puglview, mods & PUGL_MOD_SUPER, PUGL_KEY_SUPER); - } - puglview->mods = mods; - } + flagsChanged(self, event); } - @end +#endif struct PuglInternalsImpl { - PuglOpenGLView* glview; + union { + NSView* view; +#ifdef PUGL_OPENGL + PuglOpenGLView* glview; +#endif +#ifdef PUGL_CAIRO + PuglCairoView* cairoview; +#endif + }; id window; }; @@ -427,19 +774,23 @@ - (void) flagsChanged:(NSEvent*)event void puglEnterContext(PuglView* view) { +#ifdef PUGL_OPENGL [[view->impl->glview openGLContext] makeCurrentContext]; +#endif } void puglLeaveContext(PuglView* view, bool flush) { if (flush) { +#ifdef PUGL_OPENGL if (view->impl->glview->doubleBuffered) { [[view->impl->glview openGLContext] flushBuffer]; } else { glFlush(); } //[NSOpenGLContext clearCurrentContext]; +#endif } } @@ -451,22 +802,27 @@ - (void) flagsChanged:(NSEvent*)event [NSAutoreleasePool new]; [NSApplication sharedApplication]; +#ifdef PUGL_OPENGL impl->glview = [PuglOpenGLView new]; +#endif +#ifdef PUGL_CAIRO + impl->cairoview = [PuglCairoView new]; +#endif - if (!impl->glview) { + if (!impl->view) { return 1; } - - impl->glview->puglview = view; + + [impl->view setPuglview:view]; if (view->user_resizable) { - [impl->glview setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable]; + [impl->view setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable]; } if (view->parent) { - [impl->glview retain]; + [impl->view retain]; NSView* pview = (NSView*)view->parent; - [pview addSubview:impl->glview]; + [pview addSubview:impl->view]; return 0; } @@ -482,8 +838,8 @@ - (void) flagsChanged:(NSEvent*)event } [window setPuglview:view]; - [window setContentView:impl->glview]; - [window makeFirstResponder:impl->glview]; + [window setContentView:impl->view]; + [window makeFirstResponder:impl->view]; [window makeKeyAndOrderFront:window]; // wait for first puglShowWindow @@ -505,7 +861,7 @@ - (void) flagsChanged:(NSEvent*)event if (impl->window) { [impl->window setIsVisible:YES]; } else { - [view->impl->glview setHidden:NO]; + [view->impl->view setHidden:NO]; } } @@ -517,21 +873,21 @@ - (void) flagsChanged:(NSEvent*)event if (impl->window) { [impl->window setIsVisible:NO]; } else { - [impl->glview setHidden:YES]; + [impl->view setHidden:YES]; } } void puglDestroy(PuglView* view) { - view->impl->glview->puglview = NULL; + [view->impl->view setPuglview:NULL]; if (view->impl->window) { [view->impl->window close]; - [view->impl->glview release]; + [view->impl->view release]; [view->impl->window release]; } else { - [view->impl->glview release]; + [view->impl->view release]; } free(view->impl); @@ -551,13 +907,25 @@ - (void) flagsChanged:(NSEvent*)event puglPostRedisplay(PuglView* view) { view->redisplay = true; - [view->impl->glview setNeedsDisplay:YES]; + [view->impl->view setNeedsDisplay:YES]; } PuglNativeWindow puglGetNativeWindow(PuglView* view) { - return (PuglNativeWindow)view->impl->glview; + return (PuglNativeWindow)view->impl->view; +} + +void* +puglGetContext(PuglView* view) +{ +#ifdef PUGL_CAIRO + return [view->impl->cairoview cairoContext]; +#endif + return NULL; + + // may be unused + (void)view; } int diff --git a/dpf/dgl/src/pugl/pugl_win.cpp b/dpf/dgl/src/pugl/pugl_win.cpp index 9990b8ef..d8b3866d 100644 --- a/dpf/dgl/src/pugl/pugl_win.cpp +++ b/dpf/dgl/src/pugl/pugl_win.cpp @@ -1,5 +1,6 @@ /* Copyright 2012-2014 David Robillard + Copyright 2012-2019 Filipe Coelho Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -18,16 +19,22 @@ @file pugl_win.cpp Windows/WGL Pugl Implementation. */ +#include +#include +#include + #include #include #include +#ifdef PUGL_CAIRO +#include +#include +#endif +#ifdef PUGL_OPENGL #include +#endif -#include -#include -#include - -#include "pugl/pugl_internal.h" +#include "pugl_internal.h" #ifndef WM_MOUSEWHEEL # define WM_MOUSEWHEEL 0x020A @@ -48,8 +55,15 @@ HINSTANCE hInstance = NULL; struct PuglInternalsImpl { HWND hwnd; +#ifdef PUGL_OPENGL HDC hdc; HGLRC hglrc; +#endif +#ifdef PUGL_CAIRO + cairo_t* buffer_cr; + cairo_surface_t* buffer_surface; +#endif + HDC paintHdc; WNDCLASS wc; }; @@ -76,17 +90,21 @@ puglInitInternals() void puglEnterContext(PuglView* view) { +#ifdef PUGL_OPENGL wglMakeCurrent(view->impl->hdc, view->impl->hglrc); +#endif } void puglLeaveContext(PuglView* view, bool flush) { +#ifdef PUGL_OPENGL if (flush) { glFlush(); SwapBuffers(view->impl->hdc); } wglMakeCurrent(NULL, NULL); +#endif } int @@ -124,7 +142,6 @@ puglCreateWindow(PuglView* view, const char* title) if (!RegisterClass(&impl->wc)) { free((void*)impl->wc.lpszClassName); free(impl); - free(view); return 1; } @@ -155,12 +172,12 @@ puglCreateWindow(PuglView* view, const char* title) UnregisterClass(impl->wc.lpszClassName, NULL); free((void*)impl->wc.lpszClassName); free(impl); - free(view); return 1; } SetWindowLongPtr(impl->hwnd, GWLP_USERDATA, (LONG_PTR)view); +#ifdef PUGL_OPENGL impl->hdc = GetDC(impl->hwnd); PIXELFORMATDESCRIPTOR pfd; @@ -183,9 +200,9 @@ puglCreateWindow(PuglView* view, const char* title) UnregisterClass (impl->wc.lpszClassName, NULL); free((void*)impl->wc.lpszClassName); free(impl); - free(view); return 1; } +#endif return PUGL_SUCCESS; } @@ -205,13 +222,25 @@ puglHideWindow(PuglView* view) void puglDestroy(PuglView* view) { + if (!view) { + return; + } + + PuglInternals* const impl = view->impl; + +#ifdef PUGL_OPENGL wglMakeCurrent(NULL, NULL); - wglDeleteContext(view->impl->hglrc); - ReleaseDC(view->impl->hwnd, view->impl->hdc); - DestroyWindow(view->impl->hwnd); - UnregisterClass(view->impl->wc.lpszClassName, NULL); - free((void*)view->impl->wc.lpszClassName); - free(view->impl); + wglDeleteContext(impl->hglrc); + ReleaseDC(impl->hwnd, impl->hdc); +#endif +#ifdef PUGL_CAIRO + cairo_destroy(impl->buffer_cr); + cairo_surface_destroy(impl->buffer_surface); +#endif + DestroyWindow(impl->hwnd); + UnregisterClass(impl->wc.lpszClassName, NULL); + free((void*)impl->wc.lpszClassName); + free(impl); free(view); } @@ -233,14 +262,57 @@ puglReshape(PuglView* view, int width, int height) static void puglDisplay(PuglView* view) { + PuglInternals* impl = view->impl; + bool success = true; + puglEnterContext(view); - view->redisplay = false; - if (view->displayFunc) { - view->displayFunc(view); +#ifdef PUGL_CAIRO + cairo_t *wc = NULL; + cairo_t *bc = NULL; + cairo_surface_t *ws = NULL; + cairo_surface_t *bs = NULL; + + HDC hdc = impl->paintHdc; + bc = impl->buffer_cr; + bs = impl->buffer_surface; + int w = view->width; + int h = view->height; + int bw = bs ? cairo_image_surface_get_width(bs) : -1; + int bh = bs ? cairo_image_surface_get_height(bs) : -1; + ws = hdc ? cairo_win32_surface_create(hdc) : NULL; + wc = ws ? cairo_create(ws) : NULL; + if (wc && (!bc || bw != w || bh != h)) { + cairo_destroy(bc); + cairo_surface_destroy(bs); + bs = cairo_surface_create_similar_image(ws, CAIRO_FORMAT_ARGB32, w, h); + bc = bs ? cairo_create(bs) : NULL; + impl->buffer_cr = bc; + impl->buffer_surface = bs; + } + success = wc != NULL && bc != NULL; +#endif + + if (success) { + view->redisplay = false; + if (view->displayFunc) { + view->displayFunc(view); + } +#ifdef PUGL_CAIRO + cairo_set_source_surface(wc, bs, 0, 0); + cairo_paint(wc); +#endif } - puglLeaveContext(view, true); + puglLeaveContext(view, success); + +#ifdef PUGL_CAIRO + cairo_destroy(wc); + cairo_surface_destroy(ws); +#endif + + return; + (void)impl; } static PuglKey @@ -329,8 +401,9 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam) mmi->ptMinTrackSize.y = view->min_height; break; case WM_PAINT: - BeginPaint(view->impl->hwnd, &ps); + view->impl->paintHdc = BeginPaint(view->impl->hwnd, &ps); puglDisplay(view); + view->impl->paintHdc = NULL; EndPaint(view->impl->hwnd, &ps); break; case WM_MOUSEMOVE: @@ -469,6 +542,18 @@ puglGetNativeWindow(PuglView* view) return (PuglNativeWindow)view->impl->hwnd; } +void* +puglGetContext(PuglView* view) +{ +#ifdef PUGL_CAIRO + return view->impl->buffer_cr; +#endif + return NULL; + + // may be unused + (void)view; +} + int puglUpdateGeometryConstraints(PuglView* view, int min_width, int min_height, bool aspect) { diff --git a/dpf/dgl/src/pugl/pugl_x11.c b/dpf/dgl/src/pugl/pugl_x11.c index ea70db1d..3146cfcc 100644 --- a/dpf/dgl/src/pugl/pugl_x11.c +++ b/dpf/dgl/src/pugl/pugl_x11.c @@ -2,6 +2,7 @@ Copyright 2012-2014 David Robillard Copyright 2011-2012 Ben Loftis, Harrison Consoles Copyright 2013,2015 Robin Gareus + Copyright 2012-2019 Filipe Coelho Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -24,8 +25,14 @@ #include #include +#ifdef PUGL_CAIRO +#include +#include +#endif +#ifdef PUGL_OPENGL #include #include +#endif #include #include #include @@ -53,10 +60,19 @@ struct PuglInternalsImpl { Display* display; int screen; Window win; +#ifdef PUGL_CAIRO + cairo_t* xlib_cr; + cairo_t* buffer_cr; + cairo_surface_t* xlib_surface; + cairo_surface_t* buffer_surface; +#endif +#ifdef PUGL_OPENGL GLXContext ctx; Bool doubleBuffered; +#endif }; +#ifdef PUGL_OPENGL /** Attributes for single-buffered RGBA with at least 4 bits per color and a 16 bit depth buffer. @@ -102,6 +118,7 @@ static int attrListDblMS[] = { GLX_SAMPLES, 4, None }; +#endif PuglInternals* puglInitInternals(void) @@ -112,12 +129,15 @@ puglInitInternals(void) void puglEnterContext(PuglView* view) { +#ifdef PUGL_OPENGL glXMakeCurrent(view->impl->display, view->impl->win, view->impl->ctx); +#endif } void puglLeaveContext(PuglView* view, bool flush) { +#ifdef PUGL_OPENGL if (flush) { glFlush(); if (view->impl->doubleBuffered) { @@ -125,12 +145,13 @@ puglLeaveContext(PuglView* view, bool flush) } } glXMakeCurrent(view->impl->display, None, NULL); +#endif } int puglCreateWindow(PuglView* view, const char* title) { - PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals)); + PuglInternals* impl = view->impl; if (!impl) { return 1; } @@ -142,9 +163,12 @@ puglCreateWindow(PuglView* view, const char* title) return 1; } impl->screen = DefaultScreen(impl->display); - impl->doubleBuffered = True; - XVisualInfo* vi = glXChooseVisual(impl->display, impl->screen, attrListDblMS); + XVisualInfo* vi = NULL; + +#ifdef PUGL_OPENGL + impl->doubleBuffered = True; + vi = glXChooseVisual(impl->display, impl->screen, attrListDblMS); if (!vi) { vi = glXChooseVisual(impl->display, impl->screen, attrListDbl); @@ -157,6 +181,13 @@ puglCreateWindow(PuglView* view, const char* title) vi = glXChooseVisual(impl->display, impl->screen, attrListSgl); impl->doubleBuffered = False; } +#endif +#ifdef PUGL_CAIRO + XVisualInfo pat; + int n; + pat.screen = impl->screen; + vi = XGetVisualInfo(impl->display, VisualScreenMask, &pat, &n); +#endif if (!vi) { XCloseDisplay(impl->display); @@ -165,18 +196,23 @@ puglCreateWindow(PuglView* view, const char* title) } #ifdef PUGL_VERBOSE +#ifdef PUGL_OPENGL int glxMajor, glxMinor; glXQueryVersion(impl->display, &glxMajor, &glxMinor); printf("puGL: GLX-Version : %d.%d\n", glxMajor, glxMinor); #endif +#endif +#ifdef PUGL_OPENGL impl->ctx = glXCreateContext(impl->display, vi, 0, GL_TRUE); if (!impl->ctx) { + XFree(vi); XCloseDisplay(impl->display); free(impl); return 1; } +#endif Window xParent = view->parent ? (Window)view->parent @@ -201,11 +237,36 @@ puglCreateWindow(PuglView* view, const char* title) CWBorderPixel | CWColormap | CWEventMask, &attr); if (!impl->win) { +#ifdef PUGL_OPENGL + glXDestroyContext(impl->display, impl->ctx); +#endif + XFree(vi); XCloseDisplay(impl->display); free(impl); return 1; } +#ifdef PUGL_CAIRO + impl->xlib_surface = cairo_xlib_surface_create( + impl->display, impl->win, vi->visual, view->width, view->height); + if (impl->xlib_surface == NULL || cairo_surface_status(impl->xlib_surface) != CAIRO_STATUS_SUCCESS) { + printf("puGL: failed to create cairo surface\n"); + } + else { + impl->xlib_cr = cairo_create(impl->xlib_surface); + } + if (impl->xlib_cr == NULL || cairo_status(impl->xlib_cr) != CAIRO_STATUS_SUCCESS) { + cairo_destroy(impl->xlib_cr); + cairo_surface_destroy(impl->xlib_surface); + XDestroyWindow(impl->display, impl->win); + XFree(vi); + XCloseDisplay(impl->display); + free(impl); + printf("puGL: failed to create cairo context\n"); + return 1; + } +#endif + if (view->width > 1 || view->height > 1) { puglUpdateGeometryConstraints(view, view->min_width, view->min_height, view->min_width != view->width); XResizeWindow(view->impl->display, view->impl->win, view->width, view->height); @@ -227,11 +288,13 @@ puglCreateWindow(PuglView* view, const char* title) } #ifdef PUGL_VERBOSE +#ifdef PUGL_OPENGL if (glXIsDirect(impl->display, impl->ctx)) { printf("puGL: DRI enabled (to disable, set LIBGL_ALWAYS_INDIRECT=1\n"); } else { printf("puGL: No DRI available\n"); } +#endif #endif XFree(vi); @@ -244,14 +307,25 @@ puglDestroy(PuglView* view) if (!view) { return; } + + PuglInternals* const impl = view->impl; + #ifndef DGL_FILE_BROWSER_DISABLED - x_fib_close(view->impl->display); + x_fib_close(impl->display); #endif - glXDestroyContext(view->impl->display, view->impl->ctx); - XDestroyWindow(view->impl->display, view->impl->win); - XCloseDisplay(view->impl->display); - free(view->impl); +#ifdef PUGL_OPENGL + glXDestroyContext(impl->display, impl->ctx); +#endif +#ifdef PUGL_CAIRO + cairo_destroy(impl->xlib_cr); + cairo_destroy(impl->buffer_cr); + cairo_surface_destroy(impl->xlib_surface); + cairo_surface_destroy(impl->buffer_surface); +#endif + XDestroyWindow(impl->display, impl->win); + XCloseDisplay(impl->display); + free(impl); free(view); } @@ -287,14 +361,47 @@ puglReshape(PuglView* view, int width, int height) static void puglDisplay(PuglView* view) { + PuglInternals* impl = view->impl; + puglEnterContext(view); +#ifdef PUGL_CAIRO + cairo_t* bc = impl->buffer_cr; + cairo_surface_t* xs = impl->xlib_surface; + cairo_surface_t* bs = impl->buffer_surface; + int w = cairo_xlib_surface_get_width(xs); + int h = cairo_xlib_surface_get_height(xs); + + int bw = bs ? cairo_image_surface_get_width(bs) : -1; + int bh = bs ? cairo_image_surface_get_height(bs) : -1; + if (!bc || bw != w || bh != h) { + cairo_destroy(bc); + cairo_surface_destroy(bs); + bs = cairo_surface_create_similar_image(xs, CAIRO_FORMAT_ARGB32, w, h); + bc = bs ? cairo_create(bs) : NULL; + impl->buffer_cr = bc; + impl->buffer_surface = bs; + } + + if (!bc) { + puglLeaveContext(view, false); + return; + } +#endif + view->redisplay = false; if (view->displayFunc) { view->displayFunc(view); } +#ifdef PUGL_CAIRO + cairo_t* xc = impl->xlib_cr; + cairo_set_source_surface(xc, impl->buffer_surface, 0, 0); + cairo_paint(xc); +#endif + puglLeaveContext(view, true); + (void)impl; } static void @@ -554,6 +661,12 @@ puglProcessEvents(PuglView* view) } if (conf_width != -1) { +#ifdef PUGL_CAIRO + // Resize surfaces/contexts before dispatching + view->redisplay = true; + cairo_xlib_surface_set_size(view->impl->xlib_surface, + conf_width, conf_height); +#endif puglReshape(view, conf_width, conf_height); } @@ -586,6 +699,18 @@ puglGetNativeWindow(PuglView* view) return view->impl->win; } +void* +puglGetContext(PuglView* view) +{ +#ifdef PUGL_CAIRO + return view->impl->buffer_cr; +#endif + return NULL; + + // may be unused + (void)view; +} + int puglUpdateGeometryConstraints(PuglView* view, int min_width, int min_height, bool aspect) { diff --git a/dpf/distrho/DistrhoInfo.hpp b/dpf/distrho/DistrhoInfo.hpp index b38976f1..41177907 100644 --- a/dpf/distrho/DistrhoInfo.hpp +++ b/dpf/distrho/DistrhoInfo.hpp @@ -417,6 +417,10 @@ START_NAMESPACE_DISTRHO }; @endcode + This is a work-in-progress documentation page. States, MIDI, Latency, Time-Position and UI are still TODO. +*/ + +#if 0 @section States describe them @@ -431,7 +435,7 @@ START_NAMESPACE_DISTRHO @section UI describe them -*/ +#endif /* ------------------------------------------------------------------------------------------------------------ * Plugin Macros */ @@ -543,6 +547,16 @@ START_NAMESPACE_DISTRHO */ #define DISTRHO_PLUGIN_WANT_STATE 1 +/** + Wherever the plugin implements the full state API. + When this macro is enabled, the plugin must implement a new getState(const char* key) function, which the host calls when saving its session/project. + This is useful for plugins that have custom internal values not exposed to the host as key-value state pairs or parameters. + Most simple effects and synths will not need this. + @note this macro is automatically enabled if a plugin has programs and state, as the key-value state pairs need to be updated when the current program changes. + @see Plugin::getState(const char*) + */ +#define DISTRHO_PLUGIN_WANT_FULL_STATE 1 + /** Wherever the plugin wants time position information from the host. @see Plugin::getTimePosition() diff --git a/dpf/distrho/DistrhoPlugin.hpp b/dpf/distrho/DistrhoPlugin.hpp index 1da2bdb6..ebc54077 100644 --- a/dpf/distrho/DistrhoPlugin.hpp +++ b/dpf/distrho/DistrhoPlugin.hpp @@ -226,7 +226,7 @@ struct ParameterRanges { /** Get a fixed value within range. */ - const float& getFixedValue(const float& value) const noexcept + float getFixedValue(const float& value) const noexcept { if (value <= min) return min; diff --git a/dpf/distrho/DistrhoUI.hpp b/dpf/distrho/DistrhoUI.hpp index 0fa45b20..ecebc368 100644 --- a/dpf/distrho/DistrhoUI.hpp +++ b/dpf/distrho/DistrhoUI.hpp @@ -32,6 +32,13 @@ typedef DGL_NAMESPACE::NanoWidget UIWidget; typedef DGL_NAMESPACE::Widget UIWidget; #endif +#ifdef DGL_CAIRO +# include "Cairo.hpp" +#endif +#ifdef DGL_OPENGL +# include "OpenGL.hpp" +#endif + START_NAMESPACE_DISTRHO /* ------------------------------------------------------------------------------------------------------------ @@ -62,7 +69,7 @@ class UI : public UIWidget */ virtual ~UI(); -#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI +#if DISTRHO_UI_USER_RESIZABLE && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI /** Set geometry constraints for the UI when resized by the user, and optionally scale UI automatically. @see Window::setGeometryConstraints(uint,uint,bool) @@ -82,13 +89,17 @@ class UI : public UIWidget /** editParameter. - @TODO Document this. + + Touch/pressed-down event. + Lets the host know the user is tweaking a parameter. + Required in some hosts to record automation. */ void editParameter(uint32_t index, bool started); /** setParameterValue. - @TODO Document this. + + Change a parameter value in the Plugin. */ void setParameterValue(uint32_t index, float value); @@ -131,6 +142,13 @@ class UI : public UIWidget */ static const char* getNextBundlePath() noexcept; + /** + Get the scale factor that will be used for the next UI. + @note: This function is only valid during createUI(), + it will return 1.0 when called from anywhere else. + */ + static double getNextScaleFactor() noexcept; + # if DISTRHO_PLUGIN_HAS_EMBED_UI /** Get the Window Id that will be used for the next created window. diff --git a/dpf/distrho/src/DistrhoPluginChecks.h b/dpf/distrho/src/DistrhoPluginChecks.h index 2c543b17..01a52a16 100644 --- a/dpf/distrho/src/DistrhoPluginChecks.h +++ b/dpf/distrho/src/DistrhoPluginChecks.h @@ -97,7 +97,7 @@ // Define DISTRHO_PLUGIN_HAS_EMBED_UI if needed #ifndef DISTRHO_PLUGIN_HAS_EMBED_UI -# ifdef HAVE_DGL +# if defined(HAVE_CAIRO) || defined(HAVE_OPENGL) # define DISTRHO_PLUGIN_HAS_EMBED_UI 1 # else # define DISTRHO_PLUGIN_HAS_EMBED_UI 0 @@ -139,7 +139,7 @@ // ----------------------------------------------------------------------- // Disable UI if DGL or External UI is not available -#if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_HAS_EXTERNAL_UI && ! defined(HAVE_DGL) +#if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_HAS_EXTERNAL_UI && ! defined(HAVE_CAIRO) && ! defined(HAVE_OPENGL) # undef DISTRHO_PLUGIN_HAS_UI # define DISTRHO_PLUGIN_HAS_UI 0 #endif diff --git a/dpf/distrho/src/DistrhoPluginJack.cpp b/dpf/distrho/src/DistrhoPluginJack.cpp index edafaf66..7cb0684a 100644 --- a/dpf/distrho/src/DistrhoPluginJack.cpp +++ b/dpf/distrho/src/DistrhoPluginJack.cpp @@ -81,6 +81,16 @@ static void initSignalHandler() // ----------------------------------------------------------------------- +#if DISTRHO_PLUGIN_HAS_UI +// TODO +static double getDesktopScaleFactor() noexcept +{ + return 1.0; +} +#endif + +// ----------------------------------------------------------------------- + #if DISTRHO_PLUGIN_HAS_UI class PluginJack : public IdleCallback #else @@ -91,7 +101,7 @@ class PluginJack PluginJack(jack_client_t* const client) : fPlugin(this, writeMidiCallback), #if DISTRHO_PLUGIN_HAS_UI - fUI(this, 0, nullptr, setParameterValueCallback, setStateCallback, nullptr, setSizeCallback, fPlugin.getInstancePointer()), + fUI(this, 0, nullptr, setParameterValueCallback, setStateCallback, nullptr, setSizeCallback, getDesktopScaleFactor(), fPlugin.getInstancePointer()), #endif fClient(client) { diff --git a/dpf/distrho/src/DistrhoPluginLV2.cpp b/dpf/distrho/src/DistrhoPluginLV2.cpp index e66ec1d0..ed970528 100644 --- a/dpf/distrho/src/DistrhoPluginLV2.cpp +++ b/dpf/distrho/src/DistrhoPluginLV2.cpp @@ -545,7 +545,7 @@ class PluginLv2 #ifdef DISTRHO_PLUGIN_LICENSED_FOR_MOD for (uint32_t i=0; i 0) diff --git a/dpf/distrho/src/DistrhoPluginVST.cpp b/dpf/distrho/src/DistrhoPluginVST.cpp index c5cdd6e2..d8e7640f 100644 --- a/dpf/distrho/src/DistrhoPluginVST.cpp +++ b/dpf/distrho/src/DistrhoPluginVST.cpp @@ -161,12 +161,12 @@ class ParameterCheckHelper class UIVst { public: - UIVst(const audioMasterCallback audioMaster, AEffect* const effect, ParameterCheckHelper* const uiHelper, PluginExporter* const plugin, const intptr_t winId) + UIVst(const audioMasterCallback audioMaster, AEffect* const effect, ParameterCheckHelper* const uiHelper, PluginExporter* const plugin, const intptr_t winId, const float scaleFactor) : fAudioMaster(audioMaster), fEffect(effect), fUiHelper(uiHelper), fPlugin(plugin), - fUI(this, winId, editParameterCallback, setParameterCallback, setStateCallback, sendNoteCallback, setSizeCallback, plugin->getInstancePointer()), + fUI(this, winId, editParameterCallback, setParameterCallback, setStateCallback, sendNoteCallback, setSizeCallback, scaleFactor, plugin->getInstancePointer()), fShouldCaptureVstKeys(false) { // FIXME only needed for windows? @@ -575,8 +575,11 @@ class PluginVst : public ParameterCheckHelper else { d_lastUiSampleRate = fPlugin.getSampleRate(); + + // TODO + const float scaleFactor = 1.0f; - UIExporter tmpUI(nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, fPlugin.getInstancePointer()); + UIExporter tmpUI(nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, scaleFactor, fPlugin.getInstancePointer()); fVstRect.right = tmpUI.getWidth(); fVstRect.bottom = tmpUI.getHeight(); tmpUI.quit(); @@ -595,8 +598,11 @@ class PluginVst : public ParameterCheckHelper } # endif d_lastUiSampleRate = fPlugin.getSampleRate(); + + // TODO + const float scaleFactor = 1.0f; - fVstUI = new UIVst(fAudioMaster, fEffect, this, &fPlugin, (intptr_t)ptr); + fVstUI = new UIVst(fAudioMaster, fEffect, this, &fPlugin, (intptr_t)ptr, scaleFactor); # if DISTRHO_PLUGIN_WANT_FULL_STATE // Update current state from plugin side diff --git a/dpf/distrho/src/DistrhoUI.cpp b/dpf/distrho/src/DistrhoUI.cpp index 4170c82b..cc081403 100644 --- a/dpf/distrho/src/DistrhoUI.cpp +++ b/dpf/distrho/src/DistrhoUI.cpp @@ -27,8 +27,9 @@ START_NAMESPACE_DISTRHO double d_lastUiSampleRate = 0.0; void* d_lastUiDspPtr = nullptr; #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI -uintptr_t g_nextWindowId = 0; const char* g_nextBundlePath = nullptr; +double g_nextScaleFactor = 1.0; +uintptr_t g_nextWindowId = 0; #else Window* d_lastUiWindow = nullptr; #endif @@ -57,7 +58,7 @@ UI::~UI() delete pData; } -#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI +#if DISTRHO_UI_USER_RESIZABLE && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI void UI::setGeometryConstraints(uint minWidth, uint minHeight, bool keepAspectRatio, bool automaticallyScale) { DISTRHO_SAFE_ASSERT_RETURN(minWidth > 0,); @@ -67,7 +68,13 @@ void UI::setGeometryConstraints(uint minWidth, uint minHeight, bool keepAspectRa pData->minWidth = minWidth; pData->minHeight = minHeight; - getParentWindow().setGeometryConstraints(minWidth, minHeight, keepAspectRatio); + Window& window(getParentWindow()); + + const double uiScaleFactor = window.getScaling(); + window.setGeometryConstraints(minWidth * uiScaleFactor, minHeight * uiScaleFactor, keepAspectRatio); + + if (d_isNotZero(uiScaleFactor - 1.0)) + setSize(getWidth() * uiScaleFactor, getHeight() * uiScaleFactor); } #endif @@ -122,6 +129,11 @@ const char* UI::getNextBundlePath() noexcept return g_nextBundlePath; } +double UI::getNextScaleFactor() noexcept +{ + return g_nextScaleFactor; +} + # if DISTRHO_PLUGIN_HAS_EMBED_UI uintptr_t UI::getNextWindowId() noexcept { @@ -147,6 +159,7 @@ void UI::uiFileBrowserSelected(const char*) void UI::uiReshape(uint width, uint height) { +#ifdef DGL_OPENGL glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glMatrixMode(GL_PROJECTION); @@ -155,6 +168,11 @@ void UI::uiReshape(uint width, uint height) glViewport(0, 0, static_cast(width), static_cast(height)); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); +#else + // unused + (void)width; + (void)height; +#endif } /* ------------------------------------------------------------------------------------------------------------ diff --git a/dpf/distrho/src/DistrhoUIInternal.hpp b/dpf/distrho/src/DistrhoUIInternal.hpp index b81e1501..f1ebb332 100644 --- a/dpf/distrho/src/DistrhoUIInternal.hpp +++ b/dpf/distrho/src/DistrhoUIInternal.hpp @@ -37,11 +37,13 @@ START_NAMESPACE_DISTRHO extern double d_lastUiSampleRate; extern void* d_lastUiDspPtr; -#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI +#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI +extern const char* g_nextBundlePath; +extern double g_nextScaleFactor; +extern uintptr_t g_nextWindowId; +#else extern Window* d_lastUiWindow; #endif -extern uintptr_t g_nextWindowId; -extern const char* g_nextBundlePath; // ----------------------------------------------------------------------- // UI callbacks @@ -149,15 +151,17 @@ struct UI::PrivateData { #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI static inline -UI* createUiWrapper(void* const dspPtr, const uintptr_t winId, const char* const bundlePath) +UI* createUiWrapper(void* const dspPtr, const uintptr_t winId, const double scaleFactor, const char* const bundlePath) { - d_lastUiDspPtr = dspPtr; - g_nextWindowId = winId; - g_nextBundlePath = bundlePath; - UI* const ret = createUI(); - d_lastUiDspPtr = nullptr; - g_nextWindowId = 0; - g_nextBundlePath = nullptr; + d_lastUiDspPtr = dspPtr; + g_nextWindowId = winId; + g_nextScaleFactor = scaleFactor; + g_nextBundlePath = bundlePath; + UI* const ret = createUI(); + d_lastUiDspPtr = nullptr; + g_nextWindowId = 0; + g_nextScaleFactor = 1.0; + g_nextBundlePath = nullptr; return ret; } #else // DISTRHO_PLUGIN_HAS_EXTERNAL_UI @@ -175,8 +179,8 @@ UI* createUiWrapper(void* const dspPtr, Window* const window) class UIExporterWindow : public Window { public: - UIExporterWindow(Application& app, const intptr_t winId, void* const dspPtr) - : Window(app, winId, DISTRHO_UI_USER_RESIZABLE), + UIExporterWindow(Application& app, const intptr_t winId, const double scaleFactor, void* const dspPtr) + : Window(app, winId, scaleFactor, DISTRHO_UI_USER_RESIZABLE), fUI(createUiWrapper(dspPtr, this)), fIsReady(false) { @@ -214,7 +218,7 @@ class UIExporterWindow : public Window { const double scaleHorizontal = static_cast(width) / static_cast(pData->minWidth); const double scaleVertical = static_cast(height) / static_cast(pData->minHeight); - setScaling(scaleHorizontal < scaleVertical ? scaleHorizontal : scaleVertical); + _setAutoScaling(scaleHorizontal < scaleVertical ? scaleHorizontal : scaleVertical); } pData->resizeInProgress = true; @@ -254,13 +258,14 @@ class UIExporter const setStateFunc setStateCall, const sendNoteFunc sendNoteCall, const setSizeFunc setSizeCall, + const float scaleFactor = 1.0f, void* const dspPtr = nullptr, const char* const bundlePath = nullptr) #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI - : fUI(createUiWrapper(dspPtr, winId, bundlePath)), + : fUI(createUiWrapper(dspPtr, winId, scaleFactor, bundlePath)), #else : glApp(), - glWindow(glApp, winId, dspPtr), + glWindow(glApp, winId, scaleFactor, dspPtr), fChangingSize(false), fUI(glWindow.getUI()), #endif diff --git a/dpf/distrho/src/DistrhoUILV2.cpp b/dpf/distrho/src/DistrhoUILV2.cpp index 6431f9d7..140909b0 100644 --- a/dpf/distrho/src/DistrhoUILV2.cpp +++ b/dpf/distrho/src/DistrhoUILV2.cpp @@ -53,8 +53,8 @@ class UiLv2 UiLv2(const char* const bundlePath, const intptr_t winId, const LV2_Options_Option* options, const LV2_URID_Map* const uridMap, const LV2UI_Resize* const uiResz, const LV2UI_Touch* uiTouch, const LV2UI_Controller controller, const LV2UI_Write_Function writeFunc, - LV2UI_Widget* const widget, void* const dspPtr) - : fUI(this, winId, editParameterCallback, setParameterCallback, setStateCallback, sendNoteCallback, setSizeCallback, dspPtr, bundlePath), + const float scaleFactor, LV2UI_Widget* const widget, void* const dspPtr) + : fUI(this, winId, editParameterCallback, setParameterCallback, setStateCallback, sendNoteCallback, setSizeCallback, scaleFactor, dspPtr, bundlePath), fUridMap(uridMap), fUiResize(uiResz), fUiTouch(uiTouch), @@ -286,7 +286,7 @@ class UiLv2 atomMidiEvent.data[2] = velocity; // send to DSP side - fWriteFunction(fController, eventInPortIndex, sizeof(LV2_Atom_MidiEvent), fEventTransferURID, &atomMidiEvent); + fWriteFunction(fController, eventInPortIndex, lv2_atom_total_size(&atomMidiEvent.atom), fEventTransferURID, &atomMidiEvent); } #endif @@ -434,22 +434,30 @@ static LV2UI_Handle lv2ui_instantiate(const LV2UI_Descriptor*, const char* uri, } #endif + float scaleFactor = 1.0f; const intptr_t winId((intptr_t)parentId); if (options != nullptr) { + const LV2_URID uridAtomFloat(uridMap->map(uridMap->handle, LV2_ATOM__Float)); const LV2_URID uridSampleRate(uridMap->map(uridMap->handle, LV2_PARAMETERS__sampleRate)); + const LV2_URID uridScaleFactor(uridMap->map(uridMap->handle, LV2_UI__scaleFactor)); for (int i=0; options[i].key != 0; ++i) { - if (options[i].key == uridSampleRate) + /**/ if (options[i].key == uridSampleRate) { - if (options[i].type == uridMap->map(uridMap->handle, LV2_ATOM__Float)) + if (options[i].type == uridAtomFloat) d_lastUiSampleRate = *(const float*)options[i].value; else d_stderr("Host provides UI sample-rate but has wrong value type"); - - break; + } + else if (options[i].key == uridScaleFactor) + { + if (options[i].type == uridAtomFloat) + scaleFactor = *(const float*)options[i].value; + else + d_stderr("Host provides UI scale factor but has wrong value type"); } } } @@ -460,7 +468,7 @@ static LV2UI_Handle lv2ui_instantiate(const LV2UI_Descriptor*, const char* uri, d_lastUiSampleRate = 44100.0; } - return new UiLv2(bundlePath, winId, options, uridMap, uiResize, uiTouch, controller, writeFunction, widget, instance); + return new UiLv2(bundlePath, winId, options, uridMap, uiResize, uiTouch, controller, writeFunction, scaleFactor, widget, instance); } #define uiPtr ((UiLv2*)ui) diff --git a/dpf/distrho/src/lv2/ui.h b/dpf/distrho/src/lv2/ui.h index 9ee4bd10..171549c9 100644 --- a/dpf/distrho/src/lv2/ui.h +++ b/dpf/distrho/src/lv2/ui.h @@ -52,6 +52,7 @@ #define LV2_UI__portNotification LV2_UI_PREFIX "portNotification" #define LV2_UI__portSubscribe LV2_UI_PREFIX "portSubscribe" #define LV2_UI__resize LV2_UI_PREFIX "resize" +#define LV2_UI__scaleFactor LV2_UI_PREFIX "scaleFactor" #define LV2_UI__showInterface LV2_UI_PREFIX "showInterface" #define LV2_UI__touch LV2_UI_PREFIX "touch" #define LV2_UI__ui LV2_UI_PREFIX "ui" diff --git a/dpf/dpf.doxygen b/dpf/dpf.doxygen index 9c05ec0c..2516e934 100644 --- a/dpf/dpf.doxygen +++ b/dpf/dpf.doxygen @@ -242,7 +242,8 @@ SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = DOXYGEN \ - HAVE_DGL=1 \ + HAVE_CAIRO=1 \ + HAVE_OPENGL=1 \ DISTRHO_PLUGIN_NAME="Plugin Name" \ DISTRHO_PLUGIN_NUM_INPUTS=2 \ DISTRHO_PLUGIN_NUM_OUTPUTS=2 \ diff --git a/dpf/utils/lv2-ttl-generator/GNUmakefile b/dpf/utils/lv2-ttl-generator/GNUmakefile index 1042b7bd..490e9343 100644 --- a/dpf/utils/lv2-ttl-generator/GNUmakefile +++ b/dpf/utils/lv2-ttl-generator/GNUmakefile @@ -2,7 +2,7 @@ all: build -ifeq ($(WIN32),true) +ifeq ($(WINDOWS),true) build: ../lv2_ttl_generator.exe else build: ../lv2_ttl_generator diff --git a/dpf/utils/png2c.py b/dpf/utils/res2c.py similarity index 82% rename from dpf/utils/png2c.py rename to dpf/utils/res2c.py index ab023658..978af8b9 100755 --- a/dpf/utils/png2c.py +++ b/dpf/utils/res2c.py @@ -19,7 +19,7 @@ # ----------------------------------------------------- -def png2c(namespace, filenames): +def res2c(namespace, filenames): fdH = open("%s.hpp" % namespace, "w") fdH.write("/* (Auto-generated binary data file). */\n") @@ -42,12 +42,12 @@ def png2c(namespace, filenames): shortFilename = filename.rsplit(os.sep, 1)[-1].split(".", 1)[0] shortFilename = shortFilename.replace("-", "_") - pngData = open(filename, 'rb').read() + resData = open(filename, 'rb').read() print("Generating data for \"%s\"" % (filename)) fdH.write(" extern const char* %sData;\n" % shortFilename) - fdH.write(" const unsigned int %sDataSize = %i;\n" % (shortFilename, len(pngData))) + fdH.write(" const unsigned int %sDataSize = %i;\n" % (shortFilename, len(resData))) if tempIndex != len(filenames): fdH.write("\n") @@ -57,7 +57,7 @@ def png2c(namespace, filenames): curColumn = 1 fdC.write(" ") - for data in pngData: + for data in resData: if curColumn == 0: fdC.write(" ") @@ -90,24 +90,24 @@ def png2c(namespace, filenames): if __name__ == '__main__': if len(sys.argv) != 3: - print("Usage: %s " % sys.argv[0]) + print("Usage: %s " % sys.argv[0]) quit() namespace = sys.argv[1].replace("-","_") - artFolder = sys.argv[2] + resFolder = sys.argv[2] - if not os.path.exists(artFolder): - print("Folder '%s' does not exist" % artFolder) + if not os.path.exists(resFolder): + print("Folder '%s' does not exist" % resFolder) quit() - # find png files - pngFiles = [] + # find resource files + resFiles = [] - for root, dirs, files in os.walk(artFolder): - for name in [name for name in files if name.lower().endswith(".png")]: - pngFiles.append(os.path.join(root, name)) + for root, dirs, files in os.walk(resFolder): + for name in files: + resFiles.append(os.path.join(root, name)) - pngFiles.sort() + resFiles.sort() # create code now - png2c(namespace, pngFiles) + res2c(namespace, resFiles) diff --git a/plugins/Kars/DistrhoPluginKars.cpp b/plugins/Kars/DistrhoPluginKars.cpp index 910a4dc0..b3d1b438 100644 --- a/plugins/Kars/DistrhoPluginKars.cpp +++ b/plugins/Kars/DistrhoPluginKars.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Kars Plugin, based on karplong by Chris Cannam. - * Copyright (C) 2015 Filipe Coelho + * Copyright (C) 2015-2019 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -158,7 +158,8 @@ class AudioMidiSyncHelper { midiEvents(m), midiEventCount(0), remainingFrames(f), - remainingMidiEventCount(mc) {} + remainingMidiEventCount(mc), + totalFramesUsed(0) {} /** Process a batch of events untill no more are available. @@ -166,41 +167,76 @@ class AudioMidiSyncHelper { */ bool nextEvent() { - if (remainingMidiEventCount == 0) + // nothing else to do + if (remainingFrames == 0) + return false; + + // initial setup, need to find first MIDI event + if (totalFramesUsed == 0) { - if (remainingFrames == 0) - return false; + // no MIDI events at all in this process cycle + if (remainingMidiEventCount == 0) + { + frames = remainingFrames; + remainingFrames = 0; + totalFramesUsed += frames; + return true; + } + // render audio until first midi event, if needed + if (const uint32_t firstEventFrame = midiEvents[0].frame) + { + frames = midiEvents[0].frame; + remainingFrames -= frames; + totalFramesUsed += frames; + return true; + } + } + else + { for (uint32_t i=0; i(midiEvents); + for (uint32_t i=0; i < midiEventCount; ++i) + rwEvents[i].frame -= totalFramesUsed; + } + + frames = remainingFrames - firstEventFrame; remainingFrames -= frames; remainingMidiEventCount -= midiEventCount; + totalFramesUsed += frames; return true; } @@ -208,6 +244,7 @@ class AudioMidiSyncHelper { /** @internal */ uint32_t remainingFrames; uint32_t remainingMidiEventCount; + uint32_t totalFramesUsed; }; void DistrhoPluginKars::run(const float**, float** outputs, uint32_t frames, const MidiEvent* midiEvents, uint32_t midiEventCount) @@ -254,9 +291,9 @@ void DistrhoPluginKars::run(const float**, float** outputs, uint32_t frames, con if (fNotes[i].on != kNoteNull) addSamples(out, i, amsh.frames); } - } - fBlockStart += frames; + fBlockStart += amsh.frames; + } } void DistrhoPluginKars::addSamples(float* out, int voice, uint32_t frames) diff --git a/plugins/Kars/DistrhoPluginKars.hpp b/plugins/Kars/DistrhoPluginKars.hpp index 605cc6d4..e7010d30 100644 --- a/plugins/Kars/DistrhoPluginKars.hpp +++ b/plugins/Kars/DistrhoPluginKars.hpp @@ -1,6 +1,6 @@ /* * DISTRHO Kars Plugin, based on karplong by Chris Cannam. - * Copyright (C) 2015 Filipe Coelho + * Copyright (C) 2015-2019 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -70,7 +70,7 @@ class DistrhoPluginKars : public Plugin uint32_t getVersion() const noexcept override { - return d_version(1, 0, 0); + return d_version(1, 1, 0); } int64_t getUniqueId() const noexcept override diff --git a/plugins/bitcrush/Makefile b/plugins/bitcrush/Makefile index ffa5d81c..db1f4815 100644 --- a/plugins/bitcrush/Makefile +++ b/plugins/bitcrush/Makefile @@ -24,6 +24,7 @@ include ../../dpf/Makefile.plugins.mk # Extra flags BUILD_CXX_FLAGS += -I../common -I../common/gen_dsp +BUILD_CXX_FLAGS += -Wno-unused-parameter # -------------------------------------------------------------- # Enable all possible plugin types diff --git a/plugins/freeverb/Makefile b/plugins/freeverb/Makefile index 4d3830dc..bf751bb1 100644 --- a/plugins/freeverb/Makefile +++ b/plugins/freeverb/Makefile @@ -24,6 +24,7 @@ include ../../dpf/Makefile.plugins.mk # Extra flags BUILD_CXX_FLAGS += -I../common -I../common/gen_dsp +BUILD_CXX_FLAGS += -Wno-unused-parameter # -------------------------------------------------------------- # Enable all possible plugin types diff --git a/plugins/gigaverb/Makefile b/plugins/gigaverb/Makefile index 5cdf1420..044d70f1 100644 --- a/plugins/gigaverb/Makefile +++ b/plugins/gigaverb/Makefile @@ -24,6 +24,7 @@ include ../../dpf/Makefile.plugins.mk # Extra flags BUILD_CXX_FLAGS += -I../common -I../common/gen_dsp +BUILD_CXX_FLAGS += -Wno-unused-parameter # -------------------------------------------------------------- # Enable all possible plugin types diff --git a/plugins/glBars/DistrhoUIGLBars.cpp b/plugins/glBars/DistrhoUIGLBars.cpp index ef1421e9..e1fa6104 100644 --- a/plugins/glBars/DistrhoUIGLBars.cpp +++ b/plugins/glBars/DistrhoUIGLBars.cpp @@ -3,7 +3,7 @@ * Copyright (C) 1998-2000 Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies * Copyright (C) 2000 Christian Zander * Copyright (C) 2015 Nedko Arnaudov - * Copyright (C) 2016 Filipe Coelho + * Copyright (C) 2016-2019 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as diff --git a/plugins/glBars/DistrhoUIGLBars.hpp b/plugins/glBars/DistrhoUIGLBars.hpp index 72139bd8..997522bb 100644 --- a/plugins/glBars/DistrhoUIGLBars.hpp +++ b/plugins/glBars/DistrhoUIGLBars.hpp @@ -3,7 +3,7 @@ * Copyright (C) 1998-2000 Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies * Copyright (C) 2000 Christian Zander * Copyright (C) 2015 Nedko Arnaudov - * Copyright (C) 2016 Filipe Coelho + * Copyright (C) 2016-2019 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -45,7 +45,6 @@ class DistrhoUIGLBars : public UI // UI Callbacks void uiIdle() override; -// void uiReshape(uint width, uint height) override; // ------------------------------------------------------------------- // Widget Callbacks diff --git a/plugins/glBars/glBars.hpp b/plugins/glBars/glBars.hpp index 50df05c6..66f7be5f 100644 --- a/plugins/glBars/glBars.hpp +++ b/plugins/glBars/glBars.hpp @@ -3,7 +3,7 @@ * Copyright (C) 1998-2000 Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies * Copyright (C) 2000 Christian Zander * Copyright (C) 2015 Nedko Arnaudov - * Copyright (C) 2016 Filipe Coelho + * Copyright (C) 2016-2019 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,7 +20,7 @@ #ifndef GLBARS_STATE_HPP_INCLUDED #define GLBARS_STATE_HPP_INCLUDED -#include "Base.hpp" +#include "OpenGL.hpp" static inline void draw_rectangle(GLfloat x1, GLfloat y1, GLfloat z1, GLfloat x2, GLfloat y2, GLfloat z2) diff --git a/plugins/pitchshift/Makefile b/plugins/pitchshift/Makefile index 65090c21..bff87fa1 100644 --- a/plugins/pitchshift/Makefile +++ b/plugins/pitchshift/Makefile @@ -24,6 +24,7 @@ include ../../dpf/Makefile.plugins.mk # Extra flags BUILD_CXX_FLAGS += -I../common -I../common/gen_dsp +BUILD_CXX_FLAGS += -Wno-unused-parameter # -------------------------------------------------------------- # Enable all possible plugin types