comparison DPF-Prymula-audioplugins/dpf/dgl/src/NanoVG.cpp @ 3:84e66ea83026

DPF-Prymula-audioplugins-0.231015-2
author prymula <prymula76@outlook.com>
date Mon, 16 Oct 2023 21:53:34 +0200
parents
children
comparison
equal deleted inserted replaced
2:cf2cb71d31dd 3:84e66ea83026
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 // -----------------------------------------------------------------------