From de07b297ad9cfda5d5ed3468a953a4f31d3febe9 Mon Sep 17 00:00:00 2001 From: Neil Rackett Date: Fri, 10 Jul 2026 12:28:34 +0100 Subject: [PATCH] Strokes: tessellate thick strokes to triangles so joint and cap styles apply draw_pathes was hardcoded to GPU-expanded LineElements, which draw every segment as an independent quad: polylines rendered with a notch at each corner regardless of the JointStyle requested via lineStyle (a commented out branch shows a choice used to exist here). The complete miter/bevel/ round joint and cap implementation in getTriangleElements was unreachable - nothing called it. Route non-hairline strokes thicker than 1.5px through the triangle tessellator, using the same UnpackFillStyle material path as fills; hairlines and very thin strokes keep the fast LineElements path, where joints are invisible anyway. Triangle-built stroke shapes skip the LineElements shape pool (tryPoolShape already routes them to the triangle pool) and participate in the existing _lastStroke rebuild mechanism unchanged. Observed with an AS3 charting app drawing 8px polylines with JointStyle.MITER: corners rendered as two butt ends with a notch; with this change they render as proper mitered joints. --- lib/draw/GraphicsFactoryStrokes.ts | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/lib/draw/GraphicsFactoryStrokes.ts b/lib/draw/GraphicsFactoryStrokes.ts index ac208dc..cbd715b 100644 --- a/lib/draw/GraphicsFactoryStrokes.ts +++ b/lib/draw/GraphicsFactoryStrokes.ts @@ -38,10 +38,35 @@ export class GraphicsFactoryStrokes { const path = paths[i]; const style = (>path.style); - shape = targetGraphics.popEmptyStrokeShape(); - path.prepare(); + // Thick strokes are tessellated to triangles so joint styles (miter/bevel/ + // round) and cap styles actually apply: GPU-expanded LineElements draw every + // segment as an independent quad and cannot form joints, which leaves a + // notch at each corner of a polyline. Hairlines and very thin strokes keep + // the fast LineElements path — joints are invisible at those sizes. + if (style.scaleMode !== LineScaleMode.HAIRLINE && style.thickness > 1.5) { + const triElements = this.getTriangleElements([path], false, style.scaleMode); + + if (triElements) { + const triData = { + style: new Style(), + sampler: new ImageSampler(), + material: null + }; + + UnpackFillStyle[path.style.fillStyle.data_type](path.style.fillStyle, triData); + + shape = Shape.getShape(triElements, triData.material, triData.style); + + targetGraphics.addShapeInternal(shape); + } + + continue; + } + + shape = targetGraphics.popEmptyStrokeShape(); + // if (targetGraphics.scaleStrokes != null) { //use LineElements const elements = this.fillLineElements( [path],