diff --git a/src/common/rpg/systems/render/canvas.ts b/src/common/rpg/systems/render/canvas.ts new file mode 100644 index 0000000..c6e1af0 --- /dev/null +++ b/src/common/rpg/systems/render/canvas.ts @@ -0,0 +1,61 @@ +import { BrickDisplay, BrickDisplayImage } from "@common/display/brick"; +import { createCanvas } from "@common/display/canvas"; +import { Position } from "@common/rpg/components/position"; +import { BrickSprite } from "@common/rpg/components/render/brick"; +import { Hidden, Sprite } from "@common/rpg/components/sprite"; +import { System, World } from "@common/rpg/core/world"; +import { Resources } from "@common/rpg/utils/resources"; + +export class CanvasDisplaySystem extends System { + public readonly canvas: HTMLCanvasElement; + public readonly ctx: CanvasRenderingContext2D; + + constructor(); + constructor(canvas: HTMLCanvasElement); + constructor(width: number, height: number); + constructor(canvasOrWidth?: HTMLCanvasElement | number, height?: number) { + super(); + const width = typeof canvasOrWidth === 'number' ? canvasOrWidth : undefined; + let canvas = canvasOrWidth instanceof HTMLCanvasElement ? canvasOrWidth : undefined; + if (canvas == null) { + if (width == null || height == null) { + throw new Error('Canvas or width/height must be provided'); + } + canvas = createCanvas(width, height); + } + this.canvas = canvas; + const ctx = canvas.getContext('2d'); + if (ctx == null) { + throw new Error('Could not create canvas context'); + } + this.ctx = ctx; + } + + override update(world: World) { + const sprites = Array.from(world.query(Sprite, Position)).sort((a, b) => a[2].state.z - b[2].state.z); + for (const [e, sprite, pos] of sprites) { + if (e.has(Hidden)) continue; + + const { x, y } = pos.state; + const imageId = sprite.image; + + const image: CanvasImageSource | undefined = + Resources.get(HTMLImageElement, imageId) + ?? Resources.get(HTMLVideoElement, imageId) + ?? Resources.get(HTMLCanvasElement, imageId) + ?? Resources.get(SVGImageElement, imageId) + ?? Resources.get(ImageBitmap, imageId) + ?? Resources.get(OffscreenCanvas, imageId) + ?? Resources.get(VideoFrame, imageId) + + const data = Resources.get(ImageData, imageId); + if (image) { + this.ctx.drawImage(image, x, y); + } else if (data) { + this.ctx.putImageData(data, x, y); + } else { + throw new Error(`No image data found for id ${imageId}`); + } + } + } +} \ No newline at end of file