ketmar patches

This commit is contained in:
Adam D. Ruppe 2018-02-28 19:16:53 -05:00
parent bb111a1af2
commit a1c57fa9eb
2 changed files with 84 additions and 31 deletions

View File

@ -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<<level;

View File

@ -4826,9 +4826,21 @@ struct MouseEvent {
static bool equStr() (in auto ref MouseEvent event, const(char)[] str) pure nothrow @trusted @nogc {
if (str.length == 0) return false; // just in case
debug(arsd_mevent_strcmp) { import iv.cmdcon; conwriteln("str=<", str, ">"); }
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;
}