This commit is contained in:
@@ -376,12 +376,12 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer
|
|||||||
this._ctx.save();
|
this._ctx.save();
|
||||||
this._clipRow(y);
|
this._clipRow(y);
|
||||||
// Draw the image, use the bitmap if it's available
|
// Draw the image, use the bitmap if it's available
|
||||||
if (this._charAtlas.pages[glyph.texturePage].hasCanvasChanged) {
|
if (this._charAtlas.pages[glyph.texturePage].dirtyId !== this._bitmapGenerator[glyph.texturePage]?.dirtyId) {
|
||||||
if (!this._bitmapGenerator[glyph.texturePage]) {
|
if (!this._bitmapGenerator[glyph.texturePage]) {
|
||||||
this._bitmapGenerator[glyph.texturePage] = new BitmapGenerator(this._charAtlas.pages[glyph.texturePage].canvas);
|
this._bitmapGenerator[glyph.texturePage] = new BitmapGenerator(this._charAtlas.pages[glyph.texturePage].canvas);
|
||||||
}
|
}
|
||||||
this._bitmapGenerator[glyph.texturePage]?.refresh();
|
this._bitmapGenerator[glyph.texturePage]!.refresh();
|
||||||
this._charAtlas.pages[glyph.texturePage].hasCanvasChanged = false;
|
this._bitmapGenerator[glyph.texturePage]!.dirtyId = this._charAtlas.pages[glyph.texturePage].dirtyId;
|
||||||
}
|
}
|
||||||
this._ctx.drawImage(
|
this._ctx.drawImage(
|
||||||
this._bitmapGenerator[glyph.texturePage]?.bitmap || this._charAtlas!.pages[glyph.texturePage].canvas,
|
this._bitmapGenerator[glyph.texturePage]?.bitmap || this._charAtlas!.pages[glyph.texturePage].canvas,
|
||||||
@@ -440,6 +440,7 @@ class BitmapGenerator {
|
|||||||
private _commitTimeout: number | undefined = undefined;
|
private _commitTimeout: number | undefined = undefined;
|
||||||
private _bitmap: ImageBitmap | undefined = undefined;
|
private _bitmap: ImageBitmap | undefined = undefined;
|
||||||
public get bitmap(): ImageBitmap | undefined { return this._bitmap; }
|
public get bitmap(): ImageBitmap | undefined { return this._bitmap; }
|
||||||
|
public dirtyId: number = -1;
|
||||||
|
|
||||||
constructor(private readonly _canvas: HTMLCanvasElement) {
|
constructor(private readonly _canvas: HTMLCanvasElement) {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { createProgram, PROJECTION_MATRIX } from './WebglUtils';
|
import { createProgram, GLTexture, PROJECTION_MATRIX } from './WebglUtils';
|
||||||
import { IWebGL2RenderingContext, IWebGLVertexArrayObject, IRenderModel } from './Types';
|
import { IWebGL2RenderingContext, IWebGLVertexArrayObject, IRenderModel } from './Types';
|
||||||
import { NULL_CELL_CODE } from 'common/buffer/Constants';
|
import { NULL_CELL_CODE } from 'common/buffer/Constants';
|
||||||
import { Terminal } from 'xterm';
|
import { Terminal } from 'xterm';
|
||||||
@@ -94,7 +94,7 @@ export class GlyphRenderer extends Disposable {
|
|||||||
private readonly _projectionLocation: WebGLUniformLocation;
|
private readonly _projectionLocation: WebGLUniformLocation;
|
||||||
private readonly _resolutionLocation: WebGLUniformLocation;
|
private readonly _resolutionLocation: WebGLUniformLocation;
|
||||||
private readonly _textureLocation: WebGLUniformLocation;
|
private readonly _textureLocation: WebGLUniformLocation;
|
||||||
private readonly _atlasTextures: WebGLTexture[];
|
private readonly _atlasTextures: GLTexture[];
|
||||||
private readonly _attributesBuffer: WebGLBuffer;
|
private readonly _attributesBuffer: WebGLBuffer;
|
||||||
|
|
||||||
private _atlas: ITextureAtlas | undefined;
|
private _atlas: ITextureAtlas | undefined;
|
||||||
@@ -190,14 +190,14 @@ export class GlyphRenderer extends Disposable {
|
|||||||
// is ever drawn it will show characters as red rectangles.
|
// is ever drawn it will show characters as red rectangles.
|
||||||
this._atlasTextures = [];
|
this._atlasTextures = [];
|
||||||
for (let i = 0; i < TextureAtlas.maxAtlasPages; i++) {
|
for (let i = 0; i < TextureAtlas.maxAtlasPages; i++) {
|
||||||
const texture = throwIfFalsy(gl.createTexture());
|
const glTexture = new GLTexture(throwIfFalsy(gl.createTexture()));
|
||||||
this.register(toDisposable(() => gl.deleteTexture(texture)));
|
this.register(toDisposable(() => gl.deleteTexture(glTexture.texture)));
|
||||||
gl.activeTexture(gl.TEXTURE0 + i);
|
gl.activeTexture(gl.TEXTURE0 + i);
|
||||||
gl.bindTexture(gl.TEXTURE_2D, texture);
|
gl.bindTexture(gl.TEXTURE_2D, glTexture.texture);
|
||||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
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.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]));
|
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([255, 0, 0, 255]));
|
||||||
this._atlasTextures[i] = texture;
|
this._atlasTextures[i] = glTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow drawing of transparent texture
|
// Allow drawing of transparent texture
|
||||||
@@ -348,8 +348,7 @@ export class GlyphRenderer extends Disposable {
|
|||||||
|
|
||||||
// Bind the atlas page texture if they have changed
|
// Bind the atlas page texture if they have changed
|
||||||
for (let i = 0; i < this._atlas.pages.length; i++) {
|
for (let i = 0; i < this._atlas.pages.length; i++) {
|
||||||
if (this._atlas.pages[i].hasCanvasChanged) {
|
if (this._atlas.pages[i].dirtyId !== this._atlasTextures[i].dirtyId) {
|
||||||
this._atlas.pages[i].hasCanvasChanged = false;
|
|
||||||
this._bindAtlasPageTexture(gl, this._atlas, i);
|
this._bindAtlasPageTexture(gl, this._atlas, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -360,18 +359,19 @@ export class GlyphRenderer extends Disposable {
|
|||||||
|
|
||||||
public setAtlas(atlas: ITextureAtlas): void {
|
public setAtlas(atlas: ITextureAtlas): void {
|
||||||
this._atlas = atlas;
|
this._atlas = atlas;
|
||||||
for (let i = 0; i < atlas.pages.length; i++) {
|
for (const glTexture of this._atlasTextures) {
|
||||||
this._bindAtlasPageTexture(this._gl, atlas, i);
|
glTexture.dirtyId = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _bindAtlasPageTexture(gl: IWebGL2RenderingContext, atlas: ITextureAtlas, i: number): void {
|
private _bindAtlasPageTexture(gl: IWebGL2RenderingContext, atlas: ITextureAtlas, i: number): void {
|
||||||
gl.activeTexture(gl.TEXTURE0 + i);
|
gl.activeTexture(gl.TEXTURE0 + i);
|
||||||
gl.bindTexture(gl.TEXTURE_2D, this._atlasTextures[i]);
|
gl.bindTexture(gl.TEXTURE_2D, this._atlasTextures[i].texture);
|
||||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
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.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.pages[i].canvas);
|
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, atlas.pages[i].canvas);
|
||||||
gl.generateMipmap(gl.TEXTURE_2D);
|
gl.generateMipmap(gl.TEXTURE_2D);
|
||||||
|
this._atlasTextures[i].dirtyId = atlas.pages[i].dirtyId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public setDimensions(dimensions: IRenderDimensions): void {
|
public setDimensions(dimensions: IRenderDimensions): void {
|
||||||
|
|||||||
@@ -51,3 +51,13 @@ export function expandFloat32Array(source: Float32Array, max: number): Float32Ar
|
|||||||
}
|
}
|
||||||
return newArray;
|
return newArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class GLTexture {
|
||||||
|
public texture: WebGLTexture;
|
||||||
|
public dirtyId: number;
|
||||||
|
|
||||||
|
constructor(texture: WebGLTexture) {
|
||||||
|
this.texture = texture;
|
||||||
|
this.dirtyId = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ export class TextureAtlas implements ITextureAtlas {
|
|||||||
|
|
||||||
// The texture that the atlas is drawn to
|
// The texture that the atlas is drawn to
|
||||||
private _pages: AtlasPage[] = [];
|
private _pages: AtlasPage[] = [];
|
||||||
public get pages(): { canvas: HTMLCanvasElement, hasCanvasChanged: boolean }[] { return this._pages; }
|
public get pages(): { canvas: HTMLCanvasElement, dirtyId: number }[] { return this._pages; }
|
||||||
|
|
||||||
// The set of atlas pages that can be written to
|
// The set of atlas pages that can be written to
|
||||||
private _activePages: AtlasPage[] = [];
|
private _activePages: AtlasPage[] = [];
|
||||||
@@ -179,7 +179,7 @@ export class TextureAtlas implements ITextureAtlas {
|
|||||||
|
|
||||||
// Merge into the new page
|
// Merge into the new page
|
||||||
const mergedPage = this._mergePages(mergingPages, mergedPageIndex);
|
const mergedPage = this._mergePages(mergingPages, mergedPageIndex);
|
||||||
mergedPage.hasCanvasChanged = true;
|
mergedPage.dirtyId++;
|
||||||
|
|
||||||
// Replace the first _merging_ page with the _merged_ page
|
// Replace the first _merging_ page with the _merged_ page
|
||||||
this._pages[mergedPageIndex] = mergedPage;
|
this._pages[mergedPageIndex] = mergedPage;
|
||||||
@@ -238,7 +238,7 @@ export class TextureAtlas implements ITextureAtlas {
|
|||||||
for (const g of adjustingPage.glyphs) {
|
for (const g of adjustingPage.glyphs) {
|
||||||
g.texturePage--;
|
g.texturePage--;
|
||||||
}
|
}
|
||||||
adjustingPage.hasCanvasChanged = true;
|
adjustingPage.dirtyId++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -826,7 +826,7 @@ export class TextureAtlas implements ITextureAtlas {
|
|||||||
rasterizedGlyph.size.y
|
rasterizedGlyph.size.y
|
||||||
);
|
);
|
||||||
activePage.addGlyph(rasterizedGlyph);
|
activePage.addGlyph(rasterizedGlyph);
|
||||||
activePage.hasCanvasChanged = true;
|
activePage.dirtyId++;
|
||||||
|
|
||||||
return rasterizedGlyph;
|
return rasterizedGlyph;
|
||||||
}
|
}
|
||||||
@@ -936,10 +936,9 @@ class AtlasPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the canvas of the atlas page has changed, this is only set to true by the atlas, the
|
* Used to check whether the canvas of the atlas page has changed.
|
||||||
* user of the boolean is required to reset its value to false.
|
|
||||||
*/
|
*/
|
||||||
public hasCanvasChanged = false;
|
public dirtyId = 0;
|
||||||
|
|
||||||
// Texture atlas current positioning data. The texture packing strategy used is to fill from
|
// Texture atlas current positioning data. The texture packing strategy used is to fill from
|
||||||
// left-to-right and top-to-bottom. When the glyph being written is less than half of the current
|
// left-to-right and top-to-bottom. When the glyph being written is less than half of the current
|
||||||
@@ -982,7 +981,7 @@ class AtlasPage {
|
|||||||
this.currentRow.y = 0;
|
this.currentRow.y = 0;
|
||||||
this.currentRow.height = 0;
|
this.currentRow.height = 0;
|
||||||
this.fixedRows.length = 0;
|
this.fixedRows.length = 0;
|
||||||
this.hasCanvasChanged = true;
|
this.dirtyId++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -87,7 +87,7 @@ export interface IRenderer extends IDisposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface ITextureAtlas extends IDisposable {
|
export interface ITextureAtlas extends IDisposable {
|
||||||
readonly pages: { canvas: HTMLCanvasElement, hasCanvasChanged: boolean }[];
|
readonly pages: { canvas: HTMLCanvasElement, dirtyId: number }[];
|
||||||
|
|
||||||
onAddTextureAtlasCanvas: IEvent<HTMLCanvasElement>;
|
onAddTextureAtlasCanvas: IEvent<HTMLCanvasElement>;
|
||||||
onRemoveTextureAtlasCanvas: IEvent<HTMLCanvasElement>;
|
onRemoveTextureAtlasCanvas: IEvent<HTMLCanvasElement>;
|
||||||
|
|||||||
Reference in New Issue
Block a user