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.

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