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 // Color
38 
setFor(const GraphicsContext &,const bool includeAlpha)39 void Color::setFor(const GraphicsContext&, const bool includeAlpha)
40 {
41     if (includeAlpha)
42         glColor4f(red, green, blue, alpha);
43     else
44         glColor3f(red, green, blue);
45 }
46 
47 // -----------------------------------------------------------------------
48 // Line
49 
50 template<typename T>
drawLine(const Point<T> & posStart,const Point<T> & posEnd)51 static void drawLine(const Point<T>& posStart, const Point<T>& posEnd)
52 {
53     DISTRHO_SAFE_ASSERT_RETURN(posStart != posEnd,);
54 
55     glBegin(GL_LINES);
56 
57     {
58         glVertex2d(posStart.getX(), posStart.getY());
59         glVertex2d(posEnd.getX(), posEnd.getY());
60     }
61 
62     glEnd();
63 }
64 
65 template<typename T>
draw(const GraphicsContext &,const T width)66 void Line<T>::draw(const GraphicsContext&, const T width)
67 {
68     DISTRHO_SAFE_ASSERT_RETURN(width != 0,);
69 
70     glLineWidth(static_cast<GLfloat>(width));
71     drawLine<T>(posStart, posEnd);
72 }
73 
74 // deprecated calls
75 template<typename T>
draw()76 void Line<T>::draw()
77 {
78     drawLine<T>(posStart, posEnd);
79 }
80 
81 template class Line<double>;
82 template class Line<float>;
83 template class Line<int>;
84 template class Line<uint>;
85 template class Line<short>;
86 template class Line<ushort>;
87 
88 // -----------------------------------------------------------------------
89 // Circle
90 
91 template<typename T>
drawCircle(const Point<T> & pos,const uint numSegments,const float size,const float sin,const float cos,const bool outline)92 static void drawCircle(const Point<T>& pos,
93                        const uint numSegments,
94                        const float size,
95                        const float sin,
96                        const float cos,
97                        const bool outline)
98 {
99     DISTRHO_SAFE_ASSERT_RETURN(numSegments >= 3 && size > 0.0f,);
100 
101     const T origx = pos.getX();
102     const T origy = pos.getY();
103     double t, x = size, y = 0.0;
104 
105     glBegin(outline ? GL_LINE_LOOP : GL_POLYGON);
106 
107     for (uint i=0; i<numSegments; ++i)
108     {
109         glVertex2d(x + origx, y + origy);
110 
111         t = x;
112         x = cos * x - sin * y;
113         y = sin * t + cos * y;
114     }
115 
116     glEnd();
117 }
118 
119 template<typename T>
draw(const GraphicsContext &)120 void Circle<T>::draw(const GraphicsContext&)
121 {
122     drawCircle<T>(fPos, fNumSegments, fSize, fSin, fCos, false);
123 }
124 
125 template<typename T>
drawOutline(const GraphicsContext &,const T lineWidth)126 void Circle<T>::drawOutline(const GraphicsContext&, const T lineWidth)
127 {
128     DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,);
129 
130     glLineWidth(static_cast<GLfloat>(lineWidth));
131     drawCircle<T>(fPos, fNumSegments, fSize, fSin, fCos, true);
132 }
133 
134 // deprecated calls
135 template<typename T>
draw()136 void Circle<T>::draw()
137 {
138     drawCircle<T>(fPos, fNumSegments, fSize, fSin, fCos, false);
139 }
140 
141 template<typename T>
drawOutline()142 void Circle<T>::drawOutline()
143 {
144     drawCircle<T>(fPos, fNumSegments, fSize, fSin, fCos, true);
145 }
146 
147 template class Circle<double>;
148 template class Circle<float>;
149 template class Circle<int>;
150 template class Circle<uint>;
151 template class Circle<short>;
152 template class Circle<ushort>;
153 
154 // -----------------------------------------------------------------------
155 // Triangle
156 
157 template<typename T>
drawTriangle(const Point<T> & pos1,const Point<T> & pos2,const Point<T> & pos3,const bool outline)158 static void drawTriangle(const Point<T>& pos1,
159                          const Point<T>& pos2,
160                          const Point<T>& pos3,
161                          const bool outline)
162 {
163     DISTRHO_SAFE_ASSERT_RETURN(pos1 != pos2 && pos1 != pos3,);
164 
165     glBegin(outline ? GL_LINE_LOOP : GL_TRIANGLES);
166 
167     {
168         glVertex2d(pos1.getX(), pos1.getY());
169         glVertex2d(pos2.getX(), pos2.getY());
170         glVertex2d(pos3.getX(), pos3.getY());
171     }
172 
173     glEnd();
174 }
175 
176 template<typename T>
draw(const GraphicsContext &)177 void Triangle<T>::draw(const GraphicsContext&)
178 {
179     drawTriangle<T>(pos1, pos2, pos3, false);
180 }
181 
182 template<typename T>
drawOutline(const GraphicsContext &,const T lineWidth)183 void Triangle<T>::drawOutline(const GraphicsContext&, const T lineWidth)
184 {
185     DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,);
186 
187     glLineWidth(static_cast<GLfloat>(lineWidth));
188     drawTriangle<T>(pos1, pos2, pos3, true);
189 }
190 
191 // deprecated calls
192 template<typename T>
draw()193 void Triangle<T>::draw()
194 {
195     drawTriangle<T>(pos1, pos2, pos3, false);
196 }
197 
198 template<typename T>
drawOutline()199 void Triangle<T>::drawOutline()
200 {
201     drawTriangle<T>(pos1, pos2, pos3, true);
202 }
203 
204 template class Triangle<double>;
205 template class Triangle<float>;
206 template class Triangle<int>;
207 template class Triangle<uint>;
208 template class Triangle<short>;
209 template class Triangle<ushort>;
210 
211 // -----------------------------------------------------------------------
212 // Rectangle
213 
214 template<typename T>
drawRectangle(const Rectangle<T> & rect,const bool outline)215 static void drawRectangle(const Rectangle<T>& rect, const bool outline)
216 {
217     DISTRHO_SAFE_ASSERT_RETURN(rect.isValid(),);
218 
219     glBegin(outline ? GL_LINE_LOOP : GL_QUADS);
220 
221     {
222         const T x = rect.getX();
223         const T y = rect.getY();
224         const T w = rect.getWidth();
225         const T h = rect.getHeight();
226 
227         glTexCoord2f(0.0f, 0.0f);
228         glVertex2d(x, y);
229 
230         glTexCoord2f(1.0f, 0.0f);
231         glVertex2d(x+w, y);
232 
233         glTexCoord2f(1.0f, 1.0f);
234         glVertex2d(x+w, y+h);
235 
236         glTexCoord2f(0.0f, 1.0f);
237         glVertex2d(x, y+h);
238     }
239 
240     glEnd();
241 }
242 
243 template<typename T>
draw(const GraphicsContext &)244 void Rectangle<T>::draw(const GraphicsContext&)
245 {
246     drawRectangle<T>(*this, false);
247 }
248 
249 template<typename T>
drawOutline(const GraphicsContext &,const T lineWidth)250 void Rectangle<T>::drawOutline(const GraphicsContext&, const T lineWidth)
251 {
252     DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,);
253 
254     glLineWidth(static_cast<GLfloat>(lineWidth));
255     drawRectangle<T>(*this, true);
256 }
257 
258 // deprecated calls
259 template<typename T>
draw()260 void Rectangle<T>::draw()
261 {
262     drawRectangle<T>(*this, false);
263 }
264 
265 template<typename T>
drawOutline()266 void Rectangle<T>::drawOutline()
267 {
268     drawRectangle<T>(*this, true);
269 }
270 
271 template class Rectangle<double>;
272 template class Rectangle<float>;
273 template class Rectangle<int>;
274 template class Rectangle<uint>;
275 template class Rectangle<short>;
276 template class Rectangle<ushort>;
277 
278 // -----------------------------------------------------------------------
279 // OpenGLImage
280 
setupOpenGLImage(const OpenGLImage & image,GLuint textureId)281 static void setupOpenGLImage(const OpenGLImage& image, GLuint textureId)
282 {
283     DISTRHO_SAFE_ASSERT_RETURN(image.isValid(),);
284 
285     glEnable(GL_TEXTURE_2D);
286     glBindTexture(GL_TEXTURE_2D, textureId);
287 
288     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
289     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
290     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
291     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
292 
293     static const float trans[] = { 0.0f, 0.0f, 0.0f, 0.0f };
294     glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, trans);
295 
296     glPixelStorei(GL_PACK_ALIGNMENT, 1);
297     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
298     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
299                  static_cast<GLsizei>(image.getWidth()),
300                  static_cast<GLsizei>(image.getHeight()),
301                  0,
302                  asOpenGLImageFormat(image.getFormat()), GL_UNSIGNED_BYTE, image.getRawData());
303 
304     glBindTexture(GL_TEXTURE_2D, 0);
305     glDisable(GL_TEXTURE_2D);
306 }
307 
drawOpenGLImage(const OpenGLImage & image,const Point<int> & pos,const GLuint textureId,bool & setupCalled)308 static void drawOpenGLImage(const OpenGLImage& image, const Point<int>& pos, const GLuint textureId, bool& setupCalled)
309 {
310     if (textureId == 0 || image.isInvalid())
311         return;
312 
313     if (! setupCalled)
314     {
315         setupOpenGLImage(image, textureId);
316         setupCalled = true;
317     }
318 
319     glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
320 
321     glEnable(GL_TEXTURE_2D);
322     glBindTexture(GL_TEXTURE_2D, textureId);
323 
324     glBegin(GL_QUADS);
325 
326     {
327         const int x = pos.getX();
328         const int y = pos.getY();
329         const int w = static_cast<int>(image.getWidth());
330         const int h = static_cast<int>(image.getHeight());
331 
332         glTexCoord2f(0.0f, 0.0f);
333         glVertex2d(x, y);
334 
335         glTexCoord2f(1.0f, 0.0f);
336         glVertex2d(x+w, y);
337 
338         glTexCoord2f(1.0f, 1.0f);
339         glVertex2d(x+w, y+h);
340 
341         glTexCoord2f(0.0f, 1.0f);
342         glVertex2d(x, y+h);
343     }
344 
345     glEnd();
346 
347     glBindTexture(GL_TEXTURE_2D, 0);
348     glDisable(GL_TEXTURE_2D);
349 }
350 
OpenGLImage()351 OpenGLImage::OpenGLImage()
352     : ImageBase(),
353       textureId(0),
354       setupCalled(false)
355 {
356     glGenTextures(1, &textureId);
357     DISTRHO_SAFE_ASSERT(textureId != 0);
358 }
359 
OpenGLImage(const char * const rdata,const uint w,const uint h,const ImageFormat fmt)360 OpenGLImage::OpenGLImage(const char* const rdata, const uint w, const uint h, const ImageFormat fmt)
361     : ImageBase(rdata, w, h, fmt),
362       textureId(0),
363       setupCalled(false)
364 {
365     glGenTextures(1, &textureId);
366     DISTRHO_SAFE_ASSERT(textureId != 0);
367 }
368 
OpenGLImage(const char * const rdata,const Size<uint> & s,const ImageFormat fmt)369 OpenGLImage::OpenGLImage(const char* const rdata, const Size<uint>& s, const ImageFormat fmt)
370     : ImageBase(rdata, s, fmt),
371       textureId(0),
372       setupCalled(false)
373 {
374     glGenTextures(1, &textureId);
375     DISTRHO_SAFE_ASSERT(textureId != 0);
376 }
377 
OpenGLImage(const OpenGLImage & image)378 OpenGLImage::OpenGLImage(const OpenGLImage& image)
379     : ImageBase(image),
380       textureId(0),
381       setupCalled(false)
382 {
383     glGenTextures(1, &textureId);
384     DISTRHO_SAFE_ASSERT(textureId != 0);
385 }
386 
~OpenGLImage()387 OpenGLImage::~OpenGLImage()
388 {
389     if (textureId != 0)
390         glDeleteTextures(1, &textureId);
391 }
392 
loadFromMemory(const char * const rdata,const Size<uint> & s,const ImageFormat fmt)393 void OpenGLImage::loadFromMemory(const char* const rdata, const Size<uint>& s, const ImageFormat fmt) noexcept
394 {
395     setupCalled = false;
396     ImageBase::loadFromMemory(rdata, s, fmt);
397 }
398 
drawAt(const GraphicsContext &,const Point<int> & pos)399 void OpenGLImage::drawAt(const GraphicsContext&, const Point<int>& pos)
400 {
401     drawOpenGLImage(*this, pos, textureId, setupCalled);
402 }
403 
operator =(const OpenGLImage & image)404 OpenGLImage& OpenGLImage::operator=(const OpenGLImage& image) noexcept
405 {
406     rawData = image.rawData;
407     size    = image.size;
408     format  = image.format;
409     setupCalled = false;
410     return *this;
411 }
412 
413 // deprecated calls
OpenGLImage(const char * const rdata,const uint w,const uint h,const GLenum fmt)414 OpenGLImage::OpenGLImage(const char* const rdata, const uint w, const uint h, const GLenum fmt)
415     : ImageBase(rdata, w, h, asDISTRHOImageFormat(fmt)),
416       textureId(0),
417       setupCalled(false)
418 {
419     glGenTextures(1, &textureId);
420     DISTRHO_SAFE_ASSERT(textureId != 0);
421 }
422 
OpenGLImage(const char * const rdata,const Size<uint> & s,const GLenum fmt)423 OpenGLImage::OpenGLImage(const char* const rdata, const Size<uint>& s, const GLenum fmt)
424     : ImageBase(rdata, s, asDISTRHOImageFormat(fmt)),
425       textureId(0),
426       setupCalled(false)
427 {
428     glGenTextures(1, &textureId);
429     DISTRHO_SAFE_ASSERT(textureId != 0);
430 }
431 
draw()432 void OpenGLImage::draw()
433 {
434     drawOpenGLImage(*this, Point<int>(0, 0), textureId, setupCalled);
435 }
436 
drawAt(const int x,const int y)437 void OpenGLImage::drawAt(const int x, const int y)
438 {
439     drawOpenGLImage(*this, Point<int>(x, y), textureId, setupCalled);
440 }
441 
drawAt(const Point<int> & pos)442 void OpenGLImage::drawAt(const Point<int>& pos)
443 {
444     drawOpenGLImage(*this, pos, textureId, setupCalled);
445 }
446 
447 // -----------------------------------------------------------------------
448 // ImageBaseAboutWindow
449 
450 #if 0
451 template <>
452 void ImageBaseAboutWindow<OpenGLImage>::onDisplay()
453 {
454     const GraphicsContext& context(getGraphicsContext());
455     img.draw(context);
456 }
457 #endif
458 
459 template class ImageBaseAboutWindow<OpenGLImage>;
460 
461 // -----------------------------------------------------------------------
462 // ImageBaseButton
463 
464 template class ImageBaseButton<OpenGLImage>;
465 
466 // -----------------------------------------------------------------------
467 // ImageBaseKnob
468 
469 template <>
init()470 void ImageBaseKnob<OpenGLImage>::PrivateData::init()
471 {
472     glTextureId = 0;
473     glGenTextures(1, &glTextureId);
474 }
475 
476 template <>
cleanup()477 void ImageBaseKnob<OpenGLImage>::PrivateData::cleanup()
478 {
479     if (glTextureId == 0)
480         return;
481 
482     glDeleteTextures(1, &glTextureId);
483     glTextureId = 0;
484 }
485 
486 template <>
onDisplay()487 void ImageBaseKnob<OpenGLImage>::onDisplay()
488 {
489     const GraphicsContext& context(getGraphicsContext());
490     const float normValue = getNormalizedValue();
491 
492     glEnable(GL_TEXTURE_2D);
493     glBindTexture(GL_TEXTURE_2D, pData->glTextureId);
494 
495     if (! pData->isReady)
496     {
497         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
498         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
499         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
500         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
501 
502         static const float trans[] = { 0.0f, 0.0f, 0.0f, 0.0f };
503         glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, trans);
504 
505         glPixelStorei(GL_PACK_ALIGNMENT, 1);
506         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
507 
508         uint imageDataOffset = 0;
509 
510         if (pData->rotationAngle == 0)
511         {
512             DISTRHO_SAFE_ASSERT_RETURN(pData->imgLayerCount > 0,);
513             DISTRHO_SAFE_ASSERT_RETURN(normValue >= 0.0f,);
514 
515             const uint& v1(pData->isImgVertical ? pData->imgLayerWidth : pData->imgLayerHeight);
516             const uint& v2(pData->isImgVertical ? pData->imgLayerHeight : pData->imgLayerWidth);
517 
518             // TODO kImageFormatGreyscale
519             const uint layerDataSize   = v1 * v2 * ((pData->image.getFormat() == kImageFormatBGRA ||
520                                                      pData->image.getFormat() == kImageFormatRGBA) ? 4 : 3);
521             /*      */ imageDataOffset = layerDataSize * uint(normValue * float(pData->imgLayerCount-1));
522         }
523 
524         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
525                      static_cast<GLsizei>(getWidth()), static_cast<GLsizei>(getHeight()), 0,
526                      asOpenGLImageFormat(pData->image.getFormat()), GL_UNSIGNED_BYTE, pData->image.getRawData() + imageDataOffset);
527 
528         pData->isReady = true;
529     }
530 
531     const int w = static_cast<int>(getWidth());
532     const int h = static_cast<int>(getHeight());
533 
534     if (pData->rotationAngle != 0)
535     {
536         glPushMatrix();
537 
538         const int w2 = w/2;
539         const int h2 = h/2;
540 
541         glTranslatef(static_cast<float>(w2), static_cast<float>(h2), 0.0f);
542         glRotatef(normValue*static_cast<float>(pData->rotationAngle), 0.0f, 0.0f, 1.0f);
543 
544         Rectangle<int>(-w2, -h2, w, h).draw(context);
545 
546         glPopMatrix();
547     }
548     else
549     {
550         Rectangle<int>(0, 0, w, h).draw(context);
551     }
552 
553     glBindTexture(GL_TEXTURE_2D, 0);
554     glDisable(GL_TEXTURE_2D);
555 }
556 
557 template class ImageBaseKnob<OpenGLImage>;
558 
559 // -----------------------------------------------------------------------
560 // ImageBaseSlider
561 
562 template class ImageBaseSlider<OpenGLImage>;
563 
564 // -----------------------------------------------------------------------
565 // ImageBaseSwitch
566 
567 template class ImageBaseSwitch<OpenGLImage>;
568 
569 // -----------------------------------------------------------------------
570 
display(const uint width,const uint height,const double autoScaleFactor)571 void SubWidget::PrivateData::display(const uint width, const uint height, const double autoScaleFactor)
572 {
573     if (skipDrawing)
574         return;
575 
576     bool needsDisableScissor = false;
577 
578     if (needsViewportScaling)
579     {
580         // limit viewport to widget bounds
581         const int x = absolutePos.getX();
582         const int w = static_cast<int>(self->getWidth());
583         const int h = static_cast<int>(self->getHeight());
584 
585         if (viewportScaleFactor != 0.0 && viewportScaleFactor != 1.0)
586         {
587             glViewport(x,
588                        -static_cast<int>(height * viewportScaleFactor - height + absolutePos.getY() + 0.5),
589                        static_cast<int>(width * viewportScaleFactor + 0.5),
590                        static_cast<int>(height * viewportScaleFactor + 0.5));
591         }
592         else
593         {
594             const int y = static_cast<int>(height - self->getHeight()) - absolutePos.getY();
595             glViewport(x, y, w, h);
596         }
597     }
598     else if (needsFullViewportForDrawing || (absolutePos.isZero() && self->getSize() == Size<uint>(width, height)))
599     {
600         // full viewport size
601         glViewport(0,
602                    -static_cast<int>(height * autoScaleFactor - height + 0.5),
603                    static_cast<int>(width * autoScaleFactor + 0.5),
604                    static_cast<int>(height * autoScaleFactor + 0.5));
605     }
606     else
607     {
608         // set viewport pos
609         glViewport(static_cast<int>(absolutePos.getX() * autoScaleFactor + 0.5),
610                    -static_cast<int>(std::round((height * autoScaleFactor - height)
611                                      + (absolutePos.getY() * autoScaleFactor))),
612                    static_cast<int>(std::round(width * autoScaleFactor)),
613                    static_cast<int>(std::round(height * autoScaleFactor)));
614 
615         // then cut the outer bounds
616         glScissor(static_cast<int>(absolutePos.getX() * autoScaleFactor + 0.5),
617                   static_cast<int>(height - std::round((static_cast<int>(self->getHeight()) + absolutePos.getY())
618                                                        * autoScaleFactor)),
619                   static_cast<int>(std::round(self->getWidth() * autoScaleFactor)),
620                   static_cast<int>(std::round(self->getHeight() * autoScaleFactor)));
621 
622         glEnable(GL_SCISSOR_TEST);
623         needsDisableScissor = true;
624     }
625 
626     // display widget
627     self->onDisplay();
628 
629     if (needsDisableScissor)
630         glDisable(GL_SCISSOR_TEST);
631 
632     selfw->pData->displaySubWidgets(width, height, autoScaleFactor);
633 }
634 
635 // -----------------------------------------------------------------------
636 
display()637 void TopLevelWidget::PrivateData::display()
638 {
639     if (! selfw->pData->visible)
640         return;
641 
642     const Size<uint> size(window.getSize());
643     const uint width  = size.getWidth();
644     const uint height = size.getHeight();
645 
646     const double autoScaleFactor = window.pData->autoScaleFactor;
647 
648     // full viewport size
649     if (window.pData->autoScaling)
650     {
651         glViewport(0,
652                    -static_cast<int>(height * autoScaleFactor - height + 0.5),
653                    static_cast<int>(width * autoScaleFactor + 0.5),
654                    static_cast<int>(height * autoScaleFactor + 0.5));
655     }
656     else
657     {
658         glViewport(0, 0, static_cast<int>(width), static_cast<int>(height));
659     }
660 
661     // main widget drawing
662     self->onDisplay();
663 
664     // now draw subwidgets if there are any
665     selfw->pData->displaySubWidgets(width, height, autoScaleFactor);
666 }
667 
668 // -----------------------------------------------------------------------
669 
getGraphicsContext() const670 const GraphicsContext& Window::PrivateData::getGraphicsContext() const noexcept
671 {
672     return (const GraphicsContext&)graphicsContext;
673 }
674 
675 // -----------------------------------------------------------------------
676 
677 END_NAMESPACE_DGL
678