From b64543aa59ddd21693a0087a8280de5272b78af5 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Mon, 22 Dec 2025 10:57:59 -0800 Subject: [PATCH] Make medium shade consistent, make all shades less heavy --- .../customGlyphs/CustomGlyphDefinitions.ts | 49 ++++++++++--------- .../src/customGlyphs/CustomGlyphRasterizer.ts | 34 ++++++------- 2 files changed, 43 insertions(+), 40 deletions(-) diff --git a/addons/addon-webgl/src/customGlyphs/CustomGlyphDefinitions.ts b/addons/addon-webgl/src/customGlyphs/CustomGlyphDefinitions.ts index c21e9b50..3c6da65f 100644 --- a/addons/addon-webgl/src/customGlyphs/CustomGlyphDefinitions.ts +++ b/addons/addon-webgl/src/customGlyphs/CustomGlyphDefinitions.ts @@ -291,21 +291,32 @@ export const symbolsForLegacyComputingDefinitions: { [index: string]: CustomGlyp '\u{1FB6F}': () => 'M0,1 L1,1 L0.5,0.5 Z' // LOWER TRIANGULAR ONE QUARTER BLOCK }; +/** + * Rectangular shade characters - these use medium shade pattern (50%) like 0x2592. + * Each entry is [pattern, region] where region is [x, y, width, height] in 0-1 normalized + * coordinates. Pattern is the medium shade checkerboard pattern. + */ +const mediumShadePattern: CustomGlyphPatternDefinition = [ + [1, 0], + [0, 1] +]; + +const inverseMediumShadePattern: CustomGlyphPatternDefinition = [ + [0, 1], + [1, 0] +]; + +export const rectangularShadeDefinitions: { [index: string]: [CustomGlyphPatternDefinition, [number, number, number, number]] | undefined } = { + '\u{1FB8C}': [mediumShadePattern, [0, 0, 0.5, 1]], // LEFT HALF MEDIUM SHADE + '\u{1FB8D}': [mediumShadePattern, [0.5, 0, 0.5, 1]], // RIGHT HALF MEDIUM SHADE + '\u{1FB8E}': [mediumShadePattern, [0, 0, 1, 0.5]], // UPPER HALF MEDIUM SHADE + '\u{1FB8F}': [mediumShadePattern, [0, 0.5, 1, 0.5]], // LOWER HALF MEDIUM SHADE + '\u{1FB90}': [inverseMediumShadePattern, [0, 0, 1, 1]] // INVERSE MEDIUM SHADE +}; + /** Region defined as [x, y, width, height] in 0-1 normalized coordinates. */ type RegionDefinition = [number, number, number, number]; -/** - * Rectangular shade characters - these use medium shade pattern with region bounds. - * Pattern is a checkerboard that shifts 1px each row (same as medium shade). - */ -export const rectangularShadeDefinitions: { [index: string]: RegionDefinition | undefined } = { - '\u{1FB8C}': [0, 0, 0.5, 1], // LEFT HALF MEDIUM SHADE - '\u{1FB8D}': [0.5, 0, 0.5, 1], // RIGHT HALF MEDIUM SHADE - '\u{1FB8E}': [0, 0, 1, 0.5], // UPPER HALF MEDIUM SHADE - '\u{1FB8F}': [0, 0.5, 1, 0.5], // LOWER HALF MEDIUM SHADE - '\u{1FB90}': [0, 0, 1, 1] // INVERSE MEDIUM SHADE -}; - /** [solidRegion, shadeRegion] where shade region uses inverse medium shade pattern. */ type BlockShadeComboDefinition = [RegionDefinition, RegionDefinition]; @@ -326,22 +337,16 @@ export const blockShadeComboDefinitions: { [index: string]: BlockShadeComboDefin export const patternCharacterDefinitions: { [key: string]: CustomGlyphPatternDefinition | undefined } = { // Shade characters (0x2591-0x2593) '░': [ // LIGHT SHADE (25%) - [1, 0, 0, 0], - [0, 0, 0, 0], - [0, 0, 1, 0], - [0, 0, 0, 0] + [1, 0], + [0, 0] ], '▒': [ // MEDIUM SHADE (50%) [1, 0], - [0, 0], - [0, 1], - [0, 0] + [0, 1] ], '▓': [ // DARK SHADE (75%) - [0, 1], [1, 1], - [1, 0], - [1, 1] + [1, 0] ] }; diff --git a/addons/addon-webgl/src/customGlyphs/CustomGlyphRasterizer.ts b/addons/addon-webgl/src/customGlyphs/CustomGlyphRasterizer.ts index 95357024..8c77bdd7 100644 --- a/addons/addon-webgl/src/customGlyphs/CustomGlyphRasterizer.ts +++ b/addons/addon-webgl/src/customGlyphs/CustomGlyphRasterizer.ts @@ -61,7 +61,7 @@ export function tryDrawCustomGlyph( const rectangularShadeDefinition = rectangularShadeDefinitions[c]; if (rectangularShadeDefinition) { - drawRectangularShadeChar(ctx, rectangularShadeDefinition, xOffset, yOffset, deviceCellWidth, deviceCellHeight, c === '\u{1FB90}'); + drawRectangularShadeChar(ctx, rectangularShadeDefinition, xOffset, yOffset, deviceCellWidth, deviceCellHeight); return true; } @@ -214,34 +214,32 @@ function drawPatternChar( */ function drawRectangularShadeChar( ctx: CanvasRenderingContext2D, - region: [number, number, number, number], + definition: [CustomGlyphPatternDefinition, [number, number, number, number]], xOffset: number, yOffset: number, deviceCellWidth: number, - deviceCellHeight: number, - isInverse: boolean + deviceCellHeight: number ): void { + const [pattern, region] = definition; const [rx, ry, rw, rh] = region; const regionX = Math.round(xOffset + rx * deviceCellWidth); const regionY = Math.round(yOffset + ry * deviceCellHeight); const regionW = Math.round(rw * deviceCellWidth); const regionH = Math.round(rh * deviceCellHeight); - // For inverse medium shade, we use the opposite pattern (fill where medium shade doesn't) - // Medium shade pattern: fills at (x+y) % 2 === 0, so inverse fills at (x+y) % 2 === 1 - const patternOffset = isInverse ? 1 : 0; + // Save context state + ctx.save(); - for (let py = 0; py < regionH; py++) { - // Calculate the absolute y position for pattern calculation - const absY = regionY + py - yOffset; - for (let px = 0; px < regionW; px++) { - const absX = regionX + px - xOffset; - // Checkerboard pattern: fill if (x + y) % 2 matches the offset - if (((absX + absY) % 2) === patternOffset) { - ctx.fillRect(regionX + px, regionY + py, 1, 1); - } - } - } + // Clip to the region + ctx.beginPath(); + ctx.rect(regionX, regionY, regionW, regionH); + ctx.clip(); + + // Draw the pattern + drawPatternChar(ctx, pattern, xOffset, yOffset, deviceCellWidth, deviceCellHeight); + + // Restore context state + ctx.restore(); } /**