From 90cc65066dfa7dc9795c1457cde8ed509a08a4ca Mon Sep 17 00:00:00 2001 From: ICOM725 Date: Sat, 5 Sep 2026 19:53:36 +0800 Subject: [PATCH] Fix polygon stroke vertex deduplication --- src/gameobjects/shape/StrokePathWebGL.js | 2 +- .../gameobjects/shape/StrokePathWebGL.test.js | 80 +++++++++++++++++++ 2 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 tests/gameobjects/shape/StrokePathWebGL.test.js diff --git a/src/gameobjects/shape/StrokePathWebGL.js b/src/gameobjects/shape/StrokePathWebGL.js index 3fd93a1f26..fdf128f60f 100644 --- a/src/gameobjects/shape/StrokePathWebGL.js +++ b/src/gameobjects/shape/StrokePathWebGL.js @@ -46,7 +46,7 @@ var StrokePathWebGL = function (drawingContext, submitter, matrix, src, alpha, d var y = path[i + 1] - dy; if (i > 0) { - if (x === path[i - 2] && y === path[i - 1]) + if (path[i] === path[i - 2] && path[i + 1] === path[i - 1]) { // Duplicate point, skip it continue; diff --git a/tests/gameobjects/shape/StrokePathWebGL.test.js b/tests/gameobjects/shape/StrokePathWebGL.test.js new file mode 100644 index 0000000000..a33b582281 --- /dev/null +++ b/tests/gameobjects/shape/StrokePathWebGL.test.js @@ -0,0 +1,80 @@ +var StrokePathWebGL = require('../../../src/gameobjects/shape/StrokePathWebGL'); + +describe('StrokePathWebGL', function () +{ + var src; + var strokePath; + + beforeEach(function () + { + strokePath = { run: vi.fn() }; + + src = { + pathData: [ 3, 0, 6, 3, 3, 6, 0, 3, 3, 0 ], + closePath: true, + lineWidth: 2, + strokeColor: 0x000000, + strokeAlpha: 1, + customRenderNodes: {}, + defaultRenderNodes: { StrokePath: strokePath } + }; + }); + + it('preserves every corner and the closing point of a centered diamond', function () + { + StrokePathWebGL({}, {}, {}, src, 1, 3, 3); + + expect(strokePath.run.mock.calls[0][2]).toEqual([ + { x: 0, y: -3, width: 2 }, + { x: 3, y: 0, width: 2 }, + { x: 0, y: 3, width: 2 }, + { x: -3, y: 0, width: 2 }, + { x: 0, y: -3, width: 2 } + ]); + }); + + it('removes consecutive duplicate vertices with a non-zero display origin', function () + { + src.pathData = [ 3, 0, 3, 0, 3, 0, 6, 3, 3, 6, 0, 3, 3, 0 ]; + + StrokePathWebGL({}, {}, {}, src, 1, 3, 3); + + expect(strokePath.run.mock.calls[0][2]).toEqual([ + { x: 0, y: -3, width: 2 }, + { x: 3, y: 0, width: 2 }, + { x: 0, y: 3, width: 2 }, + { x: -3, y: 0, width: 2 }, + { x: 0, y: -3, width: 2 } + ]); + }); + + it('still removes consecutive duplicate vertices with a zero display origin', function () + { + src.pathData = [ 3, 0, 3, 0, 3, 0, 6, 3, 3, 6, 0, 3, 3, 0 ]; + + StrokePathWebGL({}, {}, {}, src, 1, 0, 0); + + expect(strokePath.run.mock.calls[0][2]).toEqual([ + { x: 3, y: 0, width: 2 }, + { x: 6, y: 3, width: 2 }, + { x: 3, y: 6, width: 2 }, + { x: 0, y: 3, width: 2 }, + { x: 3, y: 0, width: 2 } + ]); + }); + + it('preserves distinct vertices while omitting the closing point of an open path', function () + { + src.closePath = false; + + StrokePathWebGL({}, {}, {}, src, 1, 3, 3); + + expect(strokePath.run.mock.calls[0][2]).toEqual([ + { x: 0, y: -3, width: 2 }, + { x: 3, y: 0, width: 2 }, + { x: 0, y: 3, width: 2 }, + { x: -3, y: 0, width: 2 } + ]); + expect(strokePath.run.mock.calls[0][4]).toBe(true); + }); +});