Browse Source

Switch to using VCV nanovg; Hook mouse events; Add resize handle

tags/22.02
falkTX 3 years ago
parent
commit
ee3f3771a4
9 changed files with 379 additions and 52 deletions
  1. +6
    -0
      Makefile
  2. +1
    -1
      dpf
  3. +13
    -2
      plugins/CVCRack/CVCRackPlugin.cpp
  4. +75
    -12
      plugins/CVCRack/CVCRackUI.cpp
  5. +3
    -3
      plugins/CVCRack/DistrhoPluginInfo.h
  6. +5
    -4
      plugins/CVCRack/Makefile
  7. +185
    -0
      plugins/CVCRack/ResizeHandle.hpp
  8. +91
    -11
      plugins/CVCRack/Window.cpp
  9. +0
    -19
      plugins/CVCRack/dep.cpp

+ 6
- 0
Makefile View File

@@ -8,6 +8,8 @@ include dpf/Makefile.base.mk

all: dgl plugins gen

SKIP_NANOVG = true

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

dgl:
@@ -40,9 +42,13 @@ clean:
rm -rf plugins/CVCRack/Rack/dep/include
rm -rf plugins/CVCRack/Rack/dep/lib
rm -rf plugins/CVCRack/Rack/dep/share
rm -rf plugins/CVCRack/Rack/dep/curl-7.66.0
rm -rf plugins/CVCRack/Rack/dep/glew-2.1.0
rm -rf plugins/CVCRack/Rack/dep/jansson-2.12
rm -rf plugins/CVCRack/Rack/dep/libarchive-3.4.3
rm -rf plugins/CVCRack/Rack/dep/openssl-1.1.1d
rm -rf plugins/CVCRack/Rack/dep/speexdsp-SpeexDSP-1.2rc3
rm -rf plugins/CVCRack/Rack/dep/zstd-1.4.5

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



+ 1
- 1
dpf

@@ -1 +1 @@
Subproject commit 23f89562acbd637a23b9f0333877939ad26c0595
Subproject commit c17c260d08613ab46e13dc578104c74b5713a435

+ 13
- 2
plugins/CVCRack/CVCRackPlugin.cpp View File

@@ -25,6 +25,9 @@
#include <settings.hpp>
#include <system.hpp>
#include <ui/common.hpp>
#include <window/Window.hpp>
#include <osdialog.h>
#include "DistrhoPlugin.hpp"
@@ -53,6 +56,7 @@ struct Initializer {
// Load settings
settings::init();
#if 0
try {
settings::load();
}
@@ -66,6 +70,7 @@ struct Initializer {
}
*/
}
#endif
// Check existence of the system res/ directory
std::string resDir = asset::system("res");
@@ -88,12 +93,18 @@ struct Initializer {
plugin::init();
library::init();
// discord::init();
ui::init();
window::init();
}
~Initializer()
{
using namespace rack;
window::destroy();
ui::destroy();
// discord::destroy();
library::destroy();
midi::destroy();
@@ -104,9 +115,9 @@ struct Initializer {
}
};
static Initializer& getInitializerInstance()
static const Initializer& getInitializerInstance()
{
static Initializer init;
static const Initializer init;
return init;
}


+ 75
- 12
plugins/CVCRack/CVCRackUI.cpp View File

@@ -23,6 +23,7 @@
#include <window/Window.hpp>

#include "DistrhoUI.hpp"
#include "ResizeHandle.hpp"

GLFWAPI const char* glfwGetClipboardString(GLFWwindow* window) { return nullptr; }
GLFWAPI void glfwSetClipboardString(GLFWwindow* window, const char*) {}
@@ -32,6 +33,10 @@ GLFWAPI int glfwGetKeyScancode(int key) { return 0; }
namespace rack {
namespace window {
DISTRHO_NAMESPACE::UI* lastUI = nullptr;

void mouseButtonCallback(Window* win, int button, int action, int mods);
void cursorPosCallback(Window* win, double xpos, double ypos);
void scrollCallback(Window* win, double x, double y);
}
}

@@ -39,35 +44,33 @@ START_NAMESPACE_DISTRHO

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

