Audio plugin host https://kx.studio/carla
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.

781 lines
20KB

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