| @@ -1,5 +1,8 @@ | |||||
| # DISTRHO CVCRack | # DISTRHO CVCRack | ||||
| WORK IN PROGRESS | |||||
| WORK IN PROGRESS - nothing to see here | |||||
| Just an experiment to see how far we can go about a VCV plugin version that is opensource and uses original VCV source core directly. | |||||
| Maybe it will work, maybe not, hard to say at this point. | |||||
| This is a DPF'ied build of [VCVRack](https://github.com/VCVRack/Rack), allowing it to be used as an audio plugin. | This is a DPF'ied build of [VCVRack](https://github.com/VCVRack/Rack), allowing it to be used as an audio plugin. | ||||
| @@ -1 +1 @@ | |||||
| Subproject commit c4e1210897e804a19b3fa35d542765b3feb0236e | |||||
| Subproject commit 23f89562acbd637a23b9f0333877939ad26c0595 | |||||
| @@ -14,12 +14,102 @@ | |||||
| * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
| */ | */ | ||||
| #include <asset.hpp> | |||||
| #include <audio.hpp> | |||||
| #include <context.hpp> | |||||
| #include <library.hpp> | |||||
| #include <keyboard.hpp> | |||||
| #include <midi.hpp> | |||||
| #include <plugin.hpp> | |||||
| #include <random.hpp> | |||||
| #include <settings.hpp> | |||||
| #include <system.hpp> | |||||
| #include <osdialog.h> | |||||
| #include "DistrhoPlugin.hpp" | #include "DistrhoPlugin.hpp" | ||||
| START_NAMESPACE_DISTRHO | START_NAMESPACE_DISTRHO | ||||
| // ----------------------------------------------------------------------------------------------------------- | // ----------------------------------------------------------------------------------------------------------- | ||||
| struct Initializer { | |||||
| Initializer() | |||||
| { | |||||
| using namespace rack; | |||||
| settings::devMode = true; | |||||
| system::init(); | |||||
| asset::init(); | |||||
| logger::init(); | |||||
| random::init(); | |||||
| // Log environment | |||||
| INFO("%s %s v%s", APP_NAME.c_str(), APP_EDITION.c_str(), APP_VERSION.c_str()); | |||||
| INFO("%s", system::getOperatingSystemInfo().c_str()); | |||||
| INFO("System directory: %s", asset::systemDir.c_str()); | |||||
| INFO("User directory: %s", asset::userDir.c_str()); | |||||
| INFO("System time: %s", string::formatTimeISO(system::getUnixTime()).c_str()); | |||||
| // Load settings | |||||
| settings::init(); | |||||
| try { | |||||
| settings::load(); | |||||
| } | |||||
| catch (Exception& e) { | |||||
| std::string message = e.what(); | |||||
| message += "\n\nResetting settings to default"; | |||||
| d_stdout(message.c_str()); | |||||
| /* | |||||
| if (!osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK_CANCEL, msg.c_str())) { | |||||
| exit(1); | |||||
| } | |||||
| */ | |||||
| } | |||||
| // Check existence of the system res/ directory | |||||
| std::string resDir = asset::system("res"); | |||||
| if (!system::isDirectory(resDir)) { | |||||
| std::string message = string::f("Rack's resource directory \"%s\" does not exist. Make sure Rack is correctly installed and launched.", resDir.c_str()); | |||||
| d_stderr2(message.c_str()); | |||||
| /* | |||||
| osdialog_message(OSDIALOG_ERROR, OSDIALOG_OK, message.c_str()); | |||||
| */ | |||||
| exit(1); | |||||
| } | |||||
| INFO("Initializing environment"); | |||||
| // network::init(); | |||||
| audio::init(); | |||||
| // rtaudioInit(); | |||||
| midi::init(); | |||||
| // rtmidiInit(); | |||||
| keyboard::init(); | |||||
| plugin::init(); | |||||
| library::init(); | |||||
| // discord::init(); | |||||
| } | |||||
| ~Initializer() | |||||
| { | |||||
| using namespace rack; | |||||
| // discord::destroy(); | |||||
| library::destroy(); | |||||
| midi::destroy(); | |||||
| audio::destroy(); | |||||
| plugin::destroy(); | |||||
| INFO("Destroying logger"); | |||||
| logger::destroy(); | |||||
| } | |||||
| }; | |||||
| static Initializer& getInitializerInstance() | |||||
| { | |||||
| static Initializer init; | |||||
| return init; | |||||
| } | |||||
| /** | /** | ||||
| Plugin to demonstrate parameter outputs using meters. | Plugin to demonstrate parameter outputs using meters. | ||||
| */ | */ | ||||
| @@ -130,6 +220,7 @@ private: | |||||
| Plugin* createPlugin() | Plugin* createPlugin() | ||||
| { | { | ||||
| getInitializerInstance(); | |||||
| return new CVCRackPlugin(); | return new CVCRackPlugin(); | ||||
| } | } | ||||
| @@ -14,19 +14,92 @@ | |||||
| * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
| */ | */ | ||||
| #include <app/common.hpp> | |||||
| #include <app/Scene.hpp> | |||||
| #include <context.hpp> | |||||
| #include <engine/Engine.hpp> | |||||
| #include <patch.hpp> | |||||
| #include <ui/common.hpp> | |||||
| #include <window/Window.hpp> | |||||
| #include "DistrhoUI.hpp" | #include "DistrhoUI.hpp" | ||||
| GLFWAPI const char* glfwGetClipboardString(GLFWwindow* window) { return nullptr; } | |||||
| GLFWAPI void glfwSetClipboardString(GLFWwindow* window, const char*) {} | |||||
| GLFWAPI const char* glfwGetKeyName(int key, int scancode) { return nullptr; } | |||||
| GLFWAPI int glfwGetKeyScancode(int key) { return 0; } | |||||
| namespace rack { | |||||
| namespace window { | |||||
| DISTRHO_NAMESPACE::UI* lastUI = nullptr; | |||||
| } | |||||
| } | |||||
| START_NAMESPACE_DISTRHO | START_NAMESPACE_DISTRHO | ||||
| // ----------------------------------------------------------------------------------------------------------- | // ----------------------------------------------------------------------------------------------------------- | ||||
| struct Initializer { | |||||
| Initializer() | |||||
| { | |||||
| using namespace rack; | |||||
| ui::init(); | |||||
| window::init(); | |||||
| } | |||||
| ~Initializer() | |||||
| { | |||||
| using namespace rack; | |||||
| window::destroy(); | |||||
| ui::destroy(); | |||||
| } | |||||
| }; | |||||
| static Initializer& getInitializerInstance() | |||||
| { | |||||
| static Initializer init; | |||||
| return init; | |||||
| } | |||||
| class CVCRackUI : public UI | class CVCRackUI : public UI | ||||
| { | { | ||||
| public: | public: | ||||
| CVCRackUI() | CVCRackUI() | ||||
| : UI(128, 512) | |||||
| : UI(1280, 720) | |||||
| { | { | ||||
| setGeometryConstraints(32, 128, false); | |||||
| using namespace rack; | |||||
| // Initialize context | |||||
| INFO("Initializing context"); | |||||
| window::lastUI = this; | |||||
| contextSet(new Context); | |||||
| APP->engine = new engine::Engine; | |||||
| APP->history = new history::State; | |||||
| APP->event = new widget::EventState; | |||||
| APP->scene = new app::Scene; | |||||
| APP->event->rootWidget = APP->scene; | |||||
| APP->patch = new patch::Manager; | |||||
| /*if (!settings::headless)*/ { | |||||
| APP->window = new window::Window; | |||||
| } | |||||
| window::lastUI = nullptr; | |||||
| APP->engine->startFallbackThread(); | |||||
| } | |||||
| ~CVCRackUI() override | |||||
| { | |||||
| using namespace rack; | |||||
| delete APP; | |||||
| contextSet(NULL); | |||||
| } | |||||
| void onNanoDisplay() override | |||||
| { | |||||
| APP->window->step(); | |||||
| } | } | ||||
| protected: | protected: | ||||
| @@ -41,16 +114,6 @@ protected: | |||||
| { | { | ||||
| } | } | ||||
| /* -------------------------------------------------------------------------------------------------------- | |||||
| * Widget Callbacks */ | |||||
| /** | |||||
| The drawing function. | |||||
| */ | |||||
| void onDisplay() override | |||||
| { | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------------- | // ------------------------------------------------------------------------------------------------------- | ||||
| private: | private: | ||||
| @@ -65,6 +128,7 @@ private: | |||||
| UI* createUI() | UI* createUI() | ||||
| { | { | ||||
| getInitializerInstance(); | |||||
| return new CVCRackUI(); | return new CVCRackUI(); | ||||
| } | } | ||||
| @@ -28,6 +28,9 @@ | |||||
| #define DISTRHO_PLUGIN_WANT_DIRECT_ACCESS 1 | #define DISTRHO_PLUGIN_WANT_DIRECT_ACCESS 1 | ||||
| // #define DISTRHO_PLUGIN_LV2_CATEGORY "lv2:AnalyserPlugin" | // #define DISTRHO_PLUGIN_LV2_CATEGORY "lv2:AnalyserPlugin" | ||||
| // #define DISTRHO_PLUGIN_VST3_CATEGORIES "Fx|Analyzer" | // #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_USER_RESIZABLE 1 | ||||
| enum Parameters { | enum Parameters { | ||||
| @@ -16,11 +16,14 @@ FILES_DSP = \ | |||||
| CVCRackPlugin.cpp | CVCRackPlugin.cpp | ||||
| FILES_UI = \ | FILES_UI = \ | ||||
| CVCRackUI.cpp | |||||
| CVCRackUI.cpp \ | |||||
| dep.cpp \ | |||||
| Window.cpp | |||||
| # -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
| # Import base definitions | # Import base definitions | ||||
| # UI_TYPE = external | |||||
| include ../../dpf/Makefile.base.mk | include ../../dpf/Makefile.base.mk | ||||
| # -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
| @@ -30,8 +33,6 @@ FILES_DSP += Rack/dep/pffft/pffft.c | |||||
| FILES_DSP += Rack/dep/pffft/fftpack.c | FILES_DSP += Rack/dep/pffft/fftpack.c | ||||
| FILES_UI += Rack/dep/oui-blendish/blendish.c | FILES_UI += Rack/dep/oui-blendish/blendish.c | ||||
| FILES_UI += Rack/dep/nanovg/src/nanovg.c | |||||
| # FILES_UI += Rack/dep/glfw/deps/glad.c | |||||
| # FIXME dont use this | # FIXME dont use this | ||||
| FILES_UI += Rack/dep/osdialog/osdialog.c | FILES_UI += Rack/dep/osdialog/osdialog.c | ||||
| @@ -45,13 +46,15 @@ endif | |||||
| FILES_DSP += $(wildcard Rack/src/*.c) | FILES_DSP += $(wildcard Rack/src/*.c) | ||||
| FILES_DSP += $(wildcard Rack/src/*/*.c) | FILES_DSP += $(wildcard Rack/src/*/*.c) | ||||
| FILES_DSP += $(filter-out Rack/src/network.cpp Rack/src/rtaudio.cpp Rack/src/rtmidi.cpp, $(wildcard Rack/src/*.cpp)) | |||||
| FILES_DSP += $(wildcard Rack/src/*/*.cpp) | |||||
| 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/window/Window.cpp, $(wildcard Rack/src/*/*.cpp)) | |||||
| # EXTRA_LIBS = Rack/dep/lib/libcurl.a | |||||
| EXTRA_LIBS += Rack/dep/lib/libglfw3.a | |||||
| EXTRA_LIBS = Rack/dep/lib/libcrypto.a | |||||
| EXTRA_LIBS += Rack/dep/lib/libcurl.a | |||||
| # EXTRA_LIBS += Rack/dep/lib/libglfw3.a | |||||
| EXTRA_LIBS += Rack/dep/lib/libjansson.a | EXTRA_LIBS += Rack/dep/lib/libjansson.a | ||||
| EXTRA_LIBS += Rack/dep/lib/libspeexdsp.a | EXTRA_LIBS += Rack/dep/lib/libspeexdsp.a | ||||
| EXTRA_LIBS += Rack/dep/lib/libssl.a | |||||
| EXTRA_LIBS += Rack/dep/lib/libzstd.a | EXTRA_LIBS += Rack/dep/lib/libzstd.a | ||||
| ifeq ($(WINDOWS),true) | ifeq ($(WINDOWS),true) | ||||
| @@ -76,16 +79,20 @@ endif | |||||
| Rack/dep/lib/%.a: | Rack/dep/lib/%.a: | ||||
| $(MAKE) CMAKE="$(CMAKE) -DCMAKE_INSTALL_LIBDIR=lib -DCMAKE_INSTALL_PREFIX='$(abspath Rack/dep)'" -C Rack/dep lib/$*.a | $(MAKE) CMAKE="$(CMAKE) -DCMAKE_INSTALL_LIBDIR=lib -DCMAKE_INSTALL_PREFIX='$(abspath Rack/dep)'" -C Rack/dep lib/$*.a | ||||
| Rack/dep/lib/libcrypto.a: Rack/dep/lib/libssl.a | |||||
| # -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
| # Extra flags for VCV stuff | # Extra flags for VCV stuff | ||||
| BASE_FLAGS += -D_APP_VERSION=2.git.0 | BASE_FLAGS += -D_APP_VERSION=2.git.0 | ||||
| BASE_FLAGS += -I$(DPF_PATH)/dgl/src/nanovg | |||||
| BASE_FLAGS += -IRack/include | BASE_FLAGS += -IRack/include | ||||
| BASE_FLAGS += -IRack/dep/include | BASE_FLAGS += -IRack/dep/include | ||||
| BASE_FLAGS += -IRack/dep/filesystem/include | BASE_FLAGS += -IRack/dep/filesystem/include | ||||
| BASE_FLAGS += -IRack/dep/fuzzysearchdatabase/src | BASE_FLAGS += -IRack/dep/fuzzysearchdatabase/src | ||||
| BASE_FLAGS += -IRack/dep/glfw/deps | BASE_FLAGS += -IRack/dep/glfw/deps | ||||
| BASE_FLAGS += -IRack/dep/nanovg/src | |||||
| BASE_FLAGS += -IRack/dep/glfw/include | |||||
| # BASE_FLAGS += -IRack/dep/nanovg/src | |||||
| BASE_FLAGS += -IRack/dep/nanosvg/src | BASE_FLAGS += -IRack/dep/nanosvg/src | ||||
| BASE_FLAGS += -IRack/dep/osdialog | BASE_FLAGS += -IRack/dep/osdialog | ||||
| BASE_FLAGS += -IRack/dep/oui-blendish | BASE_FLAGS += -IRack/dep/oui-blendish | ||||
| @@ -115,8 +122,11 @@ endif | |||||
| ifeq ($(MACOS),true) | ifeq ($(MACOS),true) | ||||
| LINK_FLAGS += -framework IOKit | LINK_FLAGS += -framework IOKit | ||||
| # LINK_FLAGS += -Wl,-all_load | |||||
| endif | endif | ||||
| # LINK_FLAGS += $(OPENGL_LIBS) | |||||
| # TODO needed on windows? need to check | # TODO needed on windows? need to check | ||||
| LINK_FLAGS += -lpthread | LINK_FLAGS += -lpthread | ||||
| @@ -0,0 +1,381 @@ | |||||
| #include <map> | |||||
| #include <queue> | |||||
| #include <thread> | |||||
| #include <stb_image_write.h> | |||||
| #include <osdialog.h> | |||||
| #include <window/Window.hpp> | |||||
| #include <asset.hpp> | |||||
| #include <widget/Widget.hpp> | |||||
| #include <app/Scene.hpp> | |||||
| #include <keyboard.hpp> | |||||
| #include <context.hpp> | |||||
| #include <patch.hpp> | |||||
| #include <settings.hpp> | |||||
| #include <plugin.hpp> // used in Window::screenshot | |||||
| #include <system.hpp> // used in Window::screenshot | |||||
| #include "DistrhoUI.hpp" | |||||
| namespace rack { | |||||
| namespace window { | |||||
| extern DISTRHO_NAMESPACE::UI* lastUI; | |||||
| static const math::Vec minWindowSize = math::Vec(640, 480); | |||||
| void Font::loadFile(const std::string& filename, NVGcontext* vg) { | |||||
| this->vg = vg; | |||||
| handle = nvgCreateFont(vg, filename.c_str(), filename.c_str()); | |||||
| if (handle < 0) | |||||
| throw Exception("Failed to load font %s", filename.c_str()); | |||||
| INFO("Loaded font %s", filename.c_str()); | |||||
| } | |||||
| Font::~Font() { | |||||
| // There is no NanoVG deleteFont() function yet, so do nothing | |||||
| } | |||||
| std::shared_ptr<Font> Font::load(const std::string& filename) { | |||||
| return APP->window->loadFont(filename); | |||||
| } | |||||
| void Image::loadFile(const std::string& filename, NVGcontext* vg) { | |||||
| this->vg = vg; | |||||
| handle = nvgCreateImage(vg, filename.c_str(), NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY); | |||||
| if (handle <= 0) | |||||
| throw Exception("Failed to load image %s", filename.c_str()); | |||||
| INFO("Loaded image %s", filename.c_str()); | |||||
| } | |||||
| Image::~Image() { | |||||
| // TODO What if handle is invalid? | |||||
| if (handle >= 0) | |||||
| nvgDeleteImage(vg, handle); | |||||
| } | |||||
| std::shared_ptr<Image> Image::load(const std::string& filename) { | |||||
| return APP->window->loadImage(filename); | |||||
| } | |||||
| struct Window::Internal { | |||||
| DISTRHO_NAMESPACE::UI* ui; | |||||
| std::string lastWindowTitle; | |||||
| int lastWindowX = 0; | |||||
| int lastWindowY = 0; | |||||
| int lastWindowWidth = 0; | |||||
| int lastWindowHeight = 0; | |||||
| int frame = 0; | |||||
| bool ignoreNextMouseDelta = false; | |||||
| int frameSwapInterval = -1; | |||||
| double monitorRefreshRate = 0.0; | |||||
| double frameTime = 0.0; | |||||
| double lastFrameDuration = 0.0; | |||||
| math::Vec lastMousePos; | |||||
| std::map<std::string, std::shared_ptr<Font>> fontCache; | |||||
| std::map<std::string, std::shared_ptr<Image>> imageCache; | |||||
| bool fbDirtyOnSubpixelChange = true; | |||||
| }; | |||||
| Window::Window() { | |||||
| internal = new Internal; | |||||
| internal->ui = lastUI; | |||||
| vg = lastUI->getContext(); | |||||
| int err; | |||||
| const GLubyte* vendor = glGetString(GL_VENDOR); | |||||
| const GLubyte* renderer = glGetString(GL_RENDERER); | |||||
| const GLubyte* version = glGetString(GL_VERSION); | |||||
| INFO("Renderer: %s %s", vendor, renderer); | |||||
| INFO("OpenGL: %s", version); | |||||
| INFO("UI pointer: %p", lastUI); | |||||
| // GLEW generates GL error because it calls glGetString(GL_EXTENSIONS), we'll consume it here. | |||||
| glGetError(); | |||||
| // Load default Blendish font | |||||
| uiFont = loadFont(asset::system("res/fonts/DejaVuSans.ttf")); | |||||
| bndSetFont(uiFont->handle); | |||||
| if (APP->scene) { | |||||
| widget::Widget::ContextCreateEvent e; | |||||
| APP->scene->onContextCreate(e); | |||||
| } | |||||
| } | |||||
| Window::~Window() { | |||||
| if (APP->scene) { | |||||
| widget::Widget::ContextDestroyEvent e; | |||||
| APP->scene->onContextDestroy(e); | |||||
| } | |||||
| // Fonts and Images in the cache must be deleted before the NanoVG context is deleted | |||||
| internal->fontCache.clear(); | |||||
| internal->imageCache.clear(); | |||||
| // nvgDeleteClone(fbVg); | |||||
| delete internal; | |||||
| } | |||||
| math::Vec Window::getSize() { | |||||
| return math::Vec(1280, 720); | |||||
| } | |||||
| void Window::setSize(math::Vec size) { | |||||
| size = size.max(minWindowSize); | |||||
| } | |||||
| void Window::run() { | |||||
| internal->frame = 0; | |||||
| } | |||||
| void Window::step() { | |||||
| double frameTime = system::getTime(); | |||||
| double lastFrameTime = internal->frameTime; | |||||
| internal->frameTime = frameTime; | |||||
| internal->lastFrameDuration = frameTime - lastFrameTime; | |||||
| // DEBUG("%.2lf Hz", 1.0 / internal->lastFrameDuration); | |||||
| double t1 = 0.0, t2 = 0.0, t3 = 0.0, t4 = 0.0, t5 = 0.0; | |||||
| // Make event handlers and step() have a clean NanoVG context | |||||
| 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(); | |||||
| // glfwPollEvents(); | |||||
| contextSet(context); | |||||
| // Set window title | |||||
| std::string windowTitle = APP_NAME + " " + APP_EDITION_NAME + " " + APP_VERSION; | |||||
| if (APP->patch->path != "") { | |||||
| windowTitle += " - "; | |||||
| if (!APP->history->isSaved()) | |||||
| windowTitle += "*"; | |||||
| windowTitle += system::getFilename(APP->patch->path); | |||||
| } | |||||
| if (windowTitle != internal->lastWindowTitle) { | |||||
| internal->ui->getWindow().setTitle(windowTitle.c_str()); | |||||
| internal->lastWindowTitle = windowTitle; | |||||
| } | |||||
| // Get desired pixel ratio | |||||
| float newPixelRatio = internal->ui->getScaleFactor(); | |||||
| if (newPixelRatio != pixelRatio) { | |||||
| pixelRatio = newPixelRatio; | |||||
| APP->event->handleDirty(); | |||||
| } | |||||
| // Get framebuffer/window ratio | |||||
| int winWidth = internal->ui->getWidth(); | |||||
| int winHeight = internal->ui->getHeight(); | |||||
| int fbWidth = winWidth;// * newPixelRatio; | |||||
| int fbHeight = winHeight;// * newPixelRatio; | |||||
| windowRatio = (float)fbWidth / winWidth; | |||||
| t1 = system::getTime(); | |||||
| if (APP->scene) { | |||||
| // DEBUG("%f %f %d %d", pixelRatio, windowRatio, fbWidth, winWidth); | |||||
| // Resize scene | |||||
| APP->scene->box.size = math::Vec(fbWidth, fbHeight).div(pixelRatio); | |||||
| // Step scene | |||||
| APP->scene->step(); | |||||
| t2 = system::getTime(); | |||||
| // Render scene | |||||
| bool visible = true; | |||||
| if (visible) { | |||||
| // Update and render | |||||
| nvgBeginFrame(vg, fbWidth, fbHeight, pixelRatio); | |||||
| nvgScale(vg, pixelRatio, pixelRatio); | |||||
| // Draw scene | |||||
| widget::Widget::DrawArgs args; | |||||
| args.vg = vg; | |||||
| args.clipBox = APP->scene->box.zeroPos(); | |||||
| 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); | |||||
| nvgEndFrame(vg); | |||||
| t4 = system::getTime(); | |||||
| } | |||||
| } | |||||
| t5 = system::getTime(); | |||||
| // DEBUG("pre-step %6.1f step %6.1f draw %6.1f nvgEndFrame %6.1f glfwSwapBuffers %6.1f total %6.1f", | |||||
| // (t1 - frameTime) * 1e3f, | |||||
| // (t2 - t1) * 1e3f, | |||||
| // (t3 - t2) * 1e3f, | |||||
| // (t4 - t2) * 1e3f, | |||||
| // (t5 - t4) * 1e3f, | |||||
| // (t5 - frameTime) * 1e3f | |||||
| // ); | |||||
| internal->frame++; | |||||
| } | |||||
| void Window::screenshot(const std::string&) { | |||||
| } | |||||
| void Window::screenshotModules(const std::string&, float) { | |||||
| } | |||||
| void Window::close() { | |||||
| internal->ui->getWindow().close(); | |||||
| } | |||||
| void Window::cursorLock() { | |||||
| if (!settings::allowCursorLock) | |||||
| return; | |||||
| internal->ignoreNextMouseDelta = true; | |||||
| } | |||||
| void Window::cursorUnlock() { | |||||
| if (!settings::allowCursorLock) | |||||
| return; | |||||
| internal->ignoreNextMouseDelta = true; | |||||
| } | |||||
| bool Window::isCursorLocked() { | |||||
| return false; | |||||
| } | |||||
| int Window::getMods() { | |||||
| int mods = 0; | |||||
| /* | |||||
| if (glfwGetKey(win, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS || glfwGetKey(win, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS) | |||||
| mods |= GLFW_MOD_SHIFT; | |||||
| if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS || glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS) | |||||
| mods |= GLFW_MOD_CONTROL; | |||||
| if (glfwGetKey(win, GLFW_KEY_LEFT_ALT) == GLFW_PRESS || glfwGetKey(win, GLFW_KEY_RIGHT_ALT) == GLFW_PRESS) | |||||
| mods |= GLFW_MOD_ALT; | |||||
| if (glfwGetKey(win, GLFW_KEY_LEFT_SUPER) == GLFW_PRESS || glfwGetKey(win, GLFW_KEY_RIGHT_SUPER) == GLFW_PRESS) | |||||
| mods |= GLFW_MOD_SUPER; | |||||
| */ | |||||
| return mods; | |||||
| } | |||||
| void Window::setFullScreen(bool) { | |||||
| } | |||||
| bool Window::isFullScreen() { | |||||
| return false; | |||||
| } | |||||
| double Window::getMonitorRefreshRate() { | |||||
| return internal->monitorRefreshRate; | |||||
| } | |||||
| double Window::getFrameTime() { | |||||
| return internal->frameTime; | |||||
| } | |||||
| double Window::getLastFrameDuration() { | |||||
| return internal->lastFrameDuration; | |||||
| } | |||||
| double Window::getFrameDurationRemaining() { | |||||
| double frameDurationDesired = internal->frameSwapInterval / internal->monitorRefreshRate; | |||||
| return frameDurationDesired - (system::getTime() - internal->frameTime); | |||||
| } | |||||
| std::shared_ptr<Font> Window::loadFont(const std::string& filename) { | |||||
| const auto& pair = internal->fontCache.find(filename); | |||||
| if (pair != internal->fontCache.end()) | |||||
| return pair->second; | |||||
| // Load font | |||||
| std::shared_ptr<Font> font; | |||||
| try { | |||||
| font = std::make_shared<Font>(); | |||||
| font->loadFile(filename, vg); | |||||
| } | |||||
| catch (Exception& e) { | |||||
| WARN("%s", e.what()); | |||||
| font = NULL; | |||||
| } | |||||
| internal->fontCache[filename] = font; | |||||
| return font; | |||||
| } | |||||
| std::shared_ptr<Image> Window::loadImage(const std::string& filename) { | |||||
| const auto& pair = internal->imageCache.find(filename); | |||||
| if (pair != internal->imageCache.end()) | |||||
| return pair->second; | |||||
| // Load image | |||||
| std::shared_ptr<Image> image; | |||||
| try { | |||||
| image = std::make_shared<Image>(); | |||||
| image->loadFile(filename, vg); | |||||
| } | |||||
| catch (Exception& e) { | |||||
| WARN("%s", e.what()); | |||||
| image = NULL; | |||||
| } | |||||
| internal->imageCache[filename] = image; | |||||
| return image; | |||||
| } | |||||
| bool& Window::fbDirtyOnSubpixelChange() { | |||||
| return internal->fbDirtyOnSubpixelChange; | |||||
| } | |||||
| void init() { | |||||
| } | |||||
| void destroy() { | |||||
| } | |||||
| } // namespace window | |||||
| } // namespace rack | |||||
| @@ -0,0 +1,19 @@ | |||||
| // 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> | |||||