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.

1073 lines
31KB

  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. #include "../NanoVG.hpp"
  17. #include "SubWidgetPrivateData.hpp"
  18. #ifndef DGL_NO_SHARED_RESOURCES
  19. # include "Resources.hpp"
  20. #endif
  21. // -----------------------------------------------------------------------
  22. #if defined(DISTRHO_OS_WINDOWS)
  23. # include <windows.h>
  24. # define DGL_EXT(PROC, func) static PROC func;
  25. DGL_EXT(PFNGLACTIVETEXTUREPROC, glActiveTexture)
  26. DGL_EXT(PFNGLATTACHSHADERPROC, glAttachShader)
  27. DGL_EXT(PFNGLBINDATTRIBLOCATIONPROC, glBindAttribLocation)
  28. DGL_EXT(PFNGLBINDBUFFERPROC, glBindBuffer)
  29. DGL_EXT(PFNGLBUFFERDATAPROC, glBufferData)
  30. DGL_EXT(PFNGLCOMPILESHADERPROC, glCompileShader)
  31. DGL_EXT(PFNGLCREATEPROGRAMPROC, glCreateProgram)
  32. DGL_EXT(PFNGLCREATESHADERPROC, glCreateShader)
  33. DGL_EXT(PFNGLDELETEBUFFERSPROC, glDeleteBuffers)
  34. DGL_EXT(PFNGLDELETEPROGRAMPROC, glDeleteProgram)
  35. DGL_EXT(PFNGLDELETESHADERPROC, glDeleteShader)
  36. DGL_EXT(PFNGLDISABLEVERTEXATTRIBARRAYPROC, glDisableVertexAttribArray)
  37. DGL_EXT(PFNGLENABLEVERTEXATTRIBARRAYPROC, glEnableVertexAttribArray)
  38. DGL_EXT(PFNGLGENBUFFERSPROC, glGenBuffers)
  39. DGL_EXT(PFNGLGETPROGRAMIVPROC, glGetProgramiv)
  40. DGL_EXT(PFNGLGETPROGRAMINFOLOGPROC, glGetProgramInfoLog)
  41. DGL_EXT(PFNGLGETSHADERIVPROC, glGetShaderiv)
  42. DGL_EXT(PFNGLGETSHADERINFOLOGPROC, glGetShaderInfoLog)
  43. DGL_EXT(PFNGLGETUNIFORMLOCATIONPROC, glGetUniformLocation)
  44. DGL_EXT(PFNGLLINKPROGRAMPROC, glLinkProgram)
  45. DGL_EXT(PFNGLSHADERSOURCEPROC, glShaderSource)
  46. DGL_EXT(PFNGLSTENCILOPSEPARATEPROC, glStencilOpSeparate)
  47. DGL_EXT(PFNGLUNIFORM1IPROC, glUniform1i)
  48. DGL_EXT(PFNGLUNIFORM2FVPROC, glUniform2fv)
  49. DGL_EXT(PFNGLUNIFORM4FVPROC, glUniform4fv)
  50. DGL_EXT(PFNGLUSEPROGRAMPROC, glUseProgram)
  51. DGL_EXT(PFNGLVERTEXATTRIBPOINTERPROC, glVertexAttribPointer)
  52. DGL_EXT(PFNGLBLENDFUNCSEPARATEPROC, glBlendFuncSeparate)
  53. # ifdef DGL_USE_OPENGL3
  54. DGL_EXT(PFNGLBINDBUFFERRANGEPROC, glBindBufferRange)
  55. DGL_EXT(PFNGLBINDVERTEXARRAYPROC, glBindVertexArray)
  56. DGL_EXT(PFNGLDELETEVERTEXARRAYSPROC, glDeleteVertexArrays)
  57. DGL_EXT(PFNGLGENERATEMIPMAPPROC, glGenerateMipmap)
  58. DGL_EXT(PFNGLGETUNIFORMBLOCKINDEXPROC, glGetUniformBlockIndex)
  59. DGL_EXT(PFNGLGENVERTEXARRAYSPROC, glGenVertexArrays)
  60. DGL_EXT(PFNGLUNIFORMBLOCKBINDINGPROC, glUniformBlockBinding)
  61. # endif
  62. # undef DGL_EXT
  63. #endif
  64. // -----------------------------------------------------------------------
  65. // Include NanoVG OpenGL implementation
  66. //#define STB_IMAGE_STATIC
  67. #ifdef DGL_USE_OPENGL3
  68. # define NANOVG_GL3_IMPLEMENTATION
  69. #else
  70. # define NANOVG_GL2_IMPLEMENTATION
  71. #endif
  72. #if defined(DISTRHO_OS_MAC) && defined(NANOVG_GL3_IMPLEMENTATION)
  73. # define glBindVertexArray glBindVertexArrayAPPLE
  74. # define glDeleteVertexArrays glDeleteVertexArraysAPPLE
  75. # define glGenVertexArrays glGenVertexArraysAPPLE
  76. #endif
  77. #include "nanovg/nanovg_gl.h"
  78. #if defined(NANOVG_GL2)
  79. # define nvgCreateGL nvgCreateGL2
  80. # define nvgDeleteGL nvgDeleteGL2
  81. # define nvglCreateImageFromHandle nvglCreateImageFromHandleGL2
  82. # define nvglImageHandle nvglImageHandleGL2
  83. #elif defined(NANOVG_GL3)
  84. # define nvgCreateGL nvgCreateGL3
  85. # define nvgDeleteGL nvgDeleteGL3
  86. # define nvglCreateImageFromHandle nvglCreateImageFromHandleGL3
  87. # define nvglImageHandle nvglImageHandleGL3
  88. #elif defined(NANOVG_GLES2)
  89. # define nvgCreateGL nvgCreateGLES2
  90. # define nvgDeleteGL nvgDeleteGLES2
  91. # define nvglCreateImageFromHandle nvglCreateImageFromHandleGLES2
  92. # define nvglImageHandle nvglImageHandleGLES2
  93. #elif defined(NANOVG_GLES3)
  94. # define nvgCreateGL nvgCreateGLES3
  95. # define nvgDeleteGL nvgDeleteGLES3
  96. # define nvglCreateImageFromHandle nvglCreateImageFromHandleGLES3
  97. # define nvglImageHandle nvglImageHandleGLES3
  98. #endif
  99. static NVGcontext* nvgCreateGL_helper(int flags)
  100. {
  101. #if defined(DISTRHO_OS_WINDOWS)
  102. # if defined(__GNUC__) && (__GNUC__ >= 9)
  103. # pragma GCC diagnostic push
  104. # pragma GCC diagnostic ignored "-Wcast-function-type"
  105. # endif
  106. static bool needsInit = true;
  107. # define DGL_EXT(PROC, func) \
  108. if (needsInit) func = (PROC) wglGetProcAddress ( #func ); \
  109. DISTRHO_SAFE_ASSERT_RETURN(func != nullptr, nullptr);
  110. DGL_EXT(PFNGLACTIVETEXTUREPROC, glActiveTexture)
  111. DGL_EXT(PFNGLATTACHSHADERPROC, glAttachShader)
  112. DGL_EXT(PFNGLBINDATTRIBLOCATIONPROC, glBindAttribLocation)
  113. DGL_EXT(PFNGLBINDBUFFERPROC, glBindBuffer)
  114. DGL_EXT(PFNGLBUFFERDATAPROC, glBufferData)
  115. DGL_EXT(PFNGLCOMPILESHADERPROC, glCompileShader)
  116. DGL_EXT(PFNGLCREATEPROGRAMPROC, glCreateProgram)
  117. DGL_EXT(PFNGLCREATESHADERPROC, glCreateShader)
  118. DGL_EXT(PFNGLDELETEBUFFERSPROC, glDeleteBuffers)
  119. DGL_EXT(PFNGLDELETEPROGRAMPROC, glDeleteProgram)
  120. DGL_EXT(PFNGLDELETESHADERPROC, glDeleteShader)
  121. DGL_EXT(PFNGLDISABLEVERTEXATTRIBARRAYPROC, glDisableVertexAttribArray)
  122. DGL_EXT(PFNGLENABLEVERTEXATTRIBARRAYPROC, glEnableVertexAttribArray)
  123. DGL_EXT(PFNGLGENBUFFERSPROC, glGenBuffers)
  124. DGL_EXT(PFNGLGETPROGRAMIVPROC, glGetProgramiv)
  125. DGL_EXT(PFNGLGETPROGRAMINFOLOGPROC, glGetProgramInfoLog)
  126. DGL_EXT(PFNGLGETSHADERIVPROC, glGetShaderiv)
  127. DGL_EXT(PFNGLGETSHADERINFOLOGPROC, glGetShaderInfoLog)
  128. DGL_EXT(PFNGLGETUNIFORMLOCATIONPROC, glGetUniformLocation)
  129. DGL_EXT(PFNGLLINKPROGRAMPROC, glLinkProgram)
  130. DGL_EXT(PFNGLSHADERSOURCEPROC, glShaderSource)
  131. DGL_EXT(PFNGLSTENCILOPSEPARATEPROC, glStencilOpSeparate)
  132. DGL_EXT(PFNGLUNIFORM1IPROC, glUniform1i)
  133. DGL_EXT(PFNGLUNIFORM2FVPROC, glUniform2fv)
  134. DGL_EXT(PFNGLUNIFORM4FVPROC, glUniform4fv)
  135. DGL_EXT(PFNGLUSEPROGRAMPROC, glUseProgram)
  136. DGL_EXT(PFNGLVERTEXATTRIBPOINTERPROC, glVertexAttribPointer)
  137. DGL_EXT(PFNGLBLENDFUNCSEPARATEPROC, glBlendFuncSeparate)
  138. # ifdef DGL_USE_OPENGL3
  139. DGL_EXT(PFNGLBINDBUFFERRANGEPROC, glBindBufferRange)
  140. DGL_EXT(PFNGLBINDVERTEXARRAYPROC, glBindVertexArray)
  141. DGL_EXT(PFNGLDELETEVERTEXARRAYSPROC, glDeleteVertexArrays)
  142. DGL_EXT(PFNGLGENERATEMIPMAPPROC, glGenerateMipmap)
  143. DGL_EXT(PFNGLGETUNIFORMBLOCKINDEXPROC, glGetUniformBlockIndex)
  144. DGL_EXT(PFNGLGENVERTEXARRAYSPROC, glGenVertexArrays)
  145. DGL_EXT(PFNGLUNIFORMBLOCKBINDINGPROC, glUniformBlockBinding)
  146. # endif
  147. # undef DGL_EXT
  148. needsInit = false;
  149. # if defined(__GNUC__) && (__GNUC__ >= 9)
  150. # pragma GCC diagnostic pop
  151. # endif
  152. #endif
  153. return nvgCreateGL(flags);
  154. }
  155. // -----------------------------------------------------------------------
  156. START_NAMESPACE_DGL
  157. // -----------------------------------------------------------------------
  158. // DGL Color class conversion
  159. Color::Color(const NVGcolor& c) noexcept
  160. : red(c.r), green(c.g), blue(c.b), alpha(c.a)
  161. {
  162. fixBounds();
  163. }
  164. Color::operator NVGcolor() const noexcept
  165. {
  166. NVGcolor nc;
  167. nc.r = red;
  168. nc.g = green;
  169. nc.b = blue;
  170. nc.a = alpha;
  171. return nc;
  172. }
  173. // -----------------------------------------------------------------------
  174. // NanoImage
  175. NanoImage::NanoImage()
  176. : fHandle(),
  177. fSize() {}
  178. NanoImage::NanoImage(const Handle& handle)
  179. : fHandle(handle),
  180. fSize()
  181. {
  182. DISTRHO_SAFE_ASSERT_RETURN(fHandle.context != nullptr && fHandle.imageId != 0,);
  183. _updateSize();
  184. }
  185. NanoImage::~NanoImage()
  186. {
  187. if (fHandle.context != nullptr && fHandle.imageId != 0)
  188. nvgDeleteImage(fHandle.context, fHandle.imageId);
  189. }
  190. NanoImage& NanoImage::operator=(const Handle& handle)
  191. {
  192. if (fHandle.context != nullptr && fHandle.imageId != 0)
  193. nvgDeleteImage(fHandle.context, fHandle.imageId);
  194. fHandle.context = handle.context;
  195. fHandle.imageId = handle.imageId;
  196. _updateSize();
  197. return *this;
  198. }
  199. bool NanoImage::isValid() const noexcept
  200. {
  201. return (fHandle.context != nullptr && fHandle.imageId != 0);
  202. }
  203. Size<uint> NanoImage::getSize() const noexcept
  204. {
  205. return fSize;
  206. }
  207. GLuint NanoImage::getTextureHandle() const
  208. {
  209. DISTRHO_SAFE_ASSERT_RETURN(fHandle.context != nullptr && fHandle.imageId != 0, 0);
  210. return nvglImageHandle(fHandle.context, fHandle.imageId);
  211. }
  212. void NanoImage::_updateSize()
  213. {
  214. int w=0, h=0;
  215. nvgImageSize(fHandle.context, fHandle.imageId, &w, &h);
  216. if (w < 0) w = 0;
  217. if (h < 0) h = 0;
  218. fSize.setSize(static_cast<uint>(w), static_cast<uint>(h));
  219. }
  220. // -----------------------------------------------------------------------
  221. // Paint
  222. NanoVG::Paint::Paint() noexcept
  223. : radius(0.0f), feather(0.0f), innerColor(), outerColor(), imageId(0)
  224. {
  225. std::memset(xform, 0, sizeof(float)*6);
  226. std::memset(extent, 0, sizeof(float)*2);
  227. }
  228. NanoVG::Paint::Paint(const NVGpaint& p) noexcept
  229. : radius(p.radius), feather(p.feather), innerColor(p.innerColor), outerColor(p.outerColor), imageId(p.image)
  230. {
  231. std::memcpy(xform, p.xform, sizeof(float)*6);
  232. std::memcpy(extent, p.extent, sizeof(float)*2);
  233. }
  234. NanoVG::Paint::operator NVGpaint() const noexcept
  235. {
  236. NVGpaint p;
  237. p.radius = radius;
  238. p.feather = feather;
  239. p.innerColor = innerColor;
  240. p.outerColor = outerColor;
  241. p.image = imageId;
  242. std::memcpy(p.xform, xform, sizeof(float)*6);
  243. std::memcpy(p.extent, extent, sizeof(float)*2);
  244. return p;
  245. }
  246. // -----------------------------------------------------------------------
  247. // NanoVG
  248. NanoVG::NanoVG(int flags)
  249. : fContext(nvgCreateGL_helper(flags)),
  250. fInFrame(false),
  251. fIsSubWidget(false) {}
  252. NanoVG::~NanoVG()
  253. {
  254. DISTRHO_SAFE_ASSERT(! fInFrame);
  255. if (fContext != nullptr && ! fIsSubWidget)
  256. nvgDeleteGL(fContext);
  257. }
  258. // -----------------------------------------------------------------------
  259. void NanoVG::beginFrame(const uint width, const uint height, const float scaleFactor)
  260. {
  261. DISTRHO_SAFE_ASSERT_RETURN(scaleFactor > 0.0f,);
  262. DISTRHO_SAFE_ASSERT_RETURN(! fInFrame,);
  263. fInFrame = true;
  264. if (fContext != nullptr)
  265. nvgBeginFrame(fContext, static_cast<int>(width), static_cast<int>(height), scaleFactor);
  266. }
  267. void NanoVG::beginFrame(Widget* const widget)
  268. {
  269. DISTRHO_SAFE_ASSERT_RETURN(widget != nullptr,);
  270. DISTRHO_SAFE_ASSERT_RETURN(! fInFrame,);
  271. fInFrame = true;
  272. if (fContext == nullptr)
  273. return;
  274. if (TopLevelWidget* const tlw = widget->getTopLevelWidget())
  275. nvgBeginFrame(fContext,
  276. static_cast<int>(tlw->getWidth()),
  277. static_cast<int>(tlw->getHeight()),
  278. tlw->getScaleFactor());
  279. }
  280. void NanoVG::cancelFrame()
  281. {
  282. DISTRHO_SAFE_ASSERT_RETURN(fInFrame,);
  283. if (fContext != nullptr)
  284. nvgCancelFrame(fContext);
  285. fInFrame = false;
  286. }
  287. void NanoVG::endFrame()
  288. {
  289. DISTRHO_SAFE_ASSERT_RETURN(fInFrame,);
  290. // Save current blend state
  291. GLboolean blendEnabled;
  292. GLint blendSrc, blendDst;
  293. glGetBooleanv(GL_BLEND, &blendEnabled);
  294. glGetIntegerv(GL_BLEND_SRC_ALPHA, &blendSrc);
  295. glGetIntegerv(GL_BLEND_DST_ALPHA, &blendDst);
  296. if (fContext != nullptr)
  297. nvgEndFrame(fContext);
  298. // Restore blend state
  299. if (blendEnabled)
  300. glEnable(GL_BLEND);
  301. else
  302. glDisable(GL_BLEND);
  303. glBlendFunc(blendSrc, blendDst);
  304. fInFrame = false;
  305. }
  306. // -----------------------------------------------------------------------
  307. // State Handling
  308. void NanoVG::save()
  309. {
  310. if (fContext != nullptr)
  311. nvgSave(fContext);
  312. }
  313. void NanoVG::restore()
  314. {
  315. if (fContext != nullptr)
  316. nvgRestore(fContext);
  317. }
  318. void NanoVG::reset()
  319. {
  320. if (fContext != nullptr)
  321. nvgReset(fContext);
  322. }
  323. // -----------------------------------------------------------------------
  324. // Render styles
  325. void NanoVG::strokeColor(const Color& color)
  326. {
  327. if (fContext != nullptr)
  328. nvgStrokeColor(fContext, color);
  329. }
  330. void NanoVG::strokeColor(const int red, const int green, const int blue, const int alpha)
  331. {
  332. if (fContext != nullptr)
  333. {
  334. DISTRHO_SAFE_ASSERT_RETURN(red >= 0 && red <= 255,);
  335. DISTRHO_SAFE_ASSERT_RETURN(green >= 0 && green <= 255,);
  336. DISTRHO_SAFE_ASSERT_RETURN(blue >= 0 && blue <= 255,);
  337. DISTRHO_SAFE_ASSERT_RETURN(alpha >= 0 && alpha <= 255,);
  338. nvgStrokeColor(fContext, nvgRGBA(static_cast<uchar>(red),
  339. static_cast<uchar>(green),
  340. static_cast<uchar>(blue),
  341. static_cast<uchar>(alpha)));
  342. }
  343. }
  344. void NanoVG::strokeColor(const float red, const float green, const float blue, const float alpha)
  345. {
  346. if (fContext != nullptr)
  347. nvgStrokeColor(fContext, nvgRGBAf(red, green, blue, alpha));
  348. }
  349. void NanoVG::strokePaint(const Paint& paint)
  350. {
  351. if (fContext != nullptr)
  352. nvgStrokePaint(fContext, paint);
  353. }
  354. void NanoVG::fillColor(const Color& color)
  355. {
  356. if (fContext != nullptr)
  357. nvgFillColor(fContext, color);
  358. }
  359. void NanoVG::fillColor(const int red, const int green, const int blue, const int alpha)
  360. {
  361. if (fContext != nullptr)
  362. {
  363. DISTRHO_SAFE_ASSERT_RETURN(red >= 0 && red <= 255,);
  364. DISTRHO_SAFE_ASSERT_RETURN(green >= 0 && green <= 255,);
  365. DISTRHO_SAFE_ASSERT_RETURN(blue >= 0 && blue <= 255,);
  366. DISTRHO_SAFE_ASSERT_RETURN(alpha >= 0 && alpha <= 255,);
  367. nvgFillColor(fContext, nvgRGBA(static_cast<uchar>(red),
  368. static_cast<uchar>(green),
  369. static_cast<uchar>(blue),
  370. static_cast<uchar>(alpha)));
  371. }
  372. }
  373. void NanoVG::fillColor(const float red, const float green, const float blue, const float alpha)
  374. {
  375. if (fContext != nullptr)
  376. nvgFillColor(fContext, nvgRGBAf(red, green, blue, alpha));
  377. }
  378. void NanoVG::fillPaint(const Paint& paint)
  379. {
  380. if (fContext != nullptr)
  381. nvgFillPaint(fContext, paint);
  382. }
  383. void NanoVG::miterLimit(float limit)
  384. {
  385. if (fContext == nullptr) return;
  386. DISTRHO_SAFE_ASSERT_RETURN(limit > 0.0f,);
  387. nvgMiterLimit(fContext, limit);
  388. }
  389. void NanoVG::strokeWidth(float size)
  390. {
  391. if (fContext == nullptr) return;
  392. DISTRHO_SAFE_ASSERT_RETURN(size > 0.0f,);
  393. nvgStrokeWidth(fContext, size);
  394. }
  395. void NanoVG::lineCap(NanoVG::LineCap cap)
  396. {
  397. if (fContext != nullptr)
  398. nvgLineCap(fContext, cap);
  399. }
  400. void NanoVG::lineJoin(NanoVG::LineCap join)
  401. {
  402. if (fContext != nullptr)
  403. nvgLineJoin(fContext, join);
  404. }
  405. void NanoVG::globalAlpha(float alpha)
  406. {
  407. if (fContext != nullptr)
  408. nvgGlobalAlpha(fContext, alpha);
  409. }
  410. // -----------------------------------------------------------------------
  411. // Transforms
  412. void NanoVG::resetTransform()
  413. {
  414. if (fContext != nullptr)
  415. nvgResetTransform(fContext);
  416. }
  417. void NanoVG::transform(float a, float b, float c, float d, float e, float f)
  418. {
  419. if (fContext != nullptr)
  420. nvgTransform(fContext, a, b, c, d, e, f);
  421. }
  422. void NanoVG::translate(float x, float y)
  423. {
  424. if (fContext != nullptr)
  425. nvgTranslate(fContext, x, y);
  426. }
  427. void NanoVG::rotate(float angle)
  428. {
  429. if (fContext != nullptr)
  430. nvgRotate(fContext, angle);
  431. }
  432. void NanoVG::skewX(float angle)
  433. {
  434. if (fContext == nullptr) return;
  435. DISTRHO_SAFE_ASSERT_RETURN(angle > 0.0f,);
  436. nvgSkewX(fContext, angle);
  437. }
  438. void NanoVG::skewY(float angle)
  439. {
  440. if (fContext == nullptr) return;
  441. DISTRHO_SAFE_ASSERT_RETURN(angle > 0.0f,);
  442. nvgSkewY(fContext, angle);
  443. }
  444. void NanoVG::scale(float x, float y)
  445. {
  446. if (fContext == nullptr) return;
  447. DISTRHO_SAFE_ASSERT_RETURN(d_isNotZero(x),);
  448. DISTRHO_SAFE_ASSERT_RETURN(d_isNotZero(y),);
  449. nvgScale(fContext, x, y);
  450. }
  451. void NanoVG::currentTransform(float xform[6])
  452. {
  453. if (fContext != nullptr)
  454. nvgCurrentTransform(fContext, xform);
  455. }
  456. void NanoVG::transformIdentity(float dst[6])
  457. {
  458. nvgTransformIdentity(dst);
  459. }
  460. void NanoVG::transformTranslate(float dst[6], float tx, float ty)
  461. {
  462. nvgTransformTranslate(dst, tx, ty);
  463. }
  464. void NanoVG::transformScale(float dst[6], float sx, float sy)
  465. {
  466. nvgTransformScale(dst, sx, sy);
  467. }
  468. void NanoVG::transformRotate(float dst[6], float a)
  469. {
  470. nvgTransformRotate(dst, a);
  471. }
  472. void NanoVG::transformSkewX(float dst[6], float a)
  473. {
  474. nvgTransformSkewX(dst, a);
  475. }
  476. void NanoVG::transformSkewY(float dst[6], float a)
  477. {
  478. nvgTransformSkewY(dst, a);
  479. }
  480. void NanoVG::transformMultiply(float dst[6], const float src[6])
  481. {
  482. nvgTransformMultiply(dst, src);
  483. }
  484. void NanoVG::transformPremultiply(float dst[6], const float src[6])
  485. {
  486. nvgTransformPremultiply(dst, src);
  487. }
  488. int NanoVG::transformInverse(float dst[6], const float src[6])
  489. {
  490. return nvgTransformInverse(dst, src);
  491. }
  492. void NanoVG::transformPoint(float& dstx, float& dsty, const float xform[6], float srcx, float srcy)
  493. {
  494. nvgTransformPoint(&dstx, &dsty, xform, srcx, srcy);
  495. }
  496. float NanoVG::degToRad(float deg)
  497. {
  498. return nvgDegToRad(deg);
  499. }
  500. float NanoVG::radToDeg(float rad)
  501. {
  502. return nvgRadToDeg(rad);
  503. }
  504. // -----------------------------------------------------------------------
  505. // Images
  506. NanoImage::Handle NanoVG::createImageFromFile(const char* filename, ImageFlags imageFlags)
  507. {
  508. return createImageFromFile(filename, static_cast<int>(imageFlags));
  509. }
  510. NanoImage::Handle NanoVG::createImageFromFile(const char* filename, int imageFlags)
  511. {
  512. if (fContext == nullptr) return NanoImage::Handle();
  513. DISTRHO_SAFE_ASSERT_RETURN(filename != nullptr && filename[0] != '\0', NanoImage::Handle());
  514. return NanoImage::Handle(fContext, nvgCreateImage(fContext, filename, imageFlags));
  515. }
  516. NanoImage::Handle NanoVG::createImageFromMemory(uchar* data, uint dataSize, ImageFlags imageFlags)
  517. {
  518. return createImageFromMemory(data, dataSize, static_cast<int>(imageFlags));
  519. }
  520. NanoImage::Handle NanoVG::createImageFromMemory(uchar* data, uint dataSize, int imageFlags)
  521. {
  522. if (fContext == nullptr) return NanoImage::Handle();
  523. DISTRHO_SAFE_ASSERT_RETURN(data != nullptr, NanoImage::Handle());
  524. DISTRHO_SAFE_ASSERT_RETURN(dataSize > 0, NanoImage::Handle());
  525. return NanoImage::Handle(fContext, nvgCreateImageMem(fContext, imageFlags, data,static_cast<int>(dataSize)));
  526. }
  527. NanoImage::Handle NanoVG::createImageFromRawMemory(uint w, uint h, const uchar* data,
  528. ImageFlags imageFlags, ImageFormat format)
  529. {
  530. return createImageFromRawMemory(w, h, data, static_cast<int>(imageFlags), format);
  531. }
  532. NanoImage::Handle NanoVG::createImageFromRawMemory(uint w, uint h, const uchar* data,
  533. int imageFlags, ImageFormat format)
  534. {
  535. if (fContext == nullptr) return NanoImage::Handle();
  536. DISTRHO_SAFE_ASSERT_RETURN(data != nullptr, NanoImage::Handle());
  537. NVGtexture nvgformat;
  538. switch (format)
  539. {
  540. case kImageFormatGrayscale:
  541. nvgformat = NVG_TEXTURE_ALPHA;
  542. break;
  543. case kImageFormatBGR:
  544. nvgformat = NVG_TEXTURE_BGR;
  545. break;
  546. case kImageFormatBGRA:
  547. nvgformat = NVG_TEXTURE_BGRA;
  548. break;
  549. case kImageFormatRGB:
  550. nvgformat = NVG_TEXTURE_RGB;
  551. break;
  552. case kImageFormatRGBA:
  553. nvgformat = NVG_TEXTURE_RGBA;
  554. break;
  555. default:
  556. return NanoImage::Handle();
  557. }
  558. return NanoImage::Handle(fContext, nvgCreateImageRaw(fContext,
  559. static_cast<int>(w),
  560. static_cast<int>(h), imageFlags, nvgformat, data));
  561. }
  562. NanoImage::Handle NanoVG::createImageFromRGBA(uint w, uint h, const uchar* data, ImageFlags imageFlags)
  563. {
  564. return createImageFromRGBA(w, h, data, static_cast<int>(imageFlags));
  565. }
  566. NanoImage::Handle NanoVG::createImageFromRGBA(uint w, uint h, const uchar* data, int imageFlags)
  567. {
  568. if (fContext == nullptr) return NanoImage::Handle();
  569. DISTRHO_SAFE_ASSERT_RETURN(data != nullptr, NanoImage::Handle());
  570. return NanoImage::Handle(fContext, nvgCreateImageRGBA(fContext,
  571. static_cast<int>(w),
  572. static_cast<int>(h), imageFlags, data));
  573. }
  574. NanoImage::Handle NanoVG::createImageFromTextureHandle(GLuint textureId, uint w, uint h,
  575. ImageFlags imageFlags, bool deleteTexture)
  576. {
  577. return createImageFromTextureHandle(textureId, w, h, static_cast<int>(imageFlags), deleteTexture);
  578. }
  579. NanoImage::Handle NanoVG::createImageFromTextureHandle(GLuint textureId, uint w, uint h,
  580. int imageFlags, bool deleteTexture)
  581. {
  582. if (fContext == nullptr) return NanoImage::Handle();
  583. DISTRHO_SAFE_ASSERT_RETURN(textureId != 0, NanoImage::Handle());
  584. if (! deleteTexture)
  585. imageFlags |= NVG_IMAGE_NODELETE;
  586. return NanoImage::Handle(fContext, nvglCreateImageFromHandle(fContext,
  587. textureId,
  588. static_cast<int>(w),
  589. static_cast<int>(h), imageFlags));
  590. }
  591. // -----------------------------------------------------------------------
  592. // Paints
  593. NanoVG::Paint NanoVG::linearGradient(float sx, float sy, float ex, float ey, const Color& icol, const Color& ocol)
  594. {
  595. if (fContext == nullptr) return Paint();
  596. return nvgLinearGradient(fContext, sx, sy, ex, ey, icol, ocol);
  597. }
  598. NanoVG::Paint NanoVG::boxGradient(float x, float y, float w, float h, float r, float f, const Color& icol, const Color& ocol)
  599. {
  600. if (fContext == nullptr) return Paint();
  601. return nvgBoxGradient(fContext, x, y, w, h, r, f, icol, ocol);
  602. }
  603. NanoVG::Paint NanoVG::radialGradient(float cx, float cy, float inr, float outr, const Color& icol, const Color& ocol)
  604. {
  605. if (fContext == nullptr) return Paint();
  606. return nvgRadialGradient(fContext, cx, cy, inr, outr, icol, ocol);
  607. }
  608. NanoVG::Paint NanoVG::imagePattern(float ox, float oy, float ex, float ey, float angle, const NanoImage& image, float alpha)
  609. {
  610. if (fContext == nullptr) return Paint();
  611. const int imageId(image.fHandle.imageId);
  612. DISTRHO_SAFE_ASSERT_RETURN(imageId != 0, Paint());
  613. return nvgImagePattern(fContext, ox, oy, ex, ey, angle, imageId, alpha);
  614. }
  615. // -----------------------------------------------------------------------
  616. // Scissoring
  617. void NanoVG::scissor(float x, float y, float w, float h)
  618. {
  619. if (fContext != nullptr)
  620. nvgScissor(fContext, x, y, w, h);
  621. }
  622. void NanoVG::intersectScissor(float x, float y, float w, float h)
  623. {
  624. if (fContext != nullptr)
  625. nvgIntersectScissor(fContext, x, y, w, h);
  626. }
  627. void NanoVG::resetScissor()
  628. {
  629. if (fContext != nullptr)
  630. nvgResetScissor(fContext);
  631. }
  632. // -----------------------------------------------------------------------
  633. // Paths
  634. void NanoVG::beginPath()
  635. {
  636. if (fContext != nullptr)
  637. nvgBeginPath(fContext);
  638. }
  639. void NanoVG::moveTo(float x, float y)
  640. {
  641. if (fContext != nullptr)
  642. nvgMoveTo(fContext, x, y);
  643. }
  644. void NanoVG::lineTo(float x, float y)
  645. {
  646. if (fContext != nullptr)
  647. nvgLineTo(fContext, x, y);
  648. }
  649. void NanoVG::bezierTo(float c1x, float c1y, float c2x, float c2y, float x, float y)
  650. {
  651. if (fContext != nullptr)
  652. nvgBezierTo(fContext, c1x, c1y, c2x, c2y, x, y);
  653. }
  654. void NanoVG::quadTo(float cx, float cy, float x, float y)
  655. {
  656. if (fContext != nullptr)
  657. nvgQuadTo(fContext, cx, cy, x, y);
  658. }
  659. void NanoVG::arcTo(float x1, float y1, float x2, float y2, float radius)
  660. {
  661. if (fContext != nullptr)
  662. nvgArcTo(fContext, x1, y1, x2, y2, radius);
  663. }
  664. void NanoVG::closePath()
  665. {
  666. if (fContext != nullptr)
  667. nvgClosePath(fContext);
  668. }
  669. void NanoVG::pathWinding(NanoVG::Winding dir)
  670. {
  671. if (fContext != nullptr)
  672. nvgPathWinding(fContext, dir);
  673. }
  674. void NanoVG::arc(float cx, float cy, float r, float a0, float a1, NanoVG::Winding dir)
  675. {
  676. if (fContext != nullptr)
  677. nvgArc(fContext, cx, cy, r, a0, a1, dir);
  678. }
  679. void NanoVG::rect(float x, float y, float w, float h)
  680. {
  681. if (fContext != nullptr)
  682. nvgRect(fContext, x, y, w, h);
  683. }
  684. void NanoVG::roundedRect(float x, float y, float w, float h, float r)
  685. {
  686. if (fContext != nullptr)
  687. nvgRoundedRect(fContext, x, y, w, h, r);
  688. }
  689. void NanoVG::ellipse(float cx, float cy, float rx, float ry)
  690. {
  691. if (fContext != nullptr)
  692. nvgEllipse(fContext, cx, cy, rx, ry);
  693. }
  694. void NanoVG::circle(float cx, float cy, float r)
  695. {
  696. if (fContext != nullptr)
  697. nvgCircle(fContext, cx, cy, r);
  698. }
  699. void NanoVG::fill()
  700. {
  701. if (fContext != nullptr)
  702. nvgFill(fContext);
  703. }
  704. void NanoVG::stroke()
  705. {
  706. if (fContext != nullptr)
  707. nvgStroke(fContext);
  708. }
  709. // -----------------------------------------------------------------------
  710. // Text
  711. NanoVG::FontId NanoVG::createFontFromFile(const char* name, const char* filename)
  712. {
  713. DISTRHO_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0', -1);
  714. DISTRHO_SAFE_ASSERT_RETURN(filename != nullptr && filename[0] != '\0', -1);
  715. DISTRHO_SAFE_ASSERT_RETURN(fContext != nullptr, -1);
  716. return nvgCreateFont(fContext, name, filename);
  717. }
  718. NanoVG::FontId NanoVG::createFontFromMemory(const char* name, const uchar* data, uint dataSize, bool freeData)
  719. {
  720. DISTRHO_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0', -1);
  721. DISTRHO_SAFE_ASSERT_RETURN(data != nullptr, -1);
  722. DISTRHO_SAFE_ASSERT_RETURN(fContext != nullptr, -1);
  723. return nvgCreateFontMem(fContext, name, const_cast<uchar*>(data), static_cast<int>(dataSize), freeData);
  724. }
  725. NanoVG::FontId NanoVG::findFont(const char* name)
  726. {
  727. DISTRHO_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0', -1);
  728. DISTRHO_SAFE_ASSERT_RETURN(fContext != nullptr, -1);
  729. return nvgFindFont(fContext, name);
  730. }
  731. void NanoVG::fontSize(float size)
  732. {
  733. if (fContext == nullptr) return;
  734. DISTRHO_SAFE_ASSERT_RETURN(size > 0.0f,);
  735. nvgFontSize(fContext, size);
  736. }
  737. void NanoVG::fontBlur(float blur)
  738. {
  739. if (fContext == nullptr) return;
  740. DISTRHO_SAFE_ASSERT_RETURN(blur >= 0.0f,);
  741. nvgFontBlur(fContext, blur);
  742. }
  743. void NanoVG::textLetterSpacing(float spacing)
  744. {
  745. if (fContext == nullptr) return;
  746. DISTRHO_SAFE_ASSERT_RETURN(spacing >= 0.0f,);
  747. nvgTextLetterSpacing(fContext, spacing);
  748. }
  749. void NanoVG::textLineHeight(float lineHeight)
  750. {
  751. if (fContext == nullptr) return;
  752. DISTRHO_SAFE_ASSERT_RETURN(lineHeight > 0.0f,);
  753. nvgTextLineHeight(fContext, lineHeight);
  754. }
  755. void NanoVG::textAlign(NanoVG::Align align)
  756. {
  757. if (fContext != nullptr)
  758. nvgTextAlign(fContext, align);
  759. }
  760. void NanoVG::textAlign(int align)
  761. {
  762. if (fContext != nullptr)
  763. nvgTextAlign(fContext, align);
  764. }
  765. void NanoVG::fontFaceId(FontId font)
  766. {
  767. if (fContext == nullptr) return;
  768. DISTRHO_SAFE_ASSERT_RETURN(font >= 0,);
  769. nvgFontFaceId(fContext, font);
  770. }
  771. void NanoVG::fontFace(const char* font)
  772. {
  773. if (fContext == nullptr) return;
  774. DISTRHO_SAFE_ASSERT_RETURN(font != nullptr && font[0] != '\0',);
  775. nvgFontFace(fContext, font);
  776. }
  777. float NanoVG::text(float x, float y, const char* string, const char* end)
  778. {
  779. if (fContext == nullptr) return 0.0f;
  780. DISTRHO_SAFE_ASSERT_RETURN(string != nullptr && string[0] != '\0', 0.0f);
  781. return nvgText(fContext, x, y, string, end);
  782. }
  783. void NanoVG::textBox(float x, float y, float breakRowWidth, const char* string, const char* end)
  784. {
  785. if (fContext == nullptr) return;
  786. DISTRHO_SAFE_ASSERT_RETURN(string != nullptr && string[0] != '\0',);
  787. nvgTextBox(fContext, x, y, breakRowWidth, string, end);
  788. }
  789. float NanoVG::textBounds(float x, float y, const char* string, const char* end, Rectangle<float>& bounds)
  790. {
  791. if (fContext == nullptr) return 0.0f;
  792. DISTRHO_SAFE_ASSERT_RETURN(string != nullptr && string[0] != '\0', 0.0f);
  793. float b[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
  794. const float ret = nvgTextBounds(fContext, x, y, string, end, b);
  795. bounds = Rectangle<float>(b[0], b[1], b[2] - b[0], b[3] - b[1]);
  796. return ret;
  797. }
  798. void NanoVG::textBoxBounds(float x, float y, float breakRowWidth, const char* string, const char* end, float bounds[4])
  799. {
  800. if (fContext == nullptr) return;
  801. DISTRHO_SAFE_ASSERT_RETURN(string != nullptr && string[0] != '\0',);
  802. nvgTextBoxBounds(fContext, x, y, breakRowWidth, string, end, bounds);
  803. }
  804. int NanoVG::textGlyphPositions(float x, float y, const char* string, const char* end, NanoVG::GlyphPosition& positions, int maxPositions)
  805. {
  806. if (fContext == nullptr) return 0;
  807. DISTRHO_SAFE_ASSERT_RETURN(string != nullptr && string[0] != '\0', 0);
  808. return nvgTextGlyphPositions(fContext, x, y, string, end, (NVGglyphPosition*)&positions, maxPositions);
  809. }
  810. void NanoVG::textMetrics(float* ascender, float* descender, float* lineh)
  811. {
  812. if (fContext != nullptr)
  813. nvgTextMetrics(fContext, ascender, descender, lineh);
  814. }
  815. int NanoVG::textBreakLines(const char* string, const char* end, float breakRowWidth, NanoVG::TextRow& rows, int maxRows)
  816. {
  817. if (fContext != nullptr)
  818. return nvgTextBreakLines(fContext, string, end, breakRowWidth, (NVGtextRow*)&rows, maxRows);
  819. return 0;
  820. }
  821. #ifndef DGL_NO_SHARED_RESOURCES
  822. bool NanoVG::loadSharedResources()
  823. {
  824. if (fContext == nullptr) return false;
  825. if (nvgFindFont(fContext, NANOVG_DEJAVU_SANS_TTF) >= 0)
  826. return true;
  827. using namespace dpf_resources;
  828. return nvgCreateFontMem(fContext, NANOVG_DEJAVU_SANS_TTF, (uchar*)dejavusans_ttf, dejavusans_ttf_size, 0) >= 0;
  829. }
  830. #endif
  831. // -----------------------------------------------------------------------
  832. // NanoSubWidget
  833. template <>
  834. NanoBaseWidget<SubWidget>::NanoBaseWidget(Widget* const parent, int flags)
  835. : SubWidget(parent),
  836. NanoVG(flags)
  837. {
  838. setNeedsViewportScaling();
  839. }
  840. template class NanoBaseWidget<SubWidget>;
  841. // -----------------------------------------------------------------------
  842. // NanoTopLevelWidget
  843. template <>
  844. NanoBaseWidget<TopLevelWidget>::NanoBaseWidget(Window& windowToMapTo, int flags)
  845. : TopLevelWidget(windowToMapTo),
  846. NanoVG(flags) {}
  847. template class NanoBaseWidget<TopLevelWidget>;
  848. // -----------------------------------------------------------------------
  849. // NanoStandaloneWindow
  850. template <>
  851. NanoBaseWidget<StandaloneWindow>::NanoBaseWidget(Application& app, int flags)
  852. : StandaloneWindow(app),
  853. NanoVG(flags) {}
  854. template <>
  855. NanoBaseWidget<StandaloneWindow>::NanoBaseWidget(Application& app, Window& parentWindow, int flags)
  856. : StandaloneWindow(app, parentWindow),
  857. NanoVG(flags) {}
  858. template class NanoBaseWidget<StandaloneWindow>;
  859. // -----------------------------------------------------------------------
  860. END_NAMESPACE_DGL
  861. #undef final
  862. #if defined(__GNUC__) && (__GNUC__ >= 6)
  863. # pragma GCC diagnostic push
  864. # pragma GCC diagnostic ignored "-Wmisleading-indentation"
  865. # pragma GCC diagnostic ignored "-Wshift-negative-value"
  866. #endif
  867. extern "C" {
  868. #include "nanovg/nanovg.c"
  869. }
  870. #if defined(__GNUC__) && (__GNUC__ >= 6)
  871. # pragma GCC diagnostic pop
  872. #endif
  873. // -----------------------------------------------------------------------