struct Initializer {
Initializer()
struct Initializer2 {
Initializer2()
{
using namespace rack;

ui::init();
window::init();
}

~Initializer()
~Initializer2()
{
using namespace rack;

window::destroy();
ui::destroy();
}
};

static Initializer& getInitializerInstance()
static const Initializer2& getInitializer2Instance()
{
static Initializer init;
static const Initializer2 init;
return init;
}

class CVCRackUI : public UI
{
ResizeHandle fResizeHandle;
public:
CVCRackUI()
: UI(1280, 720)
: UI(1280, 720),
fResizeHandle(this)
{
using namespace rack;

@@ -97,11 +100,16 @@ public:
contextSet(NULL);
}

void onNanoDisplay() override
void onDisplay() override
{
APP->window->step();
}

void uiIdle() override
{
repaint();
}

protected:
/* --------------------------------------------------------------------------------------------------------
* DSP/Plugin Callbacks */
@@ -116,6 +124,61 @@ protected:

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

bool onMouse(const MouseEvent& ev) override
{
int button;
int mods = 0;
int action = ev.press;

if (ev.mod & kModifierControl)
mods |= GLFW_MOD_CONTROL;
if (ev.mod & kModifierShift)
mods |= GLFW_MOD_SHIFT;
if (ev.mod & kModifierAlt)
mods |= GLFW_MOD_ALT;

switch (ev.button)
{
case 0:
button = GLFW_MOUSE_BUTTON_MIDDLE;
break;
case 1:
button = GLFW_MOUSE_BUTTON_LEFT;
break;
case 2:
button = GLFW_MOUSE_BUTTON_RIGHT;
break;
default:
button = 0;
break;
}

mouseButtonCallback(APP->window, button, action, mods);
return true;
}

bool onMotion(const MotionEvent& ev) override
{
cursorPosCallback(APP->window, ev.pos.getX(), ev.pos.getY());
return true;
}

bool onScroll(const ScrollEvent& ev) override
{
scrollCallback(APP->window, ev.delta.getX(), ev.delta.getY());
return true;
}

#if 0
void onResize(const ResizeEvent& ev) override
{
UI::onResize(ev);
// APP->window->setSize(rack::math::Vec(ev.size.getWidth(), ev.size.getHeight()));
}
#endif

// TODO uiFocus

private:
/**
Set our UI class as non-copyable and add a leak detector just in case.
@@ -128,7 +191,7 @@ private:

UI* createUI()
{
getInitializerInstance();
getInitializer2Instance();
return new CVCRackUI();
}



+ 3
- 3
plugins/CVCRack/DistrhoPluginInfo.h View File

@@ -20,7 +20,7 @@

#define DISTRHO_PLUGIN_BRAND "DISTRHO"
#define DISTRHO_PLUGIN_NAME "CVCRack"
#define DISTRHO_PLUGIN_URI "http://distrho.sf.net/plugins/glBars"
#define DISTRHO_PLUGIN_URI "http://distrho.sf.net/plugins/CVCRack"

#define DISTRHO_PLUGIN_HAS_UI 1
#define DISTRHO_PLUGIN_NUM_INPUTS 2
@@ -30,8 +30,8 @@
// #define DISTRHO_PLUGIN_VST3_CATEGORIES "Fx|Analyzer"
// #define DISTRHO_PLUGIN_HAS_EMBED_UI 1
// #define DISTRHO_PLUGIN_HAS_EXTERNAL_UI 1
#define DISTRHO_UI_USE_NANOVG 1
#define DISTRHO_UI_USER_RESIZABLE 1
// #define DISTRHO_UI_USE_NANOVG 1
#define DISTRHO_UI_USER_RESIZABLE 0

enum Parameters {
kParameterCount


+ 5
- 4
plugins/CVCRack/Makefile View File

@@ -17,13 +17,13 @@ FILES_DSP = \

FILES_UI = \
CVCRackUI.cpp \
dep.cpp \
Window.cpp

# --------------------------------------------------------------
# Import base definitions

# UI_TYPE = external
SKIP_NANOVG = true
include ../../dpf/Makefile.base.mk

# --------------------------------------------------------------
@@ -33,6 +33,7 @@ FILES_DSP += Rack/dep/pffft/pffft.c
FILES_DSP += Rack/dep/pffft/fftpack.c

FILES_UI += Rack/dep/oui-blendish/blendish.c
FILES_UI += Rack/dep/nanovg/src/nanovg.c

# FIXME dont use this
FILES_UI += Rack/dep/osdialog/osdialog.c
@@ -46,7 +47,7 @@ endif

FILES_DSP += $(wildcard Rack/src/*.c)
FILES_DSP += $(wildcard Rack/src/*/*.c)
FILES_DSP += $(filter-out Rack/src/dep.cpp Rack/src/gamepad.cpp Rack/src/rtaudio.cpp Rack/src/rtmidi.cpp, $(wildcard Rack/src/*.cpp))
FILES_DSP += $(filter-out Rack/src/gamepad.cpp Rack/src/rtaudio.cpp Rack/src/rtmidi.cpp, $(wildcard Rack/src/*.cpp))
FILES_DSP += $(filter-out Rack/src/window/Window.cpp, $(wildcard Rack/src/*/*.cpp))

EXTRA_LIBS = Rack/dep/lib/libcrypto.a
@@ -85,14 +86,14 @@ Rack/dep/lib/libcrypto.a: Rack/dep/lib/libssl.a
# Extra flags for VCV stuff

BASE_FLAGS += -D_APP_VERSION=2.git.0
BASE_FLAGS += -I$(DPF_PATH)/dgl/src/nanovg
# BASE_FLAGS += -I$(DPF_PATH)/dgl/src/nanovg
BASE_FLAGS += -IRack/include
BASE_FLAGS += -IRack/dep/include
BASE_FLAGS += -IRack/dep/filesystem/include
BASE_FLAGS += -IRack/dep/fuzzysearchdatabase/src
BASE_FLAGS += -IRack/dep/glfw/deps
BASE_FLAGS += -IRack/dep/glfw/include
# BASE_FLAGS += -IRack/dep/nanovg/src
BASE_FLAGS += -IRack/dep/nanovg/src
BASE_FLAGS += -IRack/dep/nanosvg/src
BASE_FLAGS += -IRack/dep/osdialog
BASE_FLAGS += -IRack/dep/oui-blendish


+ 185
- 0
plugins/CVCRack/ResizeHandle.hpp View File

@@ -0,0 +1,185 @@
/*
* Resize handle for DPF
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com>
*
* Permission to use, copy, modify, and/or distribute this software for any purpose with
* or without fee is hereby granted, provided that the above copyright notice and this
* permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#pragma once

#include "TopLevelWidget.hpp"
#include "../dgl/Color.hpp"

START_NAMESPACE_DGL

/** Resize handle for DPF windows, will sit on bottom-right. */
class ResizeHandle : public TopLevelWidget
{
public:
/** Constructor for placing this handle on top of a window. */
explicit ResizeHandle(Window& window)
: TopLevelWidget(window),
handleSize(16),
resizing(false)
{
resetArea();
}

/** Overloaded constructor, will fetch the window from an existing top-level widget. */
explicit ResizeHandle(TopLevelWidget* const tlw)
: TopLevelWidget(tlw->getWindow()),
handleSize(16),
resizing(false)
{
resetArea();
}

/** Set the handle size, minimum 16. */
void setHandleSize(const uint size)
{
handleSize = std::max(16u, size);
resetArea();
}

protected:
void onDisplay() override
{
const GraphicsContext& context(getGraphicsContext());
const double lineWidth = 1.0 * getScaleFactor();

#ifdef DGL_OPENGL
glUseProgram(0);
glMatrixMode(GL_MODELVIEW);
#endif

// draw white lines, 1px wide
Color(1.0f, 1.0f, 1.0f).setFor(context);
l1.draw(context, lineWidth);
l2.draw(context, lineWidth);
l3.draw(context, lineWidth);

// draw black lines, offset by 1px and 1px wide
Color(0.0f, 0.0f, 0.0f).setFor(context);
Line<double> l1b(l1), l2b(l2), l3b(l3);
l1b.moveBy(lineWidth, lineWidth);
l2b.moveBy(lineWidth, lineWidth);
l3b.moveBy(lineWidth, lineWidth);
l1b.draw(context, lineWidth);
l2b.draw(context, lineWidth);
l3b.draw(context, lineWidth);
}

bool onMouse(const MouseEvent& ev) override
{
if (ev.button != 1)
return false;

if (ev.press && area.contains(ev.pos))
{
resizing = true;
resizingSize = Size<double>(getWidth(), getHeight());
lastResizePoint = ev.pos;
return true;
}

if (resizing && ! ev.press)
{
resizing = false;
return true;
}

return false;
}

bool onMotion(const MotionEvent& ev) override
{
if (! resizing)
return false;

const Size<double> offset(ev.pos.getX() - lastResizePoint.getX(),
ev.pos.getY() - lastResizePoint.getY());

resizingSize += offset;
lastResizePoint = ev.pos;

// TODO min width, min height
const uint minWidth = 16;
const uint minHeight = 16;

if (resizingSize.getWidth() < minWidth)
resizingSize.setWidth(minWidth);
if (resizingSize.getWidth() > 16384)
resizingSize.setWidth(16384);
if (resizingSize.getHeight() < minHeight)
resizingSize.setHeight(minHeight);
if (resizingSize.getHeight() > 16384)
resizingSize.setHeight(16384);

setSize(resizingSize.getWidth(), resizingSize.getHeight());
return true;
}

void onResize(const ResizeEvent& ev) override
{
TopLevelWidget::onResize(ev);
resetArea();
}

private:
Rectangle<uint> area;
Line<double> l1, l2, l3;
uint handleSize;

// event handling state
bool resizing;
Point<double> lastResizePoint;
Size<double> resizingSize;

void resetArea()
{
const double scaleFactor = getScaleFactor();
const uint margin = 0.0 * scaleFactor;
const uint size = handleSize * scaleFactor;

area = Rectangle<uint>(getWidth() - size - margin,
getHeight() - size - margin,
size, size);

recreateLines(area.getX(), area.getY(), size);
}

void recreateLines(const uint x, const uint y, const uint size)
{
uint linesize = size;
uint offset = 0;

// 1st line, full diagonal size
l1.setStartPos(x + size, y);
l1.setEndPos(x, y + size);

// 2nd line, bit more to the right and down, cropped
offset += size / 3;
linesize -= size / 3;
l2.setStartPos(x + linesize + offset, y + offset);
l2.setEndPos(x + offset, y + linesize + offset);

// 3rd line, even more right and down
offset += size / 3;
linesize -= size / 3;
l3.setStartPos(x + linesize + offset, y + offset);
l3.setEndPos(x + offset, y + linesize + offset);
}

DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ResizeHandle)
};

