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.

816 lines
21KB

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