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