Cleanup
[carla.git] / source / modules / dgl / src / OpenGL.cpp
blobb742637016417eb87fb47b279942f4786843d3b3
1 /*
2 * DISTRHO Plugin Framework (DPF)
3 * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
5 * Permission to use, copy, modify, and/or distribute this software for any purpose with
6 * or without fee is hereby granted, provided that the above copyright notice and this
7 * permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
10 * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
11 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
12 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
13 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #ifdef _MSC_VER
18 // instantiated template classes whose methods are defined elsewhere
19 # pragma warning(disable:4661)
20 #endif
22 #include "../OpenGL.hpp"
23 #include "../Color.hpp"
24 #include "../ImageWidgets.hpp"
26 #include "SubWidgetPrivateData.hpp"
27 #include "TopLevelWidgetPrivateData.hpp"
28 #include "WidgetPrivateData.hpp"
29 #include "WindowPrivateData.hpp"
31 // templated classes
32 #include "ImageBaseWidgets.cpp"
34 START_NAMESPACE_DGL
36 // -----------------------------------------------------------------------
38 #if defined(DGL_USE_GLES2)
39 static void notImplemented(const char* const name)
41 // d_stderr2("GLES2 function not implemented: %s", name);
43 #elif defined(DGL_USE_GLES3)
44 static void notImplemented(const char* const name)
46 d_stderr2("GLES3 function not implemented: %s", name);
48 #elif defined(DGL_USE_OPENGL3)
49 static void notImplemented(const char* const name)
51 d_stderr2("OpenGL3 function not implemented: %s", name);
53 #else
54 # define DGL_USE_COMPAT_OPENGL
55 #endif
57 // -----------------------------------------------------------------------
58 // Color
60 void Color::setFor(const GraphicsContext&, const bool includeAlpha)
62 #ifdef DGL_USE_COMPAT_OPENGL
63 if (includeAlpha)
64 glColor4f(red, green, blue, alpha);
65 else
66 glColor3f(red, green, blue);
67 #else
68 notImplemented("Color::setFor");
69 // unused
70 (void)includeAlpha;
71 #endif
74 // -----------------------------------------------------------------------
75 // Line
77 #ifdef DGL_USE_COMPAT_OPENGL
78 template<typename T>
79 static void drawLine(const Point<T>& posStart, const Point<T>& posEnd)
81 DISTRHO_SAFE_ASSERT_RETURN(posStart != posEnd,);
83 glBegin(GL_LINES);
86 glVertex2d(posStart.getX(), posStart.getY());
87 glVertex2d(posEnd.getX(), posEnd.getY());
90 glEnd();
92 #endif
94 template<typename T>
95 void Line<T>::draw(const GraphicsContext&, const T width)
97 #ifdef DGL_USE_COMPAT_OPENGL
98 DISTRHO_SAFE_ASSERT_RETURN(width != 0,);
100 glLineWidth(static_cast<GLfloat>(width));
101 drawLine<T>(posStart, posEnd);
102 #else
103 notImplemented("Line::draw");
104 #endif
107 // deprecated calls
108 template<typename T>
109 void Line<T>::draw()
111 #ifdef DGL_USE_COMPAT_OPENGL
112 drawLine<T>(posStart, posEnd);
113 #else
114 notImplemented("Line::draw");
115 #endif
118 template class Line<double>;
119 template class Line<float>;
120 template class Line<int>;
121 template class Line<uint>;
122 template class Line<short>;
123 template class Line<ushort>;
125 // -----------------------------------------------------------------------
126 // Circle
128 #ifdef DGL_USE_COMPAT_OPENGL
129 template<typename T>
130 static void drawCircle(const Point<T>& pos,
131 const uint numSegments,
132 const float size,
133 const float sin,
134 const float cos,
135 const bool outline)
137 DISTRHO_SAFE_ASSERT_RETURN(numSegments >= 3 && size > 0.0f,);
139 const T origx = pos.getX();
140 const T origy = pos.getY();
141 double t, x = size, y = 0.0;
143 glBegin(outline ? GL_LINE_LOOP : GL_POLYGON);
145 for (uint i=0; i<numSegments; ++i)
147 glVertex2d(x + origx, y + origy);
149 t = x;
150 x = cos * x - sin * y;
151 y = sin * t + cos * y;
154 glEnd();
156 #endif
158 template<typename T>
159 void Circle<T>::draw(const GraphicsContext&)
161 #ifdef DGL_USE_COMPAT_OPENGL
162 drawCircle<T>(fPos, fNumSegments, fSize, fSin, fCos, false);
163 #else
164 notImplemented("Circle::draw");
165 #endif
168 template<typename T>
169 void Circle<T>::drawOutline(const GraphicsContext&, const T lineWidth)
171 DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,);
173 glLineWidth(static_cast<GLfloat>(lineWidth));
174 #ifdef DGL_USE_COMPAT_OPENGL
175 drawCircle<T>(fPos, fNumSegments, fSize, fSin, fCos, true);
176 #else
177 notImplemented("Circle::drawOutline");
178 #endif
181 // deprecated calls
182 template<typename T>
183 void Circle<T>::draw()
185 #ifdef DGL_USE_COMPAT_OPENGL
186 drawCircle<T>(fPos, fNumSegments, fSize, fSin, fCos, false);
187 #else
188 notImplemented("Circle::draw");
189 #endif
192 template<typename T>
193 void Circle<T>::drawOutline()
195 #ifdef DGL_USE_COMPAT_OPENGL
196 drawCircle<T>(fPos, fNumSegments, fSize, fSin, fCos, true);
197 #else
198 notImplemented("Circle::drawOutline");
199 #endif
202 template class Circle<double>;
203 template class Circle<float>;
204 template class Circle<int>;
205 template class Circle<uint>;
206 template class Circle<short>;
207 template class Circle<ushort>;
209 // -----------------------------------------------------------------------
210 // Triangle
212 #ifdef DGL_USE_COMPAT_OPENGL
213 template<typename T>
214 static void drawTriangle(const Point<T>& pos1,
215 const Point<T>& pos2,
216 const Point<T>& pos3,
217 const bool outline)
219 DISTRHO_SAFE_ASSERT_RETURN(pos1 != pos2 && pos1 != pos3,);
221 glBegin(outline ? GL_LINE_LOOP : GL_TRIANGLES);
224 glVertex2d(pos1.getX(), pos1.getY());
225 glVertex2d(pos2.getX(), pos2.getY());
226 glVertex2d(pos3.getX(), pos3.getY());
229 glEnd();
231 #endif
233 template<typename T>
234 void Triangle<T>::draw(const GraphicsContext&)
236 #ifdef DGL_USE_COMPAT_OPENGL
237 drawTriangle<T>(pos1, pos2, pos3, false);
238 #else
239 notImplemented("Triangle::draw");
240 #endif
243 template<typename T>
244 void Triangle<T>::drawOutline(const GraphicsContext&, const T lineWidth)
246 DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,);
248 glLineWidth(static_cast<GLfloat>(lineWidth));
249 #ifdef DGL_USE_COMPAT_OPENGL
250 drawTriangle<T>(pos1, pos2, pos3, true);
251 #else
252 notImplemented("Triangle::drawOutline");
253 #endif
256 // deprecated calls
257 template<typename T>
258 void Triangle<T>::draw()
260 #ifdef DGL_USE_COMPAT_OPENGL
261 drawTriangle<T>(pos1, pos2, pos3, false);
262 #else
263 notImplemented("Triangle::draw");
264 #endif
267 template<typename T>
268 void Triangle<T>::drawOutline()
270 #ifdef DGL_USE_COMPAT_OPENGL
271 drawTriangle<T>(pos1, pos2, pos3, true);
272 #else
273 notImplemented("Triangle::drawOutline");
274 #endif
277 template class Triangle<double>;
278 template class Triangle<float>;
279 template class Triangle<int>;
280 template class Triangle<uint>;
281 template class Triangle<short>;
282 template class Triangle<ushort>;
284 // -----------------------------------------------------------------------
285 // Rectangle
287 #ifdef DGL_USE_COMPAT_OPENGL
288 template<typename T>
289 static void drawRectangle(const Rectangle<T>& rect, const bool outline)
291 DISTRHO_SAFE_ASSERT_RETURN(rect.isValid(),);
293 glBegin(outline ? GL_LINE_LOOP : GL_QUADS);
296 const T x = rect.getX();
297 const T y = rect.getY();
298 const T w = rect.getWidth();
299 const T h = rect.getHeight();
301 glTexCoord2f(0.0f, 0.0f);
302 glVertex2d(x, y);
304 glTexCoord2f(1.0f, 0.0f);
305 glVertex2d(x+w, y);
307 glTexCoord2f(1.0f, 1.0f);
308 glVertex2d(x+w, y+h);
310 glTexCoord2f(0.0f, 1.0f);
311 glVertex2d(x, y+h);
314 glEnd();
316 #endif
318 template<typename T>
319 void Rectangle<T>::draw(const GraphicsContext&)
321 #ifdef DGL_USE_COMPAT_OPENGL
322 drawRectangle<T>(*this, false);
323 #else
324 notImplemented("Rectangle::draw");
325 #endif
328 template<typename T>
329 void Rectangle<T>::drawOutline(const GraphicsContext&, const T lineWidth)
331 DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,);
333 glLineWidth(static_cast<GLfloat>(lineWidth));
334 #ifdef DGL_USE_COMPAT_OPENGL
335 drawRectangle<T>(*this, true);
336 #else
337 notImplemented("Rectangle::drawOutline");
338 #endif
341 // deprecated calls
342 template<typename T>
343 void Rectangle<T>::draw()
345 #ifdef DGL_USE_COMPAT_OPENGL
346 drawRectangle<T>(*this, false);
347 #else
348 notImplemented("Rectangle::draw");
349 #endif
352 template<typename T>
353 void Rectangle<T>::drawOutline()
355 #ifdef DGL_USE_COMPAT_OPENGL
356 drawRectangle<T>(*this, true);
357 #else
358 notImplemented("Rectangle::drawOutline");
359 #endif
362 template class Rectangle<double>;
363 template class Rectangle<float>;
364 template class Rectangle<int>;
365 template class Rectangle<uint>;
366 template class Rectangle<short>;
367 template class Rectangle<ushort>;
369 // -----------------------------------------------------------------------
370 // OpenGLImage
372 static void setupOpenGLImage(const OpenGLImage& image, GLuint textureId)
374 DISTRHO_SAFE_ASSERT_RETURN(image.isValid(),);
376 glEnable(GL_TEXTURE_2D);
377 glBindTexture(GL_TEXTURE_2D, textureId);
379 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
380 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
381 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
382 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
384 static const float trans[] = { 0.0f, 0.0f, 0.0f, 0.0f };
385 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, trans);
387 glPixelStorei(GL_PACK_ALIGNMENT, 1);
388 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
389 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
390 static_cast<GLsizei>(image.getWidth()),
391 static_cast<GLsizei>(image.getHeight()),
393 asOpenGLImageFormat(image.getFormat()), GL_UNSIGNED_BYTE, image.getRawData());
395 glBindTexture(GL_TEXTURE_2D, 0);
396 glDisable(GL_TEXTURE_2D);
399 static void drawOpenGLImage(const OpenGLImage& image, const Point<int>& pos, const GLuint textureId, bool& setupCalled)
401 if (textureId == 0 || image.isInvalid())
402 return;
404 if (! setupCalled)
406 setupOpenGLImage(image, textureId);
407 setupCalled = true;
410 #ifdef DGL_USE_COMPAT_OPENGL
411 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
412 #endif
414 glEnable(GL_TEXTURE_2D);
415 glBindTexture(GL_TEXTURE_2D, textureId);
417 #ifdef DGL_USE_COMPAT_OPENGL
418 glBegin(GL_QUADS);
421 const int x = pos.getX();
422 const int y = pos.getY();
423 const int w = static_cast<int>(image.getWidth());
424 const int h = static_cast<int>(image.getHeight());
426 glTexCoord2f(0.0f, 0.0f);
427 glVertex2d(x, y);
429 glTexCoord2f(1.0f, 0.0f);
430 glVertex2d(x+w, y);
432 glTexCoord2f(1.0f, 1.0f);
433 glVertex2d(x+w, y+h);
435 glTexCoord2f(0.0f, 1.0f);
436 glVertex2d(x, y+h);
439 glEnd();
440 #endif
442 glBindTexture(GL_TEXTURE_2D, 0);
443 glDisable(GL_TEXTURE_2D);
446 OpenGLImage::OpenGLImage()
447 : ImageBase(),
448 textureId(0),
449 setupCalled(false)
451 glGenTextures(1, &textureId);
452 DISTRHO_SAFE_ASSERT(textureId != 0);
455 OpenGLImage::OpenGLImage(const char* const rdata, const uint w, const uint h, const ImageFormat fmt)
456 : ImageBase(rdata, w, h, fmt),
457 textureId(0),
458 setupCalled(false)
460 glGenTextures(1, &textureId);
461 DISTRHO_SAFE_ASSERT(textureId != 0);
464 OpenGLImage::OpenGLImage(const char* const rdata, const Size<uint>& s, const ImageFormat fmt)
465 : ImageBase(rdata, s, fmt),
466 textureId(0),
467 setupCalled(false)
469 glGenTextures(1, &textureId);
470 DISTRHO_SAFE_ASSERT(textureId != 0);
473 OpenGLImage::OpenGLImage(const OpenGLImage& image)
474 : ImageBase(image),
475 textureId(0),
476 setupCalled(false)
478 glGenTextures(1, &textureId);
479 DISTRHO_SAFE_ASSERT(textureId != 0);
482 OpenGLImage::~OpenGLImage()
484 if (textureId != 0)
485 glDeleteTextures(1, &textureId);
488 void OpenGLImage::loadFromMemory(const char* const rdata, const Size<uint>& s, const ImageFormat fmt) noexcept
490 setupCalled = false;
491 ImageBase::loadFromMemory(rdata, s, fmt);
494 void OpenGLImage::drawAt(const GraphicsContext&, const Point<int>& pos)
496 drawOpenGLImage(*this, pos, textureId, setupCalled);
499 OpenGLImage& OpenGLImage::operator=(const OpenGLImage& image) noexcept
501 rawData = image.rawData;
502 size = image.size;
503 format = image.format;
504 setupCalled = false;
505 return *this;
508 // deprecated calls
509 OpenGLImage::OpenGLImage(const char* const rdata, const uint w, const uint h, const GLenum fmt)
510 : ImageBase(rdata, w, h, asDISTRHOImageFormat(fmt)),
511 textureId(0),
512 setupCalled(false)
514 glGenTextures(1, &textureId);
515 DISTRHO_SAFE_ASSERT(textureId != 0);
518 OpenGLImage::OpenGLImage(const char* const rdata, const Size<uint>& s, const GLenum fmt)
519 : ImageBase(rdata, s, asDISTRHOImageFormat(fmt)),
520 textureId(0),
521 setupCalled(false)
523 glGenTextures(1, &textureId);
524 DISTRHO_SAFE_ASSERT(textureId != 0);
527 void OpenGLImage::draw()
529 drawOpenGLImage(*this, Point<int>(0, 0), textureId, setupCalled);
532 void OpenGLImage::drawAt(const int x, const int y)
534 drawOpenGLImage(*this, Point<int>(x, y), textureId, setupCalled);
537 void OpenGLImage::drawAt(const Point<int>& pos)
539 drawOpenGLImage(*this, pos, textureId, setupCalled);
542 // -----------------------------------------------------------------------
543 // ImageBaseAboutWindow
545 #if 0
546 template <>
547 void ImageBaseAboutWindow<OpenGLImage>::onDisplay()
549 const GraphicsContext& context(getGraphicsContext());
550 img.draw(context);
552 #endif
554 template class ImageBaseAboutWindow<OpenGLImage>;
556 // -----------------------------------------------------------------------
557 // ImageBaseButton
559 template class ImageBaseButton<OpenGLImage>;
561 // -----------------------------------------------------------------------
562 // ImageBaseKnob
564 template <>
565 void ImageBaseKnob<OpenGLImage>::PrivateData::init()
567 glTextureId = 0;
568 glGenTextures(1, &glTextureId);
571 template <>
572 void ImageBaseKnob<OpenGLImage>::PrivateData::cleanup()
574 if (glTextureId == 0)
575 return;
577 glDeleteTextures(1, &glTextureId);
578 glTextureId = 0;
581 template <>
582 void ImageBaseKnob<OpenGLImage>::onDisplay()
584 const GraphicsContext& context(getGraphicsContext());
585 const float normValue = getNormalizedValue();
587 glEnable(GL_TEXTURE_2D);
588 glBindTexture(GL_TEXTURE_2D, pData->glTextureId);
590 if (! pData->isReady)
592 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
593 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
594 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
595 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
597 static const float trans[] = { 0.0f, 0.0f, 0.0f, 0.0f };
598 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, trans);
600 glPixelStorei(GL_PACK_ALIGNMENT, 1);
601 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
603 uint imageDataOffset = 0;
605 if (pData->rotationAngle == 0)
607 DISTRHO_SAFE_ASSERT_RETURN(pData->imgLayerCount > 0,);
608 DISTRHO_SAFE_ASSERT_RETURN(normValue >= 0.0f,);
610 const uint& v1(pData->isImgVertical ? pData->imgLayerWidth : pData->imgLayerHeight);
611 const uint& v2(pData->isImgVertical ? pData->imgLayerHeight : pData->imgLayerWidth);
613 // TODO kImageFormatGreyscale
614 const uint layerDataSize = v1 * v2 * ((pData->image.getFormat() == kImageFormatBGRA ||
615 pData->image.getFormat() == kImageFormatRGBA) ? 4 : 3);
616 /* */ imageDataOffset = layerDataSize * uint(normValue * float(pData->imgLayerCount-1));
619 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
620 static_cast<GLsizei>(getWidth()), static_cast<GLsizei>(getHeight()), 0,
621 asOpenGLImageFormat(pData->image.getFormat()), GL_UNSIGNED_BYTE, pData->image.getRawData() + imageDataOffset);
623 pData->isReady = true;
626 const int w = static_cast<int>(getWidth());
627 const int h = static_cast<int>(getHeight());
629 if (pData->rotationAngle != 0)
631 #ifdef DGL_USE_COMPAT_OPENGL
632 glPushMatrix();
633 #endif
635 const int w2 = w/2;
636 const int h2 = h/2;
638 #ifdef DGL_USE_COMPAT_OPENGL
639 glTranslatef(static_cast<float>(w2), static_cast<float>(h2), 0.0f);
640 glRotatef(normValue*static_cast<float>(pData->rotationAngle), 0.0f, 0.0f, 1.0f);
641 #endif
643 Rectangle<int>(-w2, -h2, w, h).draw(context);
645 #ifdef DGL_USE_COMPAT_OPENGL
646 glPopMatrix();
647 #endif
649 else
651 Rectangle<int>(0, 0, w, h).draw(context);
654 glBindTexture(GL_TEXTURE_2D, 0);
655 glDisable(GL_TEXTURE_2D);
658 template class ImageBaseKnob<OpenGLImage>;
660 // -----------------------------------------------------------------------
661 // ImageBaseSlider
663 template class ImageBaseSlider<OpenGLImage>;
665 // -----------------------------------------------------------------------
666 // ImageBaseSwitch
668 template class ImageBaseSwitch<OpenGLImage>;
670 // -----------------------------------------------------------------------
672 void SubWidget::PrivateData::display(const uint width, const uint height, const double autoScaleFactor)
674 if (skipDrawing)
675 return;
677 bool needsDisableScissor = false;
679 if (needsViewportScaling)
681 // limit viewport to widget bounds
682 const int x = absolutePos.getX();
683 const int w = static_cast<int>(self->getWidth());
684 const int h = static_cast<int>(self->getHeight());
686 if (viewportScaleFactor != 0.0 && viewportScaleFactor != 1.0)
688 glViewport(x,
689 -static_cast<int>(height * viewportScaleFactor - height + absolutePos.getY() + 0.5),
690 static_cast<int>(width * viewportScaleFactor + 0.5),
691 static_cast<int>(height * viewportScaleFactor + 0.5));
693 else
695 const int y = static_cast<int>(height - self->getHeight()) - absolutePos.getY();
696 glViewport(x, y, w, h);
699 else if (needsFullViewportForDrawing || (absolutePos.isZero() && self->getSize() == Size<uint>(width, height)))
701 // full viewport size
702 glViewport(0,
703 -static_cast<int>(height * autoScaleFactor - height + 0.5),
704 static_cast<int>(width * autoScaleFactor + 0.5),
705 static_cast<int>(height * autoScaleFactor + 0.5));
707 else
709 // set viewport pos
710 glViewport(static_cast<int>(absolutePos.getX() * autoScaleFactor + 0.5),
711 -static_cast<int>(std::round((height * autoScaleFactor - height)
712 + (absolutePos.getY() * autoScaleFactor))),
713 static_cast<int>(std::round(width * autoScaleFactor)),
714 static_cast<int>(std::round(height * autoScaleFactor)));
716 // then cut the outer bounds
717 glScissor(static_cast<int>(absolutePos.getX() * autoScaleFactor + 0.5),
718 static_cast<int>(height - std::round((static_cast<int>(self->getHeight()) + absolutePos.getY())
719 * autoScaleFactor)),
720 static_cast<int>(std::round(self->getWidth() * autoScaleFactor)),
721 static_cast<int>(std::round(self->getHeight() * autoScaleFactor)));
723 glEnable(GL_SCISSOR_TEST);
724 needsDisableScissor = true;
727 // display widget
728 self->onDisplay();
730 if (needsDisableScissor)
731 glDisable(GL_SCISSOR_TEST);
733 selfw->pData->displaySubWidgets(width, height, autoScaleFactor);
736 // -----------------------------------------------------------------------
738 void TopLevelWidget::PrivateData::display()
740 if (! selfw->pData->visible)
741 return;
743 const Size<uint> size(window.getSize());
744 const uint width = size.getWidth();
745 const uint height = size.getHeight();
747 const double autoScaleFactor = window.pData->autoScaleFactor;
749 // full viewport size
750 if (window.pData->autoScaling)
752 glViewport(0,
753 -static_cast<int>(height * autoScaleFactor - height + 0.5),
754 static_cast<int>(width * autoScaleFactor + 0.5),
755 static_cast<int>(height * autoScaleFactor + 0.5));
757 else
759 glViewport(0, 0, static_cast<int>(width), static_cast<int>(height));
762 // main widget drawing
763 self->onDisplay();
765 // now draw subwidgets if there are any
766 selfw->pData->displaySubWidgets(width, height, autoScaleFactor);
769 // -----------------------------------------------------------------------
771 void Window::PrivateData::renderToPicture(const char* const filename,
772 const GraphicsContext&,
773 const uint width,
774 const uint height)
776 FILE* const f = fopen(filename, "w");
777 DISTRHO_SAFE_ASSERT_RETURN(f != nullptr,);
779 GLubyte* const pixels = new GLubyte[width * height * 3 * sizeof(GLubyte)];
781 glFlush();
782 glReadPixels(0, 0, static_cast<GLsizei>(width), static_cast<GLsizei>(height), GL_RGB, GL_UNSIGNED_BYTE, pixels);
784 fprintf(f, "P3\n%d %d\n255\n", width, height);
785 for (uint y = 0; y < height; y++)
787 for (uint i, x = 0; x < width; x++)
789 i = 3 * ((height - y - 1) * width + x);
790 fprintf(f, "%3d %3d %3d ", pixels[i], pixels[i+1], pixels[i+2]);
792 fprintf(f, "\n");
795 delete[] pixels;
796 fclose(f);
799 // -----------------------------------------------------------------------
801 const GraphicsContext& Window::PrivateData::getGraphicsContext() const noexcept
803 return (const GraphicsContext&)graphicsContext;
806 // -----------------------------------------------------------------------
808 END_NAMESPACE_DGL