diff --git a/examples/web/index.ts b/examples/web/index.ts index 4bce785195942390dd8fed2f23321146381ca354..3261d7478f4e4214920e639c7e3d7b1716cde18a 100644 --- a/examples/web/index.ts +++ b/examples/web/index.ts @@ -524,6 +524,10 @@ class GameboyEmulator extends Observable implements Emulator { return this.fps; } + getTile(index: number): Uint8Array { + return this.gameBoy!.get_tile_buffer(index); + } + toggleRunning() { if (this.paused) { this.resume(); diff --git a/examples/web/react/app.tsx b/examples/web/react/app.tsx index 25c8ab4fc329c177f637e55795e2228fbf8c1d0d..dbdafd8857af56853448f4b53dec1784f0d79cc4 100644 --- a/examples/web/react/app.tsx +++ b/examples/web/react/app.tsx @@ -21,6 +21,7 @@ import { PanelSplit, Paragraph, Section, + Tiles, Title, Toast } from "./components"; @@ -159,6 +160,8 @@ export interface Emulator extends ObservableI { */ getFramerate(): number; + getTile(index: number): Uint8Array; + /** * Boot (or reboots) the emulator according to the provided * set of options. @@ -443,6 +446,10 @@ export const App: FC<AppProps> = ({ emulator, backgrounds = ["264653"] }) => { onClearHandler={onClearHandler} onMinimize={onMinimize} /> + <Tiles + getTile={(index) => emulator.getTile(index)} + tileCount={384} + /> <KeyboardGB /> </div> } diff --git a/examples/web/react/components/canvas/canvas.css b/examples/web/react/components/canvas/canvas.css new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/examples/web/react/components/canvas/canvas.tsx b/examples/web/react/components/canvas/canvas.tsx new file mode 100644 index 0000000000000000000000000000000000000000..b3c4df8f58e82014ed30f0cf2bf254c0515eb8a2 --- /dev/null +++ b/examples/web/react/components/canvas/canvas.tsx @@ -0,0 +1,70 @@ +import React, { FC, useEffect, useRef } from "react"; + +import "./canvas.css"; + +export type CanvasStructure = { + canvas: HTMLCanvasElement; + canvasContext: CanvasRenderingContext2D; + canvasImage: ImageData; + canvasBuffer: DataView; +}; + +type CanvasProps = { + width: number; + height: number; + scale?: number; + style?: string[]; + onCanvas?: (structure: CanvasStructure) => void; +}; + +export const Canvas: FC<CanvasProps> = ({ + width, + height, + scale = 1, + style = [], + onCanvas +}) => { + const classes = () => ["canvas", ...style].join(" "); + const canvasRef = useRef<HTMLCanvasElement>(null); + useEffect(() => { + if (canvasRef.current) { + const structure = initCanvas( + width, + width, + scale, + canvasRef.current + ); + onCanvas && onCanvas(structure); + } + }, [canvasRef]); + return ( + <canvas + ref={canvasRef} + className={classes()} + width={width} + height={height} + /> + ); +}; + +const initCanvas = ( + width: number, + height: number, + scale: number, + canvas: HTMLCanvasElement +): CanvasStructure => { + const canvasContext = canvas.getContext("2d")!; + canvasContext.imageSmoothingEnabled = false; + + const canvasImage = canvasContext.createImageData(width, height); + const canvasBuffer = new DataView(canvasImage.data.buffer); + + return { + canvas: canvas, + canvasContext: canvasContext, + canvasImage: canvasImage, + canvasBuffer: canvasBuffer + }; +}; + +export default Canvas; diff --git a/examples/web/react/components/index.ts b/examples/web/react/components/index.ts index 1de0da2be5d18c6e7531c5ea8a79b3a91e1a22db..838636b94e5c09949d1234242e97bcdccf67ca09 100644 --- a/examples/web/react/components/index.ts +++ b/examples/web/react/components/index.ts @@ -2,6 +2,7 @@ export * from "./button/button"; export * from "./button-container/button-container"; export * from "./button-increment/button-increment"; export * from "./button-switch/button-switch"; +export * from "./canvas/canvas"; export * from "./display/display"; export * from "./footer/footer"; export * from "./info/info"; diff --git a/examples/web/react/components/tiles/tiles.tsx b/examples/web/react/components/tiles/tiles.tsx index a6f522a4d54e7eb0f10bea0c3fa69e69305a2c0a..e9e3cc4bad6d46585f76a2333b0ded1f7878f1f3 100644 --- a/examples/web/react/components/tiles/tiles.tsx +++ b/examples/web/react/components/tiles/tiles.tsx @@ -1,17 +1,30 @@ import React, { FC } from "react"; import { PixelFormat } from "../../app"; +import Canvas, { CanvasStructure } from "../canvas/canvas"; import "./tiles.css"; type TilesProps = { + getTile: (index: number) => Uint8Array; + tileCount: number; style?: string[]; }; -export const Tiles: FC<TilesProps> = ({ style = [] }) => { +export const Tiles: FC<TilesProps> = ({ getTile, tileCount, style = [] }) => { const classes = () => ["title", ...style].join(" "); + const onCanvas = (structure: CanvasStructure) => { + console.info("On canvas"); + setTimeout(() => { + for (let index = 0; index < 384; index++) { + const pixels = getTile(index); + console.info("VAI desenhar"); + drawTile(index, pixels, structure); + } + }, 1000); + }; return ( <div className={classes()}> - <canvas className="canvas-tiles" width="128" height="192"></canvas> + <Canvas width={128} height={192} scale={2} onCanvas={onCanvas} /> </div> ); }; @@ -23,24 +36,20 @@ export const Tiles: FC<TilesProps> = ({ style = [] }) => { * @param index The index of the sprite to be drawn. * @param pixels Buffer of pixels that contains the RGB data * that is going to be drawn. - * @param context The canvas context to which the tile is + * @param structure The canvas context to which the tile is * growing to be drawn. - * @param buffer The data buffer to be used in the drawing - * process, re-usage of it improves performance. * @param format The pixel format of the sprite. */ const drawTile = ( index: number, pixels: Uint8Array, - canvas: HTMLCanvasElement, - context: CanvasRenderingContext2D, - canvasImage: ImageData, - buffer: DataView, + structure: CanvasStructure, format: PixelFormat = PixelFormat.RGB ) => { const line = Math.floor(index / 16); const column = index % 16; - let offset = (line * canvas.width * 8 + column * 8) * PixelFormat.RGBA; + let offset = + (line * structure.canvas.width * 8 + column * 8) * PixelFormat.RGBA; let counter = 0; for (let i = 0; i < pixels.length; i += format) { const color = @@ -48,17 +57,17 @@ const drawTile = ( (pixels[i + 1] << 16) | (pixels[i + 2] << 8) | (format === PixelFormat.RGBA ? pixels[i + 3] : 0xff); - buffer.setUint32(offset, color); + structure.canvasBuffer.setUint32(offset, color); counter++; if (counter === 8) { counter = 0; - offset += (canvas.width - 7) * PixelFormat.RGBA; + offset += (structure.canvas.width - 7) * PixelFormat.RGBA; } else { offset += PixelFormat.RGBA; } } - context.putImageData(canvasImage, 0, 0); + structure.canvasContext.putImageData(structure.canvasImage, 0, 0); }; export default Tiles;