186 lines
11 KiB
JavaScript
186 lines
11 KiB
JavaScript
|
"use strict";
|
||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||
|
var WebglUtils_1 = require("./WebglUtils");
|
||
|
var TypedArrayUtils_1 = require("common/TypedArrayUtils");
|
||
|
var Constants_1 = require("browser/renderer/atlas/Constants");
|
||
|
var CharAtlasUtils_1 = require("./atlas/CharAtlasUtils");
|
||
|
var Constants_2 = require("common/buffer/Constants");
|
||
|
var vertexShaderSource = "#version 300 es\nlayout (location = " + 0 + ") in vec2 a_position;\nlayout (location = " + 1 + ") in vec2 a_size;\nlayout (location = " + 2 + ") in vec3 a_color;\nlayout (location = " + 3 + ") in vec2 a_unitquad;\n\nuniform mat4 u_projection;\nuniform vec2 u_resolution;\n\nout vec3 v_color;\n\nvoid main() {\n vec2 zeroToOne = (a_position + (a_unitquad * a_size)) / u_resolution;\n gl_Position = u_projection * vec4(zeroToOne, 0.0, 1.0);\n v_color = a_color;\n}";
|
||
|
var fragmentShaderSource = "#version 300 es\nprecision lowp float;\n\nin vec3 v_color;\n\nout vec4 outColor;\n\nvoid main() {\n outColor = vec4(v_color, 1);\n}";
|
||
|
var INDICES_PER_RECTANGLE = 8;
|
||
|
var BYTES_PER_RECTANGLE = INDICES_PER_RECTANGLE * Float32Array.BYTES_PER_ELEMENT;
|
||
|
var INITIAL_BUFFER_RECTANGLE_CAPACITY = 20 * INDICES_PER_RECTANGLE;
|
||
|
var RectangleRenderer = (function () {
|
||
|
function RectangleRenderer(_terminal, _colors, _gl, _dimensions) {
|
||
|
this._terminal = _terminal;
|
||
|
this._colors = _colors;
|
||
|
this._gl = _gl;
|
||
|
this._dimensions = _dimensions;
|
||
|
this._vertices = {
|
||
|
count: 0,
|
||
|
attributes: new Float32Array(INITIAL_BUFFER_RECTANGLE_CAPACITY),
|
||
|
selection: new Float32Array(3 * INDICES_PER_RECTANGLE)
|
||
|
};
|
||
|
var gl = this._gl;
|
||
|
this._program = WebglUtils_1.throwIfFalsy(WebglUtils_1.createProgram(gl, vertexShaderSource, fragmentShaderSource));
|
||
|
this._resolutionLocation = WebglUtils_1.throwIfFalsy(gl.getUniformLocation(this._program, 'u_resolution'));
|
||
|
this._projectionLocation = WebglUtils_1.throwIfFalsy(gl.getUniformLocation(this._program, 'u_projection'));
|
||
|
this._vertexArrayObject = gl.createVertexArray();
|
||
|
gl.bindVertexArray(this._vertexArrayObject);
|
||
|
var unitQuadVertices = new Float32Array([0, 0, 1, 0, 0, 1, 1, 1]);
|
||
|
var unitQuadVerticesBuffer = gl.createBuffer();
|
||
|
gl.bindBuffer(gl.ARRAY_BUFFER, unitQuadVerticesBuffer);
|
||
|
gl.bufferData(gl.ARRAY_BUFFER, unitQuadVertices, gl.STATIC_DRAW);
|
||
|
gl.enableVertexAttribArray(3);
|
||
|
gl.vertexAttribPointer(3, 2, this._gl.FLOAT, false, 0, 0);
|
||
|
var unitQuadElementIndices = new Uint8Array([0, 1, 3, 0, 2, 3]);
|
||
|
var elementIndicesBuffer = gl.createBuffer();
|
||
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elementIndicesBuffer);
|
||
|
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, unitQuadElementIndices, gl.STATIC_DRAW);
|
||
|
this._attributesBuffer = WebglUtils_1.throwIfFalsy(gl.createBuffer());
|
||
|
gl.bindBuffer(gl.ARRAY_BUFFER, this._attributesBuffer);
|
||
|
gl.enableVertexAttribArray(0);
|
||
|
gl.vertexAttribPointer(0, 2, gl.FLOAT, false, BYTES_PER_RECTANGLE, 0);
|
||
|
gl.vertexAttribDivisor(0, 1);
|
||
|
gl.enableVertexAttribArray(1);
|
||
|
gl.vertexAttribPointer(1, 2, gl.FLOAT, false, BYTES_PER_RECTANGLE, 2 * Float32Array.BYTES_PER_ELEMENT);
|
||
|
gl.vertexAttribDivisor(1, 1);
|
||
|
gl.enableVertexAttribArray(2);
|
||
|
gl.vertexAttribPointer(2, 4, gl.FLOAT, false, BYTES_PER_RECTANGLE, 4 * Float32Array.BYTES_PER_ELEMENT);
|
||
|
gl.vertexAttribDivisor(2, 1);
|
||
|
this._updateCachedColors();
|
||
|
}
|
||
|
RectangleRenderer.prototype.render = function () {
|
||
|
var gl = this._gl;
|
||
|
gl.useProgram(this._program);
|
||
|
gl.bindVertexArray(this._vertexArrayObject);
|
||
|
gl.uniformMatrix4fv(this._projectionLocation, false, WebglUtils_1.PROJECTION_MATRIX);
|
||
|
gl.uniform2f(this._resolutionLocation, gl.canvas.width, gl.canvas.height);
|
||
|
gl.bindBuffer(gl.ARRAY_BUFFER, this._attributesBuffer);
|
||
|
gl.bufferData(gl.ARRAY_BUFFER, this._vertices.attributes, gl.DYNAMIC_DRAW);
|
||
|
gl.drawElementsInstanced(this._gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, this._vertices.count);
|
||
|
gl.bindBuffer(gl.ARRAY_BUFFER, this._attributesBuffer);
|
||
|
gl.bufferData(gl.ARRAY_BUFFER, this._vertices.selection, gl.DYNAMIC_DRAW);
|
||
|
gl.drawElementsInstanced(this._gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, 3);
|
||
|
};
|
||
|
RectangleRenderer.prototype.onResize = function () {
|
||
|
this._updateViewportRectangle();
|
||
|
};
|
||
|
RectangleRenderer.prototype.setColors = function () {
|
||
|
this._updateCachedColors();
|
||
|
this._updateViewportRectangle();
|
||
|
};
|
||
|
RectangleRenderer.prototype._updateCachedColors = function () {
|
||
|
this._bgFloat = this._colorToFloat32Array(this._colors.background);
|
||
|
this._selectionFloat = this._colorToFloat32Array(this._colors.selection);
|
||
|
};
|
||
|
RectangleRenderer.prototype._updateViewportRectangle = function () {
|
||
|
this._addRectangleFloat(this._vertices.attributes, 0, 0, 0, this._terminal.cols * this._dimensions.scaledCellWidth, this._terminal.rows * this._dimensions.scaledCellHeight, this._bgFloat);
|
||
|
};
|
||
|
RectangleRenderer.prototype.updateSelection = function (model, columnSelectMode) {
|
||
|
var terminal = this._terminal;
|
||
|
if (!model.hasSelection) {
|
||
|
TypedArrayUtils_1.fill(this._vertices.selection, 0, 0);
|
||
|
return;
|
||
|
}
|
||
|
if (columnSelectMode) {
|
||
|
var startCol = model.startCol;
|
||
|
var width = model.endCol - startCol;
|
||
|
var height = model.viewportCappedEndRow - model.viewportCappedStartRow + 1;
|
||
|
this._addRectangleFloat(this._vertices.selection, 0, startCol * this._dimensions.scaledCellWidth, model.viewportCappedStartRow * this._dimensions.scaledCellHeight, width * this._dimensions.scaledCellWidth, height * this._dimensions.scaledCellHeight, this._selectionFloat);
|
||
|
TypedArrayUtils_1.fill(this._vertices.selection, 0, INDICES_PER_RECTANGLE);
|
||
|
}
|
||
|
else {
|
||
|
var startCol = model.viewportStartRow === model.viewportCappedStartRow ? model.startCol : 0;
|
||
|
var startRowEndCol = model.viewportCappedStartRow === model.viewportCappedEndRow ? model.endCol : terminal.cols;
|
||
|
this._addRectangleFloat(this._vertices.selection, 0, startCol * this._dimensions.scaledCellWidth, model.viewportCappedStartRow * this._dimensions.scaledCellHeight, (startRowEndCol - startCol) * this._dimensions.scaledCellWidth, this._dimensions.scaledCellHeight, this._selectionFloat);
|
||
|
var middleRowsCount = Math.max(model.viewportCappedEndRow - model.viewportCappedStartRow - 1, 0);
|
||
|
this._addRectangleFloat(this._vertices.selection, INDICES_PER_RECTANGLE, 0, (model.viewportCappedStartRow + 1) * this._dimensions.scaledCellHeight, terminal.cols * this._dimensions.scaledCellWidth, middleRowsCount * this._dimensions.scaledCellHeight, this._selectionFloat);
|
||
|
if (model.viewportCappedStartRow !== model.viewportCappedEndRow) {
|
||
|
var endCol = model.viewportEndRow === model.viewportCappedEndRow ? model.endCol : terminal.cols;
|
||
|
this._addRectangleFloat(this._vertices.selection, INDICES_PER_RECTANGLE * 2, 0, model.viewportCappedEndRow * this._dimensions.scaledCellHeight, endCol * this._dimensions.scaledCellWidth, this._dimensions.scaledCellHeight, this._selectionFloat);
|
||
|
}
|
||
|
else {
|
||
|
TypedArrayUtils_1.fill(this._vertices.selection, 0, INDICES_PER_RECTANGLE * 2);
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
RectangleRenderer.prototype.updateBackgrounds = function (model) {
|
||
|
var terminal = this._terminal;
|
||
|
var vertices = this._vertices;
|
||
|
var rectangleCount = 1;
|
||
|
for (var y = 0; y < terminal.rows; y++) {
|
||
|
var currentStartX = -1;
|
||
|
var currentBg = Constants_2.DEFAULT_COLOR;
|
||
|
for (var x = 0; x < terminal.cols; x++) {
|
||
|
var modelIndex = ((y * terminal.cols) + x) * 4;
|
||
|
var bg = model.cells[modelIndex + 2];
|
||
|
if (bg !== currentBg) {
|
||
|
if (currentBg !== Constants_2.DEFAULT_COLOR) {
|
||
|
var offset = rectangleCount++ * INDICES_PER_RECTANGLE;
|
||
|
this._updateRectangle(vertices, offset, currentBg, currentStartX, x, y);
|
||
|
}
|
||
|
currentStartX = x;
|
||
|
currentBg = bg;
|
||
|
}
|
||
|
}
|
||
|
if (currentBg !== Constants_2.DEFAULT_COLOR) {
|
||
|
var offset = rectangleCount++ * INDICES_PER_RECTANGLE;
|
||
|
this._updateRectangle(vertices, offset, currentBg, currentStartX, terminal.cols, y);
|
||
|
}
|
||
|
}
|
||
|
vertices.count = rectangleCount;
|
||
|
};
|
||
|
RectangleRenderer.prototype._updateRectangle = function (vertices, offset, bg, startX, endX, y) {
|
||
|
var color = null;
|
||
|
if (bg === Constants_1.INVERTED_DEFAULT_COLOR) {
|
||
|
color = this._colors.foreground;
|
||
|
}
|
||
|
else if (CharAtlasUtils_1.is256Color(bg)) {
|
||
|
color = this._colors.ansi[bg];
|
||
|
}
|
||
|
else {
|
||
|
color = this._colors.foreground;
|
||
|
}
|
||
|
if (vertices.attributes.length < offset + 4) {
|
||
|
vertices.attributes = WebglUtils_1.expandFloat32Array(vertices.attributes, this._terminal.rows * this._terminal.cols * INDICES_PER_RECTANGLE);
|
||
|
}
|
||
|
var x1 = startX * this._dimensions.scaledCellWidth;
|
||
|
var y1 = y * this._dimensions.scaledCellHeight;
|
||
|
var r = ((color.rgba >> 24) & 0xFF) / 255;
|
||
|
var g = ((color.rgba >> 16) & 0xFF) / 255;
|
||
|
var b = ((color.rgba >> 8) & 0xFF) / 255;
|
||
|
this._addRectangle(vertices.attributes, offset, x1, y1, (endX - startX) * this._dimensions.scaledCellWidth, this._dimensions.scaledCellHeight, r, g, b, 1);
|
||
|
};
|
||
|
RectangleRenderer.prototype._addRectangle = function (array, offset, x1, y1, width, height, r, g, b, a) {
|
||
|
array[offset] = x1;
|
||
|
array[offset + 1] = y1;
|
||
|
array[offset + 2] = width;
|
||
|
array[offset + 3] = height;
|
||
|
array[offset + 4] = r;
|
||
|
array[offset + 5] = g;
|
||
|
array[offset + 6] = b;
|
||
|
array[offset + 7] = a;
|
||
|
};
|
||
|
RectangleRenderer.prototype._addRectangleFloat = function (array, offset, x1, y1, width, height, color) {
|
||
|
array[offset] = x1;
|
||
|
array[offset + 1] = y1;
|
||
|
array[offset + 2] = width;
|
||
|
array[offset + 3] = height;
|
||
|
array[offset + 4] = color[0];
|
||
|
array[offset + 5] = color[1];
|
||
|
array[offset + 6] = color[2];
|
||
|
array[offset + 7] = color[3];
|
||
|
};
|
||
|
RectangleRenderer.prototype._colorToFloat32Array = function (color) {
|
||
|
return new Float32Array([
|
||
|
((color.rgba >> 24) & 0xFF) / 255,
|
||
|
((color.rgba >> 16) & 0xFF) / 255,
|
||
|
((color.rgba >> 8) & 0xFF) / 255,
|
||
|
((color.rgba) & 0xFF) / 255
|
||
|
]);
|
||
|
};
|
||
|
return RectangleRenderer;
|
||
|
}());
|
||
|
exports.RectangleRenderer = RectangleRenderer;
|
||
|
//# sourceMappingURL=RectangleRenderer.js.map
|