@spearwolf/twopoint5d
Version:
Create 2.5D realtime graphics and pixelart with WebGL and three.js
106 lines • 3.52 kB
JavaScript
import { emit, eventize } from '@spearwolf/eventize';
import { Sprite, SpriteMaterial, Texture } from 'three/webgpu';
import { TextureFactory } from '../texture/TextureFactory.js';
import { OrthographicProjection } from './OrthographicProjection.js';
import { Stage2D } from './Stage2D.js';
import { StageRenderer } from './StageRenderer.js';
export class Canvas2DStage {
#fit;
get fit() {
return this.#fit;
}
set fit(value) {
if (this.#fit === value)
return;
this.#fit = value;
this.projection.viewSpecs.fit = value;
this.stage.updateProjection(true);
}
get width() {
return this.canvas.width;
}
get height() {
return this.canvas.height;
}
get scene() {
return this.stage.scene;
}
#textureFactory;
#lastWidth;
#lastHeight;
constructor(renderer, ...args) {
this.#fit = 'contain';
this.needsUpdate = false;
this.#lastWidth = 0;
this.#lastHeight = 0;
eventize(this);
this.renderer = renderer;
this.stageRenderer = new StageRenderer();
if (typeof args[0] === 'number') {
const [width, height, fit] = args;
this.#fit = fit ?? this.#fit;
this.canvas = document.createElement('canvas');
this.canvas.width = width;
this.canvas.height = height;
}
else {
const [canvas, fit] = args;
this.#fit = fit ?? this.#fit;
this.canvas = canvas;
}
this.projection = new OrthographicProjection('xy|bottom-left', {
width: this.width,
height: this.height,
fit: this.#fit,
});
this.stage = new Stage2D(this.projection);
this.stageRenderer.add(this.stage);
const material = new SpriteMaterial({ map: new Texture() });
this.sprite = new Sprite(material);
this.sprite.scale.set(this.width, this.height, 1);
this.scene.add(this.sprite);
}
makeTexture() {
if (this.texture) {
this.texture.dispose();
}
this.#textureFactory ||= new TextureFactory(this.renderer, ['nearest', 'flipy', 'srgb']);
this.texture = this.#textureFactory.create(this.canvas);
return this.texture;
}
updateTexture() {
if (this.needsUpdate) {
this.sprite.material.map = this.makeTexture();
this.sprite.material.needsUpdate = true;
this.needsUpdate = false;
}
}
setContainerSize(width, height) {
this.stage.resize(width, height);
}
setCanvasSize(width, height) {
if (this.width === width && this.height === height)
return;
this.canvas.width = width;
this.canvas.height = height;
this.sprite.scale.set(width, height, 1);
const viewSpecs = this.projection.viewSpecs;
viewSpecs.width = width;
viewSpecs.height = height;
this.stage.updateProjection(true);
}
render() {
if (this.width !== this.#lastWidth || this.height !== this.#lastHeight) {
this.dispatchEvent('resize');
this.#lastWidth = this.width;
this.#lastHeight = this.height;
}
this.dispatchEvent('render');
this.updateTexture();
this.stageRenderer.renderTo(this.renderer);
}
dispatchEvent(eventName) {
emit(this, eventName, this);
}
}
//# sourceMappingURL=Canvas2DStage.js.map