1 /*
2  * DISTRHO Plugin Framework (DPF)
3  * Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com>
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any purpose with
6  * or without fee is hereby granted, provided that the above copyright notice and this
7  * permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
10  * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
11  * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
12  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
13  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #include "../NanoVG.hpp"
18 #include "WidgetPrivateData.hpp"
19 
20 #ifndef DGL_NO_SHARED_RESOURCES
21 # include "Resources.hpp"
22 #endif
23 
24 // -----------------------------------------------------------------------
25 
26 #if defined(DISTRHO_OS_WINDOWS)
27 # include <windows.h>
28 # define DGL_EXT(PROC, func) static PROC func;
DGL_EXT(PFNGLACTIVETEXTUREPROC,glActiveTexture)29 DGL_EXT(PFNGLACTIVETEXTUREPROC,            glActiveTexture)
30 DGL_EXT(PFNGLATTACHSHADERPROC,             glAttachShader)
31 DGL_EXT(PFNGLBINDATTRIBLOCATIONPROC,       glBindAttribLocation)
32 DGL_EXT(PFNGLBINDBUFFERPROC,               glBindBuffer)
33 DGL_EXT(PFNGLBUFFERDATAPROC,               glBufferData)
34 DGL_EXT(PFNGLCOMPILESHADERPROC,            glCompileShader)
35 DGL_EXT(PFNGLCREATEPROGRAMPROC,            glCreateProgram)
36 DGL_EXT(PFNGLCREATESHADERPROC,             glCreateShader)
37 DGL_EXT(PFNGLDELETEBUFFERSPROC,            glDeleteBuffers)
38 DGL_EXT(PFNGLDELETEPROGRAMPROC,            glDeleteProgram)
39 DGL_EXT(PFNGLDELETESHADERPROC,             glDeleteShader)
40 DGL_EXT(PFNGLDISABLEVERTEXATTRIBARRAYPROC, glDisableVertexAttribArray)
41 DGL_EXT(PFNGLENABLEVERTEXATTRIBARRAYPROC,  glEnableVertexAttribArray)
42 DGL_EXT(PFNGLGENBUFFERSPROC,               glGenBuffers)
43 DGL_EXT(PFNGLGETPROGRAMIVPROC,             glGetProgramiv)
44 DGL_EXT(PFNGLGETPROGRAMINFOLOGPROC,        glGetProgramInfoLog)
45 DGL_EXT(PFNGLGETSHADERIVPROC,              glGetShaderiv)
46 DGL_EXT(PFNGLGETSHADERINFOLOGPROC,         glGetShaderInfoLog)
47 DGL_EXT(PFNGLGETUNIFORMLOCATIONPROC,       glGetUniformLocation)
48 DGL_EXT(PFNGLLINKPROGRAMPROC,              glLinkProgram)
49 DGL_EXT(PFNGLSHADERSOURCEPROC,             glShaderSource)
50 DGL_EXT(PFNGLSTENCILOPSEPARATEPROC,        glStencilOpSeparate)
51 DGL_EXT(PFNGLUNIFORM1IPROC,                glUniform1i)
52 DGL_EXT(PFNGLUNIFORM2FVPROC,               glUniform2fv)
53 DGL_EXT(PFNGLUNIFORM4FVPROC,               glUniform4fv)
54 DGL_EXT(PFNGLUSEPROGRAMPROC,               glUseProgram)
55 DGL_EXT(PFNGLVERTEXATTRIBPOINTERPROC,      glVertexAttribPointer)
56 # undef DGL_EXT
57 #endif
58 
59 // -----------------------------------------------------------------------
60 // Include NanoVG OpenGL implementation
61 
62 //#define STB_IMAGE_STATIC
63 #define NANOVG_GL2_IMPLEMENTATION
64 #include "nanovg/nanovg_gl.h"
65 
66 #if defined(NANOVG_GL2)
67 # define nvgCreateGL nvgCreateGL2
68 # define nvgDeleteGL nvgDeleteGL2
69 #elif defined(NANOVG_GL3)
70 # define nvgCreateGL nvgCreateGL3
71 # define nvgDeleteGL nvgDeleteGL3
72 #elif defined(NANOVG_GLES2)
73 # define nvgCreateGL nvgCreateGLES2
74 # define nvgDeleteGL nvgDeleteGLES2
75 #elif defined(NANOVG_GLES3)
76 # define nvgCreateGL nvgCreateGLES3
77 # define nvgDeleteGL nvgDeleteGLES3
78 #endif
79 
80 static NVGcontext* nvgCreateGL_helper(int flags)
81 {
82 #if defined(DISTRHO_OS_WINDOWS)
83     static bool needsInit = true;
84 # define DGL_EXT(PROC, func) \
85       if (needsInit) func = (PROC) wglGetProcAddress ( #func ); \
86       DISTRHO_SAFE_ASSERT_RETURN(func != nullptr, nullptr);
87 DGL_EXT(PFNGLACTIVETEXTUREPROC,            glActiveTexture)
88 DGL_EXT(PFNGLATTACHSHADERPROC,             glAttachShader)
89 DGL_EXT(PFNGLBINDATTRIBLOCATIONPROC,       glBindAttribLocation)
90 DGL_EXT(PFNGLBINDBUFFERPROC,               glBindBuffer)
91 DGL_EXT(PFNGLBUFFERDATAPROC,               glBufferData)
92 DGL_EXT(PFNGLCOMPILESHADERPROC,            glCompileShader)
93 DGL_EXT(PFNGLCREATEPROGRAMPROC,            glCreateProgram)
94 DGL_EXT(PFNGLCREATESHADERPROC,             glCreateShader)
95 DGL_EXT(PFNGLDELETEBUFFERSPROC,            glDeleteBuffers)
96 DGL_EXT(PFNGLDELETEPROGRAMPROC,            glDeleteProgram)
97 DGL_EXT(PFNGLDELETESHADERPROC,             glDeleteShader)
98 DGL_EXT(PFNGLDISABLEVERTEXATTRIBARRAYPROC, glDisableVertexAttribArray)
99 DGL_EXT(PFNGLENABLEVERTEXATTRIBARRAYPROC,  glEnableVertexAttribArray)
100 DGL_EXT(PFNGLGENBUFFERSPROC,               glGenBuffers)
101 DGL_EXT(PFNGLGETPROGRAMIVPROC,             glGetProgramiv)
102 DGL_EXT(PFNGLGETPROGRAMINFOLOGPROC,        glGetProgramInfoLog)
103 DGL_EXT(PFNGLGETSHADERIVPROC,              glGetShaderiv)
104 DGL_EXT(PFNGLGETSHADERINFOLOGPROC,         glGetShaderInfoLog)
105 DGL_EXT(PFNGLGETUNIFORMLOCATIONPROC,       glGetUniformLocation)
106 DGL_EXT(PFNGLLINKPROGRAMPROC,              glLinkProgram)
107 DGL_EXT(PFNGLSHADERSOURCEPROC,             glShaderSource)
108 DGL_EXT(PFNGLSTENCILOPSEPARATEPROC,        glStencilOpSeparate)
109 DGL_EXT(PFNGLUNIFORM1IPROC,                glUniform1i)
110 DGL_EXT(PFNGLUNIFORM2FVPROC,               glUniform2fv)
111 DGL_EXT(PFNGLUNIFORM4FVPROC,               glUniform4fv)
112 DGL_EXT(PFNGLUSEPROGRAMPROC,               glUseProgram)
113 DGL_EXT(PFNGLVERTEXATTRIBPOINTERPROC,      glVertexAttribPointer)
114 # undef DGL_EXT
115     needsInit = false;
116 #endif
117     return nvgCreateGL(flags);
118 }
119 
120 // -----------------------------------------------------------------------
121 
122 START_NAMESPACE_DGL
123 
124 // -----------------------------------------------------------------------
125 // DGL Color class conversion
126 
Color(const NVGcolor & c)127 Color::Color(const NVGcolor& c) noexcept
128     : red(c.r), green(c.g), blue(c.b), alpha(c.a)
129 {
130     fixBounds();
131 }
132 
operator NVGcolor() const133 Color::operator NVGcolor() const noexcept
134 {
135     NVGcolor nc;
136     nc.r = red;
137     nc.g = green;
138     nc.b = blue;
139     nc.a = alpha;
140     return nc;
141 }
142 
143 // -----------------------------------------------------------------------
144 // NanoImage
145 
NanoImage()146 NanoImage::NanoImage()
147     : fHandle(),
148       fSize() {}
149 
NanoImage(const Handle & handle)150 NanoImage::NanoImage(const Handle& handle)
151     : fHandle(handle),
152       fSize()
153 {
154     DISTRHO_SAFE_ASSERT_RETURN(fHandle.context != nullptr && fHandle.imageId != 0,);
155 
156     _updateSize();
157 }
158 
~NanoImage()159 NanoImage::~NanoImage()
160 {
161     if (fHandle.context != nullptr && fHandle.imageId != 0)
162         nvgDeleteImage(fHandle.context, fHandle.imageId);
163 }
164 
operator =(const Handle & handle)165 NanoImage& NanoImage::operator=(const Handle& handle)
166 {
167     if (fHandle.context != nullptr && fHandle.imageId != 0)
168         nvgDeleteImage(fHandle.context, fHandle.imageId);
169 
170     fHandle.context = handle.context;
171     fHandle.imageId = handle.imageId;
172 
173     return *this;
174 }
175 
isValid() const176 bool NanoImage::isValid() const noexcept
177 {
178     return (fHandle.context != nullptr && fHandle.imageId != 0);
179 }
180 
getSize() const181 Size<uint> NanoImage::getSize() const noexcept
182 {
183     return fSize;
184 }
185 
getTextureHandle() const186 GLuint NanoImage::getTextureHandle() const
187 {
188     DISTRHO_SAFE_ASSERT_RETURN(fHandle.context != nullptr && fHandle.imageId != 0, 0);
189 
190     return nvglImageHandle(fHandle.context, fHandle.imageId);
191 }
192 
_updateSize()193 void NanoImage::_updateSize()
194 {
195     int w=0, h=0;
196 
197     nvgImageSize(fHandle.context, fHandle.imageId, &w, &h);
198 
199     if (w < 0) w = 0;
200     if (h < 0) h = 0;
201 
202     fSize.setSize(static_cast<uint>(w), static_cast<uint>(h));
203 }
204 
205 // -----------------------------------------------------------------------
206 // Paint
207 
Paint()208 NanoVG::Paint::Paint() noexcept
209     : radius(0.0f), feather(0.0f), innerColor(), outerColor(), imageId(0)
210 {
211     std::memset(xform, 0, sizeof(float)*6);
212     std::memset(extent, 0, sizeof(float)*2);
213 }
214 
Paint(const NVGpaint & p)215 NanoVG::Paint::Paint(const NVGpaint& p) noexcept
216     : radius(p.radius), feather(p.feather), innerColor(p.innerColor), outerColor(p.outerColor), imageId(p.image)
217 {
218     std::memcpy(xform, p.xform, sizeof(float)*6);
219     std::memcpy(extent, p.extent, sizeof(float)*2);
220 }
221 
operator NVGpaint() const222 NanoVG::Paint::operator NVGpaint() const noexcept
223 {
224     NVGpaint p;
225     p.radius = radius;
226     p.feather = feather;
227     p.innerColor = innerColor;
228     p.outerColor = outerColor;
229     p.image = imageId;
230     std::memcpy(p.xform, xform, sizeof(float)*6);
231     std::memcpy(p.extent, extent, sizeof(float)*2);
232     return p;
233 }
234 
235 // -----------------------------------------------------------------------
236 // NanoVG
237 
NanoVG(int flags)238 NanoVG::NanoVG(int flags)
239     : fContext(nvgCreateGL_helper(flags)),
240       fInFrame(false),
241       fIsSubWidget(false) {}
242 
NanoVG(NanoWidget * groupWidget)243 NanoVG::NanoVG(NanoWidget* groupWidget)
244     : fContext(groupWidget->fContext),
245       fInFrame(false),
246       fIsSubWidget(true) {}
247 
~NanoVG()248 NanoVG::~NanoVG()
249 {
250     DISTRHO_SAFE_ASSERT(! fInFrame);
251 
252     if (fContext != nullptr && ! fIsSubWidget)
253         nvgDeleteGL(fContext);
254 }
255 
256 // -----------------------------------------------------------------------
257 
beginFrame(const uint width,const uint height,const float scaleFactor)258 void NanoVG::beginFrame(const uint width, const uint height, const float scaleFactor)
259 {
260     if (fContext == nullptr) return;
261     DISTRHO_SAFE_ASSERT_RETURN(scaleFactor > 0.0f,);
262     DISTRHO_SAFE_ASSERT_RETURN(! fInFrame,);
263 
264     fInFrame = true;
265     nvgBeginFrame(fContext, static_cast<int>(width), static_cast<int>(height), scaleFactor);
266 }
267 
beginFrame(Widget * const widget)268 void NanoVG::beginFrame(Widget* const widget)
269 {
270     DISTRHO_SAFE_ASSERT_RETURN(widget != nullptr,);
271     DISTRHO_SAFE_ASSERT_RETURN(! fInFrame,);
272 
273     fInFrame = true;
274 
275     if (fContext == nullptr)
276         return;
277 
278     Window& window(widget->getParentWindow());
279     nvgBeginFrame(fContext, static_cast<int>(window.getWidth()), static_cast<int>(window.getHeight()), 1.0f);
280 }
281 
cancelFrame()282 void NanoVG::cancelFrame()
283 {
284     DISTRHO_SAFE_ASSERT_RETURN(fInFrame,);
285 
286     if (fContext != nullptr)
287         nvgCancelFrame(fContext);
288 
289     fInFrame = false;
290 }
291 
endFrame()292 void NanoVG::endFrame()
293 {
294     DISTRHO_SAFE_ASSERT_RETURN(fInFrame,);
295 
296     // Save current blend state
297     GLboolean blendEnabled;
298     GLint blendSrc, blendDst;
299     glGetBooleanv(GL_BLEND, &blendEnabled);
300     glGetIntegerv(GL_BLEND_SRC_ALPHA, &blendSrc);
301     glGetIntegerv(GL_BLEND_DST_ALPHA, &blendDst);
302 
303     if (fContext != nullptr)
304         nvgEndFrame(fContext);
305 
306     // Restore blend state
307     if (blendEnabled)
308         glEnable(GL_BLEND);
309     else
310         glDisable(GL_BLEND);
311 
312     glBlendFunc(blendSrc, blendDst);
313 
314     fInFrame = false;
315 }
316 
317 // -----------------------------------------------------------------------
318 // State Handling
319 
save()320 void NanoVG::save()
321 {
322     if (fContext != nullptr)
323         nvgSave(fContext);
324 }
325 
restore()326 void NanoVG::restore()
327 {
328     if (fContext != nullptr)
329         nvgRestore(fContext);
330 }
331 
reset()332 void NanoVG::reset()
333 {
334     if (fContext != nullptr)
335         nvgReset(fContext);
336 }
337 
338 // -----------------------------------------------------------------------
339 // Render styles
340 
strokeColor(const Color & color)341 void NanoVG::strokeColor(const Color& color)
342 {
343     if (fContext != nullptr)
344         nvgStrokeColor(fContext, color);
345 }
346 
strokeColor(const int red,const int green,const int blue,const int alpha)347 void NanoVG::strokeColor(const int red, const int green, const int blue, const int alpha)
348 {
349     if (fContext != nullptr)
350     {
351         DISTRHO_SAFE_ASSERT_RETURN(red   >= 0 && red   <= 255,);
352         DISTRHO_SAFE_ASSERT_RETURN(green >= 0 && green <= 255,);
353         DISTRHO_SAFE_ASSERT_RETURN(blue  >= 0 && blue  <= 255,);
354         DISTRHO_SAFE_ASSERT_RETURN(alpha >= 0 && alpha <= 255,);
355 
356         nvgStrokeColor(fContext, nvgRGBA(static_cast<uchar>(red),
357                                          static_cast<uchar>(green),
358                                          static_cast<uchar>(blue),
359                                          static_cast<uchar>(alpha)));
360     }
361 }
362 
strokeColor(const float red,const float green,const float blue,const float alpha)363 void NanoVG::strokeColor(const float red, const float green, const float blue, const float alpha)
364 {
365     if (fContext != nullptr)
366         nvgStrokeColor(fContext, nvgRGBAf(red, green, blue, alpha));
367 }
368 
strokePaint(const Paint & paint)369 void NanoVG::strokePaint(const Paint& paint)
370 {
371     if (fContext != nullptr)
372         nvgStrokePaint(fContext, paint);
373 }
374 
fillColor(const Color & color)375 void NanoVG::fillColor(const Color& color)
376 {
377     if (fContext != nullptr)
378         nvgFillColor(fContext, color);
379 }
380 
fillColor(const int red,const int green,const int blue,const int alpha)381 void NanoVG::fillColor(const int red, const int green, const int blue, const int alpha)
382 {
383     if (fContext != nullptr)
384     {
385         DISTRHO_SAFE_ASSERT_RETURN(red   >= 0 && red   <= 255,);
386         DISTRHO_SAFE_ASSERT_RETURN(green >= 0 && green <= 255,);
387         DISTRHO_SAFE_ASSERT_RETURN(blue  >= 0 && blue  <= 255,);
388         DISTRHO_SAFE_ASSERT_RETURN(alpha >= 0 && alpha <= 255,);
389 
390         nvgFillColor(fContext, nvgRGBA(static_cast<uchar>(red),
391                                        static_cast<uchar>(green),
392                                        static_cast<uchar>(blue),
393                                        static_cast<uchar>(alpha)));
394     }
395 }
396 
fillColor(const float red,const float green,const float blue,const float alpha)397 void NanoVG::fillColor(const float red, const float green, const float blue, const float alpha)
398 {
399     if (fContext != nullptr)
400         nvgFillColor(fContext, nvgRGBAf(red, green, blue, alpha));
401 }
402 
fillPaint(const Paint & paint)403 void NanoVG::fillPaint(const Paint& paint)
404 {
405     if (fContext != nullptr)
406         nvgFillPaint(fContext, paint);
407 }
408 
miterLimit(float limit)409 void NanoVG::miterLimit(float limit)
410 {
411     if (fContext == nullptr) return;
412     DISTRHO_SAFE_ASSERT_RETURN(limit > 0.0f,);
413 
414     nvgMiterLimit(fContext, limit);
415 }
416 
strokeWidth(float size)417 void NanoVG::strokeWidth(float size)
418 {
419     if (fContext == nullptr) return;
420     DISTRHO_SAFE_ASSERT_RETURN(size > 0.0f,);
421 
422     nvgStrokeWidth(fContext, size);
423 }
424 
lineCap(NanoVG::LineCap cap)425 void NanoVG::lineCap(NanoVG::LineCap cap)
426 {
427     if (fContext != nullptr)
428         nvgLineCap(fContext, cap);
429 }
430 
lineJoin(NanoVG::LineCap join)431 void NanoVG::lineJoin(NanoVG::LineCap join)
432 {
433     if (fContext != nullptr)
434         nvgLineJoin(fContext, join);
435 }
436 
globalAlpha(float alpha)437 void NanoVG::globalAlpha(float alpha)
438 {
439     if (fContext != nullptr)
440         nvgGlobalAlpha(fContext, alpha);
441 }
442 
443 // -----------------------------------------------------------------------
444 // Transforms
445 
resetTransform()446 void NanoVG::resetTransform()
447 {
448     if (fContext != nullptr)
449         nvgResetTransform(fContext);
450 }
451 
transform(float a,float b,float c,float d,float e,float f)452 void NanoVG::transform(float a, float b, float c, float d, float e, float f)
453 {
454     if (fContext != nullptr)
455         nvgTransform(fContext, a, b, c, d, e, f);
456 }
457 
translate(float x,float y)458 void NanoVG::translate(float x, float y)
459 {
460     if (fContext != nullptr)
461         nvgTranslate(fContext, x, y);
462 }
463 
rotate(float angle)464 void NanoVG::rotate(float angle)
465 {
466     if (fContext != nullptr)
467         nvgRotate(fContext, angle);
468 }
469 
skewX(float angle)470 void NanoVG::skewX(float angle)
471 {
472     if (fContext == nullptr) return;
473     DISTRHO_SAFE_ASSERT_RETURN(angle > 0.0f,);
474 
475     nvgSkewX(fContext, angle);
476 }
477 
skewY(float angle)478 void NanoVG::skewY(float angle)
479 {
480     if (fContext == nullptr) return;
481     DISTRHO_SAFE_ASSERT_RETURN(angle > 0.0f,);
482 
483     nvgSkewY(fContext, angle);
484 }
485 
scale(float x,float y)486 void NanoVG::scale(float x, float y)
487 {
488     if (fContext == nullptr) return;
489     DISTRHO_SAFE_ASSERT_RETURN(d_isNotZero(x),);
490     DISTRHO_SAFE_ASSERT_RETURN(d_isNotZero(y),);
491 
492     nvgScale(fContext, x, y);
493 }
494 
currentTransform(float xform[6])495 void NanoVG::currentTransform(float xform[6])
496 {
497     if (fContext != nullptr)
498         nvgCurrentTransform(fContext, xform);
499 }
500 
transformIdentity(float dst[6])501 void NanoVG::transformIdentity(float dst[6])
502 {
503     nvgTransformIdentity(dst);
504 }
505 
transformTranslate(float dst[6],float tx,float ty)506 void NanoVG::transformTranslate(float dst[6], float tx, float ty)
507 {
508     nvgTransformTranslate(dst, tx, ty);
509 }
510 
transformScale(float dst[6],float sx,float sy)511 void NanoVG::transformScale(float dst[6], float sx, float sy)
512 {
513     nvgTransformScale(dst, sx, sy);
514 }
515 
transformRotate(float dst[6],float a)516 void NanoVG::transformRotate(float dst[6], float a)
517 {
518     nvgTransformRotate(dst, a);
519 }
520 
transformSkewX(float dst[6],float a)521 void NanoVG::transformSkewX(float dst[6], float a)
522 {
523     nvgTransformSkewX(dst, a);
524 }
525 
transformSkewY(float dst[6],float a)526 void NanoVG::transformSkewY(float dst[6], float a)
527 {
528     nvgTransformSkewY(dst, a);
529 }
530 
transformMultiply(float dst[6],const float src[6])531 void NanoVG::transformMultiply(float dst[6], const float src[6])
532 {
533     nvgTransformMultiply(dst, src);
534 }
535 
transformPremultiply(float dst[6],const float src[6])536 void NanoVG::transformPremultiply(float dst[6], const float src[6])
537 {
538     nvgTransformPremultiply(dst, src);
539 }
540 
transformInverse(float dst[6],const float src[6])541 int NanoVG::transformInverse(float dst[6], const float src[6])
542 {
543     return nvgTransformInverse(dst, src);
544 }
545 
transformPoint(float & dstx,float & dsty,const float xform[6],float srcx,float srcy)546 void NanoVG::transformPoint(float& dstx, float& dsty, const float xform[6], float srcx, float srcy)
547 {
548     nvgTransformPoint(&dstx, &dsty, xform, srcx, srcy);
549 }
550 
degToRad(float deg)551 float NanoVG::degToRad(float deg)
552 {
553     return nvgDegToRad(deg);
554 }
555 
radToDeg(float rad)556 float NanoVG::radToDeg(float rad)
557 {
558     return nvgRadToDeg(rad);
559 }
560 
561 // -----------------------------------------------------------------------
562 // Images
563 
createImageFromFile(const char * filename,ImageFlags imageFlags)564 NanoImage::Handle NanoVG::createImageFromFile(const char* filename, ImageFlags imageFlags)
565 {
566     return createImageFromFile(filename, static_cast<int>(imageFlags));
567 }
568 
createImageFromFile(const char * filename,int imageFlags)569 NanoImage::Handle NanoVG::createImageFromFile(const char* filename, int imageFlags)
570 {
571     if (fContext == nullptr) return NanoImage::Handle();
572     DISTRHO_SAFE_ASSERT_RETURN(filename != nullptr && filename[0] != '\0', NanoImage::Handle());
573 
574     return NanoImage::Handle(fContext, nvgCreateImage(fContext, filename, imageFlags));
575 }
576 
createImageFromMemory(uchar * data,uint dataSize,ImageFlags imageFlags)577 NanoImage::Handle NanoVG::createImageFromMemory(uchar* data, uint dataSize, ImageFlags imageFlags)
578 {
579     return createImageFromMemory(data, dataSize, static_cast<int>(imageFlags));
580 }
581 
createImageFromMemory(uchar * data,uint dataSize,int imageFlags)582 NanoImage::Handle NanoVG::createImageFromMemory(uchar* data, uint dataSize, int imageFlags)
583 {
584     if (fContext == nullptr) return NanoImage::Handle();
585     DISTRHO_SAFE_ASSERT_RETURN(data != nullptr, NanoImage::Handle());
586     DISTRHO_SAFE_ASSERT_RETURN(dataSize > 0,    NanoImage::Handle());
587 
588     return NanoImage::Handle(fContext, nvgCreateImageMem(fContext, imageFlags, data,static_cast<int>(dataSize)));
589 }
590 
createImageFromRGBA(uint w,uint h,const uchar * data,ImageFlags imageFlags)591 NanoImage::Handle NanoVG::createImageFromRGBA(uint w, uint h, const uchar* data, ImageFlags imageFlags)
592 {
593     return createImageFromRGBA(w, h, data, static_cast<int>(imageFlags));
594 }
595 
createImageFromRGBA(uint w,uint h,const uchar * data,int imageFlags)596 NanoImage::Handle NanoVG::createImageFromRGBA(uint w, uint h, const uchar* data, int imageFlags)
597 {
598     if (fContext == nullptr) return NanoImage::Handle();
599     DISTRHO_SAFE_ASSERT_RETURN(data != nullptr, NanoImage::Handle());
600 
601     return NanoImage::Handle(fContext, nvgCreateImageRGBA(fContext,
602                                                           static_cast<int>(w),
603                                                           static_cast<int>(h), imageFlags, data));
604 }
605 
createImageFromTextureHandle(GLuint textureId,uint w,uint h,ImageFlags imageFlags,bool deleteTexture)606 NanoImage::Handle NanoVG::createImageFromTextureHandle(GLuint textureId, uint w, uint h, ImageFlags imageFlags, bool deleteTexture)
607 {
608     return createImageFromTextureHandle(textureId, w, h, static_cast<int>(imageFlags), deleteTexture);
609 }
610 
createImageFromTextureHandle(GLuint textureId,uint w,uint h,int imageFlags,bool deleteTexture)611 NanoImage::Handle NanoVG::createImageFromTextureHandle(GLuint textureId, uint w, uint h, int imageFlags, bool deleteTexture)
612 {
613     if (fContext == nullptr) return NanoImage::Handle();
614     DISTRHO_SAFE_ASSERT_RETURN(textureId != 0, NanoImage::Handle());
615 
616     if (! deleteTexture)
617         imageFlags |= NVG_IMAGE_NODELETE;
618 
619     return NanoImage::Handle(fContext, nvglCreateImageFromHandle(fContext,
620                                                                  textureId,
621                                                                  static_cast<int>(w),
622                                                                  static_cast<int>(h), imageFlags));
623 }
624 
625 // -----------------------------------------------------------------------
626 // Paints
627 
linearGradient(float sx,float sy,float ex,float ey,const Color & icol,const Color & ocol)628 NanoVG::Paint NanoVG::linearGradient(float sx, float sy, float ex, float ey, const Color& icol, const Color& ocol)
629 {
630     if (fContext == nullptr) return Paint();
631     return nvgLinearGradient(fContext, sx, sy, ex, ey, icol, ocol);
632 }
633 
boxGradient(float x,float y,float w,float h,float r,float f,const Color & icol,const Color & ocol)634 NanoVG::Paint NanoVG::boxGradient(float x, float y, float w, float h, float r, float f, const Color& icol, const Color& ocol)
635 {
636     if (fContext == nullptr) return Paint();
637     return nvgBoxGradient(fContext, x, y, w, h, r, f, icol, ocol);
638 }
639 
radialGradient(float cx,float cy,float inr,float outr,const Color & icol,const Color & ocol)640 NanoVG::Paint NanoVG::radialGradient(float cx, float cy, float inr, float outr, const Color& icol, const Color& ocol)
641 {
642     if (fContext == nullptr) return Paint();
643     return nvgRadialGradient(fContext, cx, cy, inr, outr, icol, ocol);
644 }
645 
imagePattern(float ox,float oy,float ex,float ey,float angle,const NanoImage & image,float alpha)646 NanoVG::Paint NanoVG::imagePattern(float ox, float oy, float ex, float ey, float angle, const NanoImage& image, float alpha)
647 {
648     if (fContext == nullptr) return Paint();
649 
650     const int imageId(image.fHandle.imageId);
651     DISTRHO_SAFE_ASSERT_RETURN(imageId != 0, Paint());
652 
653     return nvgImagePattern(fContext, ox, oy, ex, ey, angle, imageId, alpha);
654 }
655 
656 // -----------------------------------------------------------------------
657 // Scissoring
658 
scissor(float x,float y,float w,float h)659 void NanoVG::scissor(float x, float y, float w, float h)
660 {
661     if (fContext != nullptr)
662         nvgScissor(fContext, x, y, w, h);
663 }
664 
intersectScissor(float x,float y,float w,float h)665 void NanoVG::intersectScissor(float x, float y, float w, float h)
666 {
667     if (fContext != nullptr)
668         nvgIntersectScissor(fContext, x, y, w, h);
669 }
670 
resetScissor()671 void NanoVG::resetScissor()
672 {
673     if (fContext != nullptr)
674         nvgResetScissor(fContext);
675 }
676 
677 // -----------------------------------------------------------------------
678 // Paths
679 
beginPath()680 void NanoVG::beginPath()
681 {
682     if (fContext != nullptr)
683         nvgBeginPath(fContext);
684 }
685 
moveTo(float x,float y)686 void NanoVG::moveTo(float x, float y)
687 {
688     if (fContext != nullptr)
689         nvgMoveTo(fContext, x, y);
690 }
691 
lineTo(float x,float y)692 void NanoVG::lineTo(float x, float y)
693 {
694     if (fContext != nullptr)
695         nvgLineTo(fContext, x, y);
696 }
697 
bezierTo(float c1x,float c1y,float c2x,float c2y,float x,float y)698 void NanoVG::bezierTo(float c1x, float c1y, float c2x, float c2y, float x, float y)
699 {
700     if (fContext != nullptr)
701         nvgBezierTo(fContext, c1x, c1y, c2x, c2y, x, y);
702 }
703 
quadTo(float cx,float cy,float x,float y)704 void NanoVG::quadTo(float cx, float cy, float x, float y)
705 {
706     if (fContext != nullptr)
707         nvgQuadTo(fContext, cx, cy, x, y);
708 }
709 
arcTo(float x1,float y1,float x2,float y2,float radius)710 void NanoVG::arcTo(float x1, float y1, float x2, float y2, float radius)
711 {
712     if (fContext != nullptr)
713         nvgArcTo(fContext, x1, y1, x2, y2, radius);
714 }
715 
closePath()716 void NanoVG::closePath()
717 {
718     if (fContext != nullptr)
719         nvgClosePath(fContext);
720 }
721 
pathWinding(NanoVG::Winding dir)722 void NanoVG::pathWinding(NanoVG::Winding dir)
723 {
724     if (fContext != nullptr)
725         nvgPathWinding(fContext, dir);
726 }
727 
arc(float cx,float cy,float r,float a0,float a1,NanoVG::Winding dir)728 void NanoVG::arc(float cx, float cy, float r, float a0, float a1, NanoVG::Winding dir)
729 {
730     if (fContext != nullptr)
731         nvgArc(fContext, cx, cy, r, a0, a1, dir);
732 }
733 
rect(float x,float y,float w,float h)734 void NanoVG::rect(float x, float y, float w, float h)
735 {
736     if (fContext != nullptr)
737         nvgRect(fContext, x, y, w, h);
738 }
739 
roundedRect(float x,float y,float w,float h,float r)740 void NanoVG::roundedRect(float x, float y, float w, float h, float r)
741 {
742     if (fContext != nullptr)
743         nvgRoundedRect(fContext, x, y, w, h, r);
744 }
745 
ellipse(float cx,float cy,float rx,float ry)746 void NanoVG::ellipse(float cx, float cy, float rx, float ry)
747 {
748     if (fContext != nullptr)
749         nvgEllipse(fContext, cx, cy, rx, ry);
750 }
751 
circle(float cx,float cy,float r)752 void NanoVG::circle(float cx, float cy, float r)
753 {
754     if (fContext != nullptr)
755         nvgCircle(fContext, cx, cy, r);
756 }
757 
fill()758 void NanoVG::fill()
759 {
760     if (fContext != nullptr)
761         nvgFill(fContext);
762 }
763 
stroke()764 void NanoVG::stroke()
765 {
766     if (fContext != nullptr)
767         nvgStroke(fContext);
768 }
769 
770 // -----------------------------------------------------------------------
771 // Text
772 
createFontFromFile(const char * name,const char * filename)773 NanoVG::FontId NanoVG::createFontFromFile(const char* name, const char* filename)
774 {
775     if (fContext == nullptr) return -1;
776     DISTRHO_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0', -1);
777     DISTRHO_SAFE_ASSERT_RETURN(filename != nullptr && filename[0] != '\0', -1);
778 
779     return nvgCreateFont(fContext, name, filename);
780 }
781 
createFontFromMemory(const char * name,const uchar * data,uint dataSize,bool freeData)782 NanoVG::FontId NanoVG::createFontFromMemory(const char* name, const uchar* data, uint dataSize, bool freeData)
783 {
784     if (fContext == nullptr) return -1;
785     DISTRHO_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0', -1);
786     DISTRHO_SAFE_ASSERT_RETURN(data != nullptr, -1);
787 
788     return nvgCreateFontMem(fContext, name, const_cast<uchar*>(data), static_cast<int>(dataSize), freeData);
789 }
790 
findFont(const char * name)791 NanoVG::FontId NanoVG::findFont(const char* name)
792 {
793     if (fContext == nullptr) return -1;
794     DISTRHO_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0', -1);
795 
796     return nvgFindFont(fContext, name);
797 }
798 
fontSize(float size)799 void NanoVG::fontSize(float size)
800 {
801     if (fContext == nullptr) return;
802     DISTRHO_SAFE_ASSERT_RETURN(size > 0.0f,);
803 
804     nvgFontSize(fContext, size);
805 }
806 
fontBlur(float blur)807 void NanoVG::fontBlur(float blur)
808 {
809     if (fContext == nullptr) return;
810     DISTRHO_SAFE_ASSERT_RETURN(blur >= 0.0f,);
811 
812     nvgFontBlur(fContext, blur);
813 }
814 
textLetterSpacing(float spacing)815 void NanoVG::textLetterSpacing(float spacing)
816 {
817     if (fContext == nullptr) return;
818     DISTRHO_SAFE_ASSERT_RETURN(spacing >= 0.0f,);
819 
820     nvgTextLetterSpacing(fContext, spacing);
821 }
822 
textLineHeight(float lineHeight)823 void NanoVG::textLineHeight(float lineHeight)
824 {
825     if (fContext == nullptr) return;
826     DISTRHO_SAFE_ASSERT_RETURN(lineHeight > 0.0f,);
827 
828     nvgTextLineHeight(fContext, lineHeight);
829 }
830 
textAlign(NanoVG::Align align)831 void NanoVG::textAlign(NanoVG::Align align)
832 {
833     if (fContext != nullptr)
834         nvgTextAlign(fContext, align);
835 }
836 
textAlign(int align)837 void NanoVG::textAlign(int align)
838 {
839     if (fContext != nullptr)
840         nvgTextAlign(fContext, align);
841 }
842 
fontFaceId(FontId font)843 void NanoVG::fontFaceId(FontId font)
844 {
845     if (fContext == nullptr) return;
846     DISTRHO_SAFE_ASSERT_RETURN(font >= 0,);
847 
848     nvgFontFaceId(fContext, font);
849 }
850 
fontFace(const char * font)851 void NanoVG::fontFace(const char* font)
852 {
853     if (fContext == nullptr) return;
854     DISTRHO_SAFE_ASSERT_RETURN(font != nullptr && font[0] != '\0',);
855 
856     nvgFontFace(fContext, font);
857 }
858 
text(float x,float y,const char * string,const char * end)859 float NanoVG::text(float x, float y, const char* string, const char* end)
860 {
861     if (fContext == nullptr) return 0.0f;
862     DISTRHO_SAFE_ASSERT_RETURN(string != nullptr && string[0] != '\0', 0.0f);
863 
864     return nvgText(fContext, x, y, string, end);
865 }
866 
textBox(float x,float y,float breakRowWidth,const char * string,const char * end)867 void NanoVG::textBox(float x, float y, float breakRowWidth, const char* string, const char* end)
868 {
869     if (fContext == nullptr) return;
870     DISTRHO_SAFE_ASSERT_RETURN(string != nullptr && string[0] != '\0',);
871 
872     nvgTextBox(fContext, x, y, breakRowWidth, string, end);
873 }
874 
textBounds(float x,float y,const char * string,const char * end,Rectangle<float> & bounds)875 float NanoVG::textBounds(float x, float y, const char* string, const char* end, Rectangle<float>& bounds)
876 {
877     if (fContext == nullptr) return 0.0f;
878     DISTRHO_SAFE_ASSERT_RETURN(string != nullptr && string[0] != '\0', 0.0f);
879 
880     float b[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
881     const float ret = nvgTextBounds(fContext, x, y, string, end, b);
882     bounds = Rectangle<float>(b[0], b[1], b[2] - b[0], b[3] - b[1]);
883     return ret;
884 }
885 
textBoxBounds(float x,float y,float breakRowWidth,const char * string,const char * end,float bounds[4])886 void NanoVG::textBoxBounds(float x, float y, float breakRowWidth, const char* string, const char* end, float bounds[4])
887 {
888     if (fContext == nullptr) return;
889     DISTRHO_SAFE_ASSERT_RETURN(string != nullptr && string[0] != '\0',);
890 
891     nvgTextBoxBounds(fContext, x, y, breakRowWidth, string, end, bounds);
892 }
893 
textGlyphPositions(float x,float y,const char * string,const char * end,NanoVG::GlyphPosition & positions,int maxPositions)894 int NanoVG::textGlyphPositions(float x, float y, const char* string, const char* end, NanoVG::GlyphPosition& positions, int maxPositions)
895 {
896     if (fContext == nullptr) return 0;
897     DISTRHO_SAFE_ASSERT_RETURN(string != nullptr && string[0] != '\0', 0);
898 
899     return nvgTextGlyphPositions(fContext, x, y, string, end, (NVGglyphPosition*)&positions, maxPositions);
900 }
901 
textMetrics(float * ascender,float * descender,float * lineh)902 void NanoVG::textMetrics(float* ascender, float* descender, float* lineh)
903 {
904     if (fContext != nullptr)
905         nvgTextMetrics(fContext, ascender, descender, lineh);
906 }
907 
textBreakLines(const char * string,const char * end,float breakRowWidth,NanoVG::TextRow & rows,int maxRows)908 int NanoVG::textBreakLines(const char* string, const char* end, float breakRowWidth, NanoVG::TextRow& rows, int maxRows)
909 {
910     if (fContext != nullptr)
911         return nvgTextBreakLines(fContext, string, end, breakRowWidth, (NVGtextRow*)&rows, maxRows);
912     return 0;
913 }
914 
915 #ifndef DGL_NO_SHARED_RESOURCES
loadSharedResources()916 void NanoVG::loadSharedResources()
917 {
918     if (fContext == nullptr) return;
919 
920     if (nvgFindFont(fContext, NANOVG_DEJAVU_SANS_TTF) >= 0)
921         return;
922 
923     using namespace dpf_resources;
924 
925     nvgCreateFontMem(fContext, NANOVG_DEJAVU_SANS_TTF, (const uchar*)dejavusans_ttf, dejavusans_ttf_size, 0);
926 }
927 #endif
928 
929 // -----------------------------------------------------------------------
930 
931 struct NanoWidget::PrivateData {
932     NanoWidget* const self;
933     std::vector<NanoWidget*> subWidgets;
934 
PrivateDataNanoWidget::PrivateData935     PrivateData(NanoWidget* const s)
936         : self(s),
937           subWidgets() {}
938 
~PrivateDataNanoWidget::PrivateData939     ~PrivateData()
940     {
941         subWidgets.clear();
942     }
943 };
944 
NanoWidget(Window & parent,int flags)945 NanoWidget::NanoWidget(Window& parent, int flags)
946     : Widget(parent),
947       NanoVG(flags),
948       nData(new PrivateData(this))
949 {
950     pData->needsScaling = true;
951 }
952 
NanoWidget(Widget * groupWidget,int flags)953 NanoWidget::NanoWidget(Widget* groupWidget, int flags)
954     : Widget(groupWidget, true),
955       NanoVG(flags),
956       nData(new PrivateData(this))
957 {
958     pData->needsScaling = true;
959 }
960 
NanoWidget(NanoWidget * groupWidget)961 NanoWidget::NanoWidget(NanoWidget* groupWidget)
962     : Widget(groupWidget, false),
963       NanoVG(groupWidget),
964       nData(new PrivateData(this))
965 {
966     pData->needsScaling = true;
967     pData->skipDisplay = true;
968     groupWidget->nData->subWidgets.push_back(this);
969 }
970 
~NanoWidget()971 NanoWidget::~NanoWidget()
972 {
973     delete nData;
974 }
975 
onDisplay()976 void NanoWidget::onDisplay()
977 {
978     NanoVG::beginFrame(getWidth(), getHeight());
979     onNanoDisplay();
980 
981     for (std::vector<NanoWidget*>::iterator it = nData->subWidgets.begin(); it != nData->subWidgets.end(); ++it)
982     {
983         NanoWidget* const widget(*it);
984         widget->onNanoDisplay();
985     }
986 
987     NanoVG::endFrame();
988 }
989 
990 // -----------------------------------------------------------------------
991 
992 END_NAMESPACE_DGL
993 
994 #undef final
995 
996 #if defined(__GNUC__) && (__GNUC__ >= 6)
997 # pragma GCC diagnostic push
998 # pragma GCC diagnostic ignored "-Wmisleading-indentation"
999 # pragma GCC diagnostic ignored "-Wshift-negative-value"
1000 #endif
1001 
1002 extern "C" {
1003 #include "nanovg/nanovg.c"
1004 }
1005 
1006 #if defined(__GNUC__) && (__GNUC__ >= 6)
1007 # pragma GCC diagnostic pop
1008 #endif
1009 
1010 // -----------------------------------------------------------------------
1011