|
|
@@ -36,15 +36,25 @@ |
|
|
|
#include <context.hpp> |
|
|
|
#include <patch.hpp> |
|
|
|
#include <settings.hpp> |
|
|
|
#include <plugin.hpp> // used in Window::screenshot |
|
|
|
#include <system.hpp> // used in Window::screenshot |
|
|
|
#include <system.hpp> |
|
|
|
|
|
|
|
#ifdef NDEBUG |
|
|
|
# undef DEBUG |
|
|
|
#endif |
|
|
|
|
|
|
|
// comment out if wanting to generate a local screenshot.png |
|
|
|
#define STBI_WRITE_NO_STDIO |
|
|
|
|
|
|
|
// uncomment to generate screenshots without the rack rail background (ie, transparent) |
|
|
|
// #define CARDINAL_TRANSPARENT_SCREENSHOTS |
|
|
|
|
|
|
|
// used in Window::screenshot |
|
|
|
#define STB_IMAGE_WRITE_IMPLEMENTATION |
|
|
|
#include "../src/Rack/dep/glfw/deps/stb_image_write.h" |
|
|
|
|
|
|
|
#include "DistrhoUI.hpp" |
|
|
|
#include "Application.hpp" |
|
|
|
#include "extra/String.hpp" |
|
|
|
#include "../CardinalCommon.hpp" |
|
|
|
#include "../WindowParameters.hpp" |
|
|
|
|
|
|
@@ -119,6 +129,15 @@ std::shared_ptr<Image> Image::load(const std::string& filename) { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
enum ScreenshotStep { |
|
|
|
kScreenshotStepNone, |
|
|
|
kScreenshotStepStarted, |
|
|
|
kScreenshotStepFirstPass, |
|
|
|
kScreenshotStepSecondPass, |
|
|
|
kScreenshotStepSaving |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
struct Window::Internal { |
|
|
|
std::string lastWindowTitle; |
|
|
|
|
|
|
@@ -139,6 +158,7 @@ struct Window::Internal { |
|
|
|
|
|
|
|
int frame = 0; |
|
|
|
int frameSwapInterval = 1; |
|
|
|
int generateScreenshotStep = kScreenshotStepNone; |
|
|
|
double monitorRefreshRate = 60.0; |
|
|
|
double frameTime = 0.0; |
|
|
|
double lastFrameDuration = 0.0; |
|
|
@@ -342,6 +362,26 @@ void Window::run() { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void Window__flipBitmap(uint8_t* pixels, int width, int height, int depth) { |
|
|
|
for (int y = 0; y < height / 2; y++) { |
|
|
|
const int flipY = height - y - 1; |
|
|
|
uint8_t tmp[width * depth]; |
|
|
|
std::memcpy(tmp, &pixels[y * width * depth], width * depth); |
|
|
|
std::memcpy(&pixels[y * width * depth], &pixels[flipY * width * depth], width * depth); |
|
|
|
std::memcpy(&pixels[flipY * width * depth], tmp, width * depth); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void Window__writeImagePNG(void* context, void* data, int size) { |
|
|
|
USE_NAMESPACE_DISTRHO |
|
|
|
UI* const ui = static_cast<UI*>(context); |
|
|
|
String encodedPNG("data:image/png;base64,"); |
|
|
|
encodedPNG += String::asBase64(data, size); |
|
|
|
ui->setState("screenshot", encodedPNG.buffer()); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void Window::step() { |
|
|
|
DISTRHO_SAFE_ASSERT_RETURN(internal->ui != nullptr,); |
|
|
|
|
|
|
@@ -378,6 +418,16 @@ void Window::step() { |
|
|
|
APP->event->handleDirty(); |
|
|
|
} |
|
|
|
|
|
|
|
// Hide menu and background if generating screenshot |
|
|
|
if (internal->generateScreenshotStep == kScreenshotStepStarted) { |
|
|
|
#ifdef CARDINAL_TRANSPARENT_SCREENSHOTS |
|
|
|
APP->scene->menuBar->hide(); |
|
|
|
APP->scene->rack->children.front()->hide(); |
|
|
|
#else |
|
|
|
internal->generateScreenshotStep = kScreenshotStepSecondPass; |
|
|
|
#endif |
|
|
|
} |
|
|
|
|
|
|
|
// Get framebuffer/window ratio |
|
|
|
int winWidth = internal->ui->getWidth(); |
|
|
|
int winHeight = internal->ui->getHeight(); |
|
|
@@ -388,7 +438,7 @@ void Window::step() { |
|
|
|
if (APP->scene) { |
|
|
|
// DEBUG("%f %f %d %d", pixelRatio, windowRatio, fbWidth, winWidth); |
|
|
|
// Resize scene |
|
|
|
APP->scene->box.size = math::Vec(fbWidth, fbHeight).div(pixelRatio); |
|
|
|
APP->scene->box.size = math::Vec(fbWidth, fbHeight).div(newPixelRatio); |
|
|
|
|
|
|
|
// Step scene |
|
|
|
APP->scene->step(); |
|
|
@@ -396,7 +446,7 @@ void Window::step() { |
|
|
|
// Render scene |
|
|
|
{ |
|
|
|
// Update and render |
|
|
|
nvgScale(vg, pixelRatio, pixelRatio); |
|
|
|
nvgScale(vg, newPixelRatio, newPixelRatio); |
|
|
|
|
|
|
|
// Draw scene |
|
|
|
widget::Widget::DrawArgs args; |
|
|
@@ -405,12 +455,52 @@ void Window::step() { |
|
|
|
APP->scene->draw(args); |
|
|
|
|
|
|
|
glViewport(0, 0, fbWidth, fbHeight); |
|
|
|
#ifdef CARDINAL_TRANSPARENT_SCREENSHOTS |
|
|
|
glClearColor(0.0, 0.0, 0.0, 0.0); |
|
|
|
#else |
|
|
|
glClearColor(0.0, 0.0, 0.0, 1.0); |
|
|
|
#endif |
|
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
++internal->frame; |
|
|
|
|
|
|
|
if (internal->generateScreenshotStep != kScreenshotStepNone) { |
|
|
|
++internal->generateScreenshotStep; |
|
|
|
|
|
|
|
int y = 0; |
|
|
|
#ifndef CARDINAL_TRANSPARENT_SCREENSHOTS |
|
|
|
y = APP->scene->menuBar->box.size.y * newPixelRatio; |
|
|
|
#endif |
|
|
|
|
|
|
|
// Allocate pixel color buffer |
|
|
|
uint8_t* const pixels = new uint8_t[winHeight * winWidth * 4]; |
|
|
|
|
|
|
|
// glReadPixels defaults to GL_BACK, but the back-buffer is unstable, so use the front buffer (what the user sees) |
|
|
|
glReadBuffer(GL_FRONT); |
|
|
|
glReadPixels(0, 0, winWidth, winHeight, GL_RGBA, GL_UNSIGNED_BYTE, pixels); |
|
|
|
|
|
|
|
if (internal->generateScreenshotStep == kScreenshotStepSaving) |
|
|
|
{ |
|
|
|
// Write pixels to PNG |
|
|
|
const int stride = winWidth * 4; |
|
|
|
const uint8_t* const pixelsWithOffset = pixels + (stride * y); |
|
|
|
Window__flipBitmap(pixels, winWidth, winHeight, 4); |
|
|
|
#ifdef STBI_WRITE_NO_STDIO |
|
|
|
stbi_write_png_to_func(Window__writeImagePNG, internal->ui, |
|
|
|
winWidth, winHeight - y, 4, pixelsWithOffset, stride); |
|
|
|
#else |
|
|
|
stbi_write_png("screenshot.png", winWidth, winHeight - y, 4, pixelsWithOffset, stride); |
|
|
|
#endif |
|
|
|
|
|
|
|
internal->generateScreenshotStep = kScreenshotStepNone; |
|
|
|
APP->scene->menuBar->show(); |
|
|
|
APP->scene->rack->children.front()->show(); |
|
|
|
} |
|
|
|
|
|
|
|
delete[] pixels; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@@ -456,7 +546,11 @@ void Window::setFullScreen(bool) { |
|
|
|
|
|
|
|
|
|
|
|
bool Window::isFullScreen() { |
|
|
|
#ifdef CARDINAL_TRANSPARENT_SCREENSHOTS |
|
|
|
return internal->generateScreenshotStep != kScreenshotStepNone; |
|
|
|
#else |
|
|
|
return false; |
|
|
|
#endif |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@@ -533,6 +627,11 @@ int& Window::fbCount() { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void generateScreenshot() { |
|
|
|
APP->window->internal->generateScreenshotStep = kScreenshotStepStarted; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void init() { |
|
|
|
} |
|
|
|
|
|
|
|