mirror of
https://github.com/zoriya/libpgs-js.git
synced 2026-08-27 00:00:51 +00:00
Only clearing the used area on the canvas, because clearing the whole area every frame is slow.
This commit is contained in:
@@ -6,6 +6,7 @@ import {CombinedBinaryReader} from "./utils/combinedBinaryReader";
|
||||
import {PaletteDefinitionSegment} from "./pgs/paletteDefinitionSegment";
|
||||
import {ObjectDefinitionSegment} from "./pgs/objectDefinitionSegment";
|
||||
import {WindowDefinition} from "./pgs/windowDefinitionSegment";
|
||||
import {Rect} from "./utils/rect";
|
||||
|
||||
/**
|
||||
* This handles the low-level PGS loading and rendering. This renderer can operate inside the web worker without being
|
||||
@@ -58,6 +59,9 @@ export class PgsRendererInternal {
|
||||
private canvas?: OffscreenCanvas | HTMLCanvasElement;
|
||||
private context?: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D;
|
||||
|
||||
// We keep track of the dirty area on the canvas. Clearing the whole canvas is slow when only a small area was used.
|
||||
private readonly dirtyArea = new Rect();
|
||||
|
||||
/**
|
||||
* Sets the canvas to render to.
|
||||
* @param canvas The canvas to render to.
|
||||
@@ -96,7 +100,10 @@ export class PgsRendererInternal {
|
||||
// Clear the canvas on invalid indices. It is possible to seek to a position before the first subtitle while
|
||||
// a later subtile is on screen. This subtitle must be clear, even there is no valid new subtitle data.
|
||||
// Ignoring the render would keep the previous subtitle on screen.
|
||||
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
||||
if (!this.dirtyArea.empty) {
|
||||
this.context.clearRect(this.dirtyArea.x, this.dirtyArea.y, this.dirtyArea.width, this.dirtyArea.height);
|
||||
this.dirtyArea.reset();
|
||||
}
|
||||
if (index < 0 || index >= this.displaySets.length) {
|
||||
return;
|
||||
}
|
||||
@@ -149,6 +156,10 @@ export class PgsRendererInternal {
|
||||
const pixelData = this.getPixelDataFromComposition(compositionObject, palette, ctxObjects);
|
||||
if (pixelData) {
|
||||
this.context.drawImage(pixelData, window.horizontalPosition, window.verticalPosition);
|
||||
|
||||
// Mark this area as dirty.
|
||||
this.dirtyArea.union(window.horizontalPosition, window.verticalPosition,
|
||||
pixelData.width, pixelData.height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* A simple rectangular class.
|
||||
*/
|
||||
export class Rect {
|
||||
/**
|
||||
* Gets if the rect is still empty and doesn't contain any area.
|
||||
*/
|
||||
public empty: boolean = true;
|
||||
|
||||
/**
|
||||
* Gets the x coordinate of the rectangular area if not empty.
|
||||
*/
|
||||
public x: number = 0;
|
||||
|
||||
/**
|
||||
* Gets the y coordinate of the rectangular area if not empty.
|
||||
*/
|
||||
public y: number = 0;
|
||||
|
||||
/**
|
||||
* Gets the width of the rectangular area if not empty.
|
||||
*/
|
||||
public width: number = 0;
|
||||
|
||||
/**
|
||||
* Gets the height of the rectangular area if not empty.
|
||||
*/
|
||||
public height: number = 0;
|
||||
|
||||
/**
|
||||
* Clears the rectangular.
|
||||
*/
|
||||
public reset() {
|
||||
this.empty = true;
|
||||
this.x = 0;
|
||||
this.y = 0;
|
||||
this.width = 0;
|
||||
this.height = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Grows this rectangular area to include the given area.
|
||||
* @param x The x coordinate of the new area.
|
||||
* @param y The y coordinate of the new area.
|
||||
* @param width The width of the new area. Negative values are not supported.
|
||||
* @param height The height of the new area. Negative values are not supported.
|
||||
*/
|
||||
public set(x: number, y: number, width: number = 0, height: number = 0) {
|
||||
this.empty = false;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Grows this rectangular area to include the given area.
|
||||
* @param x The x coordinate of the new area to include.
|
||||
* @param y The y coordinate of the new area to include.
|
||||
* @param width The width of the new area to include. Negative values are not supported.
|
||||
* @param height The height of the new area to include. Negative values are not supported.
|
||||
*/
|
||||
public union(x: number, y: number, width: number = 0, height: number = 0) {
|
||||
if (this.empty) {
|
||||
// First sub-rect added
|
||||
this.empty = false;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
} else {
|
||||
// Grow the rectangular area to fit the new sub-rect
|
||||
if (x < this.x) { this.width += this.x - x; this.x = x; }
|
||||
if (y < this.y) { this.height += this.y - y; this.y = y; }
|
||||
if (x + width > this.x + this.width) { this.width = x + width - this.x; }
|
||||
if (y + height > this.y + this.height) { this.height = y + height - this.y; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import {Rect} from "../src/utils/rect";
|
||||
|
||||
test('reset rect', () => {
|
||||
const rect = new Rect();
|
||||
rect.set(1, 1, 2, 2);
|
||||
expect(rect.empty).toBe(false);
|
||||
rect.reset();
|
||||
expect(rect.empty).toBe(true);
|
||||
});
|
||||
|
||||
test('grow rect in positive x direction', () => {
|
||||
const rect = new Rect();
|
||||
|
||||
rect.set(1, 1, 2, 2);
|
||||
rect.union(5, 1, 2, 2);
|
||||
|
||||
expect(rect.empty).toBe(false);
|
||||
expect(rect.x).toBe(1);
|
||||
expect(rect.y).toBe(1);
|
||||
expect(rect.width).toBe(6);
|
||||
expect(rect.height).toBe(2);
|
||||
});
|
||||
|
||||
|
||||
test('grow rect in negative x direction', () => {
|
||||
const rect = new Rect();
|
||||
|
||||
rect.set(5, 1, 2, 2);
|
||||
rect.union(1, 1, 2, 2);
|
||||
|
||||
expect(rect.empty).toBe(false);
|
||||
expect(rect.x).toBe(1);
|
||||
expect(rect.y).toBe(1);
|
||||
expect(rect.width).toBe(6);
|
||||
expect(rect.height).toBe(2);
|
||||
});
|
||||
|
||||
test('grow rect in positive y direction', () => {
|
||||
const rect = new Rect();
|
||||
|
||||
rect.set(1, 1, 2, 2);
|
||||
rect.union(1, 5, 2, 2);
|
||||
|
||||
expect(rect.empty).toBe(false);
|
||||
expect(rect.x).toBe(1);
|
||||
expect(rect.y).toBe(1);
|
||||
expect(rect.width).toBe(2);
|
||||
expect(rect.height).toBe(6);
|
||||
});
|
||||
|
||||
|
||||
test('grow rect in negative y direction', () => {
|
||||
const rect = new Rect();
|
||||
|
||||
rect.set(1, 5, 2, 2);
|
||||
rect.union(1, 1, 2, 2);
|
||||
|
||||
expect(rect.empty).toBe(false);
|
||||
expect(rect.x).toBe(1);
|
||||
expect(rect.y).toBe(1);
|
||||
expect(rect.width).toBe(2);
|
||||
expect(rect.height).toBe(6);
|
||||
});
|
||||
Reference in New Issue
Block a user