comparison DPF-Prymula-audioplugins/dpf/dgl/src/OpenGL.cpp @ 3:84e66ea83026

DPF-Prymula-audioplugins-0.231015-2
author prymula <prymula76@outlook.com>
date Mon, 16 Oct 2023 21:53:34 +0200
parents
children
comparison
equal deleted inserted replaced
2:cf2cb71d31dd 3:84e66ea83026
1 /*
2 * DISTRHO Plugin Framework (DPF)
3 * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
4 *
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.
8 *
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.
15 */
16
17 #ifdef _MSC_VER
18 // instantiated template classes whose methods are defined elsewhere
19 # pragma warning(disable:4661)
20 #endif
21
22 #include "../OpenGL.hpp"
23 #include "../Color.hpp"
24 #include "../ImageWidgets.hpp"
25
26 #include "SubWidgetPrivateData.hpp"
27 #include "TopLevelWidgetPrivateData.hpp"
28 #include "WidgetPrivateData.hpp"
29 #include "WindowPrivateData.hpp"
30
31 // templated classes
32 #include "ImageBaseWidgets.cpp"
33
34 START_NAMESPACE_DGL
35
36 // -----------------------------------------------------------------------
37
38 #ifdef DGL_USE_OPENGL3
39 static void notImplemented(const char* const name)
40 {
41 d_stderr2("OpenGL3 function not implemented: %s", name);
42 }
43 #else
44 # define DGL_USE_COMPAT_OPENGL
45 #endif
46
47 // -----------------------------------------------------------------------
48 // Color
49
50 void Color::setFor(const GraphicsContext&, const bool includeAlpha)
51 {
52 #ifdef DGL_USE_COMPAT_OPENGL
53 if (includeAlpha)
54 glColor4f(red, green, blue, alpha);
55 else
56 glColor3f(red, green, blue);
57 #else
58 notImplemented("Color::setFor");
59 // unused
60 (void)includeAlpha;
61 #endif
62 }
63
64 // -----------------------------------------------------------------------
65 // Line
66
67 #ifdef DGL_USE_COMPAT_OPENGL
68 template<typename T>
69 static void drawLine(const Point<T>& posStart, const Point<T>& posEnd)
70 {
71 DISTRHO_SAFE_ASSERT_RETURN(posStart != posEnd,);
72
73 glBegin(GL_LINES);
74
75 {
76 glVertex2d(posStart.getX(), posStart.getY());
77 glVertex2d(posEnd.getX(), posEnd.getY());
78 }
79
80 glEnd();
81 }
82 #endif
83
84 template<typename T>
85 void Line<T>::draw(const GraphicsContext&, const T width)
86 {
87 #ifdef DGL_USE_COMPAT_OPENGL
88 DISTRHO_SAFE_ASSERT_RETURN(width != 0,);
89
90 glLineWidth(static_cast<GLfloat>(width));
91 drawLine<T>(posStart, posEnd);
92 #else
93 notImplemented("Line::draw");
94 #endif
95 }
96
97 // deprecated calls
98 template<typename T>
99 void Line<T>::draw()
100 {
101 #ifdef DGL_USE_COMPAT_OPENGL
102 drawLine<T>(posStart, posEnd);
103 #else
104 notImplemented("Line::draw");
105 #endif
106 }
107
108 template class Line<double>;
109 template class Line<float>;
110 template class Line<int>;
111 template class Line<uint>;
112 template class Line<short>;
113 template class Line<ushort>;
114
115 // -----------------------------------------------------------------------
116 // Circle
117
118 #ifdef DGL_USE_COMPAT_OPENGL
119 template<typename T>
120 static void drawCircle(const Point<T>& pos,
121 const uint numSegments,
122 const float size,
123 const float sin,
124 const float cos,
125 const bool outline)
126 {
127 DISTRHO_SAFE_ASSERT_RETURN(numSegments >= 3 && size > 0.0f,);
128
129 const T origx = pos.getX();
130 const T origy = pos.getY();
131 double t, x = size, y = 0.0;
132
133 glBegin(outline ? GL_LINE_LOOP : GL_POLYGON);
134
135 for (uint i=0; i<numSegments; ++i)
136 {
137 glVertex2d(x + origx, y + origy);
138
139 t = x;
140 x = cos * x - sin * y;
141 y = sin * t + cos * y;
142 }
143
144 glEnd();
145 }
146 #endif
147
148 template<typename T>
149 void Circle<T>::draw(const GraphicsContext&)
150 {
151 #ifdef DGL_USE_COMPAT_OPENGL
152 drawCircle<T>(fPos, fNumSegments, fSize, fSin, fCos, false);
153 #else
154 notImplemented("Circle::draw");
155 #endif
156 }
157
158 template<typename T>
159 void Circle<T>::drawOutline(const GraphicsContext&, const T lineWidth)
160 {
161 DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,);
162
163 glLineWidth(static_cast<GLfloat>(lineWidth));
164 #ifdef DGL_USE_COMPAT_OPENGL
165 drawCircle<T>(fPos, fNumSegments, fSize, fSin, fCos, true);
166 #else
167 notImplemented("Circle::drawOutline");
168 #endif
169 }
170
171 // deprecated calls
172 template<typename T>
173 void Circle<T>::draw()
174 {
175 #ifdef DGL_USE_COMPAT_OPENGL
176 drawCircle<T>(fPos, fNumSegments, fSize, fSin, fCos, false);
177 #else
178 notImplemented("Circle::draw");
179 #endif
180 }
181
182 template<typename T>
183 void Circle<T>::drawOutline()
184 {
185 #ifdef DGL_USE_COMPAT_OPENGL
186 drawCircle<T>(fPos, fNumSegments, fSize, fSin, fCos, true);
187 #else
188 notImplemented("Circle::drawOutline");
189 #endif
190 }
191
192 template class Circle<double>;
193 template class Circle<float>;
194 template class Circle<int>;
195 template class Circle<uint>;
196 template class Circle<short>;
197 template class Circle<ushort>;
198
199 // -----------------------------------------------------------------------
200 // Triangle
201
202 #ifdef DGL_USE_COMPAT_OPENGL
203 template<typename T>
204 static void drawTriangle(const Point<T>& pos1,
205 const Point<T>& pos2,
206 const Point<T>& pos3,
207 const bool outline)
208 {
209 DISTRHO_SAFE_ASSERT_RETURN(pos1 != pos2 && pos1 != pos3,);
210
211 glBegin(outline ? GL_LINE_LOOP : GL_TRIANGLES);
212
213 {
214 glVertex2d(pos1.getX(), pos1.getY());
215 glVertex2d(pos2.getX(), pos2.getY());
216 glVertex2d(pos3.getX(), pos3.getY());
217 }
218
219 glEnd();
220 }
221 #endif
222
223 template<typename T>
224 void Triangle<T>::draw(const GraphicsContext&)
225 {
226 #ifdef DGL_USE_COMPAT_OPENGL
227 drawTriangle<T>(pos1, pos2, pos3, false);
228 #else
229 notImplemented("Triangle::draw");
230 #endif
231 }
232
233 template<typename T>
234 void Triangle<T>::drawOutline(const GraphicsContext&, const T lineWidth)
235 {
236 DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,);
237
238 glLineWidth(static_cast<GLfloat>(lineWidth));
239 #ifdef DGL_USE_COMPAT_OPENGL
240 drawTriangle<T>(pos1, pos2, pos3, true);
241 #else
242 notImplemented("Triangle::drawOutline");
243 #endif
244 }
245
246 // deprecated calls
247 template<typename T>
248 void Triangle<T>::draw()
249 {
250 #ifdef DGL_USE_COMPAT_OPENGL
251 drawTriangle<T>(pos1, pos2, pos3, false);
252 #else
253 notImplemented("Triangle::draw");
254 #endif
255 }
256
257 template<typename T>
258 void Triangle<T>::drawOutline()
259 {
260 #ifdef DGL_USE_COMPAT_OPENGL
261 drawTriangle<T>(pos1, pos2, pos3, true);
262 #else
263 notImplemented("Triangle::drawOutline");
264 #endif
265 }
266
267 template class Triangle<double>;
268 template class Triangle<float>;
269 template class Triangle<int>;
270 template class Triangle<uint>;
271 template class Triangle<short>;
272 template class Triangle<ushort>;
273
274 // -----------------------------------------------------------------------
275 // Rectangle
276
277 #ifdef DGL_USE_COMPAT_OPENGL
278 template<typename T>
279 static void drawRectangle(const Rectangle<T>& rect, const bool outline)
280 {
281 DISTRHO_SAFE_ASSERT_RETURN(rect.isValid(),);
282
283 glBegin(outline ? GL_LINE_LOOP : GL_QUADS);
284
285 {
286 const T x = rect.getX();
287 const T y = rect.getY();
288 const T w = rect.getWidth();
289 const T h = rect.getHeight();
290
291 glTexCoord2f(0.0f, 0.0f);
292 glVertex2d(x, y);
293
294 glTexCoord2f(1.0f, 0.0f);
295 glVertex2d(x+w, y);
296
297 glTexCoord2f(1.0f, 1.0f);
298 glVertex2d(x+w, y+h);
299
300 glTexCoord2f(0.0f, 1.0f);
301 glVertex2d(x, y+h);
302 }
303
304 glEnd();
305 }
306 #endif
307
308 template<typename T>
309 void Rectangle<T>::draw(const GraphicsContext&)
310 {
311 #ifdef DGL_USE_COMPAT_OPENGL
312 drawRectangle<T>(*this, false);
313 #else
314 notImplemented("Rectangle::draw");
315 #endif
316 }
317
318 template<typename T>
319 void Rectangle<T>::drawOutline(const GraphicsContext&, const T lineWidth)
320 {
321 DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,);
322
323 glLineWidth(static_cast<GLfloat>(lineWidth));
324 #ifdef DGL_USE_COMPAT_OPENGL
325 drawRectangle<T>(*this, true);
326 #else
327 notImplemented("Rectangle::drawOutline");
328 #endif
329 }
330
331 // deprecated calls
332 template<typename T>
333 void Rectangle<T>::draw()
334 {
335 #ifdef DGL_USE_COMPAT_OPENGL
336 drawRectangle<T>(*this, false);
337 #else
338 notImplemented("Rectangle::draw");
339 #endif
340 }
341
342 template<typename T>
343 void Rectangle<T>::drawOutline()
344 {
345 #ifdef DGL_USE_COMPAT_OPENGL
346 drawRectangle<T>(*this, true);
347 #else
348 notImplemented("Rectangle::drawOutline");
349 #endif
350 }
351
352 template class Rectangle<double>;
353 template class Rectangle<float>;
354 template class Rectangle<int>;
355 template class Rectangle<uint>;
356 template class Rectangle<short>;
357 template class Rectangle<ushort>;
358
359 // -----------------------------------------------------------------------
360 // OpenGLImage
361
362 static void setupOpenGLImage(const OpenGLImage& image, GLuint textureId)
363 {
364 DISTRHO_SAFE_ASSERT_RETURN(image.isValid(),);
365
366 glEnable(GL_TEXTURE_2D);
367 glBindTexture(GL_TEXTURE_2D, textureId);
368
369 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
370 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
371 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
372 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
373
374 static const float trans[] = { 0.0f, 0.0f, 0.0f, 0.0f };
375 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, trans);
376
377 glPixelStorei(GL_PACK_ALIGNMENT, 1);
378 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
379 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
380 static_cast<GLsizei>(image.getWidth()),
381 static_cast<GLsizei>(image.getHeight()),
382 0,
383 asOpenGLImageFormat(image.getFormat()), GL_UNSIGNED_BYTE, image.getRawData());
384
385 glBindTexture(GL_TEXTURE_2D, 0);
386 glDisable(GL_TEXTURE_2D);
387 }
388
389 static void drawOpenGLImage(const OpenGLImage& image, const Point<int>& pos, const GLuint textureId, bool& setupCalled)
390 {
391 if (textureId == 0 || image.isInvalid())
392 return;
393
394 if (! setupCalled)
395 {
396 setupOpenGLImage(image, textureId);
397 setupCalled = true;
398 }
399
400 #ifdef DGL_USE_COMPAT_OPENGL
401 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
402 #endif
403
404 glEnable(GL_TEXTURE_2D);
405 glBindTexture(GL_TEXTURE_2D, textureId);
406
407 #ifdef DGL_USE_COMPAT_OPENGL
408 glBegin(GL_QUADS);
409
410 {
411 const int x = pos.getX();
412 const int y = pos.getY();
413 const int w = static_cast<int>(image.getWidth());
414 const int h = static_cast<int>(image.getHeight());
415
416 glTexCoord2f(0.0f, 0.0f);
417 glVertex2d(x, y);
418
419 glTexCoord2f(1.0f, 0.0f);
420 glVertex2d(x+w, y);
421
422 glTexCoord2f(1.0f, 1.0f);
423 glVertex2d(x+w, y+h);
424
425 glTexCoord2f(0.0f, 1.0f);
426 glVertex2d(x, y+h);
427 }
428
429 glEnd();
430 #endif
431
432 glBindTexture(GL_TEXTURE_2D, 0);
433 glDisable(GL_TEXTURE_2D);
434 }
435
436 OpenGLImage::OpenGLImage()
437 : ImageBase(),
438 setupCalled(false),
439 textureInit(false),
440 textureId(0)
441 {
442 }
443
444 OpenGLImage::OpenGLImage(const char* const rdata, const uint w, const uint h, const ImageFormat fmt)
445 : ImageBase(rdata, w, h, fmt),
446 setupCalled(false),
447 textureInit(true),
448 textureId(0)
449 {
450 glGenTextures(1, &textureId);
451 DISTRHO_SAFE_ASSERT(textureId != 0);
452 }
453
454 OpenGLImage::OpenGLImage(const char* const rdata, const Size<uint>& s, const ImageFormat fmt)
455 : ImageBase(rdata, s, fmt),
456 setupCalled(false),
457 textureInit(true),
458 textureId(0)
459 {
460 glGenTextures(1, &textureId);
461 DISTRHO_SAFE_ASSERT(textureId != 0);
462 }
463
464 OpenGLImage::OpenGLImage(const OpenGLImage& image)
465 : ImageBase(image),
466 setupCalled(false),
467 textureInit(true),
468 textureId(0)
469 {
470 glGenTextures(1, &textureId);
471 DISTRHO_SAFE_ASSERT(textureId != 0);
472 }
473
474 OpenGLImage::~OpenGLImage()
475 {
476 if (textureId != 0)
477 glDeleteTextures(1, &textureId);
478 }
479
480 void OpenGLImage::loadFromMemory(const char* const rdata, const Size<uint>& s, const ImageFormat fmt) noexcept
481 {
482 if (!textureInit)
483 {
484 textureInit = true;
485 glGenTextures(1, &textureId);
486 DISTRHO_SAFE_ASSERT(textureId != 0);
487 }
488 setupCalled = false;
489 ImageBase::loadFromMemory(rdata, s, fmt);
490 }
491
492 void OpenGLImage::drawAt(const GraphicsContext&, const Point<int>& pos)
493 {
494 drawOpenGLImage(*this, pos, textureId, setupCalled);
495 }
496
497 OpenGLImage& OpenGLImage::operator=(const OpenGLImage& image) noexcept
498 {
499 rawData = image.rawData;
500 size = image.size;
501 format = image.format;
502 setupCalled = false;
503
504 if (image.isValid() && !textureInit)
505 {
506 textureInit = true;
507 glGenTextures(1, &textureId);
508 DISTRHO_SAFE_ASSERT(textureId != 0);
509 }
510
511 return *this;
512 }
513
514 // deprecated calls
515 OpenGLImage::OpenGLImage(const char* const rdata, const uint w, const uint h, const GLenum fmt)
516 : ImageBase(rdata, w, h, asDISTRHOImageFormat(fmt)),
517 setupCalled(false),
518 textureInit(true),
519 textureId(0)
520 {
521 glGenTextures(1, &textureId);
522 DISTRHO_SAFE_ASSERT(textureId != 0);
523 }
524
525 OpenGLImage::OpenGLImage(const char* const rdata, const Size<uint>& s, const GLenum fmt)
526 : ImageBase(rdata, s, asDISTRHOImageFormat(fmt)),
527 setupCalled(false),
528 textureInit(true),
529 textureId(0)
530 {
531 glGenTextures(1, &textureId);
532 DISTRHO_SAFE_ASSERT(textureId != 0);
533 }
534
535 void OpenGLImage::draw()
536 {
537 drawOpenGLImage(*this, Point<int>(0, 0), textureId, setupCalled);
538 }
539
540 void OpenGLImage::drawAt(const int x, const int y)
541 {
542 drawOpenGLImage(*this, Point<int>(x, y), textureId, setupCalled);
543 }
544
545 void OpenGLImage::drawAt(const Point<int>& pos)
546 {
547 drawOpenGLImage(*this, pos, textureId, setupCalled);
548 }
549
550 // -----------------------------------------------------------------------
551 // ImageBaseAboutWindow
552
553 #if 0
554 template <>
555 void ImageBaseAboutWindow<OpenGLImage>::onDisplay()
556 {
557 const GraphicsContext& context(getGraphicsContext());
558 img.draw(context);
559 }
560 #endif
561
562 template class ImageBaseAboutWindow<OpenGLImage>;
563
564 // -----------------------------------------------------------------------
565 // ImageBaseButton
566
567 template class ImageBaseButton<OpenGLImage>;
568
569 // -----------------------------------------------------------------------
570 // ImageBaseKnob
571
572 template <>
573 void ImageBaseKnob<OpenGLImage>::PrivateData::init()
574 {
575 glTextureId = 0;
576 glGenTextures(1, &glTextureId);
577 }
578
579 template <>
580 void ImageBaseKnob<OpenGLImage>::PrivateData::cleanup()
581 {
582 if (glTextureId == 0)
583 return;
584
585 glDeleteTextures(1, &glTextureId);
586 glTextureId = 0;
587 }
588
589 template <>
590 void ImageBaseKnob<OpenGLImage>::onDisplay()
591 {
592 const GraphicsContext& context(getGraphicsContext());
593 const float normValue = getNormalizedValue();
594
595 glEnable(GL_TEXTURE_2D);
596 glBindTexture(GL_TEXTURE_2D, pData->glTextureId);
597
598 if (! pData->isReady)
599 {
600 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
601 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
602 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
603 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
604
605 static const float trans[] = { 0.0f, 0.0f, 0.0f, 0.0f };
606 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, trans);
607
608 glPixelStorei(GL_PACK_ALIGNMENT, 1);
609 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
610
611 uint imageDataOffset = 0;
612
613 if (pData->rotationAngle == 0)
614 {
615 DISTRHO_SAFE_ASSERT_RETURN(pData->imgLayerCount > 0,);
616 DISTRHO_SAFE_ASSERT_RETURN(normValue >= 0.0f,);
617
618 const uint& v1(pData->isImgVertical ? pData->imgLayerWidth : pData->imgLayerHeight);
619 const uint& v2(pData->isImgVertical ? pData->imgLayerHeight : pData->imgLayerWidth);
620
621 // TODO kImageFormatGreyscale
622 const uint layerDataSize = v1 * v2 * ((pData->image.getFormat() == kImageFormatBGRA ||
623 pData->image.getFormat() == kImageFormatRGBA) ? 4 : 3);
624 /* */ imageDataOffset = layerDataSize * uint(normValue * float(pData->imgLayerCount-1));
625 }
626
627 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
628 static_cast<GLsizei>(getWidth()), static_cast<GLsizei>(getHeight()), 0,
629 asOpenGLImageFormat(pData->image.getFormat()), GL_UNSIGNED_BYTE, pData->image.getRawData() + imageDataOffset);
630
631 pData->isReady = true;
632 }
633
634 const int w = static_cast<int>(getWidth());
635 const int h = static_cast<int>(getHeight());
636
637 if (pData->rotationAngle != 0)
638 {
639 #ifdef DGL_USE_COMPAT_OPENGL
640 glPushMatrix();
641 #endif
642
643 const int w2 = w/2;
644 const int h2 = h/2;
645
646 #ifdef DGL_USE_COMPAT_OPENGL
647 glTranslatef(static_cast<float>(w2), static_cast<float>(h2), 0.0f);
648 glRotatef(normValue*static_cast<float>(pData->rotationAngle), 0.0f, 0.0f, 1.0f);
649 #endif
650
651 Rectangle<int>(-w2, -h2, w, h).draw(context);
652
653 #ifdef DGL_USE_COMPAT_OPENGL
654 glPopMatrix();
655 #endif
656 }
657 else
658 {
659 Rectangle<int>(0, 0, w, h).draw(context);
660 }
661
662 glBindTexture(GL_TEXTURE_2D, 0);
663 glDisable(GL_TEXTURE_2D);
664 }
665
666 template class ImageBaseKnob<OpenGLImage>;
667
668 // -----------------------------------------------------------------------
669 // ImageBaseSlider
670
671 template class ImageBaseSlider<OpenGLImage>;
672
673 // -----------------------------------------------------------------------
674 // ImageBaseSwitch
675
676 template class ImageBaseSwitch<OpenGLImage>;
677
678 // -----------------------------------------------------------------------
679
680 void SubWidget::PrivateData::display(const uint width, const uint height, const double autoScaleFactor)
681 {
682 if (skipDrawing)
683 return;
684
685 bool needsDisableScissor = false;
686
687 if (needsViewportScaling)
688 {
689 // limit viewport to widget bounds
690 const int x = absolutePos.getX();
691 const int w = static_cast<int>(self->getWidth());
692 const int h = static_cast<int>(self->getHeight());
693
694 if (viewportScaleFactor != 0.0 && viewportScaleFactor != 1.0)
695 {
696 glViewport(x,
697 -static_cast<int>(height * viewportScaleFactor - height + absolutePos.getY() + 0.5),
698 static_cast<int>(width * viewportScaleFactor + 0.5),
699 static_cast<int>(height * viewportScaleFactor + 0.5));
700 }
701 else
702 {
703 const int y = static_cast<int>(height - self->getHeight()) - absolutePos.getY();
704 glViewport(x, y, w, h);
705 }
706 }
707 else if (needsFullViewportForDrawing || (absolutePos.isZero() && self->getSize() == Size<uint>(width, height)))
708 {
709 // full viewport size
710 glViewport(0,
711 -static_cast<int>(height * autoScaleFactor - height + 0.5),
712 static_cast<int>(width * autoScaleFactor + 0.5),
713 static_cast<int>(height * autoScaleFactor + 0.5));
714 }
715 else
716 {
717 // set viewport pos
718 glViewport(static_cast<int>(absolutePos.getX() * autoScaleFactor + 0.5),
719 -static_cast<int>(std::round((height * autoScaleFactor - height)
720 + (absolutePos.getY() * autoScaleFactor))),
721 static_cast<int>(std::round(width * autoScaleFactor)),
722 static_cast<int>(std::round(height * autoScaleFactor)));
723
724 // then cut the outer bounds
725 glScissor(static_cast<int>(absolutePos.getX() * autoScaleFactor + 0.5),
726 static_cast<int>(height - std::round((static_cast<int>(self->getHeight()) + absolutePos.getY())
727 * autoScaleFactor)),
728 static_cast<int>(std::round(self->getWidth() * autoScaleFactor)),
729 static_cast<int>(std::round(self->getHeight() * autoScaleFactor)));
730
731 glEnable(GL_SCISSOR_TEST);
732 needsDisableScissor = true;
733 }
734
735 // display widget
736 self->onDisplay();
737
738 if (needsDisableScissor)
739 glDisable(GL_SCISSOR_TEST);
740
741 selfw->pData->displaySubWidgets(width, height, autoScaleFactor);
742 }
743
744 // -----------------------------------------------------------------------
745
746 void TopLevelWidget::PrivateData::display()
747 {
748 if (! selfw->pData->visible)
749 return;
750
751 const Size<uint> size(window.getSize());
752 const uint width = size.getWidth();
753 const uint height = size.getHeight();
754
755 const double autoScaleFactor = window.pData->autoScaleFactor;
756
757 // full viewport size
758 if (window.pData->autoScaling)
759 {
760 glViewport(0,
761 -static_cast<int>(height * autoScaleFactor - height + 0.5),
762 static_cast<int>(width * autoScaleFactor + 0.5),
763 static_cast<int>(height * autoScaleFactor + 0.5));
764 }
765 else
766 {
767 glViewport(0, 0, static_cast<int>(width), static_cast<int>(height));
768 }
769
770 // main widget drawing
771 self->onDisplay();
772
773 // now draw subwidgets if there are any
774 selfw->pData->displaySubWidgets(width, height, autoScaleFactor);
775 }
776
777 // -----------------------------------------------------------------------
778
779 void Window::PrivateData::renderToPicture(const char* const filename,
780 const GraphicsContext&,
781 const uint width,
782 const uint height)
783 {
784 FILE* const f = fopen(filename, "w");
785 DISTRHO_SAFE_ASSERT_RETURN(f != nullptr,);
786
787 GLubyte* const pixels = new GLubyte[width * height * 3 * sizeof(GLubyte)];
788
789 glFlush();
790 glReadPixels(0, 0, static_cast<GLsizei>(width), static_cast<GLsizei>(height), GL_RGB, GL_UNSIGNED_BYTE, pixels);
791
792 fprintf(f, "P3\n%d %d\n255\n", width, height);
793 for (uint y = 0; y < height; y++)
794 {
795 for (uint i, x = 0; x < width; x++)
796 {
797 i = 3 * ((height - y - 1) * width + x);
798 fprintf(f, "%3d %3d %3d ", pixels[i], pixels[i+1], pixels[i+2]);
799 }
800 fprintf(f, "\n");
801 }
802
803 delete[] pixels;
804 fclose(f);
805 }
806
807 // -----------------------------------------------------------------------
808
809 const GraphicsContext& Window::PrivateData::getGraphicsContext() const noexcept
810 {
811 return (const GraphicsContext&)graphicsContext;
812 }
813
814 // -----------------------------------------------------------------------
815
816 END_NAMESPACE_DGL