From 579ffdd576a0fa9476b9723b507ed4387bd2c0e1 Mon Sep 17 00:00:00 2001 From: Sergiotarxz Date: Thu, 23 Mar 2023 23:48:07 +0100 Subject: [PATCH] Reworking the front, the code is a mess right now, but commiting to avoid losing changes. --- js-src/components/center-element.tsx | 7 ++- js-src/components/page.tsx | 60 +++++++++++++----- public/css/styles.css | 90 +++++++++++++++++++++++++++ public/img/home.png | Bin 0 -> 6259 bytes public/index.html | 1 + public/js/bundle.js | 4 +- 6 files changed, 142 insertions(+), 20 deletions(-) create mode 100644 public/img/home.png diff --git a/js-src/components/center-element.tsx b/js-src/components/center-element.tsx index 4a41d0d..eccc2e2 100644 --- a/js-src/components/center-element.tsx +++ b/js-src/components/center-element.tsx @@ -3,6 +3,7 @@ import * as React from 'react'; export interface CenterElementProps { hidden?: boolean | undefined, children?: React.ReactNode, + full?: boolean | undefined; } type IHash = { @@ -16,7 +17,11 @@ export default function CenterElement(props: CenterElementProps) { hidden = false; } styles["display"] = hidden ? 'none' : ''; + let fullClassName = ''; + if (props.full !== undefined && props.full) { + fullClassName = 'full-height'; + } return ( -
{props.children}
+
{props.children}
); } diff --git a/js-src/components/page.tsx b/js-src/components/page.tsx index 9224014..a8c1385 100644 --- a/js-src/components/page.tsx +++ b/js-src/components/page.tsx @@ -21,6 +21,7 @@ export interface handleClickStartEmulationButtonObjectArgs { }; function handleClickStartEmulationButton({e, inputRom, inputSaveState, setHiddenFormSelectFiles, canvas, printingFrame, setPrintingFrame}: handleClickStartEmulationButtonObjectArgs) { + e.preventDefault(); if (canvas == null) { alert('Canvas does not exists?'); return; @@ -49,7 +50,7 @@ function handleClickStartEmulationButton({e, inputRom, inputSaveState, setHidden setHiddenFormSelectFiles((c: boolean) => true); const rom_array = new Uint8Array(rom_buffer); const savestate_array = new Uint8Array(savestate_buffer); - const websocket = new WebSocket(`ws://localhost:3000/ws`); + const websocket = new WebSocket(`ws://${window.location.host}/ws`); websocket.binaryType = 'arraybuffer'; websocket.onclose = (message) => { setHiddenFormSelectFiles(c => false); @@ -180,20 +181,45 @@ export default function Page() { printingFrame: printingFrame, }); }; + const [hiddenMenu, setHiddenMenu] = React.useState(true); + let firstMenuElement = React.useRef(null); return (
- -

msGBA Online Emulator for GBA.

-
- - - - - +
+
+
+ +
+
+ +
+
+ + ) => { + setHiddenMenu(true); + onStartEmulation(e) + }}/> + +
+
+ + + +
); } @@ -226,7 +252,7 @@ function useScreenDimensions() { function fillBlack(canvas: HTMLCanvasElement, ctx: CanvasRenderingContext2D) { ctx.beginPath(); ctx.rect(0, 0, canvas.width, canvas.height); - ctx.fillStyle = 'black'; + ctx.fillStyle = '#0E0E10'; ctx.fill(); } @@ -240,7 +266,7 @@ function calculateSizeEmulator(screenDimensions: EmulatorDimensions): EmulatorDi return {}; } const width = screenDimensions.width; - const height = screenDimensions.height * 0.75; + const height = screenDimensions.height; const emulatorDimensions: EmulatorDimensions = {}; if (width < MIN_WIDTH || height < MIN_HEIGHT) { return { @@ -248,8 +274,8 @@ function calculateSizeEmulator(screenDimensions: EmulatorDimensions): EmulatorDi height: MIN_HEIGHT, }; } - const ratioWidth = Math.floor(width / MIN_WIDTH); - const ratioHeight = Math.floor(height / MIN_HEIGHT); + const ratioWidth = width / MIN_WIDTH; + const ratioHeight = height / MIN_HEIGHT; if (ratioWidth < ratioHeight) { emulatorDimensions.width = MIN_WIDTH * ratioWidth; emulatorDimensions.height = MIN_HEIGHT * ratioWidth; diff --git a/public/css/styles.css b/public/css/styles.css index 120cc68..308f0f2 100644 --- a/public/css/styles.css +++ b/public/css/styles.css @@ -1,4 +1,7 @@ body { + background: #0E0E10; + color: #F5F5F5; + margin: 0; min-height: 100vh; } @@ -10,8 +13,95 @@ body .center-content { display: flex; justify-content: center; + align-items: center; +} + +.full-height { } form label, form input { display: block; } +.overlay { + position: fixed; + width: 100%; + height: 100%; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 2; + cursor: pointer; +} + +.menu-select-files { + position: fixed; + width: 100%; + height: 100%; + background: #343434; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 4; + cursor: pointer; +} + +.overlay-menu { + background: #343434; + display: flex; + align-items: center; + justify-content: center; + font-size: 30px; + position: fixed; + width: 100%; + height: 100%; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 3; + cursor: pointer; +} + +.overlay-menu li { + list-style: none; +} + +.overlay-menu a { + color: white; + text-decoration: none; +} + +.overlay-menu li a:hover,.overlay-menu li a:focus { + color: grey; +} + +.overlay > div.vertical-padding { + height: 50%; +} + +.overlay > div.controls { + position: relative; + height: 50%; +} + +.overlay > div.controls > a.gear img { + width: 70%; +} +.overlay > div.controls > a.gear { + top: 0; + left: 50%; + transform: translate(-50%, 0); + width: 60px; + height: 60px; + display: flex; + justify-content: center; + border-radius: 50%; +} +.overlay > div.controls > a.control { + position: absolute; + background: #343434; + border: none; + opacity: 75%; +} diff --git a/public/img/home.png b/public/img/home.png new file mode 100644 index 0000000000000000000000000000000000000000..c40c6b2296a5a1ebeaaf9ba657b2357fafb84de0 GIT binary patch literal 6259 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 vttncb7V~lG5Xza-|97Im|KbE~TZP8fES55(ta + diff --git a/public/js/bundle.js b/public/js/bundle.js index 7b35e7c..e2a22fb 100644 --- a/public/js/bundle.js +++ b/public/js/bundle.js @@ -96,7 +96,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac \**********************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ CenterElement)\n/* harmony export */ });\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);\n\nfunction CenterElement(props) {\n const styles = {};\n let hidden = props.hidden;\n if (hidden == null) {\n hidden = false;\n }\n styles[\"display\"] = hidden ? 'none' : '';\n return (react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", { style: styles, className: \"center-content\" }, props.children));\n}\n\n\n//# sourceURL=webpack://MSGBA-Web/./js-src/components/center-element.tsx?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ CenterElement)\n/* harmony export */ });\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);\n\nfunction CenterElement(props) {\n const styles = {};\n let hidden = props.hidden;\n if (hidden == null) {\n hidden = false;\n }\n styles[\"display\"] = hidden ? 'none' : '';\n let fullClassName = '';\n if (props.full !== undefined && props.full) {\n fullClassName = 'full-height';\n }\n return (react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", { style: styles, className: `center-content ${fullClassName}` }, props.children));\n}\n\n\n//# sourceURL=webpack://MSGBA-Web/./js-src/components/center-element.tsx?"); /***/ }), @@ -116,7 +116,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac \************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ Page)\n/* harmony export */ });\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _components_center_element__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../../components/center-element */ \"./js-src/components/center-element.tsx\");\n/* harmony import */ var _components_form_select_files__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../../components/form-select-files */ \"./js-src/components/form-select-files.tsx\");\n/* harmony import */ var _components_canvas_gba_emulator__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../../components/canvas-gba-emulator */ \"./js-src/components/canvas-gba-emulator.tsx\");\n/* harmony import */ var _endian__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../../../endian */ \"./js-src/endian.ts\");\n/* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../../../constants */ \"./js-src/constants.ts\");\n\n\n\n\n\n\n;\nfunction handleClickStartEmulationButton({ e, inputRom, inputSaveState, setHiddenFormSelectFiles, canvas, printingFrame, setPrintingFrame }) {\n if (canvas == null) {\n alert('Canvas does not exists?');\n return;\n }\n const ctx = canvas.getContext('2d');\n if (ctx == null) {\n alert('Unable to create canvas context, doing nothing');\n return;\n }\n if (inputRom == null || inputSaveState == null || inputRom.files == null || inputSaveState.files == null) {\n alert('Unable to read the files ');\n return;\n }\n if (inputRom.files.length == 0) {\n alert('There is no rom still');\n return;\n }\n if (inputSaveState.files.length == 0) {\n alert('There is no savestate still');\n return;\n }\n const rom_file = inputRom.files[0];\n const savestate_file = inputSaveState.files[0];\n rom_file.arrayBuffer().then((rom_buffer) => {\n savestate_file.arrayBuffer().then((savestate_buffer) => {\n setHiddenFormSelectFiles((c) => true);\n const rom_array = new Uint8Array(rom_buffer);\n const savestate_array = new Uint8Array(savestate_buffer);\n const websocket = new WebSocket(`ws://localhost:3000/ws`);\n websocket.binaryType = 'arraybuffer';\n websocket.onclose = (message) => {\n setHiddenFormSelectFiles(c => false);\n console.log('Closing websocket.');\n };\n websocket.onopen = () => {\n console.log('Opened websocket.');\n sendHello(websocket, rom_array, savestate_array);\n };\n setPrintingFrame(c => false);\n websocket.addEventListener('message', (event) => {\n onWebSocketPacket(event, canvas, ctx, printingFrame, setPrintingFrame);\n });\n });\n });\n}\nfunction concatU8Array(array1, array2) {\n const final_array = new Uint8Array(array1.length + array2.length);\n final_array.set(array1);\n final_array.set(array2, array1.length);\n return final_array;\n}\nfunction sendPacket(websocket, id, raw_data) {\n const packet_u8 = concatU8Array(concatU8Array(_endian__WEBPACK_IMPORTED_MODULE_4__[\"default\"].u64ToByteArrayBigEndian(id), _endian__WEBPACK_IMPORTED_MODULE_4__[\"default\"].u64ToByteArrayBigEndian(BigInt(raw_data.length))), raw_data);\n const packet_buffer = packet_u8.buffer;\n console.log('Sending packet');\n websocket.send(packet_buffer);\n}\nfunction sendHello(websocket, rom_array, savestate_array) {\n console.log('Sending hello.');\n const length_rom = BigInt(rom_array.length);\n const length_savestate = BigInt(savestate_array.length);\n const raw_data = concatU8Array(concatU8Array(concatU8Array(_endian__WEBPACK_IMPORTED_MODULE_4__[\"default\"].u64ToByteArrayBigEndian(length_rom), rom_array), _endian__WEBPACK_IMPORTED_MODULE_4__[\"default\"].u64ToByteArrayBigEndian(length_savestate)), savestate_array);\n sendPacket(websocket, _constants__WEBPACK_IMPORTED_MODULE_5__.PACKET_ID_HELLO, raw_data);\n}\nfunction onWebSocketPacket(event, canvas, ctx, printingFrame, setPrintingFrame) {\n const buffer = event.data;\n let packet_u8 = new Uint8Array(buffer);\n const id = _endian__WEBPACK_IMPORTED_MODULE_4__[\"default\"].byteArrayToU64BigEndian(packet_u8.slice(0, 8));\n packet_u8 = packet_u8.slice(8, packet_u8.length);\n const size = _endian__WEBPACK_IMPORTED_MODULE_4__[\"default\"].byteArrayToU64BigEndian(packet_u8.slice(0, 8));\n const raw_data = packet_u8.slice(8, packet_u8.length);\n packet_u8 = null;\n switch (id) {\n case _constants__WEBPACK_IMPORTED_MODULE_5__.PACKET_ID_SEND_FRAME:\n handleSendFrame(raw_data, canvas, ctx, printingFrame, setPrintingFrame);\n break;\n default:\n console.log(`Received unknown packet ${id}`);\n }\n}\nfunction handleSendFrame(raw_data, canvas, ctx, printingFrame, setPrintingFrame) {\n if (printingFrame) {\n return;\n }\n setPrintingFrame(c => true);\n let data = raw_data;\n const stride = _endian__WEBPACK_IMPORTED_MODULE_4__[\"default\"].byteArrayToU32BigEndian(data.slice(0, 4));\n data = data.slice(4, data.length);\n const output_buffer_size = _endian__WEBPACK_IMPORTED_MODULE_4__[\"default\"].byteArrayToU64BigEndian(data.slice(0, 8));\n data = data.slice(8, data.length);\n const img_data = ctx.createImageData(_constants__WEBPACK_IMPORTED_MODULE_5__.MIN_WIDTH, _constants__WEBPACK_IMPORTED_MODULE_5__.MIN_HEIGHT);\n const img_data_u8 = new Uint8Array(img_data.data.buffer);\n for (let i = 0; i < data.length; i++) {\n if (i % 4 == 3) {\n img_data_u8[i] = 255;\n continue;\n }\n img_data_u8[i] = data[i];\n }\n data = null;\n createImageBitmap(img_data).then((bitmap) => drawBitmap(bitmap, canvas, ctx, printingFrame));\n}\nfunction drawBitmap(bitmap, canvas, ctx, printingFrame) {\n ctx.drawImage(bitmap, 0, 0, canvas.width, canvas.height);\n printingFrame = false;\n}\nfunction Page() {\n const screenDimensions = useScreenDimensions();\n const emulatorDimensions = calculateSizeEmulator(screenDimensions);\n const canvasRef = react__WEBPACK_IMPORTED_MODULE_0__.useRef(null);\n function resizeCanvas() {\n const canvas = canvasRef.current;\n if (canvas == null) {\n return;\n }\n if (emulatorDimensions.width === undefined || emulatorDimensions.height === undefined) {\n return;\n }\n canvas.width = emulatorDimensions.width;\n canvas.height = emulatorDimensions.height;\n const ctx = canvas.getContext('2d');\n if (ctx == null) {\n return;\n }\n fillBlack(canvas, ctx);\n }\n ;\n const [hiddenFormSelectFiles, setHiddenFormSelectFiles] = react__WEBPACK_IMPORTED_MODULE_0__.useState(false);\n const [printingFrame, setPrintingFrame] = react__WEBPACK_IMPORTED_MODULE_0__.useState(false);\n react__WEBPACK_IMPORTED_MODULE_0__.useEffect(resizeCanvas, [emulatorDimensions]);\n const refInputRom = react__WEBPACK_IMPORTED_MODULE_0__.useRef(null);\n const refInputSaveState = react__WEBPACK_IMPORTED_MODULE_0__.useRef(null);\n const onStartEmulation = (e) => {\n handleClickStartEmulationButton({\n e: e,\n setHiddenFormSelectFiles: setHiddenFormSelectFiles,\n inputRom: refInputRom.current,\n inputSaveState: refInputSaveState.current,\n canvas: canvasRef.current,\n setPrintingFrame: setPrintingFrame,\n printingFrame: printingFrame,\n });\n };\n return (react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_components_center_element__WEBPACK_IMPORTED_MODULE_1__[\"default\"], null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"h2\", null, \"msGBA Online Emulator for GBA.\")),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_components_center_element__WEBPACK_IMPORTED_MODULE_1__[\"default\"], null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_components_canvas_gba_emulator__WEBPACK_IMPORTED_MODULE_3__[\"default\"], { canvasRef: canvasRef })),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_components_center_element__WEBPACK_IMPORTED_MODULE_1__[\"default\"], { hidden: hiddenFormSelectFiles },\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_components_form_select_files__WEBPACK_IMPORTED_MODULE_2__[\"default\"], { refInputRom: refInputRom, refInputSaveState: refInputSaveState, onStartEmulation: onStartEmulation }))));\n}\nfunction getScreenDimensions() {\n return {\n width: document.body.clientWidth,\n height: document.body.clientHeight\n };\n}\nfunction useScreenDimensions() {\n const [screenDimensions, setScreenDimensions] = react__WEBPACK_IMPORTED_MODULE_0__.useState(getScreenDimensions());\n react__WEBPACK_IMPORTED_MODULE_0__.useEffect(() => {\n function onResize() {\n setScreenDimensions(getScreenDimensions());\n }\n window.addEventListener(\"resize\", onResize);\n return () => {\n window.removeEventListener(\"resize\", onResize);\n };\n }, []);\n return screenDimensions;\n}\nfunction fillBlack(canvas, ctx) {\n ctx.beginPath();\n ctx.rect(0, 0, canvas.width, canvas.height);\n ctx.fillStyle = 'black';\n ctx.fill();\n}\n;\nfunction calculateSizeEmulator(screenDimensions) {\n if (screenDimensions.width === undefined || screenDimensions.height === undefined) {\n console.error(screenDimensions, 'screenDimensions has undefined fields');\n return {};\n }\n const width = screenDimensions.width;\n const height = screenDimensions.height * 0.75;\n const emulatorDimensions = {};\n if (width < _constants__WEBPACK_IMPORTED_MODULE_5__.MIN_WIDTH || height < _constants__WEBPACK_IMPORTED_MODULE_5__.MIN_HEIGHT) {\n return {\n width: _constants__WEBPACK_IMPORTED_MODULE_5__.MIN_WIDTH,\n height: _constants__WEBPACK_IMPORTED_MODULE_5__.MIN_HEIGHT,\n };\n }\n const ratioWidth = Math.floor(width / _constants__WEBPACK_IMPORTED_MODULE_5__.MIN_WIDTH);\n const ratioHeight = Math.floor(height / _constants__WEBPACK_IMPORTED_MODULE_5__.MIN_HEIGHT);\n if (ratioWidth < ratioHeight) {\n emulatorDimensions.width = _constants__WEBPACK_IMPORTED_MODULE_5__.MIN_WIDTH * ratioWidth;\n emulatorDimensions.height = _constants__WEBPACK_IMPORTED_MODULE_5__.MIN_HEIGHT * ratioWidth;\n }\n else {\n emulatorDimensions.height = _constants__WEBPACK_IMPORTED_MODULE_5__.MIN_HEIGHT * ratioHeight;\n emulatorDimensions.width = _constants__WEBPACK_IMPORTED_MODULE_5__.MIN_WIDTH * ratioHeight;\n }\n return emulatorDimensions;\n}\n\n\n//# sourceURL=webpack://MSGBA-Web/./js-src/components/page.tsx?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ Page)\n/* harmony export */ });\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _components_center_element__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../../components/center-element */ \"./js-src/components/center-element.tsx\");\n/* harmony import */ var _components_form_select_files__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../../components/form-select-files */ \"./js-src/components/form-select-files.tsx\");\n/* harmony import */ var _components_canvas_gba_emulator__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../../components/canvas-gba-emulator */ \"./js-src/components/canvas-gba-emulator.tsx\");\n/* harmony import */ var _endian__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../../../endian */ \"./js-src/endian.ts\");\n/* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../../../constants */ \"./js-src/constants.ts\");\n\n\n\n\n\n\n;\nfunction handleClickStartEmulationButton({ e, inputRom, inputSaveState, setHiddenFormSelectFiles, canvas, printingFrame, setPrintingFrame }) {\n e.preventDefault();\n if (canvas == null) {\n alert('Canvas does not exists?');\n return;\n }\n const ctx = canvas.getContext('2d');\n if (ctx == null) {\n alert('Unable to create canvas context, doing nothing');\n return;\n }\n if (inputRom == null || inputSaveState == null || inputRom.files == null || inputSaveState.files == null) {\n alert('Unable to read the files ');\n return;\n }\n if (inputRom.files.length == 0) {\n alert('There is no rom still');\n return;\n }\n if (inputSaveState.files.length == 0) {\n alert('There is no savestate still');\n return;\n }\n const rom_file = inputRom.files[0];\n const savestate_file = inputSaveState.files[0];\n rom_file.arrayBuffer().then((rom_buffer) => {\n savestate_file.arrayBuffer().then((savestate_buffer) => {\n setHiddenFormSelectFiles((c) => true);\n const rom_array = new Uint8Array(rom_buffer);\n const savestate_array = new Uint8Array(savestate_buffer);\n const websocket = new WebSocket(`ws://${window.location.host}/ws`);\n websocket.binaryType = 'arraybuffer';\n websocket.onclose = (message) => {\n setHiddenFormSelectFiles(c => false);\n console.log('Closing websocket.');\n };\n websocket.onopen = () => {\n console.log('Opened websocket.');\n sendHello(websocket, rom_array, savestate_array);\n };\n setPrintingFrame(c => false);\n websocket.addEventListener('message', (event) => {\n onWebSocketPacket(event, canvas, ctx, printingFrame, setPrintingFrame);\n });\n });\n });\n}\nfunction concatU8Array(array1, array2) {\n const final_array = new Uint8Array(array1.length + array2.length);\n final_array.set(array1);\n final_array.set(array2, array1.length);\n return final_array;\n}\nfunction sendPacket(websocket, id, raw_data) {\n const packet_u8 = concatU8Array(concatU8Array(_endian__WEBPACK_IMPORTED_MODULE_4__[\"default\"].u64ToByteArrayBigEndian(id), _endian__WEBPACK_IMPORTED_MODULE_4__[\"default\"].u64ToByteArrayBigEndian(BigInt(raw_data.length))), raw_data);\n const packet_buffer = packet_u8.buffer;\n console.log('Sending packet');\n websocket.send(packet_buffer);\n}\nfunction sendHello(websocket, rom_array, savestate_array) {\n console.log('Sending hello.');\n const length_rom = BigInt(rom_array.length);\n const length_savestate = BigInt(savestate_array.length);\n const raw_data = concatU8Array(concatU8Array(concatU8Array(_endian__WEBPACK_IMPORTED_MODULE_4__[\"default\"].u64ToByteArrayBigEndian(length_rom), rom_array), _endian__WEBPACK_IMPORTED_MODULE_4__[\"default\"].u64ToByteArrayBigEndian(length_savestate)), savestate_array);\n sendPacket(websocket, _constants__WEBPACK_IMPORTED_MODULE_5__.PACKET_ID_HELLO, raw_data);\n}\nfunction onWebSocketPacket(event, canvas, ctx, printingFrame, setPrintingFrame) {\n const buffer = event.data;\n let packet_u8 = new Uint8Array(buffer);\n const id = _endian__WEBPACK_IMPORTED_MODULE_4__[\"default\"].byteArrayToU64BigEndian(packet_u8.slice(0, 8));\n packet_u8 = packet_u8.slice(8, packet_u8.length);\n const size = _endian__WEBPACK_IMPORTED_MODULE_4__[\"default\"].byteArrayToU64BigEndian(packet_u8.slice(0, 8));\n const raw_data = packet_u8.slice(8, packet_u8.length);\n packet_u8 = null;\n switch (id) {\n case _constants__WEBPACK_IMPORTED_MODULE_5__.PACKET_ID_SEND_FRAME:\n handleSendFrame(raw_data, canvas, ctx, printingFrame, setPrintingFrame);\n break;\n default:\n console.log(`Received unknown packet ${id}`);\n }\n}\nfunction handleSendFrame(raw_data, canvas, ctx, printingFrame, setPrintingFrame) {\n if (printingFrame) {\n return;\n }\n setPrintingFrame(c => true);\n let data = raw_data;\n const stride = _endian__WEBPACK_IMPORTED_MODULE_4__[\"default\"].byteArrayToU32BigEndian(data.slice(0, 4));\n data = data.slice(4, data.length);\n const output_buffer_size = _endian__WEBPACK_IMPORTED_MODULE_4__[\"default\"].byteArrayToU64BigEndian(data.slice(0, 8));\n data = data.slice(8, data.length);\n const img_data = ctx.createImageData(_constants__WEBPACK_IMPORTED_MODULE_5__.MIN_WIDTH, _constants__WEBPACK_IMPORTED_MODULE_5__.MIN_HEIGHT);\n const img_data_u8 = new Uint8Array(img_data.data.buffer);\n for (let i = 0; i < data.length; i++) {\n if (i % 4 == 3) {\n img_data_u8[i] = 255;\n continue;\n }\n img_data_u8[i] = data[i];\n }\n data = null;\n createImageBitmap(img_data).then((bitmap) => drawBitmap(bitmap, canvas, ctx, printingFrame));\n}\nfunction drawBitmap(bitmap, canvas, ctx, printingFrame) {\n ctx.drawImage(bitmap, 0, 0, canvas.width, canvas.height);\n printingFrame = false;\n}\nfunction Page() {\n const screenDimensions = useScreenDimensions();\n const emulatorDimensions = calculateSizeEmulator(screenDimensions);\n const canvasRef = react__WEBPACK_IMPORTED_MODULE_0__.useRef(null);\n function resizeCanvas() {\n const canvas = canvasRef.current;\n if (canvas == null) {\n return;\n }\n if (emulatorDimensions.width === undefined || emulatorDimensions.height === undefined) {\n return;\n }\n canvas.width = emulatorDimensions.width;\n canvas.height = emulatorDimensions.height;\n const ctx = canvas.getContext('2d');\n if (ctx == null) {\n return;\n }\n fillBlack(canvas, ctx);\n }\n ;\n const [hiddenFormSelectFiles, setHiddenFormSelectFiles] = react__WEBPACK_IMPORTED_MODULE_0__.useState(false);\n const [printingFrame, setPrintingFrame] = react__WEBPACK_IMPORTED_MODULE_0__.useState(false);\n react__WEBPACK_IMPORTED_MODULE_0__.useEffect(resizeCanvas, [emulatorDimensions]);\n const refInputRom = react__WEBPACK_IMPORTED_MODULE_0__.useRef(null);\n const refInputSaveState = react__WEBPACK_IMPORTED_MODULE_0__.useRef(null);\n const onStartEmulation = (e) => {\n handleClickStartEmulationButton({\n e: e,\n setHiddenFormSelectFiles: setHiddenFormSelectFiles,\n inputRom: refInputRom.current,\n inputSaveState: refInputSaveState.current,\n canvas: canvasRef.current,\n setPrintingFrame: setPrintingFrame,\n printingFrame: printingFrame,\n });\n };\n const [hiddenMenu, setHiddenMenu] = react__WEBPACK_IMPORTED_MODULE_0__.useState(true);\n let firstMenuElement = react__WEBPACK_IMPORTED_MODULE_0__.useRef(null);\n return (react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", { className: \"overlay\" },\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", { className: \"vertical-padding\" }),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", { className: \"controls\" },\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"a\", { ref: firstMenuElement, className: \"gear control\", onClick: (e) => {\n if (firstMenuElement.current == null) {\n console.log('wtf?');\n return;\n }\n firstMenuElement.current.focus();\n setHiddenMenu(false);\n } },\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"img\", { src: \"/img/home.png\", alt: \"Go to menu. (House icon)\" })))),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", { style: { display: (hiddenMenu ? 'none' : '') }, className: \"overlay-menu\" },\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"ul\", null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"li\", null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"a\", { href: \"#\", onClick: (e) => setHiddenMenu(true) }, \"Exit\")),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"li\", null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"a\", { href: \"#\", onClick: (e) => setHiddenMenu(true) }, \"Exit\")))),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", { style: { display: 'none' }, className: \"menu-select-files\" },\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_components_center_element__WEBPACK_IMPORTED_MODULE_1__[\"default\"], null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_components_form_select_files__WEBPACK_IMPORTED_MODULE_2__[\"default\"], { refInputRom: refInputRom, refInputSaveState: refInputSaveState, onStartEmulation: (e) => {\n setHiddenMenu(true);\n onStartEmulation(e);\n } }))),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_components_center_element__WEBPACK_IMPORTED_MODULE_1__[\"default\"], { full: true },\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_components_canvas_gba_emulator__WEBPACK_IMPORTED_MODULE_3__[\"default\"], { canvasRef: canvasRef })))));\n}\nfunction getScreenDimensions() {\n return {\n width: document.body.clientWidth,\n height: document.body.clientHeight\n };\n}\nfunction useScreenDimensions() {\n const [screenDimensions, setScreenDimensions] = react__WEBPACK_IMPORTED_MODULE_0__.useState(getScreenDimensions());\n react__WEBPACK_IMPORTED_MODULE_0__.useEffect(() => {\n function onResize() {\n setScreenDimensions(getScreenDimensions());\n }\n window.addEventListener(\"resize\", onResize);\n return () => {\n window.removeEventListener(\"resize\", onResize);\n };\n }, []);\n return screenDimensions;\n}\nfunction fillBlack(canvas, ctx) {\n ctx.beginPath();\n ctx.rect(0, 0, canvas.width, canvas.height);\n ctx.fillStyle = '#0E0E10';\n ctx.fill();\n}\n;\nfunction calculateSizeEmulator(screenDimensions) {\n if (screenDimensions.width === undefined || screenDimensions.height === undefined) {\n console.error(screenDimensions, 'screenDimensions has undefined fields');\n return {};\n }\n const width = screenDimensions.width;\n const height = screenDimensions.height;\n const emulatorDimensions = {};\n if (width < _constants__WEBPACK_IMPORTED_MODULE_5__.MIN_WIDTH || height < _constants__WEBPACK_IMPORTED_MODULE_5__.MIN_HEIGHT) {\n return {\n width: _constants__WEBPACK_IMPORTED_MODULE_5__.MIN_WIDTH,\n height: _constants__WEBPACK_IMPORTED_MODULE_5__.MIN_HEIGHT,\n };\n }\n const ratioWidth = width / _constants__WEBPACK_IMPORTED_MODULE_5__.MIN_WIDTH;\n const ratioHeight = height / _constants__WEBPACK_IMPORTED_MODULE_5__.MIN_HEIGHT;\n if (ratioWidth < ratioHeight) {\n emulatorDimensions.width = _constants__WEBPACK_IMPORTED_MODULE_5__.MIN_WIDTH * ratioWidth;\n emulatorDimensions.height = _constants__WEBPACK_IMPORTED_MODULE_5__.MIN_HEIGHT * ratioWidth;\n }\n else {\n emulatorDimensions.height = _constants__WEBPACK_IMPORTED_MODULE_5__.MIN_HEIGHT * ratioHeight;\n emulatorDimensions.width = _constants__WEBPACK_IMPORTED_MODULE_5__.MIN_WIDTH * ratioHeight;\n }\n return emulatorDimensions;\n}\n\n\n//# sourceURL=webpack://MSGBA-Web/./js-src/components/page.tsx?"); /***/ }),