DPF

DISTRHO Plugin Framework
Log | Files | Refs | Submodules | README | LICENSE

NanoVG.cpp (36623B)


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