DISTRHO Plugin Framework
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

800 lines
21KB

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