From a1c57fa9eb2d00adafc2860855e3bd42fd7f6611 Mon Sep 17 00:00:00 2001 From: "Adam D. Ruppe" Date: Wed, 28 Feb 2018 19:16:53 -0500 Subject: [PATCH] ketmar patches --- nanovega.d | 47 ++++++++++++++++++++++++++-------- simpledisplay.d | 68 ++++++++++++++++++++++++++++++++++--------------- 2 files changed, 84 insertions(+), 31 deletions(-) diff --git a/nanovega.d b/nanovega.d index 9092c03..2b1b99e 100644 --- a/nanovega.d +++ b/nanovega.d @@ -1845,6 +1845,9 @@ public void beginFrame (NVGContext ctx, int windowWidth, int windowHeight, float ctx.recset = null; ctx.recstart = -1; + ctx.pathPickId = NVGNoPick; + ctx.pathPickRegistered = 0; + ctx.drawCallCount = 0; ctx.fillTriCount = 0; ctx.strokeTriCount = 0; @@ -5208,6 +5211,8 @@ public void currFillHitId (NVGContext ctx, int id) nothrow @trusted @nogc { nvg__pickSceneInsert(ps, pp); } +public alias currFillPickId = currFillHitId; /// Ditto. + /// Marks the stroke of the current path as pickable with the specified id. /// Note that you can create and mark path without rasterizing it. /// Group: picking_api @@ -5217,6 +5222,8 @@ public void currStrokeHitId (NVGContext ctx, int id) nothrow @trusted @nogc { nvg__pickSceneInsert(ps, pp); } +public alias currStrokePickId = currStrokeHitId; /// Ditto. + // Marks the saved path set (fill) as pickable with the specified id. // $(WARNING this doesn't work right yet (it is using current context transformation and other settings instead of record settings)!) // Group: picking_api @@ -5612,6 +5619,7 @@ void nvg__segmentDir (NVGpickScene* ps, NVGpickSubPath* psp, NVGsegment* seg, fl } void nvg__pickSubPathAddFillSupports (NVGpickScene* ps, NVGpickSubPath* psp) { + if (psp.firstSegment == -1) return; NVGsegment* segments = &ps.segments[psp.firstSegment]; for (int s = 0; s < psp.nsegments; ++s) { NVGsegment* seg = &segments[s]; @@ -5626,6 +5634,7 @@ void nvg__pickSubPathAddFillSupports (NVGpickScene* ps, NVGpickSubPath* psp) { } void nvg__pickSubPathAddStrokeSupports (NVGpickScene* ps, NVGpickSubPath* psp, float strokeWidth, int lineCap, int lineJoin, float miterLimit) { + if (psp.firstSegment == -1) return; immutable bool closed = psp.closed; const(float)* points = ps.points; NVGsegment* seg = null; @@ -5770,7 +5779,7 @@ NVGpickPath* nvg__pickPathCreate (NVGContext context, const(float)[] acommands, float[2] start = void; int firstPoint; - int hasHoles = 0; + //bool hasHoles = false; NVGpickSubPath* prev = null; float[8] points = void; @@ -5788,6 +5797,17 @@ NVGpickPath* nvg__pickPathCreate (NVGContext context, const(float)[] acommands, pp.id = id; + bool hasPoints = false; + + void closeIt () { + if (psp is null || !hasPoints) return; + if (ps.points[(ps.npoints-1)*2] != start.ptr[0] || ps.points[(ps.npoints-1)*2+1] != start.ptr[1]) { + firstPoint = nvg__pickSceneAddPoints(ps, start.ptr, 1); + nvg__pickSubPathAddSegment(ps, psp, firstPoint-1, Command.LineTo, NVGSegmentFlags.Corner); + } + psp.closed = true; + } + while (i < ncommands) { int cmd = cast(int)commands[i++]; switch (cmd) { @@ -5807,12 +5827,14 @@ NVGpickPath* nvg__pickPathCreate (NVGContext context, const(float)[] acommands, psp.next = prev; nvg__pickSceneAddPoints(ps, tfxy, 1); + hasPoints = true; break; case Command.LineTo: // one coordinate pair const(float)* tfxy = commands+i; i += 2; firstPoint = nvg__pickSceneAddPoints(ps, tfxy, 1); nvg__pickSubPathAddSegment(ps, psp, firstPoint-1, cmd, NVGSegmentFlags.Corner); + hasPoints = true; break; case Command.BezierTo: // three coordinate pairs const(float)* tfxy = commands+i; @@ -5860,17 +5882,14 @@ NVGpickPath* nvg__pickPathCreate (NVGContext context, const(float)[] acommands, firstPoint = nvg__pickSceneAddPoints(ps, tfxy, 3); nvg__pickSubPathAddSegment(ps, psp, firstPoint-1, cmd, NVGSegmentFlags.Corner); } + hasPoints = true; break; case Command.Close: - if (ps.points[(ps.npoints-1)*2] != start.ptr[0] || ps.points[(ps.npoints-1)*2+1] != start.ptr[1]) { - firstPoint = nvg__pickSceneAddPoints(ps, start.ptr, 1); - nvg__pickSubPathAddSegment(ps, psp, firstPoint-1, Command.LineTo, NVGSegmentFlags.Corner); - } - psp.closed = true; + closeIt(); break; case Command.Winding: psp.winding = cast(short)cast(int)commands[i]; - if (psp.winding == NVGSolidity.Hole) hasHoles = 1; + //if (psp.winding == NVGSolidity.Hole) hasHoles = true; i += 1; break; default: @@ -5878,6 +5897,9 @@ NVGpickPath* nvg__pickPathCreate (NVGContext context, const(float)[] acommands, } } + // force-close filled pathes + if (psp !is null && !forStroke && hasPoints && !psp.closed) closeIt(); + pp.flags = (forStroke ? NVGPathFlags.Stroke : NVGPathFlags.Fill); pp.subPaths = psp; pp.strokeWidth = state.strokeWidth*0.5f; @@ -5895,6 +5917,7 @@ NVGpickPath* nvg__pickPathCreate (NVGContext context, const(float)[] acommands, nvg__pickSubPathAddFillSupports(ps, curpsp); } + if (curpsp.firstSegment == -1) continue; segments = &ps.segments[curpsp.firstSegment]; nvg__initBounds(curpsp.bounds); for (int s = 0; s < curpsp.nsegments; ++s) { @@ -6388,6 +6411,7 @@ void nvg__closestBezier (const(float)* points, float x, float y, float* closest, // 0 If (x,y) is not contained by the path. int nvg__pickSubPathStroke (const NVGpickScene* ps, const NVGpickSubPath* psp, float x, float y, float strokeWidth, int lineCap, int lineJoin) { if (!nvg__pointInBounds(x, y, psp.bounds)) return 0; + if (psp.firstSegment == -1) return 0; float[2] closest = void; float[2] d = void; @@ -6478,6 +6502,7 @@ int nvg__pickSubPathStroke (const NVGpickScene* ps, const NVGpickSubPath* psp, f // 0 If (x,y) is not contained by the path. int nvg__pickSubPath (const NVGpickScene* ps, const NVGpickSubPath* psp, float x, float y, bool evenOddMode) { if (!nvg__pointInBounds(x, y, psp.bounds)) return 0; + if (psp.firstSegment == -1) return 0; const(NVGsegment)* seg = &ps.segments[psp.firstSegment]; int nsegments = psp.nsegments; @@ -6564,10 +6589,10 @@ bool nvg__pickPathTestBounds (NVGContext ctx, const NVGpickScene* ps, const NVGp return false; } -int nvg__countBitsUsed (int v) { +int nvg__countBitsUsed (uint v) pure { pragma(inline, true); - import core.bitop : popcnt; - return (v != 0 ? popcnt(cast(uint)v) : 0); + import core.bitop : bsr; + return (v != 0 ? bsr(v)+1 : 0); } void nvg__pickSceneInsert (NVGpickScene* ps, NVGpickPath* pp) { @@ -6598,6 +6623,8 @@ void nvg__pickSceneInsert (NVGpickScene* ps, NVGpickPath* pp) { // to calculate the level to insert at (the level at which the bounds fit in a single cell) level = nvg__min(base-nvg__countBitsUsed(cellbounds.ptr[0]), base-nvg__countBitsUsed(cellbounds.ptr[1])); if (level < 0) level = 0; + //{ import core.stdc.stdio; printf("LEVEL: %d; bounds=(%g,%g)-(%g,%g)\n", level, pp.bounds[0], pp.bounds[1], pp.bounds[2], pp.bounds[3]); } + //level = 0; // Find the correct cell in the chosen level, clamping to the edges. levelwidth = 1<"); } + enum Flag : uint { Up = 0x8000_0000U, Down = 0x4000_0000U, Any = 0x1000_0000U } auto anchor = str; uint mods = 0; // uint.max == any + // interesting bits in kmod + uint kmodmask = + ModifierState.shift| + ModifierState.ctrl| + ModifierState.alt| + ModifierState.windows| + ModifierState.leftButtonDown| + ModifierState.middleButtonDown| + ModifierState.rightButtonDown| + 0; uint lastButt = uint.max; // otherwise, bit 31 means "down" + bool wasButtons = false; while (str.length) { if (str.ptr[0] <= ' ') { while (str.length && str.ptr[0] <= ' ') str = str[1..$]; @@ -4872,24 +4884,28 @@ struct MouseEvent { } if (wep == 0) return false; // just in case uint bnum; - enum UpDown { None = -1, Up, Down } + enum UpDown { None = -1, Up, Down, Any } auto updown = UpDown.None; // 0: up; 1: down switch (buf[0..wep]) { // left button case "lmbup": case "leftup": updown = UpDown.Up; goto case "lmb"; case "lmbdown": case "leftdown": updown = UpDown.Down; goto case "lmb"; + case "lmbany": case "leftany": updown = UpDown.Any; goto case "lmb"; case "lmb": case "left": bnum = 0; break; // middle button case "mmbup": case "middleup": updown = UpDown.Up; goto case "mmb"; case "mmbdown": case "middledown": updown = UpDown.Down; goto case "mmb"; + case "mmbany": case "middleany": updown = UpDown.Any; goto case "mmb"; case "mmb": case "middle": bnum = 1; break; // right button case "rmbup": case "rightup": updown = UpDown.Up; goto case "rmb"; case "rmbdown": case "rightdown": updown = UpDown.Down; goto case "rmb"; + case "rmbany": case "rightany": updown = UpDown.Any; goto case "rmb"; case "rmb": case "right": bnum = 2; break; // wheel case "wheelup": updown = UpDown.Up; goto case "wheel"; case "wheeldown": updown = UpDown.Down; goto case "wheel"; + case "wheelany": updown = UpDown.Any; goto case "wheel"; case "wheel": bnum = 3; break; // motion case "motion": bnum = 7; break; @@ -4910,14 +4926,17 @@ struct MouseEvent { } if (wep == 2 && buf[0..wep] == "up") updown = UpDown.Up; else if (wep == 4 && buf[0..wep] == "down") updown = UpDown.Down; + else if (wep == 3 && buf[0..wep] == "any") updown = UpDown.Any; // remove parsed part if (updown != UpDown.None) str = str[wep+1..$]; - } else if (updown == UpDown.None) { - updown = (bnum < 7 ? UpDown.Down : UpDown.Up); } - assert(updown != UpDown.None); + if (updown == UpDown.None) { + updown = UpDown.Down; + } + wasButtons = wasButtons || (bnum <= 2); + //assert(updown != UpDown.None); debug(arsd_mevent_strcmp) { import iv.cmdcon; conprintfln(" 1: mods=0x%08x; bnum=%u; updown=%s [%s]", mods, bnum, updown, str); } - // if we have a previous button, it goes to modifiers (unless it is a wheel) + // if we have a previous button, it goes to modifiers (unless it is a wheel or motion) if (lastButt != lastButt.max) { if ((lastButt&0xff) >= 3) return false; // wheel or motion if (mods != mods.max) { @@ -4927,38 +4946,45 @@ struct MouseEvent { case 1: butbit = ModifierState.middleButtonDown; break; case 2: butbit = ModifierState.rightButtonDown; break; } - if (lastButt >= 0x8000_0000U) mods |= butbit; else mods &= ~butbit; + if (lastButt&Flag.Down) mods |= butbit; + else if (lastButt&Flag.Up) mods &= ~butbit; + else if (lastButt&Flag.Any) kmodmask &= ~butbit; } } // remember last button - lastButt = bnum|(updown == UpDown.Up ? 0 : 0x8000_0000U); + lastButt = bnum|(updown == UpDown.Up ? Flag.Up : updown == UpDown.Any ? Flag.Any : Flag.Down); } // no button -- nothing to do if (lastButt == lastButt.max) return false; // done parsing, check if something's left foreach (immutable char ch; str) if (ch > ' ') return false; // oops - debug(arsd_mevent_strcmp) { import iv.cmdcon; conprintfln(" *: mods=0x%08x; lastButt=0x%08x; kmod=0x%08x; type=%s", mods, lastButt, event.modifierState, event.type); } + // remove action button from mask + if ((lastButt&0xff) < 3) { + final switch (lastButt&0x03) { + case 0: kmodmask &= ~cast(uint)ModifierState.leftButtonDown; break; + case 1: kmodmask &= ~cast(uint)ModifierState.middleButtonDown; break; + case 2: kmodmask &= ~cast(uint)ModifierState.rightButtonDown; break; + } + } + // special case: "Motion" means "ignore buttons" + if ((lastButt&0xff) == 7 && !wasButtons) { + debug(arsd_mevent_strcmp) { import iv.cmdcon; conwriteln(" *: special motion"); } + kmodmask &= ~cast(uint)(ModifierState.leftButtonDown|ModifierState.middleButtonDown|ModifierState.rightButtonDown); + } + uint kmod = event.modifierState&kmodmask; + debug(arsd_mevent_strcmp) { import iv.cmdcon; conprintfln(" *: mods=0x%08x; lastButt=0x%08x; kmod=0x%08x; type=%s", mods, lastButt, kmod, event.type); } // check modifier state if (mods != mods.max) { - enum InterestingMods = - ModifierState.shift| - ModifierState.ctrl| - ModifierState.alt| - ModifierState.windows| - ModifierState.leftButtonDown| - ModifierState.middleButtonDown| - ModifierState.rightButtonDown| - 0; - if ((event.modifierState&InterestingMods) != mods) return false; + if (kmod != mods) return false; } // now check type if ((lastButt&0xff) == 7) { // motion if (event.type != MouseEventType.motion) return false; } else { - // buttions - if ((lastButt >= 0x8000_0000U && event.type != MouseEventType.buttonPressed) || - (lastButt < 0x8000_0000U && event.type != MouseEventType.buttonReleased)) + // buttons + if (((lastButt&Flag.Down) != 0 && event.type != MouseEventType.buttonPressed) || + ((lastButt&Flag.Up) != 0 && event.type != MouseEventType.buttonReleased)) { return false; }