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.

675 lines
18KB

  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 "Common.hpp"
  24. #include "SubWidgetPrivateData.hpp"
  25. #include "TopLevelWidgetPrivateData.hpp"
  26. #include "WidgetPrivateData.hpp"
  27. #include "WindowPrivateData.hpp"
  28. // templated classes
  29. #include "ImageBaseWidgets.cpp"
  30. START_NAMESPACE_DGL
  31. // -----------------------------------------------------------------------
  32. // Color
  33. void Color::setFor(const GraphicsContext&, const bool includeAlpha)
  34. {
  35. if (includeAlpha)
  36. glColor4f(red, green, blue, alpha);
  37. else
  38. glColor3f(red, green, blue);
  39. }
  40. // -----------------------------------------------------------------------
  41. // Line
  42. template<typename T>
  43. static void drawLine(const Point<T>& posStart, const Point<T>& posEnd)
  44. {
  45. DISTRHO_SAFE_ASSERT_RETURN(posStart != posEnd,);
  46. glBegin(GL_LINES);
  47. {
  48. glVertex2d(posStart.getX(), posStart.getY());
  49. glVertex2d(posEnd.getX(), posEnd.getY());
  50. }
  51. glEnd();
  52. }
  53. template<typename T>
  54. void Line<T>::draw(const GraphicsContext&, const T width)
  55. {
  56. DISTRHO_SAFE_ASSERT_RETURN(width != 0,);
  57. glLineWidth(static_cast<GLfloat>(width));
  58. drawLine<T>(posStart, posEnd);
  59. }
  60. // deprecated calls
  61. template<typename T>
  62. void Line<T>::draw()
  63. {
  64. drawLine<T>(posStart, posEnd);
  65. }
  66. template class Line<double>;
  67. template class Line<float>;
  68. template class Line<int>;
  69. template class Line<uint>;
  70. template class Line<short>;
  71. template class Line<ushort>;
  72. // -----------------------------------------------------------------------
  73. // Circle
  74. template<typename T>
  75. static void drawCircle(const Point<T>& pos,
  76. const uint numSegments,
  77. const float size,
  78. const float sin,
  79. const float cos,
  80. const bool outline)
  81. {
  82. DISTRHO_SAFE_ASSERT_RETURN(numSegments >= 3 && size > 0.0f,);
  83. const T origx = pos.getX();
  84. const T origy = pos.getY();
  85. double t, x = size, y = 0.0;
  86. glBegin(outline ? GL_LINE_LOOP : GL_POLYGON);
  87. for (uint i=0; i<numSegments; ++i)
  88. {
  89. glVertex2d(x + origx, y + origy);
  90. t = x;
  91. x = cos * x - sin * y;
  92. y = sin * t + cos * y;
  93. }
  94. glEnd();
  95. }
  96. template<typename T>
  97. void Circle<T>::draw(const GraphicsContext&)
  98. {
  99. drawCircle<T>(fPos, fNumSegments, fSize, fSin, fCos, false);
  100. }
  101. template<typename T>
  102. void Circle<T>::drawOutline(const GraphicsContext&, const T lineWidth)
  103. {
  104. DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,);
  105. glLineWidth(static_cast<GLfloat>(lineWidth));
  106. drawCircle<T>(fPos, fNumSegments, fSize, fSin, fCos, true);
  107. }
  108. // deprecated calls
  109. template<typename T>
  110. void Circle<T>::draw()
  111. {
  112. drawCircle<T>(fPos, fNumSegments, fSize, fSin, fCos, false);
  113. }
  114. template<typename T>
  115. void Circle<T>::drawOutline()
  116. {
  117. drawCircle<T>(fPos, fNumSegments, fSize, fSin, fCos, true);
  118. }
  119. template class Circle<double>;
  120. template class Circle<float>;
  121. template class Circle<int>;
  122. template class Circle<uint>;
  123. template class Circle<short>;
  124. template class Circle<ushort>;
  125. // -----------------------------------------------------------------------
  126. // Triangle
  127. template<typename T>
  128. static void drawTriangle(const Point<T>& pos1,
  129. const Point<T>& pos2,
  130. const Point<T>& pos3,
  131. const bool outline)
  132. {
  133. DISTRHO_SAFE_ASSERT_RETURN(pos1 != pos2 && pos1 != pos3,);
  134. glBegin(outline ? GL_LINE_LOOP : GL_TRIANGLES);
  135. {
  136. glVertex2d(pos1.getX(), pos1.getY());
  137. glVertex2d(pos2.getX(), pos2.getY());
  138. glVertex2d(pos3.getX(), pos3.getY());
  139. }
  140. glEnd();
  141. }
  142. template<typename T>
  143. void Triangle<T>::draw(const GraphicsContext&)
  144. {
  145. drawTriangle<T>(pos1, pos2, pos3, false);
  146. }
  147. template<typename T>
  148. void Triangle<T>::drawOutline(const GraphicsContext&, const T lineWidth)
  149. {
  150. DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,);
  151. glLineWidth(static_cast<GLfloat>(lineWidth));
  152. drawTriangle<T>(pos1, pos2, pos3, true);
  153. }
  154. // deprecated calls
  155. template<typename T>
  156. void Triangle<T>::draw()
  157. {
  158. drawTriangle<T>(pos1, pos2, pos3, false);
  159. }
  160. template<typename T>
  161. void Triangle<T>::drawOutline()
  162. {
  163. drawTriangle<T>(pos1, pos2, pos3, true);
  164. }
  165. template class Triangle<double>;
  166. template class Triangle<float>;
  167. template class Triangle<int>;
  168. template class Triangle<uint>;
  169. template class Triangle<short>;
  170. template class Triangle<ushort>;
  171. // -----------------------------------------------------------------------
  172. // Rectangle
  173. template<typename T>
  174. static void drawRectangle(const Rectangle<T>& rect, const bool outline)
  175. {
  176. DISTRHO_SAFE_ASSERT_RETURN(rect.isValid(),);
  177. glBegin(outline ? GL_LINE_LOOP : GL_QUADS);
  178. {
  179. const T x = rect.getX();
  180. const T y = rect.getY();
  181. const T w = rect.getWidth();
  182. const T h = rect.getHeight();
  183. glTexCoord2f(0.0f, 0.0f);
  184. glVertex2d(x, y);
  185. glTexCoord2f(1.0f, 0.0f);
  186. glVertex2d(x+w, y);
  187. glTexCoord2f(1.0f, 1.0f);
  188. glVertex2d(x+w, y+h);
  189. glTexCoord2f(0.0f, 1.0f);
  190. glVertex2d(x, y+h);
  191. }
  192. glEnd();
  193. }
  194. template<typename T>
  195. void Rectangle<T>::draw(const GraphicsContext&)
  196. {
  197. drawRectangle<T>(*this, false);
  198. }
  199. template<typename T>
  200. void Rectangle<T>::drawOutline(const GraphicsContext&, const T lineWidth)
  201. {
  202. DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,);
  203. glLineWidth(static_cast<GLfloat>(lineWidth));
  204. drawRectangle<T>(*this, true);
  205. }
  206. // deprecated calls
  207. template<typename T>
  208. void Rectangle<T>::draw()
  209. {
  210. drawRectangle<T>(*this, false);
  211. }
  212. template<typename T>
  213. void Rectangle<T>::drawOutline()
  214. {
  215. drawRectangle<T>(*this, true);
  216. }
  217. template class Rectangle<double>;
  218. template class Rectangle<float>;
  219. template class Rectangle<int>;
  220. template class Rectangle<uint>;
  221. template class Rectangle<short>;
  222. template class Rectangle<ushort>;
  223. // -----------------------------------------------------------------------
  224. // OpenGLImage
  225. static void setupOpenGLImage(const OpenGLImage& image, GLuint textureId)
  226. {
  227. DISTRHO_SAFE_ASSERT_RETURN(image.isValid(),);
  228. glEnable(GL_TEXTURE_2D);
  229. glBindTexture(GL_TEXTURE_2D, textureId);
  230. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  231. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  232. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
  233. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
  234. static const float trans[] = { 0.0f, 0.0f, 0.0f, 0.0f };
  235. glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, trans);
  236. glPixelStorei(GL_PACK_ALIGNMENT, 1);
  237. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  238. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
  239. static_cast<GLsizei>(image.getWidth()),
  240. static_cast<GLsizei>(image.getHeight()),
  241. 0,
  242. asOpenGLImageFormat(image.getFormat()), GL_UNSIGNED_BYTE, image.getRawData());
  243. glBindTexture(GL_TEXTURE_2D, 0);
  244. glDisable(GL_TEXTURE_2D);
  245. }
  246. static void drawOpenGLImage(const OpenGLImage& image, const Point<int>& pos, const GLuint textureId, bool& setupCalled)
  247. {
  248. if (textureId == 0 || image.isInvalid())
  249. return;
  250. if (! setupCalled)
  251. {
  252. setupOpenGLImage(image, textureId);
  253. setupCalled = true;
  254. }
  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 = ((pData->usingLog ? pData->invlogscale(pData->value) : pData->value) - pData->minimum)
  394. / (pData->maximum - pData->minimum);
  395. glEnable(GL_TEXTURE_2D);
  396. glBindTexture(GL_TEXTURE_2D, pData->glTextureId);
  397. if (! pData->isReady)
  398. {
  399. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  400. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  401. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
  402. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
  403. static const float trans[] = { 0.0f, 0.0f, 0.0f, 0.0f };
  404. glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, trans);
  405. glPixelStorei(GL_PACK_ALIGNMENT, 1);
  406. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  407. uint imageDataOffset = 0;
  408. if (pData->rotationAngle == 0)
  409. {
  410. DISTRHO_SAFE_ASSERT_RETURN(pData->imgLayerCount > 0,);
  411. DISTRHO_SAFE_ASSERT_RETURN(normValue >= 0.0f,);
  412. const uint& v1(pData->isImgVertical ? pData->imgLayerWidth : pData->imgLayerHeight);
  413. const uint& v2(pData->isImgVertical ? pData->imgLayerHeight : pData->imgLayerWidth);
  414. // TODO kImageFormatGreyscale
  415. const uint layerDataSize = v1 * v2 * ((pData->image.getFormat() == kImageFormatBGRA ||
  416. pData->image.getFormat() == kImageFormatRGBA) ? 4 : 3);
  417. /* */ imageDataOffset = layerDataSize * uint(normValue * float(pData->imgLayerCount-1));
  418. }
  419. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
  420. static_cast<GLsizei>(getWidth()), static_cast<GLsizei>(getHeight()), 0,
  421. asOpenGLImageFormat(pData->image.getFormat()), GL_UNSIGNED_BYTE, pData->image.getRawData() + imageDataOffset);
  422. pData->isReady = true;
  423. }
  424. const int w = static_cast<int>(getWidth());
  425. const int h = static_cast<int>(getHeight());
  426. if (pData->rotationAngle != 0)
  427. {
  428. glPushMatrix();
  429. const int w2 = w/2;
  430. const int h2 = h/2;
  431. glTranslatef(static_cast<float>(w2), static_cast<float>(h2), 0.0f);
  432. glRotatef(normValue*static_cast<float>(pData->rotationAngle), 0.0f, 0.0f, 1.0f);
  433. Rectangle<int>(-w2, -h2, w, h).draw(context);
  434. glPopMatrix();
  435. }
  436. else
  437. {
  438. Rectangle<int>(0, 0, w, h).draw(context);
  439. }
  440. glBindTexture(GL_TEXTURE_2D, 0);
  441. glDisable(GL_TEXTURE_2D);
  442. }
  443. template class ImageBaseKnob<OpenGLImage>;
  444. // -----------------------------------------------------------------------
  445. // ImageBaseSlider
  446. template class ImageBaseSlider<OpenGLImage>;
  447. // -----------------------------------------------------------------------
  448. // ImageBaseSwitch
  449. template class ImageBaseSwitch<OpenGLImage>;
  450. // -----------------------------------------------------------------------
  451. void SubWidget::PrivateData::display(const uint width, const uint height, const double autoScaleFactor)
  452. {
  453. if (skipDrawing)
  454. return;
  455. bool needsDisableScissor = false;
  456. if (needsViewportScaling)
  457. {
  458. // limit viewport to widget bounds
  459. const int x = absolutePos.getX();
  460. const int w = static_cast<int>(self->getWidth());
  461. const int h = static_cast<int>(self->getHeight());
  462. if (viewportScaleFactor != 0.0 && viewportScaleFactor != 1.0)
  463. {
  464. glViewport(x,
  465. -static_cast<int>(height * viewportScaleFactor - height + absolutePos.getY() + 0.5),
  466. static_cast<int>(width * viewportScaleFactor + 0.5),
  467. static_cast<int>(height * viewportScaleFactor + 0.5));
  468. }
  469. else
  470. {
  471. const int y = static_cast<int>(height - self->getHeight()) - absolutePos.getY();
  472. glViewport(x, y, w, h);
  473. }
  474. }
  475. else if (needsFullViewportForDrawing || (absolutePos.isZero() && self->getSize() == Size<uint>(width, height)))
  476. {
  477. // full viewport size
  478. glViewport(0, 0, static_cast<int>(width), static_cast<int>(height));
  479. }
  480. else
  481. {
  482. // set viewport pos
  483. glViewport(static_cast<int>(absolutePos.getX() * autoScaleFactor + 0.5),
  484. -static_cast<int>(std::round((height * autoScaleFactor - height)
  485. + (absolutePos.getY() * autoScaleFactor))),
  486. static_cast<int>(std::round(width * autoScaleFactor)),
  487. static_cast<int>(std::round(height * autoScaleFactor)));
  488. // then cut the outer bounds
  489. glScissor(static_cast<int>(absolutePos.getX() * autoScaleFactor + 0.5),
  490. static_cast<int>(height - std::round((static_cast<int>(self->getHeight()) + absolutePos.getY())
  491. * autoScaleFactor)),
  492. static_cast<int>(std::round(self->getWidth() * autoScaleFactor)),
  493. static_cast<int>(std::round(self->getHeight() * autoScaleFactor)));
  494. glEnable(GL_SCISSOR_TEST);
  495. needsDisableScissor = true;
  496. }
  497. // display widget
  498. self->onDisplay();
  499. if (needsDisableScissor)
  500. glDisable(GL_SCISSOR_TEST);
  501. selfw->pData->displaySubWidgets(width, height, autoScaleFactor);
  502. }
  503. // -----------------------------------------------------------------------
  504. void TopLevelWidget::PrivateData::display()
  505. {
  506. if (! selfw->pData->visible)
  507. return;
  508. const Size<uint> size(window.getSize());
  509. const uint width = size.getWidth();
  510. const uint height = size.getHeight();
  511. const double autoScaleFactor = window.pData->autoScaleFactor;
  512. // full viewport size
  513. if (window.pData->autoScaling)
  514. {
  515. glViewport(0,
  516. -static_cast<int>(height * autoScaleFactor - height),
  517. static_cast<int>(width * autoScaleFactor),
  518. static_cast<int>(height * autoScaleFactor));
  519. }
  520. else
  521. {
  522. glViewport(0, 0, static_cast<int>(width), static_cast<int>(height));
  523. }
  524. // main widget drawing
  525. self->onDisplay();
  526. // now draw subwidgets if there are any
  527. selfw->pData->displaySubWidgets(width, height, autoScaleFactor);
  528. }
  529. // -----------------------------------------------------------------------
  530. const GraphicsContext& Window::PrivateData::getGraphicsContext() const noexcept
  531. {
  532. return (const GraphicsContext&)graphicsContext;
  533. }
  534. // -----------------------------------------------------------------------
  535. END_NAMESPACE_DGL