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.

586 lines
16KB

  1. /*
  2. * DISTRHO Plugin Framework (DPF)
  3. * Copyright (C) 2012-2025 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. // Check for correct build config
  32. #ifndef DGL_OPENGL
  33. # error Build config error, OpenGL was NOT requested while building OpenGL2 code
  34. #endif
  35. #ifdef DGL_CAIRO
  36. # error Build config error, Cairo requested while building OpenGL2 code
  37. #endif
  38. #ifdef DGL_VULKAN
  39. # error Build config error, Vulkan requested while building OpenGL2 code
  40. #endif
  41. #ifdef DGL_USE_GLES2
  42. # error Build config error, GLESv2 requested while building OpenGL2 code
  43. #endif
  44. #ifdef DGL_USE_GLES3
  45. # error Build config error, GLESv3 requested while building OpenGL2 code
  46. #endif
  47. #ifdef DGL_USE_OPENGL3
  48. # error Build config error, OpenGL3 requested while building OpenGL2 code
  49. #endif
  50. // --------------------------------------------------------------------------------------------------------------------
  51. // Color
  52. void Color::setFor(const GraphicsContext&, const bool includeAlpha)
  53. {
  54. if (includeAlpha)
  55. glColor4f(red, green, blue, alpha);
  56. else
  57. glColor3f(red, green, blue);
  58. }
  59. // --------------------------------------------------------------------------------------------------------------------
  60. // Line
  61. template<typename T>
  62. static void drawLine(const Point<T>& posStart, const Point<T>& posEnd)
  63. {
  64. DISTRHO_SAFE_ASSERT_RETURN(posStart != posEnd,);
  65. glBegin(GL_LINES);
  66. {
  67. glVertex2d(posStart.getX(), posStart.getY());
  68. glVertex2d(posEnd.getX(), posEnd.getY());
  69. }
  70. glEnd();
  71. }
  72. template<typename T>
  73. void Line<T>::draw(const GraphicsContext&, const T width)
  74. {
  75. DISTRHO_SAFE_ASSERT_RETURN(width != 0,);
  76. glLineWidth(static_cast<GLfloat>(width));
  77. drawLine<T>(posStart, posEnd);
  78. }
  79. #if DGL_ALLOW_DEPRECATED_METHODS
  80. template<typename T>
  81. void Line<T>::draw()
  82. {
  83. drawLine<T>(posStart, posEnd);
  84. }
  85. #endif
  86. // --------------------------------------------------------------------------------------------------------------------
  87. // Circle
  88. template<typename T>
  89. static void drawCircle(const Point<T>& pos,
  90. const uint numSegments,
  91. const float size,
  92. const float sin,
  93. const float cos,
  94. const bool outline)
  95. {
  96. DISTRHO_SAFE_ASSERT_RETURN(numSegments >= 3 && size > 0.0f,);
  97. const double origx = static_cast<double>(pos.getX());
  98. const double origy = static_cast<double>(pos.getY());
  99. double t;
  100. double x = size;
  101. double y = 0.0;
  102. glBegin(outline ? GL_LINE_LOOP : GL_POLYGON);
  103. for (uint i = 0; i < numSegments; ++i)
  104. {
  105. glVertex2d(x + origx, y + origy);
  106. t = x;
  107. x = cos * x - sin * y;
  108. y = sin * t + cos * y;
  109. }
  110. glEnd();
  111. }
  112. template<typename T>
  113. static void drawCircle(const GraphicsContext&,
  114. const Point<T>& pos,
  115. const uint numSegments,
  116. const float size,
  117. const float sin,
  118. const float cos,
  119. const bool outline)
  120. {
  121. drawCircle<T>(pos, numSegments, size, sin, cos, outline);
  122. }
  123. template<typename T>
  124. void Circle<T>::draw(const GraphicsContext& context)
  125. {
  126. drawCircle<T>(context, fPos, fNumSegments, fSize, fSin, fCos, false);
  127. }
  128. template<typename T>
  129. void Circle<T>::drawOutline(const GraphicsContext& context, const T lineWidth)
  130. {
  131. DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,);
  132. glLineWidth(static_cast<GLfloat>(lineWidth));
  133. drawCircle<T>(context, fPos, fNumSegments, fSize, fSin, fCos, true);
  134. }
  135. #if DGL_ALLOW_DEPRECATED_METHODS
  136. template<typename T>
  137. void Circle<T>::draw()
  138. {
  139. drawCircle<T>(fPos, fNumSegments, fSize, fSin, fCos, false);
  140. }
  141. template<typename T>
  142. void Circle<T>::drawOutline()
  143. {
  144. drawCircle<T>(fPos, fNumSegments, fSize, fSin, fCos, true);
  145. }
  146. #endif
  147. // --------------------------------------------------------------------------------------------------------------------
  148. // Triangle
  149. template<typename T>
  150. static void drawTriangle(const Point<T>& pos1,
  151. const Point<T>& pos2,
  152. const Point<T>& pos3,
  153. const bool outline)
  154. {
  155. DISTRHO_SAFE_ASSERT_RETURN(pos1 != pos2 && pos1 != pos3,);
  156. glBegin(outline ? GL_LINE_LOOP : GL_TRIANGLES);
  157. {
  158. glVertex2d(pos1.getX(), pos1.getY());
  159. glVertex2d(pos2.getX(), pos2.getY());
  160. glVertex2d(pos3.getX(), pos3.getY());
  161. }
  162. glEnd();
  163. }
  164. template<typename T>
  165. static void drawTriangle(const GraphicsContext&,
  166. const Point<T>& pos1,
  167. const Point<T>& pos2,
  168. const Point<T>& pos3,
  169. const bool outline)
  170. {
  171. drawTriangle<T>(pos1, pos2, pos3, outline);
  172. }
  173. template<typename T>
  174. void Triangle<T>::draw(const GraphicsContext&)
  175. {
  176. drawTriangle<T>(pos1, pos2, pos3, false);
  177. }
  178. template<typename T>
  179. void Triangle<T>::drawOutline(const GraphicsContext&, const T lineWidth)
  180. {
  181. DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,);
  182. glLineWidth(static_cast<GLfloat>(lineWidth));
  183. drawTriangle<T>(pos1, pos2, pos3, true);
  184. }
  185. #if DGL_ALLOW_DEPRECATED_METHODS
  186. template<typename T>
  187. void Triangle<T>::draw()
  188. {
  189. drawTriangle<T>(pos1, pos2, pos3, false);
  190. }
  191. template<typename T>
  192. void Triangle<T>::drawOutline()
  193. {
  194. drawTriangle<T>(pos1, pos2, pos3, true);
  195. }
  196. #endif
  197. // --------------------------------------------------------------------------------------------------------------------
  198. // Rectangle
  199. template<typename T>
  200. static void drawRectangle(const Rectangle<T>& rect, const bool outline)
  201. {
  202. DISTRHO_SAFE_ASSERT_RETURN(rect.isValid(),);
  203. glBegin(outline ? GL_LINE_LOOP : GL_QUADS);
  204. {
  205. const T x = rect.getX();
  206. const T y = rect.getY();
  207. const T w = rect.getWidth();
  208. const T h = rect.getHeight();
  209. glTexCoord2f(0.0f, 0.0f);
  210. glVertex2d(x, y);
  211. glTexCoord2f(1.0f, 0.0f);
  212. glVertex2d(x+w, y);
  213. glTexCoord2f(1.0f, 1.0f);
  214. glVertex2d(x+w, y+h);
  215. glTexCoord2f(0.0f, 1.0f);
  216. glVertex2d(x, y+h);
  217. }
  218. glEnd();
  219. }
  220. template<typename T>
  221. void Rectangle<T>::draw(const GraphicsContext&)
  222. {
  223. drawRectangle<T>(*this, false);
  224. }
  225. template<typename T>
  226. void Rectangle<T>::drawOutline(const GraphicsContext&, const T lineWidth)
  227. {
  228. DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,);
  229. glLineWidth(static_cast<GLfloat>(lineWidth));
  230. drawRectangle<T>(*this, true);
  231. }
  232. #if DGL_ALLOW_DEPRECATED_METHODS
  233. template<typename T>
  234. void Rectangle<T>::draw()
  235. {
  236. drawRectangle<T>(*this, false);
  237. }
  238. template<typename T>
  239. void Rectangle<T>::drawOutline()
  240. {
  241. drawRectangle<T>(*this, true);
  242. }
  243. #endif
  244. // --------------------------------------------------------------------------------------------------------------------
  245. // OpenGLImage
  246. static void setupOpenGLImage(const OpenGLImage& image, GLuint textureId)
  247. {
  248. DISTRHO_SAFE_ASSERT_RETURN(image.isValid(),);
  249. glEnable(GL_TEXTURE_2D);
  250. glBindTexture(GL_TEXTURE_2D, textureId);
  251. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  252. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  253. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
  254. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
  255. static const float trans[] = { 0.0f, 0.0f, 0.0f, 0.0f };
  256. glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, trans);
  257. glPixelStorei(GL_PACK_ALIGNMENT, 1);
  258. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  259. glTexImage2D(GL_TEXTURE_2D,
  260. 0,
  261. GL_RGBA,
  262. static_cast<GLsizei>(image.getWidth()),
  263. static_cast<GLsizei>(image.getHeight()),
  264. 0,
  265. asOpenGLImageFormat(image.getFormat()),
  266. GL_UNSIGNED_BYTE,
  267. image.getRawData());
  268. glBindTexture(GL_TEXTURE_2D, 0);
  269. glDisable(GL_TEXTURE_2D);
  270. }
  271. static void drawOpenGLImage(const OpenGLImage& image, const Point<int>& pos, const GLuint textureId, bool& setupCalled)
  272. {
  273. if (textureId == 0 || image.isInvalid())
  274. return;
  275. if (! setupCalled)
  276. {
  277. setupOpenGLImage(image, textureId);
  278. setupCalled = true;
  279. }
  280. glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
  281. glEnable(GL_TEXTURE_2D);
  282. glBindTexture(GL_TEXTURE_2D, textureId);
  283. glBegin(GL_QUADS);
  284. {
  285. const int x = pos.getX();
  286. const int y = pos.getY();
  287. const int w = static_cast<int>(image.getWidth());
  288. const int h = static_cast<int>(image.getHeight());
  289. glTexCoord2f(0.0f, 0.0f);
  290. glVertex2d(x, y);
  291. glTexCoord2f(1.0f, 0.0f);
  292. glVertex2d(x+w, y);
  293. glTexCoord2f(1.0f, 1.0f);
  294. glVertex2d(x+w, y+h);
  295. glTexCoord2f(0.0f, 1.0f);
  296. glVertex2d(x, y+h);
  297. }
  298. glEnd();
  299. glBindTexture(GL_TEXTURE_2D, 0);
  300. glDisable(GL_TEXTURE_2D);
  301. }
  302. void OpenGLImage::drawAt(const GraphicsContext&, const Point<int>& pos)
  303. {
  304. drawOpenGLImage(*this, pos, textureId, setupCalled);
  305. }
  306. #if DGL_ALLOW_DEPRECATED_METHODS
  307. void OpenGLImage::draw()
  308. {
  309. drawOpenGLImage(*this, Point<int>(0, 0), textureId, setupCalled);
  310. }
  311. void OpenGLImage::drawAt(const int x, const int y)
  312. {
  313. drawOpenGLImage(*this, Point<int>(x, y), textureId, setupCalled);
  314. }
  315. void OpenGLImage::drawAt(const Point<int>& pos)
  316. {
  317. drawOpenGLImage(*this, pos, textureId, setupCalled);
  318. }
  319. #endif
  320. // --------------------------------------------------------------------------------------------------------------------
  321. // ImageBaseAboutWindow
  322. #if 0
  323. template <>
  324. void ImageBaseAboutWindow<OpenGLImage>::onDisplay()
  325. {
  326. const GraphicsContext& context(getGraphicsContext());
  327. img.draw(context);
  328. }
  329. #endif
  330. template class ImageBaseAboutWindow<OpenGLImage>;
  331. // --------------------------------------------------------------------------------------------------------------------
  332. // ImageBaseButton
  333. template class ImageBaseButton<OpenGLImage>;
  334. // --------------------------------------------------------------------------------------------------------------------
  335. // ImageBaseKnob
  336. template <>
  337. void ImageBaseKnob<OpenGLImage>::PrivateData::init()
  338. {
  339. glTextureId = 0;
  340. glGenTextures(1, &glTextureId);
  341. }
  342. template <>
  343. void ImageBaseKnob<OpenGLImage>::PrivateData::cleanup()
  344. {
  345. if (glTextureId == 0)
  346. return;
  347. glDeleteTextures(1, &glTextureId);
  348. glTextureId = 0;
  349. }
  350. template <>
  351. void ImageBaseKnob<OpenGLImage>::onDisplay()
  352. {
  353. const GraphicsContext& context(getGraphicsContext());
  354. const float normValue = getNormalizedValue();
  355. glEnable(GL_TEXTURE_2D);
  356. glBindTexture(GL_TEXTURE_2D, pData->glTextureId);
  357. if (! pData->isReady)
  358. {
  359. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  360. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  361. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
  362. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
  363. static const float trans[] = { 0.0f, 0.0f, 0.0f, 0.0f };
  364. glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, trans);
  365. glPixelStorei(GL_PACK_ALIGNMENT, 1);
  366. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  367. uint imageDataOffset = 0;
  368. if (pData->rotationAngle == 0)
  369. {
  370. DISTRHO_SAFE_ASSERT_RETURN(pData->imgLayerCount > 0,);
  371. DISTRHO_SAFE_ASSERT_RETURN(normValue >= 0.0f,);
  372. const uint& v1(pData->isImgVertical ? pData->imgLayerWidth : pData->imgLayerHeight);
  373. const uint& v2(pData->isImgVertical ? pData->imgLayerHeight : pData->imgLayerWidth);
  374. // TODO kImageFormatGreyscale
  375. const uint layerDataSize = v1 * v2 * ((pData->image.getFormat() == kImageFormatBGRA ||
  376. pData->image.getFormat() == kImageFormatRGBA) ? 4 : 3);
  377. /* */ imageDataOffset = layerDataSize * uint(normValue * float(pData->imgLayerCount-1));
  378. }
  379. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
  380. static_cast<GLsizei>(getWidth()), static_cast<GLsizei>(getHeight()), 0,
  381. asOpenGLImageFormat(pData->image.getFormat()), GL_UNSIGNED_BYTE, pData->image.getRawData() + imageDataOffset);
  382. pData->isReady = true;
  383. }
  384. const int w = static_cast<int>(getWidth());
  385. const int h = static_cast<int>(getHeight());
  386. if (pData->rotationAngle != 0)
  387. {
  388. glPushMatrix();
  389. const int w2 = w/2;
  390. const int h2 = h/2;
  391. glTranslatef(static_cast<float>(w2), static_cast<float>(h2), 0.0f);
  392. glRotatef(normValue*static_cast<float>(pData->rotationAngle), 0.0f, 0.0f, 1.0f);
  393. Rectangle<int>(-w2, -h2, w, h).draw(context);
  394. glPopMatrix();
  395. }
  396. else
  397. {
  398. Rectangle<int>(0, 0, w, h).draw(context);
  399. }
  400. glBindTexture(GL_TEXTURE_2D, 0);
  401. glDisable(GL_TEXTURE_2D);
  402. }
  403. template class ImageBaseKnob<OpenGLImage>;
  404. // --------------------------------------------------------------------------------------------------------------------
  405. // ImageBaseSlider
  406. template class ImageBaseSlider<OpenGLImage>;
  407. // --------------------------------------------------------------------------------------------------------------------
  408. // ImageBaseSwitch
  409. template class ImageBaseSwitch<OpenGLImage>;
  410. // --------------------------------------------------------------------------------------------------------------------
  411. void Window::PrivateData::createContextIfNeeded()
  412. {
  413. }
  414. void Window::PrivateData::destroyContext()
  415. {
  416. }
  417. void Window::PrivateData::startContext()
  418. {
  419. const PuglArea size = puglGetSizeHint(view, PUGL_CURRENT_SIZE);
  420. glEnable(GL_BLEND);
  421. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  422. glViewport(0, 0, static_cast<GLsizei>(size.width), static_cast<GLsizei>(size.height));
  423. glMatrixMode(GL_PROJECTION);
  424. glLoadIdentity();
  425. glOrtho(0.0, static_cast<GLdouble>(size.width), static_cast<GLdouble>(size.height), 0.0, 0.0, 1.0);
  426. glViewport(0, 0, static_cast<GLsizei>(size.width), static_cast<GLsizei>(size.height));
  427. glMatrixMode(GL_MODELVIEW);
  428. glLoadIdentity();
  429. }
  430. void Window::PrivateData::endContext()
  431. {
  432. }
  433. // --------------------------------------------------------------------------------------------------------------------
  434. #ifndef DGL_GEOMETRY_CPP_INCLUDED
  435. template class Line<double>;
  436. template class Line<float>;
  437. template class Line<int>;
  438. template class Line<uint>;
  439. template class Line<short>;
  440. template class Line<ushort>;
  441. template class Circle<double>;
  442. template class Circle<float>;
  443. template class Circle<int>;
  444. template class Circle<uint>;
  445. template class Circle<short>;
  446. template class Circle<ushort>;
  447. template class Triangle<double>;
  448. template class Triangle<float>;
  449. template class Triangle<int>;
  450. template class Triangle<uint>;
  451. template class Triangle<short>;
  452. template class Triangle<ushort>;
  453. template class Rectangle<double>;
  454. template class Rectangle<float>;
  455. template class Rectangle<int>;
  456. template class Rectangle<uint>;
  457. template class Rectangle<short>;
  458. template class Rectangle<ushort>;
  459. #endif
  460. // --------------------------------------------------------------------------------------------------------------------
  461. END_NAMESPACE_DGL