|  |  | @@ -362,24 +362,55 @@ void Window::run() { | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | static void Window__flipBitmap(uint8_t* pixels, int width, int height, int depth) { | 
		
	
		
			
			|  |  |  | static void Window__flipBitmap(uint8_t* pixels, const int width, const int height, const 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::memmove(&pixels[y * width * depth], &pixels[flipY * width * depth], width * depth); | 
		
	
		
			
			|  |  |  | std::memcpy(&pixels[flipY * width * depth], tmp, width * depth); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | #ifdef STBI_WRITE_NO_STDIO | 
		
	
		
			
			|  |  |  | static void Window__downscaleBitmap(uint8_t* pixels, int& width, int& height) { | 
		
	
		
			
			|  |  |  | int targetWidth = width; | 
		
	
		
			
			|  |  |  | int targetHeight = height; | 
		
	
		
			
			|  |  |  | double scale = 1.0; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | if (targetWidth > 300) { | 
		
	
		
			
			|  |  |  | scale = width / 300.0; | 
		
	
		
			
			|  |  |  | targetWidth = 300; | 
		
	
		
			
			|  |  |  | targetHeight = height / scale; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | if (targetHeight > 200) { | 
		
	
		
			
			|  |  |  | scale = height / 200.0; | 
		
	
		
			
			|  |  |  | targetHeight = 200; | 
		
	
		
			
			|  |  |  | targetWidth = width / scale; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | DISTRHO_SAFE_ASSERT_INT_RETURN(targetWidth <= 300, targetWidth,); | 
		
	
		
			
			|  |  |  | DISTRHO_SAFE_ASSERT_INT_RETURN(targetHeight <= 200, targetHeight,); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | // FIXME worst possible quality :/ | 
		
	
		
			
			|  |  |  | for (int y = 0; y < targetHeight; ++y) { | 
		
	
		
			
			|  |  |  | const int ys = static_cast<int>(y * scale); | 
		
	
		
			
			|  |  |  | for (int x = 0; x < targetWidth; ++x) { | 
		
	
		
			
			|  |  |  | const int xs = static_cast<int>(x * scale); | 
		
	
		
			
			|  |  |  | std::memmove(pixels + (width * y + x) * 3, pixels + (width * ys + xs) * 3, 3); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | width = targetWidth; | 
		
	
		
			
			|  |  |  | height = targetHeight; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | 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()); | 
		
	
		
			
			|  |  |  | ui->setState("screenshot", String::asBase64(data, size).buffer()); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | #endif | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | void Window::step() { | 
		
	
	
		
			
				|  |  | @@ -470,28 +501,33 @@ void Window::step() { | 
		
	
		
			
			|  |  |  | ++internal->generateScreenshotStep; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | int y = 0; | 
		
	
		
			
			|  |  |  | #ifndef CARDINAL_TRANSPARENT_SCREENSHOTS | 
		
	
		
			
			|  |  |  | #ifdef CARDINAL_TRANSPARENT_SCREENSHOTS | 
		
	
		
			
			|  |  |  | constexpr const int depth = 4; | 
		
	
		
			
			|  |  |  | #else | 
		
	
		
			
			|  |  |  | y = APP->scene->menuBar->box.size.y * newPixelRatio; | 
		
	
		
			
			|  |  |  | constexpr const int depth = 3; | 
		
	
		
			
			|  |  |  | #endif | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | // Allocate pixel color buffer | 
		
	
		
			
			|  |  |  | uint8_t* const pixels = new uint8_t[winHeight * winWidth * 4]; | 
		
	
		
			
			|  |  |  | uint8_t* const pixels = new uint8_t[winHeight * winWidth * depth]; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | // 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); | 
		
	
		
			
			|  |  |  | glReadPixels(0, 0, winWidth, winHeight, depth == 3 ? GL_RGB : 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); | 
		
	
		
			
			|  |  |  | const int stride = winWidth * depth; | 
		
	
		
			
			|  |  |  | uint8_t* const pixelsWithOffset = pixels + (stride * y); | 
		
	
		
			
			|  |  |  | Window__flipBitmap(pixels, winWidth, winHeight, depth); | 
		
	
		
			
			|  |  |  | winHeight -= y; | 
		
	
		
			
			|  |  |  | #ifdef STBI_WRITE_NO_STDIO | 
		
	
		
			
			|  |  |  | Window__downscaleBitmap(pixelsWithOffset, winWidth, winHeight); | 
		
	
		
			
			|  |  |  | stbi_write_png_to_func(Window__writeImagePNG, internal->ui, | 
		
	
		
			
			|  |  |  | winWidth, winHeight - y, 4, pixelsWithOffset, stride); | 
		
	
		
			
			|  |  |  | winWidth, winHeight, depth, pixelsWithOffset, stride); | 
		
	
		
			
			|  |  |  | #else | 
		
	
		
			
			|  |  |  | stbi_write_png("screenshot.png", winWidth, winHeight - y, 4, pixelsWithOffset, stride); | 
		
	
		
			
			|  |  |  | stbi_write_png("screenshot.png", winWidth, winHeight, depth, pixelsWithOffset, stride); | 
		
	
		
			
			|  |  |  | #endif | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | internal->generateScreenshotStep = kScreenshotStepNone; | 
		
	
	
		
			
				|  |  | 
 |