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 // -----------------------------------------------------------------------