Collection of DPF-based plugins for packaging
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.

708 lines
19KB

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