END_NAMESPACE_DGL

+ 91
- 11
plugins/CVCRack/Window.cpp View File

@@ -68,6 +68,7 @@ std::shared_ptr<Image> Image::load(const std::string& filename) {

struct Window::Internal {
DISTRHO_NAMESPACE::UI* ui;
math::Vec size;

std::string lastWindowTitle;

@@ -94,11 +95,18 @@ struct Window::Internal {
Window::Window() {
internal = new Internal;
internal->ui = lastUI;

vg = lastUI->getContext();
internal->size = minWindowSize;

int err;

// Set up GLEW
glewExperimental = GL_TRUE;
err = glewInit();
if (err != GLEW_OK) {
osdialog_message(OSDIALOG_ERROR, OSDIALOG_OK, "Could not initialize GLEW. Does your graphics card support OpenGL 2.0 or greater? If so, make sure you have the latest graphics drivers installed.");
exit(1);
}

const GLubyte* vendor = glGetString(GL_VENDOR);
const GLubyte* renderer = glGetString(GL_RENDERER);
const GLubyte* version = glGetString(GL_VERSION);
@@ -109,6 +117,21 @@ Window::Window() {
// GLEW generates GL error because it calls glGetString(GL_EXTENSIONS), we'll consume it here.
glGetError();

// Set up NanoVG
int nvgFlags = NVG_ANTIALIAS;
#if defined NANOVG_GL2
vg = nvgCreateGL2(nvgFlags);
fbVg = nvgCreateSharedGL2(vg, nvgFlags);
#elif defined NANOVG_GL3
vg = nvgCreateGL3(nvgFlags);
#elif defined NANOVG_GLES2
vg = nvgCreateGLES2(nvgFlags);
#endif
if (!vg) {
osdialog_message(OSDIALOG_ERROR, OSDIALOG_OK, "Could not initialize NanoVG. Does your graphics card support OpenGL 2.0 or greater? If so, make sure you have the latest graphics drivers installed.");
exit(1);
}

// Load default Blendish font
uiFont = loadFont(asset::system("res/fonts/DejaVuSans.ttf"));
bndSetFont(uiFont->handle);
@@ -132,17 +155,26 @@ Window::~Window() {

// nvgDeleteClone(fbVg);

#if defined NANOVG_GL2
nvgDeleteGL2(vg);
nvgDeleteGL2(fbVg);
#elif defined NANOVG_GL3
nvgDeleteGL3(vg);
#elif defined NANOVG_GLES2
nvgDeleteGLES2(vg);
#endif

delete internal;
}


math::Vec Window::getSize() {
return math::Vec(1280, 720);
return internal->size;
}


void Window::setSize(math::Vec size) {
size = size.max(minWindowSize);
internal->size = size.max(minWindowSize);
}


@@ -163,14 +195,12 @@ void Window::step() {
nvgReset(vg);

bndSetFont(uiFont->handle);
nvgFillColor(vg, nvgRGBf(1, 1, 1));
nvgStrokeColor(vg, nvgRGBf(1, 1, 1));

// Poll events
// Save and restore context because event handler set their own context based on which window they originate from.
Context* context = contextGet();
// Context* context = contextGet();
// glfwPollEvents();
contextSet(context);
// contextSet(context);

// Set window title
std::string windowTitle = APP_NAME + " " + APP_EDITION_NAME + " " + APP_VERSION;
@@ -223,9 +253,9 @@ void Window::step() {
APP->scene->draw(args);
t3 = system::getTime();

// glViewport(0, -winHeight, fbWidth, fbHeight);
// glClearColor(0.0, 0.0, 0.0, 1.0);
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glViewport(0, 0, fbWidth, fbHeight);
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
nvgEndFrame(vg);
t4 = system::getTime();
}
@@ -370,6 +400,56 @@ bool& Window::fbDirtyOnSubpixelChange() {
}


void mouseButtonCallback(Window* win, int button, int action, int mods) {
/*
#if defined ARCH_MAC
// Remap Ctrl-left click to right click on Mac
if (button == GLFW_MOUSE_BUTTON_LEFT && (mods & RACK_MOD_MASK) == GLFW_MOD_CONTROL) {
button = GLFW_MOUSE_BUTTON_RIGHT;
mods &= ~GLFW_MOD_CONTROL;
}
// Remap Ctrl-shift-left click to middle click on Mac
if (button == GLFW_MOUSE_BUTTON_LEFT && (mods & RACK_MOD_MASK) == (GLFW_MOD_CONTROL | GLFW_MOD_SHIFT)) {
button = GLFW_MOUSE_BUTTON_MIDDLE;
mods &= ~(GLFW_MOD_CONTROL | GLFW_MOD_SHIFT);
}
#endif
*/

APP->event->handleButton(win->internal->lastMousePos, button, action, mods);
}

void cursorPosCallback(Window* win, double xpos, double ypos) {
math::Vec mousePos = math::Vec(xpos, ypos).div(win->pixelRatio / win->windowRatio).round();
math::Vec mouseDelta = mousePos.minus(win->internal->lastMousePos);

// Workaround for GLFW warping mouse to a different position when the cursor is locked or unlocked.
if (win->internal->ignoreNextMouseDelta) {
win->internal->ignoreNextMouseDelta = false;
mouseDelta = math::Vec();
}

win->internal->lastMousePos = mousePos;

APP->event->handleHover(mousePos, mouseDelta);

// Keyboard/mouse MIDI driver
math::Vec scaledPos(xpos / win->internal->ui->getWidth(), ypos / win->internal->ui->getHeight());
keyboard::mouseMove(scaledPos);
}

void scrollCallback(Window* win, double x, double y) {
math::Vec scrollDelta = math::Vec(x, y);
#if defined ARCH_MAC
scrollDelta = scrollDelta.mult(10.0);
#else
scrollDelta = scrollDelta.mult(50.0);
#endif

APP->event->handleScroll(win->internal->lastMousePos, scrollDelta);
}


void init() {
}



+ 0
- 19
plugins/CVCRack/dep.cpp View File

@@ -1,19 +0,0 @@
// This source file compiles those annoying implementation-in-header libraries

#include <common.hpp> // for fopen_u8

#define GLEW_STATIC
#define GLEW_NO_GLU
#include <GL/glew.h>

#include <nanovg.h>

#define BLENDISH_IMPLEMENTATION
#include <blendish.h>

#define NANOSVG_IMPLEMENTATION
#define NANOSVG_ALL_COLOR_KEYWORDS
#include <nanosvg.h>

#define STB_IMAGE_WRITE_IMPLEMENTATION
#include <stb_image_write.h>

Loading…
Cancel
Save