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.

1011 lines
28KB

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