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.

1002 lines
28KB

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