diff --git a/src/vs/editor/common/view/minimapCharRenderer.ts b/src/vs/editor/common/view/minimapCharRenderer.ts new file mode 100644 index 0000000000000000000000000000000000000000..3f86f17a9a70032d58b1b1132c05595d7589521a --- /dev/null +++ b/src/vs/editor/common/view/minimapCharRenderer.ts @@ -0,0 +1,255 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import { CharCode } from 'vs/base/common/charCode'; + +export const enum Constants { + START_CH_CODE = 32, // Space + END_CH_CODE = 126, // Tilde (~) + CHAR_COUNT = END_CH_CODE - START_CH_CODE + 1, + + SAMPLED_CHAR_HEIGHT = 16, + SAMPLED_CHAR_WIDTH = 10, + SAMPLED_HALF_CHAR_WIDTH = SAMPLED_CHAR_WIDTH / 2, + + x2_CHAR_HEIGHT = 4, + x2_CHAR_WIDTH = 2, + + x1_CHAR_HEIGHT = 2, + x1_CHAR_WIDTH = 1, + + RGBA_CHANNELS_CNT = 4, + CA_CHANNELS_CNT = 2, +} + +export class MinimapCharRendererFactory { + + public static create(source: Uint8ClampedArray): MinimapCharRenderer { + const expectedLength = (Constants.SAMPLED_CHAR_HEIGHT * Constants.SAMPLED_CHAR_WIDTH * Constants.RGBA_CHANNELS_CNT * Constants.CHAR_COUNT); + if (source.length !== expectedLength) { + throw new Error('Unexpected source in MinimapCharRenderer'); + } + + let x2CharData = MinimapCharRendererFactory._downsample2x(source); + let x1CharData = MinimapCharRendererFactory._downsample1x(source); + return new MinimapCharRenderer(x2CharData, x1CharData); + } + + + private static _downsample2x(data: Uint8ClampedArray): Uint8ClampedArray { + // chars are 2 x 4px (width x height) + const resultLen = Constants.x2_CHAR_HEIGHT * Constants.x2_CHAR_WIDTH * Constants.CA_CHANNELS_CNT * Constants.CHAR_COUNT; + const result = new Uint16Array(resultLen); + for (let i = 0; i < resultLen; i++) { + result[i] = 0; + } + + let inputOffset = 0, globalOutputOffset = 0; + for (let i = 0; i < Constants.SAMPLED_CHAR_HEIGHT; i++) { + + let outputOffset = globalOutputOffset; + + for (let chIndex = 0; chIndex < Constants.CHAR_COUNT; chIndex++) { + let color = 0; + let alpha = 0; + for (let j = 0; j < Constants.SAMPLED_HALF_CHAR_WIDTH; j++) { + color += data[inputOffset]; // R + alpha += data[inputOffset + 3]; // A + inputOffset += Constants.RGBA_CHANNELS_CNT; + } + result[outputOffset] += color; + result[outputOffset + 1] += alpha; + outputOffset += Constants.CA_CHANNELS_CNT; + + color = 0; + alpha = 0; + for (let j = 0; j < Constants.SAMPLED_HALF_CHAR_WIDTH; j++) { + color += data[inputOffset]; // R + alpha += data[inputOffset + 3]; // A + inputOffset += Constants.RGBA_CHANNELS_CNT; + } + result[outputOffset] += color; + result[outputOffset + 1] += alpha; + outputOffset += Constants.CA_CHANNELS_CNT; + } + + if (i === 2 || i === 5 || i === 8) { + globalOutputOffset = outputOffset; + } + } + + const actualResult = new Uint8ClampedArray(resultLen); + for (let i = 0; i < resultLen; i++) { + actualResult[i] = result[i] / 12; // 15 it should be + } + + return actualResult; + } + + private static _downsample1x(data: Uint8ClampedArray): Uint8ClampedArray { + // chars are 1 x 2px (width x height) + const resultLen = Constants.x1_CHAR_HEIGHT * Constants.x1_CHAR_WIDTH * Constants.CA_CHANNELS_CNT * Constants.CHAR_COUNT; + const result = new Uint16Array(resultLen); + for (let i = 0; i < resultLen; i++) { + result[i] = 0; + } + + let inputOffset = 0, globalOutputOffset = 0; + for (let i = 0; i < 16; i++) { + + let outputOffset = globalOutputOffset; + + for (let chIndex = 0; chIndex < Constants.CHAR_COUNT; chIndex++) { + let color = 0; + let alpha = 0; + for (let j = 0; j < Constants.SAMPLED_CHAR_WIDTH; j++) { + color += data[inputOffset]; // R + alpha += data[inputOffset + 3]; // A + inputOffset += Constants.RGBA_CHANNELS_CNT; + } + result[outputOffset] += color; + result[outputOffset + 1] += alpha; + outputOffset += Constants.CA_CHANNELS_CNT; + } + + if (i === 5) { + globalOutputOffset = outputOffset; + } + } + + const actualResult = new Uint8ClampedArray(resultLen); + for (let i = 0; i < resultLen; i++) { + actualResult[i] = result[i] / 50; // 60 it should be + } + + return actualResult; + } + + +} + +export class MinimapCharRenderer { + + _minimapCharRendererBrand: void; + + public readonly x2charData: Uint8ClampedArray; + public readonly x1charData: Uint8ClampedArray; + + constructor(x2CharData, x1CharData) { + this.x2charData = x2CharData; + this.x1charData = x1CharData; + } + + /** + * Assumes a line height of 4px and a char width of 2px + */ + public x2RenderChar(target: Uint8ClampedArray, lineLen: number, lineIndex: number, charIndex: number, chCode: number): void { + const x2CharData = this.x2charData; + + const outWidth = Constants.x2_CHAR_WIDTH * Constants.RGBA_CHANNELS_CNT * lineLen; + const sourceWidth = Constants.x2_CHAR_WIDTH * Constants.CA_CHANNELS_CNT * Constants.CHAR_COUNT; + + if (chCode < Constants.START_CH_CODE || chCode > Constants.END_CH_CODE) { + chCode = CharCode.N; + } + const chIndex = chCode - Constants.START_CH_CODE; + + let sourceOffset = chIndex * Constants.x2_CHAR_WIDTH * Constants.CA_CHANNELS_CNT; + const c1 = x2CharData[sourceOffset]; + const a1 = x2CharData[sourceOffset + 1]; + const c2 = x2CharData[sourceOffset + 2]; + const a2 = x2CharData[sourceOffset + 3]; + + sourceOffset += sourceWidth; + const c3 = x2CharData[sourceOffset]; + const a3 = x2CharData[sourceOffset + 1]; + const c4 = x2CharData[sourceOffset + 2]; + const a4 = x2CharData[sourceOffset + 3]; + + sourceOffset += sourceWidth; + const c5 = x2CharData[sourceOffset]; + const a5 = x2CharData[sourceOffset + 1]; + const c6 = x2CharData[sourceOffset + 2]; + const a6 = x2CharData[sourceOffset + 3]; + + sourceOffset += sourceWidth; + const c7 = x2CharData[sourceOffset]; + const a7 = x2CharData[sourceOffset + 1]; + const c8 = x2CharData[sourceOffset + 2]; + const a8 = x2CharData[sourceOffset + 3]; + + let resultOffset = Constants.x2_CHAR_WIDTH * Constants.RGBA_CHANNELS_CNT * charIndex; + target[resultOffset + 0] = c1; + target[resultOffset + 1] = c1; + target[resultOffset + 2] = c1; + target[resultOffset + 3] = a1; + target[resultOffset + 4] = c2; + target[resultOffset + 5] = c2; + target[resultOffset + 6] = c2; + target[resultOffset + 7] = a2; + resultOffset += outWidth; + target[resultOffset + 0] = c3; + target[resultOffset + 1] = c3; + target[resultOffset + 2] = c3; + target[resultOffset + 3] = a3; + target[resultOffset + 4] = c4; + target[resultOffset + 5] = c4; + target[resultOffset + 6] = c4; + target[resultOffset + 7] = a4; + resultOffset += outWidth; + target[resultOffset + 0] = c5; + target[resultOffset + 1] = c5; + target[resultOffset + 2] = c5; + target[resultOffset + 3] = a5; + target[resultOffset + 4] = c6; + target[resultOffset + 5] = c6; + target[resultOffset + 6] = c6; + target[resultOffset + 7] = a6; + resultOffset += outWidth; + target[resultOffset + 0] = c7; + target[resultOffset + 1] = c7; + target[resultOffset + 2] = c7; + target[resultOffset + 3] = a7; + target[resultOffset + 4] = c8; + target[resultOffset + 5] = c8; + target[resultOffset + 6] = c8; + target[resultOffset + 7] = a8; + } + + /** + * Assumes a line height of 2px and a char width of 1px + */ + public x1RenderChar(target: Uint8ClampedArray, lineLen: number, lineIndex: number, charIndex: number, chCode: number): void { + const x1CharData = this.x1charData; + + const outWidth = Constants.x1_CHAR_WIDTH * Constants.RGBA_CHANNELS_CNT * lineLen; + const sourceWidth = Constants.x1_CHAR_WIDTH * Constants.CA_CHANNELS_CNT * Constants.CHAR_COUNT; + + if (chCode < Constants.START_CH_CODE || chCode > Constants.END_CH_CODE) { + chCode = CharCode.N; + } + const chIndex = chCode - Constants.START_CH_CODE; + + let sourceOffset = chIndex * Constants.x1_CHAR_WIDTH * Constants.CA_CHANNELS_CNT; + const c1 = x1CharData[sourceOffset]; + const a1 = x1CharData[sourceOffset + 1]; + + sourceOffset += sourceWidth; + const c2 = x1CharData[sourceOffset]; + const a2 = x1CharData[sourceOffset + 1]; + + let resultOffset = Constants.x1_CHAR_WIDTH * Constants.RGBA_CHANNELS_CNT * charIndex; + target[resultOffset + 0] = c1; + target[resultOffset + 1] = c1; + target[resultOffset + 2] = c1; + target[resultOffset + 3] = a1; + resultOffset += outWidth; + target[resultOffset + 0] = c2; + target[resultOffset + 1] = c2; + target[resultOffset + 2] = c2; + target[resultOffset + 3] = a2; + } +} diff --git a/src/vs/editor/test/browser/view/minimapFontCreator.html b/src/vs/editor/test/browser/view/minimapFontCreator.html new file mode 100644 index 0000000000000000000000000000000000000000..9ddd334797aa8833ff6e2deb9c4489c625fbfbb0 --- /dev/null +++ b/src/vs/editor/test/browser/view/minimapFontCreator.html @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/vs/editor/test/browser/view/minimapFontCreator.ts b/src/vs/editor/test/browser/view/minimapFontCreator.ts new file mode 100644 index 0000000000000000000000000000000000000000..90cd654094b399573b15cb03b3571ec3fe3a8f23 --- /dev/null +++ b/src/vs/editor/test/browser/view/minimapFontCreator.ts @@ -0,0 +1,68 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import { Constants, MinimapCharRendererFactory } from 'vs/editor/common/view/minimapCharRenderer'; + +let canvas = document.getElementById('my-canvas'); +let ctx = canvas.getContext('2d'); + +canvas.style.height = 100 + 'px'; +canvas.height = 100; + +canvas.width = Constants.CHAR_COUNT * Constants.SAMPLED_CHAR_WIDTH; +canvas.style.width = (Constants.CHAR_COUNT * Constants.SAMPLED_CHAR_WIDTH) + 'px'; + +ctx.fillStyle = '#ffffff'; +ctx.font = 'bold 16px monospace'; +for (let chCode = Constants.START_CH_CODE; chCode <= Constants.END_CH_CODE; chCode++) { + ctx.fillText(String.fromCharCode(chCode), (chCode - Constants.START_CH_CODE) * Constants.SAMPLED_CHAR_WIDTH, Constants.SAMPLED_CHAR_HEIGHT); +} + +let sampleData = ctx.getImageData(0, 4, Constants.SAMPLED_CHAR_WIDTH * Constants.CHAR_COUNT, Constants.SAMPLED_CHAR_HEIGHT); +let minimapCharRenderer = MinimapCharRendererFactory.create(sampleData.data); + +renderImageData(sampleData.data, sampleData.width, sampleData.height, 10, 100); + +let x2 = new Uint8ClampedArray(Constants.x2_CHAR_HEIGHT * Constants.x2_CHAR_WIDTH * Constants.RGBA_CHANNELS_CNT * Constants.CHAR_COUNT); +for (let chCode = Constants.START_CH_CODE; chCode <= Constants.END_CH_CODE; chCode++) { + minimapCharRenderer.x2RenderChar(x2, Constants.CHAR_COUNT, 0, chCode - Constants.START_CH_CODE, chCode); +} +renderImageData(x2, Constants.x2_CHAR_WIDTH * Constants.CHAR_COUNT, Constants.x2_CHAR_HEIGHT, 10, 400); + +let x1 = new Uint8ClampedArray(Constants.x1_CHAR_HEIGHT * Constants.x1_CHAR_WIDTH * Constants.RGBA_CHANNELS_CNT * Constants.CHAR_COUNT); +for (let chCode = Constants.START_CH_CODE; chCode <= Constants.END_CH_CODE; chCode++) { + minimapCharRenderer.x1RenderChar(x1, Constants.CHAR_COUNT, 0, chCode - Constants.START_CH_CODE, chCode); +} +renderImageData(x1, Constants.x1_CHAR_WIDTH * Constants.CHAR_COUNT, Constants.x1_CHAR_HEIGHT, 10, 500); + + +function renderImageData(data: Uint8ClampedArray, width: number, height: number, left: number, top: number): void { + let output = ''; + var offset = 0; + var PX_SIZE = 15; + for (var i = 0; i < height; i++) { + for (var j = 0; j < width; j++) { + var R = data[offset]; + var G = data[offset + 1]; + var B = data[offset + 2]; + var A = data[offset + 3]; + offset += 4; + + output += `
`; + } + } + + var domNode = document.createElement('div'); + domNode.style.position = 'absolute'; + domNode.style.top = top + 'px'; + domNode.style.left = left + 'px'; + domNode.style.width = (width * PX_SIZE) + 'px'; + domNode.style.height = (height * PX_SIZE) + 'px'; + domNode.style.border = '1px solid #ccc'; + domNode.style.background = '#000000'; + domNode.innerHTML = output; + document.body.appendChild(domNode); +} diff --git a/src/vs/editor/test/common/view/minimapCharRenderer.test.ts b/src/vs/editor/test/common/view/minimapCharRenderer.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..647c004b15be27985e83354df91ef680e5ffc973 --- /dev/null +++ b/src/vs/editor/test/common/view/minimapCharRenderer.test.ts @@ -0,0 +1,103 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import * as assert from 'assert'; +import { Constants, MinimapCharRendererFactory } from 'vs/editor/common/view/minimapCharRenderer'; + +suite('MinimapCharRenderer', () => { + + let sampleData: Uint8ClampedArray = null; + + suiteSetup(() => { + sampleData = new Uint8ClampedArray(Constants.SAMPLED_CHAR_HEIGHT * Constants.SAMPLED_CHAR_WIDTH * Constants.RGBA_CHANNELS_CNT * Constants.CHAR_COUNT); + }); + + suiteTeardown(() => { + sampleData = null; + }); + + setup(() => { + for (let i = 0; i < sampleData.length; i++) { + sampleData[i] = 0; + } + + }); + + const sampleD = [ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xd0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xd0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xd0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0d, 0xff, 0xff, 0xff, 0xa3, 0xff, 0xff, 0xff, 0xf3, 0xff, 0xff, 0xff, 0xe5, 0xff, 0xff, 0xff, 0x5e, 0xff, 0xff, 0xff, 0xd0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xa4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0x10, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x94, 0xff, 0xff, 0xff, 0x02, 0xff, 0xff, 0xff, 0x6a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0x3b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x22, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x03, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0x47, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xd6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0x31, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0x0e, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x69, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x9b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xb9, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0e, 0xff, 0xff, 0xff, 0xa7, 0xff, 0xff, 0xff, 0xf5, 0xff, 0xff, 0xff, 0xe8, 0xff, 0xff, 0xff, 0x71, 0xff, 0xff, 0xff, 0xd0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ]; + + function setSampleData(charCode: number, data: number[]) { + const rowWidth = Constants.SAMPLED_CHAR_WIDTH * Constants.RGBA_CHANNELS_CNT * Constants.CHAR_COUNT; + let chIndex = charCode - Constants.START_CH_CODE; + + let globalOutputOffset = chIndex * Constants.SAMPLED_CHAR_WIDTH * Constants.RGBA_CHANNELS_CNT; + let inputOffset = 0; + for (let i = 0; i < Constants.SAMPLED_CHAR_HEIGHT; i++) { + let outputOffset = globalOutputOffset; + for (let j = 0; j < Constants.SAMPLED_CHAR_WIDTH; j++) { + for (let channel = 0; channel < Constants.RGBA_CHANNELS_CNT; channel++) { + sampleData[outputOffset] = data[inputOffset]; + inputOffset++; + outputOffset++; + } + } + globalOutputOffset += rowWidth; + } + } + + test('letter d @ 2x', () => { + setSampleData(' '.charCodeAt(0), sampleD); + let renderer = MinimapCharRendererFactory.create(sampleData); + + let dest = new Uint8ClampedArray(Constants.x2_CHAR_HEIGHT * Constants.x2_CHAR_WIDTH * Constants.RGBA_CHANNELS_CNT); + renderer.x2RenderChar(dest, 1, 0, 0, ' '.charCodeAt(0)); + + let actual: number[] = []; + for (let i = 0; i < dest.length; i++) { + actual[i] = dest[i]; + } + assert.deepEqual(actual, [ + 0x00, 0x00, 0x00, 0x00, 0xbf, 0xbf, 0xbf, 0x92, + 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbe, + 0xff, 0xff, 0xff, 0x94, 0xd4, 0xd4, 0xd4, 0x97, + 0xff, 0xff, 0xff, 0xb1, 0xff, 0xff, 0xff, 0xbb, + ]); + }); + + test('letter d @ 1x', () => { + setSampleData(' '.charCodeAt(0), sampleD); + let renderer = MinimapCharRendererFactory.create(sampleData); + + let dest = new Uint8ClampedArray(Constants.x1_CHAR_HEIGHT * Constants.x1_CHAR_WIDTH * Constants.RGBA_CHANNELS_CNT); + renderer.x1RenderChar(dest, 1, 0, 0, ' '.charCodeAt(0)); + + let actual: number[] = []; + for (let i = 0; i < dest.length; i++) { + actual[i] = dest[i]; + } + assert.deepEqual(actual, [ + 0xad, 0xad, 0xad, 0x7d, + 0xeb, 0xeb, 0xeb, 0x9f, + ]); + }); + +}); \ No newline at end of file