diff --git a/nanovega.d b/nanovega.d
index 4dd9f13..9092c03 100644
--- a/nanovega.d
+++ b/nanovega.d
@@ -22,6 +22,125 @@
The NanoVega API is modeled loosely on HTML5 canvas API.
If you know canvas, you're up to speed with NanoVega in no time.
+$(SIDE_BY_SIDE
+
+ $(COLUMN
+
+ D code with nanovega:
+
+ ---
+ import arsd.simpledisplay;
+
+ import arsd.nanovega;
+
+ void main () {
+ NVGContext nvg; // our NanoVega context
+
+ // we need at least OpenGL2 with GLSL to use NanoVega,
+ // so let's tell simpledisplay about that
+ setOpenGLContextVersion(2, 0);
+
+ // now create OpenGL window
+ auto sdmain = new SimpleWindow(800, 600, "NanoVega Simple Sample", OpenGlOptions.yes, Resizability.allowResizing);
+
+ // we need to destroy NanoVega context on window close
+ // stricly speaking, it is not necessary, as nothing fatal
+ // will happen if you'll forget it, but let's be polite.
+ // note that we cannot do that *after* our window was closed,
+ // as we need alive OpenGL context to do proper cleanup.
+ sdmain.onClosing = delegate () {
+ nvg.kill();
+ };
+
+ // this is called just before our window will be shown for the first time.
+ // we must create NanoVega context here, as it needs to initialize
+ // internal OpenGL subsystem with valid OpenGL context.
+ sdmain.visibleForTheFirstTime = delegate () {
+ sdmain.setAsCurrentOpenGlContext(); // make this window's OpenGL context active
+
+ // yes, that's all
+ nvg = nvgCreateContext();
+ if (nvg is null) assert(0, "cannot initialize NanoVega");
+ };
+
+ // this callback will be called when we will need to repaint our window
+ sdmain.redrawOpenGlScene = delegate () {
+ // fix viewport (we can do this in resize event, or here, it doesn't matter)
+ glViewport(0, 0, sdmain.width, sdmain.height);
+
+ // clear window
+ glClearColor(0, 0, 0, 0);
+ glClear(glNVGClearFlags); // use NanoVega API to get flags for OpenGL call
+
+ {
+ nvg.beginFrame(sdmain.width, sdmain.height); // begin rendering
+ scope(exit) nvg.endFrame(); // and flush render queue on exit
+
+ nvg.beginPath(); // start new path
+ nvg.roundedRect(20.5, 30.5, sdmain.width-40, sdmain.height-60, 8); // .5 to draw at pixel center (see NanoVega documentation)
+ // now set filling mode for our rectangle
+ // you can create colors using HTML syntax, or with convenient constants
+ nvg.fillPaint = nvg.linearGradient(20.5, 30.5, sdmain.width-40, sdmain.height-60, NVGColor("#f70"), NVGColor.green);
+ // now fill our rect
+ nvg.fill();
+ // and draw a nice outline
+ nvg.strokeColor = NVGColor.white;
+ nvg.strokeWidth = 2;
+ nvg.stroke();
+ // that's all, folks!
+ }
+ };
+
+ sdmain.eventLoop(0, // no pulse timer required
+ delegate (KeyEvent event) {
+ if (event == "*-Q" || event == "Escape") { sdmain.close(); return; } // quit on Q, Ctrl+Q, and so on
+ },
+ );
+
+ flushGui(); // let OS do it's cleanup
+ }
+ ---
+ )
+
+ $(COLUMN
+ Javascript code with HTML5 Canvas
+
+ ```html
+
+
+
+ NanoVega Simple Sample (HTML5 Translation)
+
+
+
+
+
+
+
+ ```
+ )
+)
+
Creating drawing context
========================
@@ -210,7 +329,7 @@ The following code illustrates the OpenGL state touched by the rendering code:
NanoVega allows you to load image files in various formats (if arsd loaders are in place) to be used for rendering.
In addition you can upload your own image.
- The parameter imageFlags is combination of flags defined in [NVGImageFlag].
+ The parameter imageFlagsList is a list of flags defined in [NVGImageFlag].
If you will use your image as fill pattern, it will be scaled by default. To make it repeat, pass
[NVGImageFlag.RepeatX] and [NVGImageFlag.RepeatY] flags to image creation function respectively.
@@ -395,7 +514,6 @@ version(nanovg_disable_vfs) {
import core.stdc.stdlib : malloc, realloc, free;
import core.stdc.string : memset, memcpy, strlen;
import std.math : PI;
-//import arsd.fontstash;
version(Posix) {
version = nanovg_use_freetype;
@@ -771,7 +889,7 @@ public:
static NVGColor fromArsd (in Color c) { pragma(inline, true); return NVGColor(c.r, c.g, c.b, c.a); } ///
///
this (in Color c) {
- pragma(inline, true);
+ version(aliced) pragma(inline, true);
r = c.r/255.0f;
g = c.g/255.0f;
b = c.b/255.0f;
@@ -845,16 +963,124 @@ public:
}
+//version = nanovega_debug_image_manager;
+//version = nanovega_debug_image_manager_rc;
+
+/** NanoVega image handle.
+ *
+ * This is refcounted struct, so you don't need to do anything special to free it once it is allocated.
+ *
+ * Group: images
+ */
+struct NVGImage {
+private:
+ NVGContext ctx;
+ int id; // backend image id
+
+public:
+ ///
+ this() (in auto ref NVGImage src) nothrow @trusted @nogc {
+ version(nanovega_debug_image_manager_rc) { import core.stdc.stdio; printf("NVGImage %p created from %p (imgid=%d)\n", &this, src, src.id); }
+ ctx = cast(NVGContext)src.ctx;
+ id = src.id;
+ if (ctx !is null) ctx.nvg__imageIncRef(id);
+ }
+
+ ///
+ ~this () nothrow @trusted @nogc { version(aliced) pragma(inline, true); clear(); }
+
+ ///
+ this (this) nothrow @trusted @nogc {
+ if (ctx !is null) {
+ version(nanovega_debug_image_manager_rc) { import core.stdc.stdio; printf("NVGImage %p postblit (imgid=%d)\n", &this, id); }
+ ctx.nvg__imageIncRef(id);
+ }
+ }
+
+ ///
+ void opAssign() (in auto ref NVGImage src) nothrow @trusted @nogc {
+ version(nanovega_debug_image_manager_rc) { import core.stdc.stdio; printf("NVGImage %p (imgid=%d) assigned from %p (imgid=%d)\n", &this, id, &src, src.id); }
+ if (src.ctx !is null) (cast(NVGContext)src.ctx).nvg__imageIncRef(src.id);
+ if (ctx !is null) ctx.nvg__imageDecRef(id);
+ ctx = cast(NVGContext)src.ctx;
+ id = src.id;
+ }
+
+ /// Is this image valid?
+ @property bool valid () const pure nothrow @safe @nogc { pragma(inline, true); return (id > 0 && ctx.valid); }
+
+ /// Is this image valid?
+ @property bool isSameContext (const(NVGContext) actx) const pure nothrow @safe @nogc { pragma(inline, true); return (actx !is null && ctx is actx); }
+
+ /// Returns image width, or zero for invalid image.
+ int width () const nothrow @trusted @nogc {
+ int w = 0;
+ if (valid) {
+ int h = void;
+ ctx.params.renderGetTextureSize(cast(void*)ctx.params.userPtr, id, &w, &h);
+ }
+ return w;
+ }
+
+ /// Returns image height, or zero for invalid image.
+ int height () const nothrow @trusted @nogc {
+ int h = 0;
+ if (valid) {
+ int w = void;
+ ctx.params.renderGetTextureSize(cast(void*)ctx.params.userPtr, id, &w, &h);
+ }
+ return h;
+ }
+
+ /// Free this image.
+ void clear () nothrow @trusted @nogc {
+ if (ctx !is null) {
+ version(nanovega_debug_image_manager_rc) { import core.stdc.stdio; printf("NVGImage %p cleared (imgid=%d)\n", &this, id); }
+ ctx.nvg__imageDecRef(id);
+ ctx = null;
+ id = 0;
+ }
+ }
+}
+
+
/// Paint parameters for various fills. Don't change anything here!
/// Group: render_styles
public struct NVGPaint {
NVGMatrix xform;
- float[2] extent;
- float radius;
- float feather;
+ float[2] extent = 0.0f;
+ float radius = 0.0f;
+ float feather = 0.0f;
NVGColor innerColor; /// this can be used to modulate images (fill/font)
NVGColor outerColor;
- int image;
+ NVGImage image;
+
+ this() (in auto ref NVGPaint p) nothrow @trusted @nogc {
+ xform = p.xform;
+ extent[] = p.extent[];
+ radius = p.radius;
+ feather = p.feather;
+ innerColor = p.innerColor;
+ outerColor = p.outerColor;
+ image = p.image;
+ }
+
+ void opAssign() (in auto ref NVGPaint p) nothrow @trusted @nogc {
+ xform = p.xform;
+ extent[] = p.extent[];
+ radius = p.radius;
+ feather = p.feather;
+ innerColor = p.innerColor;
+ outerColor = p.outerColor;
+ image = p.image;
+ }
+
+ void clear () nothrow @trusted @nogc {
+ version(aliced) pragma(inline, true);
+ import core.stdc.string : memset;
+ image.clear();
+ memset(&this, 0, this.sizeof);
+ }
}
/// Path winding.
@@ -1019,7 +1245,7 @@ alias NVGImageFlags = NVGImageFlag; /// Backwards compatibility for [NVGImageFla
// ////////////////////////////////////////////////////////////////////////// //
-package/*(arsd)*/:
+private:
static T* xdup(T) (const(T)* ptr, int count) nothrow @trusted @nogc {
import core.stdc.stdlib : malloc;
@@ -1039,7 +1265,7 @@ enum NVGtexture {
struct NVGscissor {
NVGMatrix xform;
- float[2] extent;
+ float[2] extent = -1.0f;
}
struct NVGvertex {
@@ -1139,23 +1365,28 @@ enum PointFlag : int {
struct NVGstate {
NVGCompositeOperationState compositeOperation;
- bool shapeAntiAlias;
+ bool shapeAntiAlias = true;
NVGPaint fill;
NVGPaint stroke;
- float strokeWidth;
- float miterLimit;
- NVGLineCap lineJoin;
- NVGLineCap lineCap;
- float alpha;
+ float strokeWidth = 1.0f;
+ float miterLimit = 10.0f;
+ NVGLineCap lineJoin = NVGLineCap.Miter;
+ NVGLineCap lineCap = NVGLineCap.Butt;
+ float alpha = 1.0f;
NVGMatrix xform;
NVGscissor scissor;
- float fontSize;
- float letterSpacing;
- float lineHeight;
- float fontBlur;
+ float fontSize = 16.0f;
+ float letterSpacing = 0.0f;
+ float lineHeight = 1.0f;
+ float fontBlur = 0.0f;
NVGTextAlign textAlign;
- int fontId;
- bool evenOddMode; // use even-odd filling rule (required for some svgs); otherwise use non-zero fill
+ int fontId = 0;
+ bool evenOddMode = false; // use even-odd filling rule (required for some svgs); otherwise use non-zero fill
+
+ void clearPaint () nothrow @trusted @nogc {
+ fill.clear();
+ stroke.clear();
+ }
}
struct NVGpoint {
@@ -1305,7 +1536,7 @@ private:
float fringeWidth;
float devicePxRatio;
FONScontext* fs;
- int[NVG_MAX_FONTIMAGES] fontImages;
+ NVGImage[NVG_MAX_FONTIMAGES] fontImages;
int fontImageIdx;
int drawCallCount;
int fillTriCount;
@@ -1324,11 +1555,38 @@ private:
NVGMatrix gpuAffine;
int mWidth, mHeight;
float mDeviceRatio;
- void delegate (NVGContext ctx) nothrow @trusted @nogc cleanup;
+ // image manager
+ int imageCount; // number of alive images in this context
+ bool contextAlive; // context can be dead, but still contain some images
@disable this (this); // no copies
}
+void nvg__imageIncRef (NVGContext ctx, int imgid) nothrow @trusted @nogc {
+ if (ctx !is null && imgid > 0) {
+ ++ctx.imageCount;
+ version(nanovega_debug_image_manager_rc) { import core.stdc.stdio; printf("image[++]ref: context %p: %d image refs (%d)\n", ctx, ctx.imageCount, imgid); }
+ if (ctx.contextAlive) ctx.params.renderTextureIncRef(ctx.params.userPtr, imgid);
+ }
+}
+
+void nvg__imageDecRef (NVGContext ctx, int imgid) nothrow @trusted @nogc {
+ if (ctx !is null && imgid > 0) {
+ assert(ctx.imageCount > 0);
+ --ctx.imageCount;
+ version(nanovega_debug_image_manager_rc) { import core.stdc.stdio; printf("image[--]ref: context %p: %d image refs (%d)\n", ctx, ctx.imageCount, imgid); }
+ if (ctx.contextAlive) ctx.params.renderDeleteTexture(ctx.params.userPtr, imgid);
+ version(nanovega_debug_image_manager) if (!ctx.contextAlive) { import core.stdc.stdio; printf("image[--]ref: zombie context %p: %d image refs (%d)\n", ctx, ctx.imageCount, imgid); }
+ if (!ctx.contextAlive && ctx.imageCount == 0) {
+ // it is finally safe to free context memory
+ import core.stdc.stdlib : free;
+ version(nanovega_debug_image_manager) { import core.stdc.stdio; printf("killed zombie context %p\n", ctx); }
+ free(ctx);
+ }
+ }
+}
+
+
public import core.stdc.math :
nvg__sqrtf = sqrtf,
nvg__modf = fmodf,
@@ -1435,14 +1693,16 @@ NVGstate* nvg__getState (NVGContext ctx) pure nothrow @trusted @nogc {
}
// Constructor called by the render back-end.
-package/*(arsd)*/ NVGContext createInternal (NVGparams* params) nothrow @trusted @nogc {
+NVGContext createInternal (NVGparams* params) nothrow @trusted @nogc {
FONSparams fontParams = void;
NVGContext ctx = cast(NVGContext)malloc(NVGcontextinternal.sizeof);
if (ctx is null) goto error;
memset(ctx, 0, NVGcontextinternal.sizeof);
+ ctx.contextAlive = true;
+
ctx.params = *params;
- ctx.fontImages[0..NVG_MAX_FONTIMAGES] = 0;
+ //ctx.fontImages[0..NVG_MAX_FONTIMAGES] = 0;
ctx.commands = cast(float*)malloc(float.sizeof*NVG_INIT_COMMANDS_SIZE);
if (ctx.commands is null) goto error;
@@ -1473,8 +1733,10 @@ package/*(arsd)*/ NVGContext createInternal (NVGparams* params) nothrow @trusted
if (ctx.fs is null) goto error;
// create font texture
- ctx.fontImages[0] = ctx.params.renderCreateTexture(ctx.params.userPtr, NVGtexture.Alpha, fontParams.width, fontParams.height, (ctx.params.fontAA ? 0 : NVGImageFlag.NoFiltering), null);
- if (ctx.fontImages[0] == 0) goto error;
+ ctx.fontImages[0].id = ctx.params.renderCreateTexture(ctx.params.userPtr, NVGtexture.Alpha, fontParams.width, fontParams.height, (ctx.params.fontAA ? 0 : NVGImageFlag.NoFiltering), null);
+ if (ctx.fontImages[0].id == 0) goto error;
+ ctx.fontImages[0].ctx = ctx;
+ ctx.nvg__imageIncRef(ctx.fontImages[0].id);
ctx.fontImageIdx = 0;
ctx.pathPickId = -1;
@@ -1488,33 +1750,34 @@ error:
}
// Called by render backend.
-package/*(arsd)*/ NVGparams* internalParams (NVGContext ctx) nothrow @trusted @nogc {
+NVGparams* internalParams (NVGContext ctx) nothrow @trusted @nogc {
return &ctx.params;
}
// Destructor called by the render back-end.
-package/*(arsd)*/ void deleteInternal (ref NVGContext ctx) nothrow @trusted @nogc {
+void deleteInternal (ref NVGContext ctx) nothrow @trusted @nogc {
if (ctx is null) return;
-
+ if (ctx.contextAlive) {
if (ctx.commands !is null) free(ctx.commands);
nvg__deletePathCache(ctx.cache);
if (ctx.fs) fonsDeleteInternal(ctx.fs);
- foreach (uint i; 0..NVG_MAX_FONTIMAGES) {
- if (ctx.fontImages[i] != 0) {
- ctx.deleteImage(ctx.fontImages[i]);
- ctx.fontImages[i] = 0;
- }
- }
+ foreach (uint i; 0..NVG_MAX_FONTIMAGES) ctx.fontImages[i].clear();
if (ctx.params.renderDelete !is null) ctx.params.renderDelete(ctx.params.userPtr);
if (ctx.pickScene !is null) nvg__deletePickScene(ctx.pickScene);
- if (ctx.cleanup !is null) ctx.cleanup(ctx);
+ ctx.contextAlive = false;
+ if (ctx.imageCount == 0) {
+ version(nanovega_debug_image_manager) { import core.stdc.stdio; printf("destroyed context %p\n", ctx); }
free(ctx);
+ } else {
+ version(nanovega_debug_image_manager) { import core.stdc.stdio; printf("context %p is zombie now (%d image refs)\n", ctx, ctx.imageCount); }
+ }
+ }
}
/// Delete NanoVega context.
@@ -1526,6 +1789,11 @@ public void kill (ref NVGContext ctx) nothrow @trusted @nogc {
}
}
+/// Returns `true` if the given context is not `null` and can be used for painting.
+/// Group: context_management
+public bool valid (in NVGContext ctx) pure nothrow @trusted @nogc { pragma(inline, true); return (ctx !is null && ctx.contextAlive); }
+
+
// ////////////////////////////////////////////////////////////////////////// //
// Frame Management
@@ -1562,6 +1830,7 @@ public void beginFrame (NVGContext ctx, int windowWidth, int windowHeight, float
if (isNaN(devicePixelRatio)) devicePixelRatio = (windowHeight > 0 ? cast(float)windowWidth/cast(float)windowHeight : 1024.0/768.0);
+ foreach (ref NVGstate st; ctx.states[0..ctx.nstates]) st.clearPaint();
ctx.nstates = 0;
ctx.save();
ctx.reset();
@@ -1609,13 +1878,13 @@ public void endFrame (NVGContext ctx) nothrow @trusted @nogc {
NVGstate* state = nvg__getState(ctx);
ctx.params.renderFlush(ctx.params.userPtr, state.compositeOperation);
if (ctx.fontImageIdx != 0) {
- int fontImage = ctx.fontImages[ctx.fontImageIdx];
+ auto fontImage = ctx.fontImages[ctx.fontImageIdx];
int j = 0, iw, ih;
// delete images that smaller than current one
- if (fontImage == 0) return;
+ if (!fontImage.valid) return;
ctx.imageSize(fontImage, iw, ih);
foreach (int i; 0..ctx.fontImageIdx) {
- if (ctx.fontImages[i] != 0) {
+ if (ctx.fontImages[i].valid) {
int nw, nh;
ctx.imageSize(ctx.fontImages[i], nw, nh);
if (nw < iw || nh < ih) {
@@ -1630,7 +1899,7 @@ public void endFrame (NVGContext ctx) nothrow @trusted @nogc {
ctx.fontImages[0] = fontImage;
ctx.fontImageIdx = 0;
// clear all images after j
- ctx.fontImages[j..NVG_MAX_FONTIMAGES] = 0;
+ ctx.fontImages[j..NVG_MAX_FONTIMAGES] = NVGImage.init;
}
}
@@ -1690,9 +1959,7 @@ private:
void clearNode (int idx) nothrow @trusted @nogc {
if (idx < 0 || idx >= nnodes) return;
Node* node = &nodes[idx];
- if (svctx !is null && node.paint.image > 0) {
- svctx.params.renderDeleteTexture(svctx.params.userPtr, node.paint.image);
- }
+ if (svctx !is null && node.paint.image.valid) node.paint.image.clear();
if (node.path !is null) node.path.clear();
}
@@ -1873,7 +2140,6 @@ void appendCurrentPathToCache (NVGContext ctx, NVGPathSet svp, in ref NVGPaint p
NVGpathCache* cc = node.path;
cc.copyFrom(ctx.cache);
node.paint = paint;
- ctx.params.renderTextureIncRef(ctx.params.userPtr, node.paint.image);
// copy path commands (we may need 'em for picking)
version(all) {
cc.ncommands = ctx.ncommands;
@@ -2431,8 +2697,7 @@ public float nvgRadians() (in float rad) pure nothrow @safe @nogc { pragma(inlin
// ////////////////////////////////////////////////////////////////////////// //
void nvg__setPaintColor() (ref NVGPaint p, in auto ref NVGColor color) nothrow @trusted @nogc {
- //pragma(inline, true);
- memset(&p, 0, p.sizeof);
+ p.clear();
p.xform.identity;
p.radius = 0.0f;
p.feather = 1.0f;
@@ -2452,7 +2717,10 @@ void nvg__setPaintColor() (ref NVGPaint p, in auto ref NVGColor color) nothrow @
*/
public bool save (NVGContext ctx) nothrow @trusted @nogc {
if (ctx.nstates >= NVG_MAX_STATES) return false;
- if (ctx.nstates > 0) memcpy(&ctx.states[ctx.nstates], &ctx.states[ctx.nstates-1], NVGstate.sizeof);
+ if (ctx.nstates > 0) {
+ //memcpy(&ctx.states[ctx.nstates], &ctx.states[ctx.nstates-1], NVGstate.sizeof);
+ ctx.states[ctx.nstates] = ctx.states[ctx.nstates-1];
+ }
++ctx.nstates;
return true;
}
@@ -2461,6 +2729,7 @@ public bool save (NVGContext ctx) nothrow @trusted @nogc {
/// Group: state_handling
public bool restore (NVGContext ctx) nothrow @trusted @nogc {
if (ctx.nstates <= 1) return false;
+ ctx.states[ctx.nstates-1].clearPaint();
--ctx.nstates;
return true;
}
@@ -2469,7 +2738,7 @@ public bool restore (NVGContext ctx) nothrow @trusted @nogc {
/// Group: state_handling
public void reset (NVGContext ctx) nothrow @trusted @nogc {
NVGstate* state = nvg__getState(ctx);
- memset(state, 0, (*state).sizeof);
+ state.clearPaint();
nvg__setPaintColor(state.fill, nvgRGBA(255, 255, 255, 255));
nvg__setPaintColor(state.stroke, nvgRGBA(0, 0, 0, 255));
@@ -2482,8 +2751,7 @@ public void reset (NVGContext ctx) nothrow @trusted @nogc {
state.alpha = 1.0f;
state.xform.identity;
- state.scissor.extent.ptr[0] = -1.0f;
- state.scissor.extent.ptr[1] = -1.0f;
+ state.scissor.extent[] = -1.0f;
state.fontSize = 16.0f;
state.letterSpacing = 0.0f;
@@ -2693,9 +2961,7 @@ public void scale (NVGContext ctx, in float x, in float y) nothrow @trusted @nog
/// Creates image by loading it from the disk from specified file name.
/// Returns handle to the image or 0 on error.
/// Group: images
-public int createImage() (NVGContext ctx, const(char)[] filename, const(/*NVGImageFlag*/uint)[] imageFlagsList...) {
- uint imageFlags = 0;
- foreach (immutable uint flag; imageFlagsList) imageFlags |= flag;
+public NVGImage createImage() (NVGContext ctx, const(char)[] filename, const(NVGImageFlag)[] imageFlagsList...) {
static if (NanoVegaHasArsdImage) {
import arsd.image;
// do we have new arsd API to load images?
@@ -2705,28 +2971,30 @@ public int createImage() (NVGContext ctx, const(char)[] filename, const(/*NVGIma
try {
auto oimg = MemoryImage.fromImageFile(filename);
if (auto img = cast(TrueColorImage)oimg) {
- scope(exit) { oimg.destroy; }
- return ctx.createImageRGBA(img.width, img.height, img.imageData.bytes[], imageFlags);
+ oimg = null;
+ scope(exit) { delete img.imageData.bytes; delete img; }
+ return ctx.createImageRGBA(img.width, img.height, img.imageData.bytes[], imageFlagsList);
} else {
TrueColorImage img = oimg.getAsTrueColorImage;
- oimg.destroy;
- scope(exit) { img.destroy; }
- return ctx.createImageRGBA(img.width, img.height, img.imageData.bytes[], imageFlags);
+ if (auto xi = cast(IndexedImage)oimg) { delete xi.palette; delete xi.data; delete xi; }
+ oimg = null;
+ scope(exit) { delete img.imageData.bytes; delete img; }
+ return ctx.createImageRGBA(img.width, img.height, img.imageData.bytes[], imageFlagsList);
}
} catch (Exception) {}
- return 0;
+ return NVGImage.init;
} else {
import std.internal.cstring;
ubyte* img;
- int w, h, n, image;
+ int w, h, n;
stbi_set_unpremultiply_on_load(1);
stbi_convert_iphone_png_to_rgb(1);
img = stbi_load(filename.tempCString, &w, &h, &n, 4);
if (img is null) {
//printf("Failed to load %s - %s\n", filename, stbi_failure_reason());
- return 0;
+ return NVGImage.init;
}
- image = ctx.createImageRGBA(w, h, img[0..w*h*4], imageFlags);
+ auto image = ctx.createImageRGBA(w, h, img[0..w*h*4], imageFlagsList);
stbi_image_free(img);
return image;
}
@@ -2736,32 +3004,28 @@ static if (NanoVegaHasArsdImage) {
/// Creates image by loading it from the specified memory image.
/// Returns handle to the image or 0 on error.
/// Group: images
- public int createImageFromMemoryImage() (NVGContext ctx, MemoryImage img, const(/*NVGImageFlag*/uint)[] imageFlagsList...) {
- if (img is null) return 0;
- uint imageFlags = 0;
- foreach (immutable uint flag; imageFlagsList) imageFlags |= flag;
+ public NVGImage createImageFromMemoryImage() (NVGContext ctx, MemoryImage img, const(NVGImageFlag)[] imageFlagsList...) {
+ if (img is null) return NVGImage.init;
if (auto tc = cast(TrueColorImage)img) {
- return ctx.createImageRGBA(tc.width, tc.height, tc.imageData.bytes[], imageFlags);
+ return ctx.createImageRGBA(tc.width, tc.height, tc.imageData.bytes[], imageFlagsList);
} else {
auto tc = img.getAsTrueColorImage;
- scope(exit) { tc.destroy; }
- return ctx.createImageRGBA(tc.width, tc.height, tc.imageData.bytes[], imageFlags);
+ scope(exit) { delete tc.imageData.bytes; delete tc; }
+ return ctx.createImageRGBA(tc.width, tc.height, tc.imageData.bytes[], imageFlagsList);
}
}
} else {
/// Creates image by loading it from the specified chunk of memory.
/// Returns handle to the image or 0 on error.
/// Group: images
- public int createImageMem() (NVGContext ctx, const(ubyte)* data, int ndata, const(/*NVGImageFlag*/uint)[] imageFlagsList...) {
+ public NVGImage createImageMem() (NVGContext ctx, const(ubyte)* data, int ndata, const(NVGImageFlag)[] imageFlagsList...) {
int w, h, n, image;
ubyte* img = stbi_load_from_memory(data, ndata, &w, &h, &n, 4);
if (img is null) {
//printf("Failed to load %s - %s\n", filename, stbi_failure_reason());
- return 0;
+ return NVGImage.init;
}
- uint imageFlags = 0;
- foreach (immutable uint flag; imageFlagsList) imageFlags |= flag;
- image = ctx.createImageRGBA(w, h, img[0..w*h*4], imageFlags);
+ image = ctx.createImageRGBA(w, h, img[0..w*h*4], imageFlagsList);
stbi_image_free(img);
return image;
}
@@ -2770,34 +3034,45 @@ static if (NanoVegaHasArsdImage) {
/// Creates image from specified image data.
/// Returns handle to the image or 0 on error.
/// Group: images
-public int createImageRGBA (NVGContext ctx, int w, int h, const(void)[] data, const(/*NVGImageFlag*/uint)[] imageFlagsList...) nothrow @trusted @nogc {
- if (w < 1 || h < 1 || data.length < w*h*4) return 0;
+public NVGImage createImageRGBA (NVGContext ctx, int w, int h, const(void)[] data, const(NVGImageFlag)[] imageFlagsList...) nothrow @trusted @nogc {
+ if (w < 1 || h < 1 || data.length < w*h*4) return NVGImage.init;
uint imageFlags = 0;
foreach (immutable uint flag; imageFlagsList) imageFlags |= flag;
- return ctx.params.renderCreateTexture(ctx.params.userPtr, NVGtexture.RGBA, w, h, imageFlags, cast(const(ubyte)*)data.ptr);
+ NVGImage res;
+ res.id = ctx.params.renderCreateTexture(ctx.params.userPtr, NVGtexture.RGBA, w, h, imageFlags, cast(const(ubyte)*)data.ptr);
+ if (res.id > 0) {
+ res.ctx = ctx;
+ ctx.nvg__imageIncRef(res.id);
+ }
+ return res;
}
/// Updates image data specified by image handle.
/// Group: images
-public void updateImage (NVGContext ctx, int image, const(void)[] data) nothrow @trusted @nogc {
- if (image > 0) {
+public void updateImage() (NVGContext ctx, auto ref NVGImage image, const(void)[] data) nothrow @trusted @nogc {
+ if (image.valid) {
int w, h;
- ctx.params.renderGetTextureSize(ctx.params.userPtr, image, &w, &h);
- ctx.params.renderUpdateTexture(ctx.params.userPtr, image, 0, 0, w, h, cast(const(ubyte)*)data.ptr);
+ if (image.ctx !is ctx) assert(0, "NanoVega: you cannot use image from one context in another context");
+ ctx.params.renderGetTextureSize(ctx.params.userPtr, image.id, &w, &h);
+ ctx.params.renderUpdateTexture(ctx.params.userPtr, image.id, 0, 0, w, h, cast(const(ubyte)*)data.ptr);
}
}
/// Returns the dimensions of a created image.
/// Group: images
-public void imageSize (NVGContext ctx, int image, out int w, out int h) nothrow @trusted @nogc {
- if (image > 0) ctx.params.renderGetTextureSize(ctx.params.userPtr, image, &w, &h);
+public void imageSize() (NVGContext ctx, in auto ref NVGImage image, out int w, out int h) nothrow @trusted @nogc {
+ if (image.valid) {
+ if (image.ctx !is ctx) assert(0, "NanoVega: you cannot use image from one context in another context");
+ ctx.params.renderGetTextureSize(cast(void*)ctx.params.userPtr, image.id, &w, &h);
+ }
}
/// Deletes created image.
/// Group: images
-public void deleteImage (NVGContext ctx, int image) nothrow @trusted @nogc {
- if (ctx is null || image <= 0) return;
- ctx.params.renderDeleteTexture(ctx.params.userPtr, image);
+public void deleteImage() (NVGContext ctx, ref NVGImage image) nothrow @trusted @nogc {
+ if (ctx is null || !image.valid) return;
+ if (image.ctx !is ctx) assert(0, "NanoVega: you cannot use image from one context in another context");
+ image.clear();
}
@@ -2948,7 +3223,7 @@ public NVGPaint boxGradient (NVGContext ctx, float x, float y, float w, float h,
*
* Group: paints
*/
-public NVGPaint imagePattern (NVGContext ctx, float cx, float cy, float w, float h, float angle, int image, float alpha=1) nothrow @trusted @nogc {
+public NVGPaint imagePattern() (NVGContext ctx, float cx, float cy, float w, float h, float angle, in auto ref NVGImage image, float alpha=1) nothrow @trusted @nogc {
NVGPaint p = void;
memset(&p, 0, p.sizeof);
@@ -2969,41 +3244,32 @@ public NVGPaint imagePattern (NVGContext ctx, float cx, float cy, float w, float
/// Linear gradient with multiple stops.
/// $(WARNING THIS IS EXPERIMENTAL API AND MAY BE CHANGED/BROKEN IN NEXT RELEASES!)
/// Group: paints
-public alias NVGLGS = NVGLGSdata*;
-
-private struct NVGLGSdata {
- int imgid; // 0: invalid
+public struct NVGLGS {
+private:
+ NVGImage imgid;
// [imagePattern] arguments
- float cx, cy, w, h, angle;
+ float cx, cy, dim, angle;
+public:
@disable this (this); // no copies
- public @property bool valid () const pure nothrow @safe @nogc { pragma(inline, true); return (imgid > 0); } ///
+ @property bool valid () const pure nothrow @safe @nogc { pragma(inline, true); return imgid.valid; } ///
+ void clear () nothrow @safe @nogc { pragma(inline, true); imgid.clear(); } ///
}
-/// Destroy linear gradient with stops
-/// $(WARNING THIS IS EXPERIMENTAL API AND MAY BE CHANGED/BROKEN IN NEXT RELEASES!)
-/// Group: paints
-public void kill (NVGContext ctx, ref NVGLGS lgs) nothrow @trusted @nogc {
- if (lgs is null) return;
- if (lgs.imgid > 0) { ctx.deleteImage(lgs.imgid); lgs.imgid = 0; }
- free(lgs);
- lgs = null;
-}
-
-/** Sets linear gradient with stops, created with [createLinearGradientWithStops].
+/** Returns [NVGPaint] for linear gradient with stops, created with [createLinearGradientWithStops].
* The gradient is transformed by the current transform when it is passed to [fillPaint] or [strokePaint].
*
* $(WARNING THIS IS EXPERIMENTAL API AND MAY BE CHANGED/BROKEN IN NEXT RELEASES!)
* Group: paints
*/
-public NVGPaint linearGradient (NVGContext ctx, NVGLGS lgs) nothrow @trusted @nogc {
- if (lgs is null || !lgs.valid) {
+public NVGPaint asPaint() (NVGContext ctx, in auto ref NVGLGS lgs) nothrow @trusted @nogc {
+ if (!lgs.valid) {
NVGPaint p = void;
memset(&p, 0, p.sizeof);
nvg__setPaintColor(p, NVGColor.red);
return p;
} else {
- return ctx.imagePattern(lgs.cx, lgs.cy, lgs.w, lgs.h, lgs.angle, lgs.imgid);
+ return ctx.imagePattern(lgs.cx, lgs.cy, lgs.dim, lgs.dim, lgs.angle, lgs.imgid);
}
}
@@ -3011,20 +3277,24 @@ public NVGPaint linearGradient (NVGContext ctx, NVGLGS lgs) nothrow @trusted @no
/// $(WARNING THIS IS EXPERIMENTAL API AND MAY BE CHANGED/BROKEN IN NEXT RELEASES!)
/// Group: paints
public struct NVGGradientStop {
- float offset; /// [0..1]
+ float offset = 0; /// [0..1]
NVGColor color; ///
+
+ ///
+ this() (in float aofs, in auto ref NVGColor aclr) nothrow @trusted @nogc { pragma(inline, true); offset = aofs; color = aclr; }
+ this() (in float aofs, in Color aclr) nothrow @trusted @nogc { pragma(inline, true); offset = aofs; color = NVGColor(aclr); }
}
/// Create linear gradient data suitable to use with `linearGradient(res)`.
/// Don't forget to destroy the result when you don't need it anymore with `ctx.kill(res);`.
/// $(WARNING THIS IS EXPERIMENTAL API AND MAY BE CHANGED/BROKEN IN NEXT RELEASES!)
/// Group: paints
-public NVGLGS createLinearGradientWithStops (NVGContext ctx, float sx, float sy, float ex, float ey, const(NVGGradientStop)[] stops) nothrow @trusted @nogc {
+public NVGLGS createLinearGradientWithStops (NVGContext ctx, in float sx, in float sy, in float ex, in float ey, const(NVGGradientStop)[] stops...) nothrow @trusted @nogc {
// based on the code by Jorge Acereda
enum NVG_GRADIENT_SAMPLES = 1024;
static void gradientSpan (uint* dst, const(NVGGradientStop)* s0, const(NVGGradientStop)* s1) nothrow @trusted @nogc {
- float s0o = nvg__clamp(s0.offset, 0.0f, 1.0f);
- float s1o = nvg__clamp(s1.offset, 0.0f, 1.0f);
+ immutable float s0o = nvg__clamp(s0.offset, 0.0f, 1.0f);
+ immutable float s1o = nvg__clamp(s1.offset, 0.0f, 1.0f);
uint s = cast(uint)(s0o*NVG_GRADIENT_SAMPLES);
uint e = cast(uint)(s1o*NVG_GRADIENT_SAMPLES);
uint sc = 0xffffffffU;
@@ -3037,11 +3307,12 @@ public NVGLGS createLinearGradientWithStops (NVGContext ctx, float sx, float sy,
uint dg = cast(uint)((s1.color.rgba[1]*sc-g)/(e-s));
uint db = cast(uint)((s1.color.rgba[2]*sc-b)/(e-s));
uint da = cast(uint)((s1.color.rgba[3]*sc-a)/(e-s));
- for (uint i = s; i < e; ++i) {
+ dst += s;
+ foreach (immutable _; s..e) {
version(BigEndian) {
- dst[i] = ((r>>sh)<<24)+((g>>sh)<<16)+((b>>sh)<<8)+((a>>sh)<<0);
+ *dst++ = ((r>>sh)<<24)+((g>>sh)<<16)+((b>>sh)<<8)+((a>>sh)<<0);
} else {
- dst[i] = ((a>>sh)<<24)+((b>>sh)<<16)+((g>>sh)<<8)+((r>>sh)<<0);
+ *dst++ = ((a>>sh)<<24)+((b>>sh)<<16)+((g>>sh)<<8)+((r>>sh)<<0);
}
r += dr;
g += dg;
@@ -3050,35 +3321,33 @@ public NVGLGS createLinearGradientWithStops (NVGContext ctx, float sx, float sy,
}
}
+ NVGLGS res;
+
uint[NVG_GRADIENT_SAMPLES] data = void;
- float w = ex-sx;
- float h = ey-sy;
- float len = nvg__sqrtf(w*w + h*h);
+ immutable float w = ex-sx;
+ immutable float h = ey-sy;
+ res.dim = nvg__sqrtf(w*w+h*h);
+
+ res.cx = sx;
+ res.cy = sy;
+ res.angle =
+ (/*nvg__absf(h) < 0.0001 ? 0 :
+ nvg__absf(w) < 0.0001 ? 90.nvgDegrees :*/
+ nvg__atan2f(h/*ey-sy*/, w/*ex-sx*/));
+
+ if (stops.length > 0) {
auto s0 = NVGGradientStop(0, nvgRGBAf(0, 0, 0, 1));
auto s1 = NVGGradientStop(1, nvgRGBAf(1, 1, 1, 1));
- int img;
if (stops.length > 64) stops = stops[0..64];
if (stops.length) {
s0.color = stops[0].color;
s1.color = stops[$-1].color;
}
gradientSpan(data.ptr, &s0, (stops.length ? stops.ptr : &s1));
- if (stops.length) {
foreach (immutable i; 0..stops.length-1) gradientSpan(data.ptr, stops.ptr+i, stops.ptr+i+1);
- }
gradientSpan(data.ptr, (stops.length ? stops.ptr+stops.length-1 : &s0), &s1);
- img = ctx.createImageRGBA(NVG_GRADIENT_SAMPLES, 1, data[], NVGImageFlag.RepeatX, NVGImageFlag.RepeatY);
- if (img <= 0) return null;
- // allocate data
- NVGLGS res = cast(NVGLGS)malloc((*NVGLGS).sizeof);
- if (res is null) { ctx.deleteImage(img); return null; }
- // fill result
- res.imgid = img;
- res.cx = sx;
- res.cy = sy;
- res.w = len;
- res.h = len;
- res.angle = nvg__atan2f(ey-sy, ex-sx);
+ res.imgid = ctx.createImageRGBA(NVG_GRADIENT_SAMPLES, 1, data[], NVGImageFlag.RepeatX, NVGImageFlag.RepeatY);
+ }
return res;
}
@@ -6414,8 +6683,7 @@ void nvg__pickBeginFrame (NVGContext ctx, int width, int height) {
/** Creates font by loading it from the disk from specified file name.
* Returns handle to the font or FONS_INVALID (aka -1) on error.
- * use "fontname:noaa" as [name] to turn off antialiasing (if font driver supports that).
- * Maximum font name length is 63 chars, and it will be truncated.
+ * Use "fontname:noaa" as [name] to turn off antialiasing (if font driver supports that).
*
* On POSIX systems it is possible to use fontconfig font names too.
* `:noaa` in font path is still allowed, but it must be the last option.
@@ -6429,7 +6697,6 @@ public int createFont (NVGContext ctx, const(char)[] name, const(char)[] path) n
/** Creates font by loading it from the specified memory chunk.
* Returns handle to the font or FONS_INVALID (aka -1) on error.
* Won't free data on error.
- * Maximum font name length is 63 chars, and it will be truncated.
*
* Group: text_api
*/
@@ -6560,8 +6827,14 @@ public int fontFaceId (NVGContext ctx) nothrow @trusted @nogc {
return nvg__getState(ctx).fontId;
}
-/// Sets the font face based on specified name of current text style.
-/// Group: text_api
+/** Sets the font face based on specified name of current text style.
+ *
+ * The underlying implementation is using O(1) data structure to lookup
+ * font names, so you probably should use this function instead of [fontFaceId]
+ * to make your code more robust and less error-prone.
+ *
+ * Group: text_api
+ */
public void fontFace (NVGContext ctx, const(char)[] font) nothrow @trusted @nogc {
pragma(inline, true);
nvg__getState(ctx).fontId = fonsGetFontByName(ctx.fs, font);
@@ -6836,16 +7109,16 @@ float nvg__getFontScale (NVGstate* state) nothrow @safe @nogc {
void nvg__flushTextTexture (NVGContext ctx) nothrow @trusted @nogc {
int[4] dirty = void;
if (fonsValidateTexture(ctx.fs, dirty.ptr)) {
- int fontImage = ctx.fontImages[ctx.fontImageIdx];
+ auto fontImage = &ctx.fontImages[ctx.fontImageIdx];
// Update texture
- if (fontImage != 0) {
+ if (fontImage.valid) {
int iw, ih;
const(ubyte)* data = fonsGetTextureData(ctx.fs, &iw, &ih);
int x = dirty[0];
int y = dirty[1];
int w = dirty[2]-dirty[0];
int h = dirty[3]-dirty[1];
- ctx.params.renderUpdateTexture(ctx.params.userPtr, fontImage, x, y, w, h, data);
+ ctx.params.renderUpdateTexture(ctx.params.userPtr, fontImage.id, x, y, w, h, data);
}
}
}
@@ -6855,14 +7128,18 @@ bool nvg__allocTextAtlas (NVGContext ctx) nothrow @trusted @nogc {
nvg__flushTextTexture(ctx);
if (ctx.fontImageIdx >= NVG_MAX_FONTIMAGES-1) return false;
// if next fontImage already have a texture
- if (ctx.fontImages[ctx.fontImageIdx+1] != 0) {
+ if (ctx.fontImages[ctx.fontImageIdx+1].valid) {
ctx.imageSize(ctx.fontImages[ctx.fontImageIdx+1], iw, ih);
} else {
// calculate the new font image size and create it
ctx.imageSize(ctx.fontImages[ctx.fontImageIdx], iw, ih);
if (iw > ih) ih *= 2; else iw *= 2;
if (iw > NVG_MAX_FONTIMAGE_SIZE || ih > NVG_MAX_FONTIMAGE_SIZE) iw = ih = NVG_MAX_FONTIMAGE_SIZE;
- ctx.fontImages[ctx.fontImageIdx+1] = ctx.params.renderCreateTexture(ctx.params.userPtr, NVGtexture.Alpha, iw, ih, (ctx.params.fontAA ? 0 : NVGImageFlag.NoFiltering), null);
+ ctx.fontImages[ctx.fontImageIdx+1].id = ctx.params.renderCreateTexture(ctx.params.userPtr, NVGtexture.Alpha, iw, ih, (ctx.params.fontAA ? 0 : NVGImageFlag.NoFiltering), null);
+ if (ctx.fontImages[ctx.fontImageIdx+1].id > 0) {
+ ctx.fontImages[ctx.fontImageIdx+1].ctx = ctx;
+ ctx.nvg__imageIncRef(ctx.fontImages[ctx.fontImageIdx+1].id);
+ }
}
++ctx.fontImageIdx;
fonsResetAtlas(ctx.fs, iw, ih);
@@ -10610,16 +10887,18 @@ public enum NVGContextFlag : int {
/// Nothing special, i.e. empty flag.
None = 0,
/// Flag indicating if geometry based anti-aliasing is used (may not be needed when using MSAA).
- Antialias = 1<<0,
+ Antialias = 1U<<0,
/** Flag indicating if strokes should be drawn using stencil buffer. The rendering will be a little
* slower, but path overlaps (i.e. self-intersecting or sharp turns) will be drawn just once. */
- StencilStrokes = 1<<1,
+ StencilStrokes = 1U<<1,
/// Flag indicating that additional debug checks are done.
- Debug = 1<<2,
+ Debug = 1U<<2,
/// Filter (antialias) fonts
- FontAA = 1<<7,
+ FontAA = 1U<<7,
/// Don't filter (antialias) fonts
- FontNoAA = 1<<8,
+ FontNoAA = 1U<<8,
+ /// You can use this as a substitute for default flags, for cases like this: `nvgCreateContext(NVGContextFlag.Default, NVGContextFlag.Debug);`.
+ Default = 1U<<31,
}
public enum NANOVG_GL_USE_STATE_FILTER = true;
@@ -11272,8 +11551,8 @@ bool glnvg__convertPaint (GLNVGcontext* gl, GLNVGfragUniforms* frag, NVGPaint* p
frag.strokeMult = (width*0.5f+fringe*0.5f)/fringe;
frag.strokeThr = strokeThr;
- if (paint.image != 0) {
- tex = glnvg__findTexture(gl, paint.image);
+ if (paint.image.valid) {
+ tex = glnvg__findTexture(gl, paint.image.id);
if (tex is null) return false;
if ((tex.flags&NVGImageFlag.FlipY) != 0) {
/*
@@ -11465,6 +11744,7 @@ void glnvg__affine (GLNVGcontext* gl, GLNVGcall* call) nothrow @trusted @nogc {
void glnvg__renderCancel (void* uptr) nothrow @trusted @nogc {
GLNVGcontext* gl = cast(GLNVGcontext*)uptr;
+ foreach (ref GLNVGcall c; gl.calls[0..gl.ncalls]) if (c.image > 0) glnvg__deleteTexture(gl, c.image);
gl.nverts = 0;
gl.npaths = 0;
gl.ncalls = 0;
@@ -11566,6 +11846,8 @@ void glnvg__renderFlush (void* uptr, NVGCompositeOperationState compositeOperati
case GLNVG_AFFINE: glnvg__affine(gl, call); break;
default: break;
}
+ // and free texture, why not
+ glnvg__deleteTexture(gl, call.image);
}
glDisableVertexAttribArray(0);
@@ -11678,7 +11960,8 @@ void glnvg__renderFill (void* uptr, NVGPaint* paint, NVGscissor* scissor, float
call.pathOffset = glnvg__allocPaths(gl, npaths);
if (call.pathOffset == -1) goto error;
call.pathCount = npaths;
- call.image = paint.image;
+ call.image = paint.image.id;
+ if (call.image > 0) glnvg__renderTextureIncRef(uptr, call.image);
if (npaths == 1 && paths[0].convex) {
call.type = GLNVG_CONVEXFILL;
@@ -11753,7 +12036,8 @@ void glnvg__renderStroke (void* uptr, NVGPaint* paint, NVGscissor* scissor, floa
call.pathOffset = glnvg__allocPaths(gl, npaths);
if (call.pathOffset == -1) goto error;
call.pathCount = npaths;
- call.image = paint.image;
+ call.image = paint.image.id;
+ if (call.image > 0) glnvg__renderTextureIncRef(uptr, call.image);
// Allocate vertices for all the paths.
maxverts = glnvg__maxVertCount(paths, npaths);
@@ -11801,7 +12085,8 @@ void glnvg__renderTriangles (void* uptr, NVGPaint* paint, NVGscissor* scissor, c
if (call is null) return;
call.type = GLNVG_TRIANGLES;
- call.image = paint.image;
+ call.image = paint.image.id;
+ if (call.image > 0) glnvg__renderTextureIncRef(uptr, call.image);
// Allocate vertices for all the paths.
call.triangleOffset = glnvg__allocVerts(gl, nverts);
@@ -11850,20 +12135,28 @@ void glnvg__renderDelete (void* uptr) nothrow @trusted @nogc {
}
+/** Creates NanoVega contexts for OpenGL2+.
+ *
+ * Specify creation flags as additional arguments, like this:
+ * `nvgCreateContext(NVGContextFlag.Antialias, NVGContextFlag.StencilStrokes);`
+ *
+ * If you won't specify any flags, defaults will be used:
+ * `[NVGContextFlag.Antialias, NVGContextFlag.StencilStrokes]`.
+ *
+ * Group: context_management
+ */
+public NVGContext nvgCreateContext (const(NVGContextFlag)[] flagList...) nothrow @trusted @nogc {
version(aliced) {
- private enum NVGDefaultContextFlagsXX = NVGContextFlag.Antialias|NVGContextFlag.StencilStrokes|NVGContextFlag.FontNoAA;
+ enum DefaultFlags = NVGContextFlag.Antialias|NVGContextFlag.StencilStrokes|NVGContextFlag.FontNoAA;
} else {
- private enum NVGDefaultContextFlagsXX = NVGContextFlag.Antialias|NVGContextFlag.StencilStrokes;
+ enum DefaultFlags = NVGContextFlag.Antialias|NVGContextFlag.StencilStrokes;
+ }
+ uint flags = 0;
+ if (flagList.length != 0) {
+ foreach (immutable flg; flagList) flags |= (flg != NVGContextFlag.Default ? flg : DefaultFlags);
+ } else {
+ flags = DefaultFlags;
}
-
-/// Default flags for [nvgCreateContext].
-/// Group: context_management
-public enum NVGDefaultContextFlags = NVGDefaultContextFlagsXX;
-
-/// Creates NanoVega contexts for OpenGL2+.
-/// Flags should be combination (bitwise or) of the [NVGContextFlag] members.
-/// Group: context_management
-public NVGContext nvgCreateContext (int flags=NVGDefaultContextFlags) nothrow @trusted @nogc {
NVGparams params = void;
NVGContext ctx = null;
version(nanovg_builtin_opengl_bindings) nanovgInitOpenGL(); // why not?