| @@ -382,6 +382,13 @@ public: | |||||
| */ | */ | ||||
| void repaint(const Rectangle<uint>& rect) noexcept; | void repaint(const Rectangle<uint>& rect) noexcept; | ||||
| /** | |||||
| Render this window's content into a picture file, specified by @a filename. | |||||
| Window must be visible and on screen. | |||||
| Written picture format is PPM. | |||||
| */ | |||||
| void renderToPicture(const char* filename); | |||||
| /** | /** | ||||
| Run this window as a modal, blocking input events from the parent. | Run this window as a modal, blocking input events from the parent. | ||||
| Only valid for windows that have been created with another window as parent (as passed in the constructor). | Only valid for windows that have been created with another window as parent (as passed in the constructor). | ||||
| @@ -808,6 +808,13 @@ void TopLevelWidget::PrivateData::display() | |||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| void Window::PrivateData::renderToPicture(const char*, const GraphicsContext&, uint, uint) | |||||
| { | |||||
| notImplemented("Window::PrivateData::renderToPicture"); | |||||
| } | |||||
| // ----------------------------------------------------------------------- | |||||
| const GraphicsContext& Window::PrivateData::getGraphicsContext() const noexcept | const GraphicsContext& Window::PrivateData::getGraphicsContext() const noexcept | ||||
| { | { | ||||
| GraphicsContext& context((GraphicsContext&)graphicsContext); | GraphicsContext& context((GraphicsContext&)graphicsContext); | ||||
| @@ -667,6 +667,34 @@ void TopLevelWidget::PrivateData::display() | |||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| void Window::PrivateData::renderToPicture(const char* const filename, | |||||
| const GraphicsContext&, | |||||
| const uint width, | |||||
| const uint height) | |||||
| { | |||||
| FILE* const f = fopen(filename, "w"); | |||||
| DISTRHO_SAFE_ASSERT_RETURN(f != nullptr,); | |||||
| GLubyte* const pixels = new GLubyte[width * height * 3 * sizeof(GLubyte)]; | |||||
| glFlush(); | |||||
| glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels); | |||||
| fprintf(f, "P3\n%d %d\n255\n", width, height); | |||||
| for (uint y = 0; y < height; y++) { | |||||
| for (uint i, x = 0; x < width; x++) { | |||||
| i = 3 * ((height - y - 1) * width + x); | |||||
| fprintf(f, "%3d %3d %3d ", pixels[i], pixels[i+1], pixels[i+2]); | |||||
| } | |||||
| fprintf(f, "\n"); | |||||
| } | |||||
| delete[] pixels; | |||||
| fclose(f); | |||||
| } | |||||
| // ----------------------------------------------------------------------- | |||||
| const GraphicsContext& Window::PrivateData::getGraphicsContext() const noexcept | const GraphicsContext& Window::PrivateData::getGraphicsContext() const noexcept | ||||
| { | { | ||||
| return (const GraphicsContext&)graphicsContext; | return (const GraphicsContext&)graphicsContext; | ||||
| @@ -231,6 +231,13 @@ void TopLevelWidget::PrivateData::display() | |||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| void Window::PrivateData::renderToPicture(const char*, const GraphicsContext&, uint, uint) | |||||
| { | |||||
| notImplemented("Window::PrivateData::renderToPicture"); | |||||
| } | |||||
| // ----------------------------------------------------------------------- | |||||
| const GraphicsContext& Window::PrivateData::getGraphicsContext() const noexcept | const GraphicsContext& Window::PrivateData::getGraphicsContext() const noexcept | ||||
| { | { | ||||
| return (const GraphicsContext&)graphicsContext; | return (const GraphicsContext&)graphicsContext; | ||||
| @@ -336,6 +336,11 @@ void Window::repaint(const Rectangle<uint>& rect) noexcept | |||||
| puglPostRedisplayRect(pData->view, prect); | puglPostRedisplayRect(pData->view, prect); | ||||
| } | } | ||||
| void Window::renderToPicture(const char* const filename) | |||||
| { | |||||
| pData->filenameToRenderInto = strdup(filename); | |||||
| } | |||||
| void Window::runAsModal(bool blockWait) | void Window::runAsModal(bool blockWait) | ||||
| { | { | ||||
| pData->runAsModal(blockWait); | pData->runAsModal(blockWait); | ||||
| @@ -95,6 +95,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s) | |||||
| minHeight(0), | minHeight(0), | ||||
| keepAspectRatio(false), | keepAspectRatio(false), | ||||
| ignoreIdleCallbacks(false), | ignoreIdleCallbacks(false), | ||||
| filenameToRenderInto(nullptr), | |||||
| #ifdef DISTRHO_OS_WINDOWS | #ifdef DISTRHO_OS_WINDOWS | ||||
| win32SelectedFile(nullptr), | win32SelectedFile(nullptr), | ||||
| #endif | #endif | ||||
| @@ -120,6 +121,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, PrivateData* c | |||||
| minHeight(0), | minHeight(0), | ||||
| keepAspectRatio(false), | keepAspectRatio(false), | ||||
| ignoreIdleCallbacks(false), | ignoreIdleCallbacks(false), | ||||
| filenameToRenderInto(nullptr), | |||||
| #ifdef DISTRHO_OS_WINDOWS | #ifdef DISTRHO_OS_WINDOWS | ||||
| win32SelectedFile(nullptr), | win32SelectedFile(nullptr), | ||||
| #endif | #endif | ||||
| @@ -149,6 +151,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, | |||||
| minHeight(0), | minHeight(0), | ||||
| keepAspectRatio(false), | keepAspectRatio(false), | ||||
| ignoreIdleCallbacks(false), | ignoreIdleCallbacks(false), | ||||
| filenameToRenderInto(nullptr), | |||||
| #ifdef DISTRHO_OS_WINDOWS | #ifdef DISTRHO_OS_WINDOWS | ||||
| win32SelectedFile(nullptr), | win32SelectedFile(nullptr), | ||||
| #endif | #endif | ||||
| @@ -180,6 +183,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, | |||||
| minHeight(0), | minHeight(0), | ||||
| keepAspectRatio(false), | keepAspectRatio(false), | ||||
| ignoreIdleCallbacks(false), | ignoreIdleCallbacks(false), | ||||
| filenameToRenderInto(nullptr), | |||||
| #ifdef DISTRHO_OS_WINDOWS | #ifdef DISTRHO_OS_WINDOWS | ||||
| win32SelectedFile(nullptr), | win32SelectedFile(nullptr), | ||||
| #endif | #endif | ||||
| @@ -195,6 +199,7 @@ Window::PrivateData::~PrivateData() | |||||
| { | { | ||||
| appData->idleCallbacks.remove(this); | appData->idleCallbacks.remove(this); | ||||
| appData->windows.remove(self); | appData->windows.remove(self); | ||||
| std::free(filenameToRenderInto); | |||||
| if (view == nullptr) | if (view == nullptr) | ||||
| return; | return; | ||||
| @@ -744,6 +749,14 @@ void Window::PrivateData::onPuglExpose() | |||||
| widget->pData->display(); | widget->pData->display(); | ||||
| } | } | ||||
| #endif | #endif | ||||
| if (char* const filename = filenameToRenderInto) | |||||
| { | |||||
| const PuglRect rect = puglGetFrame(view); | |||||
| filenameToRenderInto = nullptr; | |||||
| renderToPicture(filename, getGraphicsContext(), static_cast<uint>(rect.width), static_cast<uint>(rect.height)); | |||||
| std::free(filename); | |||||
| } | |||||
| } | } | ||||
| void Window::PrivateData::onPuglClose() | void Window::PrivateData::onPuglClose() | ||||
| @@ -77,6 +77,9 @@ struct Window::PrivateData : IdleCallback { | |||||
| /** Whether to ignore idle callback requests, useful for temporary windows. */ | /** Whether to ignore idle callback requests, useful for temporary windows. */ | ||||
| bool ignoreIdleCallbacks; | bool ignoreIdleCallbacks; | ||||
| /** Render to a picture file when non-null, automatically free+unset after saving. */ | |||||
| char* filenameToRenderInto; | |||||
| #ifdef DISTRHO_OS_WINDOWS | #ifdef DISTRHO_OS_WINDOWS | ||||
| /** Selected file for openFileBrowser on windows, stored for fake async operation. */ | /** Selected file for openFileBrowser on windows, stored for fake async operation. */ | ||||
| const char* win32SelectedFile; | const char* win32SelectedFile; | ||||
| @@ -162,6 +165,8 @@ struct Window::PrivateData : IdleCallback { | |||||
| # endif | # endif | ||||
| #endif | #endif | ||||
| static void renderToPicture(const char* filename, const GraphicsContext& context, uint width, uint height); | |||||
| // modal handling | // modal handling | ||||
| void startModal(); | void startModal(); | ||||
| void stopModal(); | void stopModal(); | ||||