| @@ -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 | |||
| # -------------------------------------------------------------- | |||
| @@ -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 | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| @@ -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 | |||
| @@ -28,7 +28,7 @@ List of plugins made with DPF:<br/> | |||
| - [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) | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -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 <GL/glu.h> files also need CALLBACK defined */ | |||
| #ifndef CALLBACK | |||
| # if defined(_MSC_VER) | |||
| # if (defined(_M_MRX000) || defined(_M_IX86) || defined(_M_ALPHA) || defined(_M_PPC)) && !defined(MIDL_PASS) | |||
| # define CALLBACK __stdcall | |||
| # else | |||
| # define CALLBACK | |||
| # endif | |||
| # else | |||
| # define CALLBACK __stdcall | |||
| # endif | |||
| # define DGL_CALLBACK_DEFINED | |||
| #endif // CALLBACK | |||
| /* Most GL/glu.h variants on Windows need wchar_t */ | |||
| #include <cstddef> | |||
| #endif // DISTRHO_OS_WINDOWS | |||
| // ----------------------------------------------------------------------- | |||
| // OpenGL includes | |||
| #ifdef DISTRHO_OS_MAC | |||
| # include <OpenGL/gl.h> | |||
| #else | |||
| # ifndef DISTRHO_OS_WINDOWS | |||
| # define GL_GLEXT_PROTOTYPES | |||
| # endif | |||
| # include <GL/gl.h> | |||
| # include <GL/glext.h> | |||
| #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. | |||
| */ | |||
| @@ -0,0 +1,40 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| * permission notice appear in all copies. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||
| * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||
| * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||
| * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||
| * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||
| * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
| */ | |||
| #ifndef DGL_CAIRO_HPP_INCLUDED | |||
| #define DGL_CAIRO_HPP_INCLUDED | |||
| #include "Base.hpp" | |||
| #include <cairo/cairo.h> | |||
| START_NAMESPACE_DGL | |||
| // ----------------------------------------------------------------------- | |||
| /** | |||
| Graphics context. | |||
| */ | |||
| struct GraphicsContext | |||
| { | |||
| cairo_t* cairo; // FIXME proper name.. | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| END_NAMESPACE_DGL | |||
| #endif | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -482,6 +482,7 @@ private: | |||
| // cached values | |||
| float fTheta, fCos, fSin; | |||
| /** @internal */ | |||
| void _draw(const bool outline); | |||
| }; | |||
| @@ -516,16 +517,6 @@ public: | |||
| */ | |||
| Triangle(const Triangle<T>& 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 @@ public: | |||
| */ | |||
| 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<T>& operator=(const Triangle<T>& tri) noexcept; | |||
| bool operator==(const Triangle<T>& tri) const noexcept; | |||
| bool operator!=(const Triangle<T>& tri) const noexcept; | |||
| @@ -556,6 +557,7 @@ public: | |||
| private: | |||
| Point<T> fPos1, fPos2, fPos3; | |||
| /** @internal */ | |||
| void _draw(const bool outline); | |||
| }; | |||
| @@ -740,6 +742,7 @@ private: | |||
| Point<T> fPos; | |||
| Size<T> fSize; | |||
| /** @internal */ | |||
| void _draw(const bool outline); | |||
| }; | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -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 @@ public: | |||
| 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<uint>& size, const GLenum format = GL_BGRA, const GLenum type = GL_UNSIGNED_BYTE); | |||
| Image(const char* const rawData, | |||
| const Size<uint>& size, | |||
| const GLenum format = GL_BGRA, | |||
| const GLenum type = GL_UNSIGNED_BYTE); | |||
| /** | |||
| Constructor using another image data. | |||
| @@ -63,44 +71,26 @@ public: | |||
| /** | |||
| 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<uint>& 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<uint>& getSize() const noexcept; | |||
| /** | |||
| Get the raw image data. | |||
| */ | |||
| const char* getRawData() const noexcept; | |||
| void loadFromMemory(const char* const rawData, | |||
| const Size<uint>& size, | |||
| const GLenum format = GL_BGRA, | |||
| const GLenum type = GL_UNSIGNED_BYTE) noexcept; | |||
| /** | |||
| Get the image format. | |||
| @@ -113,27 +103,15 @@ public: | |||
| 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<int>& 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<int>& pos) override; | |||
| private: | |||
| const char* fRawData; | |||
| Size<uint> fSize; | |||
| GLenum fFormat; | |||
| GLenum fType; | |||
| GLuint fTextureId; | |||
| @@ -144,4 +122,4 @@ private: | |||
| END_NAMESPACE_DGL | |||
| #endif // DGL_IMAGE_HPP_INCLUDED | |||
| #endif | |||
| @@ -0,0 +1,125 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| * permission notice appear in all copies. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||
| * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||
| * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||
| * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||
| * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||
| * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
| */ | |||
| #ifndef DGL_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<uint>& 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<uint>& 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<int>& 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<int>& pos) = 0; | |||
| const char* fRawData; | |||
| Size<uint> fSize; | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| END_NAMESPACE_DGL | |||
| #endif // DGL_IMAGE_HPP_INCLUDED | |||
| @@ -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) | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -18,6 +18,7 @@ | |||
| #define DGL_NANO_WIDGET_HPP_INCLUDED | |||
| #include "Color.hpp" | |||
| #include "OpenGL.hpp" | |||
| #include "Widget.hpp" | |||
| #ifndef DGL_NO_SHARED_RESOURCES | |||
| @@ -0,0 +1,121 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| * permission notice appear in all copies. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||
| * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||
| * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||
| * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||
| * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||
| * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
| */ | |||
| #ifndef DGL_OPENGL_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 <GL/glu.h> files also need CALLBACK defined */ | |||
| #ifndef CALLBACK | |||
| # if defined(_MSC_VER) | |||
| # if (defined(_M_MRX000) || defined(_M_IX86) || defined(_M_ALPHA) || defined(_M_PPC)) && !defined(MIDL_PASS) | |||
| # define CALLBACK __stdcall | |||
| # else | |||
| # define CALLBACK | |||
| # endif | |||
| # else | |||
| # define CALLBACK __stdcall | |||
| # endif | |||
| # define DGL_CALLBACK_DEFINED | |||
| #endif // CALLBACK | |||
| /* Most GL/glu.h variants on Windows need wchar_t */ | |||
| #include <cstddef> | |||
| #endif // DISTRHO_OS_WINDOWS | |||
| // ----------------------------------------------------------------------- | |||
| // OpenGL includes | |||
| #ifdef DISTRHO_OS_MAC | |||
| # include <OpenGL/gl.h> | |||
| #else | |||
| # ifndef DISTRHO_OS_WINDOWS | |||
| # define GL_GLEXT_PROTOTYPES | |||
| # endif | |||
| # include <GL/gl.h> | |||
| # include <GL/glext.h> | |||
| #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 | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -77,7 +77,7 @@ public: | |||
| 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 @@ public: | |||
| 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 @@ public: | |||
| 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 @@ protected: | |||
| virtual void fileBrowserSelected(const char* filename); | |||
| #endif | |||
| // internal | |||
| void _setAutoScaling(double scaling) noexcept; | |||
| private: | |||
| struct PrivateData; | |||
| PrivateData* const pData; | |||
| @@ -0,0 +1,27 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| * permission notice appear in all copies. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||
| * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||
| * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||
| * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||
| * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||
| * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
| */ | |||
| #include "../Base.hpp" | |||
| START_NAMESPACE_DGL | |||
| // ----------------------------------------------------------------------- | |||
| // nothing here yet | |||
| // ----------------------------------------------------------------------- | |||
| END_NAMESPACE_DGL | |||
| @@ -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<uchar>(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 | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -441,21 +441,6 @@ void Line<T>::moveBy(const Point<T>& pos) noexcept | |||
| fPosEnd.moveBy(pos); | |||
| } | |||
| template<typename T> | |||
| void Line<T>::draw() | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(fPosStart != fPosEnd,); | |||
| glBegin(GL_LINES); | |||
| { | |||
| glVertex2d(fPosStart.fX, fPosStart.fY); | |||
| glVertex2d(fPosEnd.fX, fPosEnd.fY); | |||
| } | |||
| glEnd(); | |||
| } | |||
| template<typename T> | |||
| bool Line<T>::isNull() const noexcept | |||
| { | |||
| @@ -650,27 +635,6 @@ bool Circle<T>::operator!=(const Circle<T>& cir) const noexcept | |||
| return (fPos != cir.fPos || d_isNotEqual(fSize, cir.fSize) || fNumSegments != cir.fNumSegments); | |||
| } | |||
| template<typename T> | |||
| void Circle<T>::_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<fNumSegments; ++i) | |||
| { | |||
| glVertex2d(x + fPos.fX, y + fPos.fY); | |||
| t = x; | |||
| x = fCos * x - fSin * y; | |||
| y = fSin * t + fCos * y; | |||
| } | |||
| glEnd(); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // Triangle | |||
| @@ -698,18 +662,6 @@ Triangle<T>::Triangle(const Triangle<T>& tri) noexcept | |||
| fPos2(tri.fPos2), | |||
| fPos3(tri.fPos3) {} | |||
| template<typename T> | |||
| void Triangle<T>::draw() | |||
| { | |||
| _draw(false); | |||
| } | |||
| template<typename T> | |||
| void Triangle<T>::drawOutline() | |||
| { | |||
| _draw(true); | |||
| } | |||
| template<typename T> | |||
| bool Triangle<T>::isNull() const noexcept | |||
| { | |||
| @@ -734,6 +686,18 @@ bool Triangle<T>::isInvalid() const noexcept | |||
| return fPos1 == fPos2 || fPos1 == fPos3; | |||
| } | |||
| template<typename T> | |||
| void Triangle<T>::draw() | |||
| { | |||
| _draw(false); | |||
| } | |||
| template<typename T> | |||
| void Triangle<T>::drawOutline() | |||
| { | |||
| _draw(true); | |||
| } | |||
| template<typename T> | |||
| Triangle<T>& Triangle<T>::operator=(const Triangle<T>& tri) noexcept | |||
| { | |||
| @@ -755,22 +719,6 @@ bool Triangle<T>::operator!=(const Triangle<T>& tri) const noexcept | |||
| return (fPos1 != tri.fPos1 || fPos2 != tri.fPos2 || fPos3 != tri.fPos3); | |||
| } | |||
| template<typename T> | |||
| void Triangle<T>::_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<T>::operator!=(const Rectangle<T>& rect) const noexcept | |||
| return (fPos != rect.fPos || fSize != rect.fSize); | |||
| } | |||
| template<typename T> | |||
| void Rectangle<T>::_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 | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -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<uint>& 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<uint>& 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<uint>& 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<uint>(width, height), format, type); | |||
| } | |||
| void Image::loadFromMemory(const char* const rawData, const Size<uint>& size, const GLenum format, const GLenum type) noexcept | |||
| void Image::loadFromMemory(const char* const rawData, | |||
| const Size<uint>& 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<uint>& 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<uint>& 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<int>(x, y)); | |||
| fRawData = image.fRawData; | |||
| fSize = image.fSize; | |||
| fFormat = image.fFormat; | |||
| fType = image.fType; | |||
| fIsReady = false; | |||
| return *this; | |||
| } | |||
| void Image::drawAt(const Point<int>& pos) | |||
| void Image::_drawAt(const Point<int>& pos) | |||
| { | |||
| if (fTextureId == 0 || ! isValid()) | |||
| return; | |||
| @@ -169,26 +147,4 @@ void Image::drawAt(const Point<int>& 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 | |||
| @@ -0,0 +1,106 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| * permission notice appear in all copies. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||
| * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||
| * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||
| * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||
| * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||
| * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
| */ | |||
| #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<uint>& 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<uint>& ImageBase::getSize() const noexcept | |||
| { | |||
| return fSize; | |||
| } | |||
| const char* ImageBase::getRawData() const noexcept | |||
| { | |||
| return fRawData; | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| void ImageBase::draw() | |||
| { | |||
| _drawAt(Point<int>()); | |||
| } | |||
| void ImageBase::drawAt(const int x, const int y) | |||
| { | |||
| _drawAt(Point<int>(x, y)); | |||
| } | |||
| void ImageBase::drawAt(const Point<int>& 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 | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -14,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 | |||
| // ----------------------------------------------------------------------- | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2018 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -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 | |||
| @@ -0,0 +1,157 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| * permission notice appear in all copies. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||
| * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||
| * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||
| * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||
| * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||
| * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
| */ | |||
| #include "../Geometry.hpp" | |||
| #include "../OpenGL.hpp" | |||
| START_NAMESPACE_DGL | |||
| // ----------------------------------------------------------------------- | |||
| // Line | |||
| template<typename T> | |||
| void Line<T>::draw() | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(fPosStart != fPosEnd,); | |||
| glBegin(GL_LINES); | |||
| { | |||
| glVertex2d(fPosStart.fX, fPosStart.fY); | |||
| glVertex2d(fPosEnd.fX, fPosEnd.fY); | |||
| } | |||
| glEnd(); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // Circle | |||
| template<typename T> | |||
| void Circle<T>::_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<fNumSegments; ++i) | |||
| { | |||
| glVertex2d(x + fPos.fX, y + fPos.fY); | |||
| t = x; | |||
| x = fCos * x - fSin * y; | |||
| y = fSin * t + fCos * y; | |||
| } | |||
| glEnd(); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // Triangle | |||
| template<typename T> | |||
| void Triangle<T>::_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<typename T> | |||
| void Rectangle<T>::_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<double>; | |||
| template class Point<float>; | |||
| template class Point<int>; | |||
| template class Point<uint>; | |||
| template class Point<short>; | |||
| template class Point<ushort>; | |||
| template class Size<double>; | |||
| template class Size<float>; | |||
| template class Size<int>; | |||
| template class Size<uint>; | |||
| template class Size<short>; | |||
| template class Size<ushort>; | |||
| template class Line<double>; | |||
| template class Line<float>; | |||
| template class Line<int>; | |||
| template class Line<uint>; | |||
| template class Line<short>; | |||
| template class Line<ushort>; | |||
| template class Circle<double>; | |||
| template class Circle<float>; | |||
| template class Circle<int>; | |||
| template class Circle<uint>; | |||
| template class Circle<short>; | |||
| template class Circle<ushort>; | |||
| template class Triangle<double>; | |||
| template class Triangle<float>; | |||
| template class Triangle<int>; | |||
| template class Triangle<uint>; | |||
| template class Triangle<short>; | |||
| template class Triangle<ushort>; | |||
| template class Rectangle<double>; | |||
| template class Rectangle<float>; | |||
| template class Rectangle<int>; | |||
| template class Rectangle<uint>; | |||
| template class Rectangle<short>; | |||
| template class Rectangle<ushort>; | |||
| // ----------------------------------------------------------------------- | |||
| END_NAMESPACE_DGL | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -0,0 +1,107 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| * permission notice appear in all copies. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||
| * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||
| * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||
| * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||
| * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||
| * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
| */ | |||
| #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<uint>(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 | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2018 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -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<uint>(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) | |||
| { | |||
| @@ -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<Modifier>(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<float>(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<Widget*> fWidgets; | |||
| @@ -1081,7 +1097,7 @@ struct Window::PrivateData { | |||
| HWND hwndParent; | |||
| #elif defined(DISTRHO_OS_MAC) | |||
| bool fNeedsIdle; | |||
| PuglOpenGLView* mView; | |||
| NSView<PuglGenericView>* 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<GLsizei>(width), static_cast<GLsizei>(height)); | |||
| glMatrixMode(GL_MODELVIEW); | |||
| glLoadIdentity(); | |||
| #endif | |||
| } | |||
| void Window::onClose() | |||
| @@ -1,5 +1,6 @@ | |||
| /* | |||
| Copyright 2012-2014 David Robillard <http://drobilla.net> | |||
| Copyright 2012-2019 Filipe Coelho <falktx@falktx.com> | |||
| Permission to use, copy, modify, and/or distribute this software for any | |||
| purpose with or without fee is hereby granted, provided that the above | |||
| @@ -29,19 +30,13 @@ | |||
| platforms so they are included here to allow for pure portable programs. | |||
| */ | |||
| #ifdef __APPLE__ | |||
| # include "OpenGL/gl.h" | |||
| # include <OpenGL/gl.h> | |||
| #else | |||
| # ifdef _WIN32 | |||
| # include <winsock2.h> | |||
| # include <windows.h> /* 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 <GL/gl.h> | |||
| #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); | |||
| /** | |||
| @@ -1,5 +1,6 @@ | |||
| /* | |||
| Copyright 2012-2014 David Robillard <http://drobilla.net> | |||
| Copyright 2012-2019 Filipe Coelho <falktx@falktx.com> | |||
| Permission to use, copy, modify, and/or distribute this software for any | |||
| purpose with or without fee is hereby granted, provided that the above | |||
| @@ -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 | |||
| } | |||
| @@ -1,5 +1,6 @@ | |||
| /* | |||
| Copyright 2012 David Robillard <http://drobilla.net> | |||
| Copyright 2012-2019 Filipe Coelho <falktx@falktx.com> | |||
| Permission to use, copy, modify, and/or distribute this software for any | |||
| purpose with or without fee is hereby granted, provided that the above | |||
| @@ -20,6 +21,10 @@ | |||
| #include <stdlib.h> | |||
| #ifdef PUGL_CAIRO | |||
| #import <cairo.h> | |||
| #import <cairo-quartz.h> | |||
| #endif | |||
| #import <Cocoa/Cocoa.h> | |||
| #include "pugl_internal.h" | |||
| @@ -93,7 +98,200 @@ puglDisplay(PuglView* view) | |||
| } | |||
| } | |||
| @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<PuglGenericView> *self, NSEvent* event) | |||
| { | |||
| [[NSCursor arrowCursor] set]; | |||
| (void)self; | |||
| (void)event; | |||
| } | |||
| static void | |||
| updateTrackingAreas(NSView<PuglGenericView> *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<PuglGenericView> *self, NSWindow* newWindow) | |||
| { | |||
| if (newWindow != nil) { | |||
| [newWindow setAcceptsMouseMovedEvents:YES]; | |||
| [newWindow makeFirstResponder:self]; | |||
| } | |||
| } | |||
| static void | |||
| reshape(NSView<PuglGenericView> *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<PuglGenericView> *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<PuglGenericView> *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<PuglGenericView> *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<PuglGenericView> *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<PuglGenericView> *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<PuglGenericView> *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<PuglGenericView> *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<PuglGenericView> | |||
| { | |||
| @public | |||
| PuglView* puglview; | |||
| @@ -101,6 +299,11 @@ puglDisplay(PuglView* view) | |||
| 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 @@ puglDisplay(PuglView* view) | |||
| @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 @@ puglDisplay(PuglView* view) | |||
| [[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 @@ puglDisplay(PuglView* view) | |||
| - (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<PuglGenericView> | |||
| { | |||
| 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<PuglGenericView>* view; | |||
| #ifdef PUGL_OPENGL | |||
| PuglOpenGLView* glview; | |||
| #endif | |||
| #ifdef PUGL_CAIRO | |||
| PuglCairoView* cairoview; | |||
| #endif | |||
| }; | |||
| id window; | |||
| }; | |||
| @@ -427,19 +774,23 @@ puglInitInternals() | |||
| 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 @@ puglCreateWindow(PuglView* view, const char* title) | |||
| [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 @@ puglCreateWindow(PuglView* view, const char* title) | |||
| } | |||
| [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 @@ puglShowWindow(PuglView* view) | |||
| if (impl->window) { | |||
| [impl->window setIsVisible:YES]; | |||
| } else { | |||
| [view->impl->glview setHidden:NO]; | |||
| [view->impl->view setHidden:NO]; | |||
| } | |||
| } | |||
| @@ -517,21 +873,21 @@ puglHideWindow(PuglView* view) | |||
| 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 | |||
| 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 | |||
| @@ -1,5 +1,6 @@ | |||
| /* | |||
| Copyright 2012-2014 David Robillard <http://drobilla.net> | |||
| Copyright 2012-2019 Filipe Coelho <falktx@falktx.com> | |||
| Permission to use, copy, modify, and/or distribute this software for any | |||
| purpose with or without fee is hereby granted, provided that the above | |||
| @@ -18,16 +19,22 @@ | |||
| @file pugl_win.cpp Windows/WGL Pugl Implementation. | |||
| */ | |||
| #include <ctime> | |||
| #include <cstdio> | |||
| #include <cstdlib> | |||
| #include <winsock2.h> | |||
| #include <windows.h> | |||
| #include <windowsx.h> | |||
| #ifdef PUGL_CAIRO | |||
| #include <cairo/cairo.h> | |||
| #include <cairo/cairo-win32.h> | |||
| #endif | |||
| #ifdef PUGL_OPENGL | |||
| #include <GL/gl.h> | |||
| #endif | |||
| #include <ctime> | |||
| #include <cstdio> | |||
| #include <cstdlib> | |||
| #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) | |||
| { | |||
| @@ -2,6 +2,7 @@ | |||
| Copyright 2012-2014 David Robillard <http://drobilla.net> | |||
| Copyright 2011-2012 Ben Loftis, Harrison Consoles | |||
| Copyright 2013,2015 Robin Gareus <robin@gareus.org> | |||
| Copyright 2012-2019 Filipe Coelho <falktx@falktx.com> | |||
| Permission to use, copy, modify, and/or distribute this software for any | |||
| purpose with or without fee is hereby granted, provided that the above | |||
| @@ -24,8 +25,14 @@ | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #ifdef PUGL_CAIRO | |||
| #include <cairo/cairo.h> | |||
| #include <cairo/cairo-xlib.h> | |||
| #endif | |||
| #ifdef PUGL_OPENGL | |||
| #include <GL/gl.h> | |||
| #include <GL/glx.h> | |||
| #endif | |||
| #include <X11/Xatom.h> | |||
| #include <X11/Xlib.h> | |||
| #include <X11/Xutil.h> | |||
| @@ -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) | |||
| { | |||
| @@ -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() | |||
| @@ -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; | |||
| @@ -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 @@ public: | |||
| */ | |||
| 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 @@ public: | |||
| /** | |||
| 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 @@ public: | |||
| */ | |||
| 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. | |||
| @@ -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 | |||
| @@ -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 @@ public: | |||
| 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) | |||
| { | |||
| @@ -545,7 +545,7 @@ public: | |||
| #ifdef DISTRHO_PLUGIN_LICENSED_FOR_MOD | |||
| for (uint32_t i=0; i<DISTRHO_PLUGIN_NUM_OUTPUTS; ++i) | |||
| mod_license_run_noise(fRunCount, fPortAudioOuts[i], sampleCount, i); | |||
| mod_license_run_silence(fRunCount, fPortAudioOuts[i], sampleCount, i); | |||
| #endif | |||
| #if DISTRHO_PLUGIN_WANT_TIMEPOS | |||
| @@ -719,7 +719,7 @@ void lv2_generate_ttl(const char* const basename) | |||
| if (value.length() < 10) | |||
| presetString += " \"" + value + "\" ;\n"; | |||
| else | |||
| presetString += "\n\"\"\"\n" + value + "\n\"\"\" ;\n"; | |||
| presetString += "\n\"\"\"" + value + "\"\"\" ;\n"; | |||
| } | |||
| if (numParameters > 0) | |||
| @@ -161,12 +161,12 @@ public: | |||
| 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 @@ public: | |||
| 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 @@ public: | |||
| } | |||
| # 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 | |||
| @@ -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<GLsizei>(width), static_cast<GLsizei>(height)); | |||
| glMatrixMode(GL_MODELVIEW); | |||
| glLoadIdentity(); | |||
| #else | |||
| // unused | |||
| (void)width; | |||
| (void)height; | |||
| #endif | |||
| } | |||
| /* ------------------------------------------------------------------------------------------------------------ | |||
| @@ -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 @@ protected: | |||
| { | |||
| const double scaleHorizontal = static_cast<double>(width) / static_cast<double>(pData->minWidth); | |||
| const double scaleVertical = static_cast<double>(height) / static_cast<double>(pData->minHeight); | |||
| setScaling(scaleHorizontal < scaleVertical ? scaleHorizontal : scaleVertical); | |||
| _setAutoScaling(scaleHorizontal < scaleVertical ? scaleHorizontal : scaleVertical); | |||
| } | |||
| pData->resizeInProgress = true; | |||
| @@ -254,13 +258,14 @@ public: | |||
| 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 | |||
| @@ -53,8 +53,8 @@ public: | |||
| 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 @@ protected: | |||
| 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) | |||
| @@ -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" | |||
| @@ -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 \ | |||
| @@ -2,7 +2,7 @@ | |||
| all: build | |||
| ifeq ($(WIN32),true) | |||
| ifeq ($(WINDOWS),true) | |||
| build: ../lv2_ttl_generator.exe | |||
| else | |||
| build: ../lv2_ttl_generator | |||
| @@ -19,7 +19,7 @@ import os, sys | |||
| # ----------------------------------------------------- | |||
| 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 <namespace> <artwork-folder>" % sys.argv[0]) | |||
| print("Usage: %s <namespace> <resource-folder>" % 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) | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Kars Plugin, based on karplong by Chris Cannam. | |||
| * Copyright (C) 2015 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2015-2019 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -158,7 +158,8 @@ public: | |||
| 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 @@ public: | |||
| */ | |||
| 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<DISTRHO_PLUGIN_NUM_OUTPUTS; ++i) | |||
| outputs[i] += frames; | |||
| } | |||
| if (midiEventCount != 0) | |||
| midiEvents += midiEventCount; | |||
| // no more MIDI events available | |||
| if (remainingMidiEventCount == 0) | |||
| { | |||
| frames = remainingFrames; | |||
| midiEvents = nullptr; | |||
| midiEventCount = 0; | |||
| remainingFrames = 0; | |||
| totalFramesUsed += frames; | |||
| return true; | |||
| } | |||
| const uint32_t eventFrame = midiEvents[0].frame; | |||
| DISTRHO_SAFE_ASSERT_RETURN(eventFrame < remainingFrames, false); | |||
| // if there were midi events before, increment pointer | |||
| if (midiEventCount != 0) | |||
| midiEvents += midiEventCount; | |||
| midiEventCount = 1; | |||
| const uint32_t firstEventFrame = midiEvents[0].frame; | |||
| DISTRHO_SAFE_ASSERT_RETURN((firstEventFrame - frames) < remainingFrames, false); | |||
| for (uint32_t i=1; i<remainingMidiEventCount; ++i) | |||
| midiEventCount = 1; | |||
| while (midiEventCount < remainingMidiEventCount) | |||
| { | |||
| if (midiEvents[i].frame != eventFrame) | |||
| { | |||
| midiEventCount = i; | |||
| if (midiEvents[midiEventCount].frame == firstEventFrame) | |||
| ++midiEventCount; | |||
| else | |||
| break; | |||
| } | |||
| } | |||
| frames = remainingFrames - eventFrame; | |||
| if (totalFramesUsed != 0) | |||
| { | |||
| // need to modify timestamp of midi events | |||
| MidiEvent* const rwEvents = const_cast<MidiEvent*>(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 @@ private: | |||
| /** @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) | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Kars Plugin, based on karplong by Chris Cannam. | |||
| * Copyright (C) 2015 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2015-2019 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -70,7 +70,7 @@ protected: | |||
| uint32_t getVersion() const noexcept override | |||
| { | |||
| return d_version(1, 0, 0); | |||
| return d_version(1, 1, 0); | |||
| } | |||
| int64_t getUniqueId() const noexcept override | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -3,7 +3,7 @@ | |||
| * Copyright (C) 1998-2000 Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies | |||
| * Copyright (C) 2000 Christian Zander <phoenix@minion.de> | |||
| * Copyright (C) 2015 Nedko Arnaudov | |||
| * Copyright (C) 2016 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2016-2019 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * This program is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU General Public License as | |||
| @@ -3,7 +3,7 @@ | |||
| * Copyright (C) 1998-2000 Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies | |||
| * Copyright (C) 2000 Christian Zander <phoenix@minion.de> | |||
| * Copyright (C) 2015 Nedko Arnaudov | |||
| * Copyright (C) 2016 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2016-2019 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * 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 @@ protected: | |||
| // UI Callbacks | |||
| void uiIdle() override; | |||
| // void uiReshape(uint width, uint height) override; | |||
| // ------------------------------------------------------------------- | |||
| // Widget Callbacks | |||
| @@ -3,7 +3,7 @@ | |||
| * Copyright (C) 1998-2000 Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies | |||
| * Copyright (C) 2000 Christian Zander <phoenix@minion.de> | |||
| * Copyright (C) 2015 Nedko Arnaudov | |||
| * Copyright (C) 2016 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2016-2019 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * 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) | |||
| @@ -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 | |||