mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
Bring texturePage partially to atlas
This commit is contained in:
@@ -85,18 +85,17 @@ let $leftCellPadding = 0;
|
||||
let $clippedPixels = 0;
|
||||
|
||||
export class GlyphRenderer extends Disposable {
|
||||
private readonly _program: WebGLProgram;
|
||||
private readonly _vertexArrayObject: IWebGLVertexArrayObject;
|
||||
private readonly _projectionLocation: WebGLUniformLocation;
|
||||
private readonly _resolutionLocation: WebGLUniformLocation;
|
||||
private readonly _textureLocation: WebGLUniformLocation;
|
||||
private readonly _atlasTexture: WebGLTexture;
|
||||
private readonly _atlasTexture1: WebGLTexture;
|
||||
private readonly _attributesBuffer: WebGLBuffer;
|
||||
|
||||
private _atlas: ITextureAtlas | undefined;
|
||||
|
||||
private _program: WebGLProgram;
|
||||
private _vertexArrayObject: IWebGLVertexArrayObject;
|
||||
private _projectionLocation: WebGLUniformLocation;
|
||||
private _resolutionLocation: WebGLUniformLocation;
|
||||
private _textureLocation: WebGLUniformLocation;
|
||||
private readonly _nullTexture: WebGLTexture;
|
||||
private _atlasTexture: WebGLTexture;
|
||||
private _attributesBuffer: WebGLBuffer;
|
||||
private _activeBuffer: number = 0;
|
||||
|
||||
private _vertices: IVertices = {
|
||||
count: 0,
|
||||
attributes: new Float32Array(0),
|
||||
@@ -172,16 +171,17 @@ export class GlyphRenderer extends Disposable {
|
||||
this.register(toDisposable(() => gl.deleteTexture(this._atlasTexture)));
|
||||
gl.activeTexture(gl.TEXTURE0);
|
||||
gl.bindTexture(gl.TEXTURE_2D, this._atlasTexture);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([0, 0, 255, 255]));
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||
|
||||
this._nullTexture = throwIfFalsy(gl.createTexture());
|
||||
this._atlasTexture1 = throwIfFalsy(gl.createTexture());
|
||||
this.register(toDisposable(() => gl.deleteTexture(this._atlasTexture1)));
|
||||
gl.activeTexture(gl.TEXTURE0 + 1);
|
||||
gl.bindTexture(gl.TEXTURE_2D, this._nullTexture);
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([255, 0, 0, 255]));
|
||||
gl.bindTexture(gl.TEXTURE_2D, this._atlasTexture1);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([255, 0, 0, 255]));
|
||||
|
||||
// Allow drawing of transparent texture
|
||||
gl.enable(gl.BLEND);
|
||||
@@ -234,7 +234,7 @@ export class GlyphRenderer extends Disposable {
|
||||
array[$i + 2] = ($glyph.size.x - $clippedPixels) / this._dimensions.device.canvas.width;
|
||||
array[$i + 3] = $glyph.size.y / this._dimensions.device.canvas.height;
|
||||
// a_texpage
|
||||
array[$i + 4] = 0;
|
||||
array[$i + 4] = $glyph.texturePage;
|
||||
// a_texcoord
|
||||
array[$i + 5] = $glyph.texturePositionClipSpace.x + $clippedPixels / this._atlas.cacheCanvas.width;
|
||||
array[$i + 6] = $glyph.texturePositionClipSpace.y;
|
||||
@@ -249,7 +249,7 @@ export class GlyphRenderer extends Disposable {
|
||||
array[$i + 2] = $glyph.size.x / this._dimensions.device.canvas.width;
|
||||
array[$i + 3] = $glyph.size.y / this._dimensions.device.canvas.height;
|
||||
// a_texpage
|
||||
array[$i + 4] = 0;
|
||||
array[$i + 4] = $glyph.texturePage;
|
||||
// a_texcoord
|
||||
array[$i + 5] = $glyph.texturePositionClipSpace.x;
|
||||
array[$i + 6] = $glyph.texturePositionClipSpace.y;
|
||||
@@ -333,16 +333,18 @@ export class GlyphRenderer extends Disposable {
|
||||
// TODO: Make nicer
|
||||
const layerTextureUnits = new Int32Array([0, 1]);
|
||||
gl.uniform1iv(this._textureLocation, layerTextureUnits);
|
||||
gl.uniform1i(this._textureLocation, 0);
|
||||
gl.activeTexture(gl.TEXTURE0 + 0);
|
||||
gl.bindTexture(gl.TEXTURE_2D, this._atlasTexture);
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this._atlas.cacheCanvas);
|
||||
// TODO: Why is mipmap here?
|
||||
gl.generateMipmap(gl.TEXTURE_2D);
|
||||
|
||||
// TODO: Check if the particular texture page changed
|
||||
gl.activeTexture(gl.TEXTURE0 + 1);
|
||||
gl.bindTexture(gl.TEXTURE_2D, this._atlasTexture1);
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this._atlas.cacheCanvas1!);
|
||||
gl.generateMipmap(gl.TEXTURE_2D);
|
||||
}
|
||||
|
||||
gl.activeTexture(gl.TEXTURE0 + 1);
|
||||
gl.bindTexture(gl.TEXTURE_2D, this._nullTexture);
|
||||
|
||||
// Set uniforms
|
||||
gl.uniformMatrix4fv(this._projectionLocation, false, PROJECTION_MATRIX);
|
||||
@@ -356,9 +358,19 @@ export class GlyphRenderer extends Disposable {
|
||||
const gl = this._gl;
|
||||
this._atlas = atlas;
|
||||
|
||||
gl.activeTexture(gl.TEXTURE0);
|
||||
gl.bindTexture(gl.TEXTURE_2D, this._atlasTexture);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, atlas.cacheCanvas);
|
||||
gl.generateMipmap(gl.TEXTURE_2D);
|
||||
|
||||
gl.activeTexture(gl.TEXTURE0 + 1);
|
||||
gl.bindTexture(gl.TEXTURE_2D, this._atlasTexture1);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, atlas.cacheCanvas1!);
|
||||
gl.generateMipmap(gl.TEXTURE_2D);
|
||||
}
|
||||
|
||||
public setDimensions(dimensions: IRenderDimensions): void {
|
||||
|
||||
@@ -30,9 +30,10 @@ const TEXTURE_CAPACITY = Math.floor(TEXTURE_HEIGHT * 0.8);
|
||||
* A shared object which is used to draw nothing for a particular cell.
|
||||
*/
|
||||
const NULL_RASTERIZED_GLYPH: IRasterizedGlyph = {
|
||||
offset: { x: 0, y: 0 },
|
||||
texturePage: 0,
|
||||
texturePosition: { x: 0, y: 0 },
|
||||
texturePositionClipSpace: { x: 0, y: 0 },
|
||||
offset: { x: 0, y: 0 },
|
||||
size: { x: 0, y: 0 },
|
||||
sizeClipSpace: { x: 0, y: 0 }
|
||||
};
|
||||
@@ -56,7 +57,9 @@ export class TextureAtlas implements ITextureAtlas {
|
||||
|
||||
// The texture that the atlas is drawn to
|
||||
public cacheCanvas: HTMLCanvasElement;
|
||||
public cacheCanvas1: HTMLCanvasElement | undefined;
|
||||
private _cacheCtx: CanvasRenderingContext2D;
|
||||
private _cacheCtx1: CanvasRenderingContext2D | undefined;
|
||||
|
||||
private _tmpCanvas: HTMLCanvasElement;
|
||||
// A temporary context that glyphs are drawn to before being transfered to the atlas.
|
||||
@@ -89,23 +92,34 @@ export class TextureAtlas implements ITextureAtlas {
|
||||
private readonly _config: ICharAtlasConfig,
|
||||
private readonly _unicodeService: IUnicodeService
|
||||
) {
|
||||
this.cacheCanvas = document.createElement('canvas');
|
||||
this.cacheCanvas.width = TEXTURE_WIDTH;
|
||||
this.cacheCanvas.height = TEXTURE_HEIGHT;
|
||||
this.cacheCanvas = this._createCanvas(TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
||||
// The canvas needs alpha because we use clearColor to convert the background color to alpha.
|
||||
// It might also contain some characters with transparent backgrounds if allowTransparency is
|
||||
// set.
|
||||
this._cacheCtx = throwIfFalsy(this.cacheCanvas.getContext('2d', { alpha: true }));
|
||||
|
||||
this._tmpCanvas = document.createElement('canvas');
|
||||
this._tmpCanvas.width = this._config.deviceCellWidth * 4 + TMP_CANVAS_GLYPH_PADDING * 2;
|
||||
this._tmpCanvas.height = this._config.deviceCellHeight + TMP_CANVAS_GLYPH_PADDING * 2;
|
||||
this.cacheCanvas1 = this._createCanvas(TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
||||
this._cacheCtx1 = throwIfFalsy(this.cacheCanvas1.getContext('2d', { alpha: true }));
|
||||
this._cacheCtx1.fillStyle = 'rgb(255, 255, 0)';
|
||||
this._cacheCtx1.fillRect(0, 0, TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
||||
|
||||
this._tmpCanvas = this._createCanvas(
|
||||
this._config.deviceCellWidth * 4 + TMP_CANVAS_GLYPH_PADDING * 2,
|
||||
this._config.deviceCellHeight + TMP_CANVAS_GLYPH_PADDING * 2
|
||||
);
|
||||
this._tmpCtx = throwIfFalsy(this._tmpCanvas.getContext('2d', {
|
||||
alpha: this._config.allowTransparency,
|
||||
willReadFrequently: true
|
||||
}));
|
||||
}
|
||||
|
||||
private _createCanvas(width: number, height: number): HTMLCanvasElement {
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
return canvas;
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
if (this.cacheCanvas.parentElement) {
|
||||
this.cacheCanvas.parentElement.removeChild(this.cacheCanvas);
|
||||
@@ -759,6 +773,7 @@ export class TextureAtlas implements ITextureAtlas {
|
||||
}
|
||||
}
|
||||
return {
|
||||
texturePage: 1,
|
||||
texturePosition: { x: 0, y: 0 },
|
||||
texturePositionClipSpace: { x: 0, y: 0 },
|
||||
size: {
|
||||
|
||||
+6
@@ -88,6 +88,8 @@ export interface IRenderer extends IDisposable {
|
||||
|
||||
export interface ITextureAtlas extends IDisposable {
|
||||
readonly cacheCanvas: HTMLCanvasElement;
|
||||
readonly cacheCanvas1: HTMLCanvasElement | undefined;
|
||||
|
||||
hasCanvasChanged: boolean;
|
||||
|
||||
/**
|
||||
@@ -120,6 +122,10 @@ export interface IRasterizedGlyph {
|
||||
* in pixels.
|
||||
*/
|
||||
offset: IVector;
|
||||
/**
|
||||
* The index of the texture page that the glyph is on.
|
||||
*/
|
||||
texturePage: number;
|
||||
/**
|
||||
* the x and y position of the glyph in the texture in pixels.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user