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.

836 lines
22KB

  1. /*
  2. * DISTRHO Plugin Framework (DPF)
  3. * Copyright (C) 2012-2015 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 "../Window.hpp"
  18. // -----------------------------------------------------------------------
  19. // Ignore some warnings if debugging
  20. #if 0 //def DEBUG
  21. # define NANOVG_GL3 0
  22. # define NANOVG_GLES2 0
  23. # define NANOVG_GLES3 0
  24. # define NANOVG_GL_USE_UNIFORMBUFFER 0
  25. # if defined(__clang__)
  26. # pragma clang diagnostic push
  27. # pragma clang diagnostic ignored "-Weverything"
  28. # elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
  29. # pragma GCC diagnostic push
  30. # pragma GCC diagnostic ignored "-Wall"
  31. # pragma GCC diagnostic ignored "-Wextra"
  32. # pragma GCC diagnostic ignored "-Wconversion"
  33. # pragma GCC diagnostic ignored "-Weffc++"
  34. # pragma GCC diagnostic ignored "-Wsign-conversion"
  35. # pragma GCC diagnostic ignored "-Wundef"
  36. # pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
  37. # endif
  38. #endif
  39. // -----------------------------------------------------------------------
  40. // Include NanoVG OpenGL implementation
  41. //#define STB_IMAGE_STATIC 1
  42. #define NANOVG_GL2_IMPLEMENTATION 1
  43. #include "nanovg/nanovg_gl.h"
  44. #include "oui-blendish/blendish.h"
  45. #if defined(NANOVG_GL2)
  46. # define nvgCreateGL nvgCreateGL2
  47. # define nvgDeleteGL nvgDeleteGL2
  48. #elif defined(NANOVG_GL3)
  49. # define nvgCreateGL nvgCreateGL3
  50. # define nvgDeleteGL nvgDeleteGL3
  51. #elif defined(NANOVG_GLES2)
  52. # define nvgCreateGL nvgCreateGLES2
  53. # define nvgDeleteGL nvgDeleteGLES2
  54. #elif defined(NANOVG_GLES3)
  55. # define nvgCreateGL nvgCreateGLES3
  56. # define nvgDeleteGL nvgDeleteGLES3
  57. #endif
  58. // -----------------------------------------------------------------------
  59. // Restore normal state if debugging
  60. #if 0//def DEBUG
  61. # if defined(__clang__)
  62. # pragma clang diagnostic pop
  63. # elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
  64. # pragma GCC diagnostic pop
  65. # endif
  66. #endif
  67. // -----------------------------------------------------------------------
  68. START_NAMESPACE_DGL
  69. // -----------------------------------------------------------------------
  70. // Paint
  71. NanoVG::Paint::Paint() noexcept
  72. : radius(0.0f), feather(0.0f), innerColor(), outerColor(), imageId(0)
  73. {
  74. std::memset(xform, 0, sizeof(float)*6);
  75. std::memset(extent, 0, sizeof(float)*2);
  76. }
  77. NanoVG::Paint::Paint(const NVGpaint& p) noexcept
  78. : radius(p.radius), feather(p.feather), innerColor(p.innerColor), outerColor(p.outerColor), imageId(p.image)
  79. {
  80. std::memcpy(xform, p.xform, sizeof(float)*6);
  81. std::memcpy(extent, p.extent, sizeof(float)*2);
  82. }
  83. NanoVG::Paint::operator NVGpaint() const noexcept
  84. {
  85. NVGpaint p;
  86. p.radius = radius;
  87. p.feather = feather;
  88. p.innerColor = innerColor;
  89. p.outerColor = outerColor;
  90. p.image = imageId;
  91. std::memcpy(p.xform, xform, sizeof(float)*6);
  92. std::memcpy(p.extent, extent, sizeof(float)*2);
  93. return p;
  94. }
  95. // -----------------------------------------------------------------------
  96. // NanoImage
  97. NanoImage::NanoImage(NVGcontext* const context, const int imageId) noexcept
  98. : fContext(context),
  99. fImageId(imageId),
  100. fSize(),
  101. leakDetector_NanoImage()
  102. {
  103. _updateSize();
  104. }
  105. NanoImage::~NanoImage()
  106. {
  107. if (fContext != nullptr && fImageId != 0)
  108. nvgDeleteImage(fContext, fImageId);
  109. }
  110. Size<uint> NanoImage::getSize() const noexcept
  111. {
  112. return fSize;
  113. }
  114. GLuint NanoImage::getTextureHandle() const
  115. {
  116. return nvglImageHandle(fContext, fImageId);
  117. }
  118. void NanoImage::updateImage(const uchar* const data)
  119. {
  120. DISTRHO_SAFE_ASSERT_RETURN(data != nullptr,);
  121. if (fContext != nullptr && fImageId != 0)
  122. {
  123. nvgUpdateImage(fContext, fImageId, data);
  124. _updateSize();
  125. }
  126. }
  127. void NanoImage::_updateSize()
  128. {
  129. int w=0, h=0;
  130. if (fContext != nullptr && fImageId != 0)
  131. {
  132. nvgImageSize(fContext, fImageId, &w, &h);
  133. if (w < 0) w = 0;
  134. if (h < 0) h = 0;
  135. }
  136. fSize.setSize(static_cast<uint>(w), static_cast<uint>(h));
  137. }
  138. // -----------------------------------------------------------------------
  139. // NanoVG
  140. NanoVG::NanoVG(int flags)
  141. : fContext(nvgCreateGL(flags)),
  142. fInFrame(false),
  143. leakDetector_NanoVG()
  144. {
  145. DISTRHO_SAFE_ASSERT_RETURN(fContext != nullptr,);
  146. }
  147. NanoVG::~NanoVG()
  148. {
  149. DISTRHO_SAFE_ASSERT(! fInFrame);
  150. if (fContext != nullptr)
  151. nvgDeleteGL(fContext);
  152. }
  153. // -----------------------------------------------------------------------
  154. void NanoVG::beginFrame(const uint width, const uint height, const float scaleFactor)
  155. {
  156. if (fContext == nullptr) return;
  157. DISTRHO_SAFE_ASSERT_RETURN(scaleFactor > 0.0f,);
  158. DISTRHO_SAFE_ASSERT_RETURN(! fInFrame,);
  159. fInFrame = true;
  160. nvgBeginFrame(fContext, static_cast<int>(width), static_cast<int>(height), scaleFactor);
  161. }
  162. void NanoVG::beginFrame(Widget* const widget)
  163. {
  164. if (fContext == nullptr) return;
  165. DISTRHO_SAFE_ASSERT_RETURN(widget != nullptr,);
  166. DISTRHO_SAFE_ASSERT_RETURN(! fInFrame,);
  167. Window& window(widget->getParentWindow());
  168. fInFrame = true;
  169. nvgBeginFrame(fContext, static_cast<int>(window.getWidth()), static_cast<int>(window.getHeight()), 1.0f);
  170. }
  171. void NanoVG::cancelFrame()
  172. {
  173. DISTRHO_SAFE_ASSERT_RETURN(fInFrame,);
  174. if (fContext != nullptr)
  175. nvgCancelFrame(fContext);
  176. fInFrame = false;
  177. }
  178. void NanoVG::endFrame()
  179. {
  180. DISTRHO_SAFE_ASSERT_RETURN(fInFrame,);
  181. // Save current blend state
  182. GLboolean blendEnabled;
  183. GLint blendSrc, blendDst;
  184. glGetBooleanv(GL_BLEND, &blendEnabled);
  185. glGetIntegerv(GL_BLEND_SRC_ALPHA, &blendSrc);
  186. glGetIntegerv(GL_BLEND_DST_ALPHA, &blendDst);
  187. if (fContext != nullptr)
  188. nvgEndFrame(fContext);
  189. // Restore blend state
  190. if (blendEnabled)
  191. glEnable(GL_BLEND);
  192. else
  193. glDisable(GL_BLEND);
  194. glBlendFunc(blendSrc, blendDst);
  195. fInFrame = false;
  196. }
  197. // -----------------------------------------------------------------------
  198. // State Handling
  199. void NanoVG::save()
  200. {
  201. if (fContext != nullptr)
  202. nvgSave(fContext);
  203. }
  204. void NanoVG::restore()
  205. {
  206. if (fContext != nullptr)
  207. nvgRestore(fContext);
  208. }
  209. void NanoVG::reset()
  210. {
  211. if (fContext != nullptr)
  212. nvgReset(fContext);
  213. }
  214. // -----------------------------------------------------------------------
  215. // Render styles
  216. void NanoVG::strokeColor(const Color& color)
  217. {
  218. if (fContext != nullptr)
  219. nvgStrokeColor(fContext, color);
  220. }
  221. void NanoVG::strokeColor(const int red, const int green, const int blue, const int alpha)
  222. {
  223. if (fContext != nullptr)
  224. {
  225. DISTRHO_SAFE_ASSERT_RETURN(red >= 0 && red <= 255,);
  226. DISTRHO_SAFE_ASSERT_RETURN(green >= 0 && green <= 255,);
  227. DISTRHO_SAFE_ASSERT_RETURN(blue >= 0 && blue <= 255,);
  228. DISTRHO_SAFE_ASSERT_RETURN(alpha >= 0 && alpha <= 255,);
  229. nvgStrokeColor(fContext, nvgRGBA(static_cast<uchar>(red),
  230. static_cast<uchar>(green),
  231. static_cast<uchar>(blue),
  232. static_cast<uchar>(alpha)));
  233. }
  234. }
  235. void NanoVG::strokeColor(const float red, const float green, const float blue, const float alpha)
  236. {
  237. if (fContext != nullptr)
  238. nvgStrokeColor(fContext, nvgRGBAf(red, green, blue, alpha));
  239. }
  240. void NanoVG::strokePaint(const Paint& paint)
  241. {
  242. if (fContext != nullptr)
  243. nvgStrokePaint(fContext, paint);
  244. }
  245. void NanoVG::fillColor(const Color& color)
  246. {
  247. if (fContext != nullptr)
  248. nvgFillColor(fContext, color);
  249. }
  250. void NanoVG::fillColor(const int red, const int green, const int blue, const int alpha)
  251. {
  252. if (fContext != nullptr)
  253. {
  254. DISTRHO_SAFE_ASSERT_RETURN(red >= 0 && red <= 255,);
  255. DISTRHO_SAFE_ASSERT_RETURN(green >= 0 && green <= 255,);
  256. DISTRHO_SAFE_ASSERT_RETURN(blue >= 0 && blue <= 255,);
  257. DISTRHO_SAFE_ASSERT_RETURN(alpha >= 0 && alpha <= 255,);
  258. nvgFillColor(fContext, nvgRGBA(static_cast<uchar>(red),
  259. static_cast<uchar>(green),
  260. static_cast<uchar>(blue),
  261. static_cast<uchar>(alpha)));
  262. }
  263. }
  264. void NanoVG::fillColor(const float red, const float green, const float blue, const float alpha)
  265. {
  266. if (fContext != nullptr)
  267. nvgFillColor(fContext, nvgRGBAf(red, green, blue, alpha));
  268. }
  269. void NanoVG::fillPaint(const Paint& paint)
  270. {
  271. if (fContext != nullptr)
  272. nvgFillPaint(fContext, paint);
  273. }
  274. void NanoVG::miterLimit(float limit)
  275. {
  276. if (fContext == nullptr) return;
  277. DISTRHO_SAFE_ASSERT_RETURN(limit > 0.0f,);
  278. nvgMiterLimit(fContext, limit);
  279. }
  280. void NanoVG::strokeWidth(float size)
  281. {
  282. if (fContext == nullptr) return;
  283. DISTRHO_SAFE_ASSERT_RETURN(size > 0.0f,);
  284. nvgStrokeWidth(fContext, size);
  285. }
  286. void NanoVG::lineCap(NanoVG::LineCap cap)
  287. {
  288. if (fContext != nullptr)
  289. nvgLineCap(fContext, cap);
  290. }
  291. void NanoVG::lineJoin(NanoVG::LineCap join)
  292. {
  293. if (fContext != nullptr)
  294. nvgLineJoin(fContext, join);
  295. }
  296. void NanoVG::globalAlpha(float alpha)
  297. {
  298. if (fContext != nullptr)
  299. nvgGlobalAlpha(fContext, alpha);
  300. }
  301. // -----------------------------------------------------------------------
  302. // Transforms
  303. void NanoVG::resetTransform()
  304. {
  305. if (fContext != nullptr)
  306. nvgResetTransform(fContext);
  307. }
  308. void NanoVG::transform(float a, float b, float c, float d, float e, float f)
  309. {
  310. if (fContext != nullptr)
  311. nvgTransform(fContext, a, b, c, d, e, f);
  312. }
  313. void NanoVG::translate(float x, float y)
  314. {
  315. if (fContext != nullptr)
  316. nvgTranslate(fContext, x, y);
  317. }
  318. void NanoVG::rotate(float angle)
  319. {
  320. if (fContext == nullptr) return;
  321. DISTRHO_SAFE_ASSERT_RETURN(angle > 0.0f,);
  322. nvgRotate(fContext, angle);
  323. }
  324. void NanoVG::skewX(float angle)
  325. {
  326. if (fContext == nullptr) return;
  327. DISTRHO_SAFE_ASSERT_RETURN(angle > 0.0f,);
  328. nvgSkewX(fContext, angle);
  329. }
  330. void NanoVG::skewY(float angle)
  331. {
  332. if (fContext == nullptr) return;
  333. DISTRHO_SAFE_ASSERT_RETURN(angle > 0.0f,);
  334. nvgSkewY(fContext, angle);
  335. }
  336. void NanoVG::scale(float x, float y)
  337. {
  338. if (fContext == nullptr) return;
  339. DISTRHO_SAFE_ASSERT_RETURN(x > 0.0f,);
  340. DISTRHO_SAFE_ASSERT_RETURN(y > 0.0f,);
  341. nvgScale(fContext, x, y);
  342. }
  343. void NanoVG::currentTransform(float xform[6])
  344. {
  345. if (fContext != nullptr)
  346. nvgCurrentTransform(fContext, xform);
  347. }
  348. void NanoVG::transformIdentity(float dst[6])
  349. {
  350. nvgTransformIdentity(dst);
  351. }
  352. void NanoVG::transformTranslate(float dst[6], float tx, float ty)
  353. {
  354. nvgTransformTranslate(dst, tx, ty);
  355. }
  356. void NanoVG::transformScale(float dst[6], float sx, float sy)
  357. {
  358. nvgTransformScale(dst, sx, sy);
  359. }
  360. void NanoVG::transformRotate(float dst[6], float a)
  361. {
  362. nvgTransformRotate(dst, a);
  363. }
  364. void NanoVG::transformSkewX(float dst[6], float a)
  365. {
  366. nvgTransformSkewX(dst, a);
  367. }
  368. void NanoVG::transformSkewY(float dst[6], float a)
  369. {
  370. nvgTransformSkewY(dst, a);
  371. }
  372. void NanoVG::transformMultiply(float dst[6], const float src[6])
  373. {
  374. nvgTransformMultiply(dst, src);
  375. }
  376. void NanoVG::transformPremultiply(float dst[6], const float src[6])
  377. {
  378. nvgTransformPremultiply(dst, src);
  379. }
  380. int NanoVG::transformInverse(float dst[6], const float src[6])
  381. {
  382. return nvgTransformInverse(dst, src);
  383. }
  384. void NanoVG::transformPoint(float& dstx, float& dsty, const float xform[6], float srcx, float srcy)
  385. {
  386. nvgTransformPoint(&dstx, &dsty, xform, srcx, srcy);
  387. }
  388. float NanoVG::degToRad(float deg)
  389. {
  390. return nvgDegToRad(deg);
  391. }
  392. float NanoVG::radToDeg(float rad)
  393. {
  394. return nvgRadToDeg(rad);
  395. }
  396. // -----------------------------------------------------------------------
  397. // Images
  398. NanoImage* NanoVG::createImage(const char* filename, int imageFlags)
  399. {
  400. if (fContext == nullptr) return nullptr;
  401. DISTRHO_SAFE_ASSERT_RETURN(filename != nullptr && filename[0] != '\0', nullptr);
  402. if (const int imageId = nvgCreateImage(fContext, filename, imageFlags))
  403. return new NanoImage(fContext, imageId);
  404. return nullptr;
  405. }
  406. NanoImage* NanoVG::createImageMem(uchar* data, int ndata, int imageFlags)
  407. {
  408. if (fContext == nullptr) return nullptr;
  409. DISTRHO_SAFE_ASSERT_RETURN(data != nullptr, nullptr);
  410. DISTRHO_SAFE_ASSERT_RETURN(ndata > 0, nullptr);
  411. if (const int imageId = nvgCreateImageMem(fContext, imageFlags, data, ndata))
  412. return new NanoImage(fContext, imageId);
  413. return nullptr;
  414. }
  415. NanoImage* NanoVG::createImageRGBA(uint w, uint h, const uchar* data, int imageFlags)
  416. {
  417. if (fContext == nullptr) return nullptr;
  418. DISTRHO_SAFE_ASSERT_RETURN(data != nullptr, nullptr);
  419. if (const int imageId = nvgCreateImageRGBA(fContext, static_cast<int>(w), static_cast<int>(h), imageFlags, data))
  420. return new NanoImage(fContext, imageId);
  421. return nullptr;
  422. }
  423. NanoImage* NanoVG::createImageFromTextureHandle(GLuint textureId, uint w, uint h, int imageFlags, bool deleteTexture)
  424. {
  425. if (fContext == nullptr) return nullptr;
  426. DISTRHO_SAFE_ASSERT_RETURN(textureId != 0, nullptr);
  427. if (! deleteTexture)
  428. imageFlags |= NVG_IMAGE_NODELETE;
  429. if (const int imageId = nvglCreateImageFromHandle(fContext, textureId, static_cast<int>(w), static_cast<int>(h), imageFlags))
  430. return new NanoImage(fContext, imageId);
  431. return nullptr;
  432. }
  433. // -----------------------------------------------------------------------
  434. // Paints
  435. NanoVG::Paint NanoVG::linearGradient(float sx, float sy, float ex, float ey, const Color& icol, const Color& ocol)
  436. {
  437. if (fContext == nullptr) return Paint();
  438. return nvgLinearGradient(fContext, sx, sy, ex, ey, icol, ocol);
  439. }
  440. NanoVG::Paint NanoVG::boxGradient(float x, float y, float w, float h, float r, float f, const Color& icol, const Color& ocol)
  441. {
  442. if (fContext == nullptr) return Paint();
  443. return nvgBoxGradient(fContext, x, y, w, h, r, f, icol, ocol);
  444. }
  445. NanoVG::Paint NanoVG::radialGradient(float cx, float cy, float inr, float outr, const Color& icol, const Color& ocol)
  446. {
  447. if (fContext == nullptr) return Paint();
  448. return nvgRadialGradient(fContext, cx, cy, inr, outr, icol, ocol);
  449. }
  450. NanoVG::Paint NanoVG::imagePattern(float ox, float oy, float ex, float ey, float angle, const NanoImage* image, float alpha)
  451. {
  452. if (fContext == nullptr) return Paint();
  453. DISTRHO_SAFE_ASSERT_RETURN(image != nullptr, Paint());
  454. return nvgImagePattern(fContext, ox, oy, ex, ey, angle, image->fImageId, alpha);
  455. }
  456. // -----------------------------------------------------------------------
  457. // Scissoring
  458. void NanoVG::scissor(float x, float y, float w, float h)
  459. {
  460. if (fContext != nullptr)
  461. nvgScissor(fContext, x, y, w, h);
  462. }
  463. void NanoVG::intersectScissor(float x, float y, float w, float h)
  464. {
  465. if (fContext != nullptr)
  466. nvgIntersectScissor(fContext, x, y, w, h);
  467. }
  468. void NanoVG::resetScissor()
  469. {
  470. if (fContext != nullptr)
  471. nvgResetScissor(fContext);
  472. }
  473. // -----------------------------------------------------------------------
  474. // Paths
  475. void NanoVG::beginPath()
  476. {
  477. if (fContext != nullptr)
  478. nvgBeginPath(fContext);
  479. }
  480. void NanoVG::moveTo(float x, float y)
  481. {
  482. if (fContext != nullptr)
  483. nvgMoveTo(fContext, x, y);
  484. }
  485. void NanoVG::lineTo(float x, float y)
  486. {
  487. if (fContext != nullptr)
  488. nvgLineTo(fContext, x, y);
  489. }
  490. void NanoVG::bezierTo(float c1x, float c1y, float c2x, float c2y, float x, float y)
  491. {
  492. if (fContext != nullptr)
  493. nvgBezierTo(fContext, c1x, c1y, c2x, c2y, x, y);
  494. }
  495. void NanoVG::quadTo(float cx, float cy, float x, float y)
  496. {
  497. if (fContext != nullptr)
  498. nvgQuadTo(fContext, cx, cy, x, y);
  499. }
  500. void NanoVG::arcTo(float x1, float y1, float x2, float y2, float radius)
  501. {
  502. if (fContext != nullptr)
  503. nvgArcTo(fContext, x1, y1, x2, y2, radius);
  504. }
  505. void NanoVG::closePath()
  506. {
  507. if (fContext != nullptr)
  508. nvgClosePath(fContext);
  509. }
  510. void NanoVG::pathWinding(NanoVG::Winding dir)
  511. {
  512. if (fContext != nullptr)
  513. nvgPathWinding(fContext, dir);
  514. }
  515. void NanoVG::arc(float cx, float cy, float r, float a0, float a1, NanoVG::Winding dir)
  516. {
  517. if (fContext != nullptr)
  518. nvgArc(fContext, cx, cy, r, a0, a1, dir);
  519. }
  520. void NanoVG::rect(float x, float y, float w, float h)
  521. {
  522. if (fContext != nullptr)
  523. nvgRect(fContext, x, y, w, h);
  524. }
  525. void NanoVG::roundedRect(float x, float y, float w, float h, float r)
  526. {
  527. if (fContext != nullptr)
  528. nvgRoundedRect(fContext, x, y, w, h, r);
  529. }
  530. void NanoVG::ellipse(float cx, float cy, float rx, float ry)
  531. {
  532. if (fContext != nullptr)
  533. nvgEllipse(fContext, cx, cy, rx, ry);
  534. }
  535. void NanoVG::circle(float cx, float cy, float r)
  536. {
  537. if (fContext != nullptr)
  538. nvgCircle(fContext, cx, cy, r);
  539. }
  540. void NanoVG::fill()
  541. {
  542. if (fContext != nullptr)
  543. nvgFill(fContext);
  544. }
  545. void NanoVG::stroke()
  546. {
  547. if (fContext != nullptr)
  548. nvgStroke(fContext);
  549. }
  550. // -----------------------------------------------------------------------
  551. // Text
  552. NanoVG::FontId NanoVG::createFont(const char* name, const char* filename)
  553. {
  554. if (fContext == nullptr) return -1;
  555. DISTRHO_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0', -1);
  556. DISTRHO_SAFE_ASSERT_RETURN(filename != nullptr && filename[0] != '\0', -1);
  557. return nvgCreateFont(fContext, name, filename);
  558. }
  559. NanoVG::FontId NanoVG::createFontMem(const char* name, const uchar* data, int ndata, bool freeData)
  560. {
  561. if (fContext == nullptr) return -1;
  562. DISTRHO_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0', -1);
  563. DISTRHO_SAFE_ASSERT_RETURN(data != nullptr, -1);
  564. return nvgCreateFontMem(fContext, name, const_cast<uchar*>(data), ndata, freeData);
  565. }
  566. NanoVG::FontId NanoVG::findFont(const char* name)
  567. {
  568. if (fContext == nullptr) return -1;
  569. DISTRHO_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0', -1);
  570. return nvgFindFont(fContext, name);
  571. }
  572. void NanoVG::fontSize(float size)
  573. {
  574. if (fContext == nullptr) return;
  575. DISTRHO_SAFE_ASSERT_RETURN(size > 0.0f,);
  576. nvgFontSize(fContext, size);
  577. }
  578. void NanoVG::fontBlur(float blur)
  579. {
  580. if (fContext == nullptr) return;
  581. DISTRHO_SAFE_ASSERT_RETURN(blur >= 0.0f,);
  582. nvgFontBlur(fContext, blur);
  583. }
  584. void NanoVG::textLetterSpacing(float spacing)
  585. {
  586. if (fContext == nullptr) return;
  587. DISTRHO_SAFE_ASSERT_RETURN(spacing >= 0.0f,);
  588. nvgTextLetterSpacing(fContext, spacing);
  589. }
  590. void NanoVG::textLineHeight(float lineHeight)
  591. {
  592. if (fContext == nullptr) return;
  593. DISTRHO_SAFE_ASSERT_RETURN(lineHeight > 0.0f,);
  594. nvgTextLineHeight(fContext, lineHeight);
  595. }
  596. void NanoVG::textAlign(NanoVG::Align align)
  597. {
  598. if (fContext != nullptr)
  599. nvgTextAlign(fContext, align);
  600. }
  601. void NanoVG::textAlign(int align)
  602. {
  603. if (fContext != nullptr)
  604. nvgTextAlign(fContext, align);
  605. }
  606. void NanoVG::fontFaceId(FontId font)
  607. {
  608. if (fContext == nullptr) return;
  609. DISTRHO_SAFE_ASSERT_RETURN(font >= 0,);
  610. nvgFontFaceId(fContext, font);
  611. }
  612. void NanoVG::fontFace(const char* font)
  613. {
  614. if (fContext == nullptr) return;
  615. DISTRHO_SAFE_ASSERT_RETURN(font != nullptr && font[0] != '\0',);
  616. nvgFontFace(fContext, font);
  617. }
  618. float NanoVG::text(float x, float y, const char* string, const char* end)
  619. {
  620. if (fContext == nullptr) return 0.0f;
  621. DISTRHO_SAFE_ASSERT_RETURN(string != nullptr && string[0] != '\0', 0.0f);
  622. return nvgText(fContext, x, y, string, end);
  623. }
  624. void NanoVG::textBox(float x, float y, float breakRowWidth, const char* string, const char* end)
  625. {
  626. if (fContext == nullptr) return;
  627. DISTRHO_SAFE_ASSERT_RETURN(string != nullptr && string[0] != '\0',);
  628. nvgTextBox(fContext, x, y, breakRowWidth, string, end);
  629. }
  630. float NanoVG::textBounds(float x, float y, const char* string, const char* end, Rectangle<float>& bounds)
  631. {
  632. if (fContext == nullptr) return 0.0f;
  633. DISTRHO_SAFE_ASSERT_RETURN(string != nullptr && string[0] != '\0', 0.0f);
  634. float b[4];
  635. const float ret = nvgTextBounds(fContext, x, y, string, end, b);
  636. bounds = Rectangle<float>(b[0], b[1], b[2], b[3]);
  637. return ret;
  638. }
  639. void NanoVG::textBoxBounds(float x, float y, float breakRowWidth, const char* string, const char* end, float* bounds)
  640. {
  641. if (fContext == nullptr) return;
  642. DISTRHO_SAFE_ASSERT_RETURN(string != nullptr && string[0] != '\0',);
  643. nvgTextBoxBounds(fContext, x, y, breakRowWidth, string, end, bounds);
  644. }
  645. int NanoVG::textGlyphPositions(float x, float y, const char* string, const char* end, NanoVG::GlyphPosition* positions, int maxPositions)
  646. {
  647. if (fContext == nullptr) return 0;
  648. DISTRHO_SAFE_ASSERT_RETURN(string != nullptr && string[0] != '\0', 0);
  649. return nvgTextGlyphPositions(fContext, x, y, string, end, (NVGglyphPosition*)positions, maxPositions);
  650. }
  651. void NanoVG::textMetrics(float* ascender, float* descender, float* lineh)
  652. {
  653. if (fContext != nullptr)
  654. nvgTextMetrics(fContext, ascender, descender, lineh);
  655. }
  656. int NanoVG::textBreakLines(const char* string, const char* end, float breakRowWidth, NanoVG::TextRow* rows, int maxRows)
  657. {
  658. if (fContext != nullptr)
  659. return nvgTextBreakLines(fContext, string, end, breakRowWidth, (NVGtextRow*)rows, maxRows);
  660. return 0;
  661. }
  662. // -----------------------------------------------------------------------
  663. END_NAMESPACE_DGL
  664. extern "C" {
  665. #include "nanovg/nanovg.c"
  666. }
  667. // -----------------------------------------------------------------------