OpenGL.cpp (21385B)
1 /* 2 * DISTRHO Plugin Framework (DPF) 3 * Copyright (C) 2012-2024 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 (d_isNotZero(viewportScaleFactor) && d_isNotEqual(viewportScaleFactor, 1.0)) 695 { 696 glViewport(x, 697 -d_roundToIntPositive(height * viewportScaleFactor - height + absolutePos.getY()), 698 d_roundToIntPositive(width * viewportScaleFactor), 699 d_roundToIntPositive(height * viewportScaleFactor)); 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, 0, static_cast<int>(width), static_cast<int>(height)); 711 } 712 else 713 { 714 // set viewport pos 715 glViewport(d_roundToIntPositive(absolutePos.getX() * autoScaleFactor), 716 -d_roundToIntPositive(absolutePos.getY() * autoScaleFactor), 717 static_cast<int>(width), 718 static_cast<int>(height)); 719 720 // then cut the outer bounds 721 glScissor(d_roundToIntPositive(absolutePos.getX() * autoScaleFactor), 722 d_roundToIntPositive(height - (static_cast<int>(self->getHeight()) + absolutePos.getY()) * autoScaleFactor), 723 d_roundToIntPositive(self->getWidth() * autoScaleFactor), 724 d_roundToIntPositive(self->getHeight() * autoScaleFactor)); 725 726 glEnable(GL_SCISSOR_TEST); 727 needsDisableScissor = true; 728 } 729 730 // display widget 731 self->onDisplay(); 732 733 if (needsDisableScissor) 734 glDisable(GL_SCISSOR_TEST); 735 736 selfw->pData->displaySubWidgets(width, height, autoScaleFactor); 737 } 738 739 // ----------------------------------------------------------------------- 740 741 void TopLevelWidget::PrivateData::display() 742 { 743 if (! selfw->pData->visible) 744 return; 745 746 const Size<uint> size(window.getSize()); 747 const uint width = size.getWidth(); 748 const uint height = size.getHeight(); 749 750 // full viewport size 751 glViewport(0, 0, static_cast<int>(width), static_cast<int>(height)); 752 753 // main widget drawing 754 self->onDisplay(); 755 756 // now draw subwidgets if there are any 757 selfw->pData->displaySubWidgets(width, height, window.pData->autoScaleFactor); 758 } 759 760 // ----------------------------------------------------------------------- 761 762 void Window::PrivateData::renderToPicture(const char* const filename, 763 const GraphicsContext&, 764 const uint width, 765 const uint height) 766 { 767 FILE* const f = fopen(filename, "w"); 768 DISTRHO_SAFE_ASSERT_RETURN(f != nullptr,); 769 770 GLubyte* const pixels = new GLubyte[width * height * 3 * sizeof(GLubyte)]; 771 772 glFlush(); 773 glReadPixels(0, 0, static_cast<GLsizei>(width), static_cast<GLsizei>(height), GL_RGB, GL_UNSIGNED_BYTE, pixels); 774 775 fprintf(f, "P3\n%d %d\n255\n", width, height); 776 for (uint y = 0; y < height; y++) 777 { 778 for (uint i, x = 0; x < width; x++) 779 { 780 i = 3 * ((height - y - 1) * width + x); 781 fprintf(f, "%3d %3d %3d ", pixels[i], pixels[i+1], pixels[i+2]); 782 } 783 fprintf(f, "\n"); 784 } 785 786 delete[] pixels; 787 fclose(f); 788 } 789 790 // ----------------------------------------------------------------------- 791 792 const GraphicsContext& Window::PrivateData::getGraphicsContext() const noexcept 793 { 794 return (const GraphicsContext&)graphicsContext; 795 } 796 797 // ----------------------------------------------------------------------- 798 799 END_NAMESPACE_DGL