Migrating the project to typescript.
This commit is contained in:
parent
d7b9d9d664
commit
13a948b21a
|
@ -1,7 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
import {MIN_WIDTH, MIN_HEIGHT} from '/constants';
|
|
||||||
|
|
||||||
export default function CanvasGBAEmulator(props) {
|
|
||||||
return (<canvas ref={props.canvasRef} width={MIN_WIDTH} height={MIN_HEIGHT}></canvas>);
|
|
||||||
}
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
import {MIN_WIDTH, MIN_HEIGHT} from '/constants';
|
||||||
|
|
||||||
|
export interface CanvasGBAEmulatorProps {
|
||||||
|
canvasRef: React.RefObject<HTMLCanvasElement>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function CanvasGBAEmulator(props: CanvasGBAEmulatorProps) {
|
||||||
|
return (<canvas ref={props.canvasRef} width={MIN_WIDTH} height={MIN_HEIGHT}></canvas>);
|
||||||
|
}
|
|
@ -1,13 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
export default function CenterElement(props) {
|
|
||||||
let hidden = props.hidden;
|
|
||||||
if (hidden == null) {
|
|
||||||
hidden = false;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div style={{
|
|
||||||
display: hidden ? 'none':''
|
|
||||||
}} className="center-content">{props.children}</div>
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
export interface CenterElementProps {
|
||||||
|
hidden?: boolean | undefined,
|
||||||
|
children?: React.ReactNode,
|
||||||
|
}
|
||||||
|
|
||||||
|
type IHash = {
|
||||||
|
[id: string]: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function CenterElement(props: CenterElementProps) {
|
||||||
|
const styles: IHash = {};
|
||||||
|
let hidden = props.hidden;
|
||||||
|
if (hidden == null) {
|
||||||
|
hidden = false;
|
||||||
|
}
|
||||||
|
styles["display"] = hidden ? 'none' : '';
|
||||||
|
return (
|
||||||
|
<div style={styles} className="center-content">{props.children}</div>
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,6 +1,12 @@
|
||||||
import React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
export default function FormSelectFiles(props) {
|
export interface FormSelectFilesProps {
|
||||||
|
refInputRom: React.RefObject<HTMLInputElement>;
|
||||||
|
refInputSaveState: React.RefObject<HTMLInputElement>;
|
||||||
|
onStartEmulation: React.MouseEventHandler<HTMLInputElement>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function FormSelectFiles(props: FormSelectFilesProps) {
|
||||||
const inputRom = props.refInputRom ? props.refInputRom : React.useRef(null);
|
const inputRom = props.refInputRom ? props.refInputRom : React.useRef(null);
|
||||||
const inputSaveState = props.refInputSaveState ? props.refInputSaveState : React.useRef(null);
|
const inputSaveState = props.refInputSaveState ? props.refInputSaveState : React.useRef(null);
|
||||||
const onStartEmulation = props.onStartEmulation;
|
const onStartEmulation = props.onStartEmulation;
|
||||||
|
@ -15,7 +21,7 @@ export default function FormSelectFiles(props) {
|
||||||
Savestate (A ss file from mgba...)
|
Savestate (A ss file from mgba...)
|
||||||
<input type="file" ref={inputSaveState} name="savestate"/>
|
<input type="file" ref={inputSaveState} name="savestate"/>
|
||||||
</label>
|
</label>
|
||||||
<input type="button" value="Start emulation" onClick={onStartEmulation} ref={props.startEmulationButton}/>
|
<input type="button" value="Start emulation" onClick={onStartEmulation}/>
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
import React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
import CenterElement from '/components/center-element';
|
import CenterElement from '/components/center-element';
|
||||||
import FormSelectFiles from '/components/form-select-files';
|
import FormSelectFiles from '/components/form-select-files';
|
||||||
|
@ -8,9 +8,32 @@ import Endian from '/endian';
|
||||||
|
|
||||||
import {MIN_WIDTH, MIN_HEIGHT, PACKET_ID_HELLO, PACKET_ID_SEND_FRAME} from '/constants';
|
import {MIN_WIDTH, MIN_HEIGHT, PACKET_ID_HELLO, PACKET_ID_SEND_FRAME} from '/constants';
|
||||||
|
|
||||||
function handleClickStartEmulationButton({e, inputRom, inputSaveState, setHiddenFormSelectFiles, canvas}) {
|
type setBooleanCallback = (c: boolean) => boolean;
|
||||||
|
|
||||||
|
export interface handleClickStartEmulationButtonObjectArgs {
|
||||||
|
e: React.MouseEvent<HTMLInputElement>;
|
||||||
|
inputRom: HTMLInputElement | null;
|
||||||
|
inputSaveState: HTMLInputElement | null;
|
||||||
|
setHiddenFormSelectFiles: (c: setBooleanCallback) => void;
|
||||||
|
canvas: HTMLCanvasElement | null;
|
||||||
|
printingFrame: boolean;
|
||||||
|
setPrintingFrame: (c: setBooleanCallback) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
function handleClickStartEmulationButton({e, inputRom, inputSaveState, setHiddenFormSelectFiles, canvas, printingFrame, setPrintingFrame}: handleClickStartEmulationButtonObjectArgs) {
|
||||||
|
if (canvas == null) {
|
||||||
|
alert('Canvas does not exists?');
|
||||||
|
return;
|
||||||
|
}
|
||||||
const ctx = canvas.getContext('2d')
|
const ctx = canvas.getContext('2d')
|
||||||
e.preventDefault();
|
if (ctx == null) {
|
||||||
|
alert('Unable to create canvas context, doing nothing');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (inputRom == null || inputSaveState == null || inputRom.files == null || inputSaveState.files == null) {
|
||||||
|
alert('Unable to read the files ');
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (inputRom.files.length == 0) {
|
if (inputRom.files.length == 0) {
|
||||||
alert('There is no rom still');
|
alert('There is no rom still');
|
||||||
return;
|
return;
|
||||||
|
@ -23,42 +46,37 @@ function handleClickStartEmulationButton({e, inputRom, inputSaveState, setHidden
|
||||||
const savestate_file = inputSaveState.files[0];
|
const savestate_file = inputSaveState.files[0];
|
||||||
rom_file.arrayBuffer().then((rom_buffer) => {
|
rom_file.arrayBuffer().then((rom_buffer) => {
|
||||||
savestate_file.arrayBuffer().then((savestate_buffer) => {
|
savestate_file.arrayBuffer().then((savestate_buffer) => {
|
||||||
|
setHiddenFormSelectFiles((c: boolean) => true);
|
||||||
const rom_array = new Uint8Array(rom_buffer);
|
const rom_array = new Uint8Array(rom_buffer);
|
||||||
const savestate_array = new Uint8Array(savestate_buffer);
|
const savestate_array = new Uint8Array(savestate_buffer);
|
||||||
const websocket = new WebSocket(`ws://localhost:3000/ws`);
|
const websocket = new WebSocket(`ws://localhost:3000/ws`);
|
||||||
websocket.binaryType = 'arraybuffer';
|
websocket.binaryType = 'arraybuffer';
|
||||||
websocket.onclose = (message) => console.log('CLOSE', message);
|
websocket.onclose = (message) => {
|
||||||
websocket.onopen = () => {
|
|
||||||
setHiddenFormSelectFiles(c => false);
|
setHiddenFormSelectFiles(c => false);
|
||||||
|
console.log('Closing websocket.');
|
||||||
|
}
|
||||||
|
websocket.onopen = () => {
|
||||||
console.log('Opened websocket.');
|
console.log('Opened websocket.');
|
||||||
sendHello(websocket, rom_array, savestate_array);
|
sendHello(websocket, rom_array, savestate_array);
|
||||||
};
|
};
|
||||||
websocket.addEventListener('message', (event) => onWebSocketPacket(event, canvas, ctx));
|
setPrintingFrame(c => false);
|
||||||
|
websocket.addEventListener('message', (event) => {
|
||||||
|
onWebSocketPacket(event, canvas, ctx, printingFrame, setPrintingFrame)
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function concatU8Array(array1, array2) {
|
function concatU8Array(array1: Uint8Array, array2: Uint8Array) {
|
||||||
const final_array = new Uint8Array(array1.length + array2.length);
|
const final_array = new Uint8Array(array1.length + array2.length);
|
||||||
final_array.set(array1);
|
final_array.set(array1);
|
||||||
final_array.set(array2, array1.length);
|
final_array.set(array2, array1.length);
|
||||||
return final_array;
|
return final_array;
|
||||||
}
|
}
|
||||||
|
|
||||||
function u64ToByteArrayBigEndian(input_number) {
|
function sendPacket(websocket: WebSocket, id: bigint, raw_data: Uint8Array) {
|
||||||
const buffer = new ArrayBuffer(8);
|
|
||||||
const buffer8 = new Uint8Array(buffer);
|
|
||||||
const buffer64 = new BigUint64Array(buffer);
|
|
||||||
buffer64[0] = input_number;
|
|
||||||
if (Endian.isLittleEndian()) {
|
|
||||||
buffer8.reverse();
|
|
||||||
}
|
|
||||||
return buffer8;
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendPacket(websocket, id, raw_data) {
|
|
||||||
const packet_u8 = concatU8Array(
|
const packet_u8 = concatU8Array(
|
||||||
concatU8Array(u64ToByteArrayBigEndian(id), u64ToByteArrayBigEndian(BigInt(raw_data.length))),
|
concatU8Array(Endian.u64ToByteArrayBigEndian(id), Endian.u64ToByteArrayBigEndian(BigInt(raw_data.length))),
|
||||||
raw_data
|
raw_data
|
||||||
);
|
);
|
||||||
const packet_buffer = packet_u8.buffer;
|
const packet_buffer = packet_u8.buffer;
|
||||||
|
@ -66,50 +84,48 @@ function sendPacket(websocket, id, raw_data) {
|
||||||
websocket.send(packet_buffer);
|
websocket.send(packet_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendHello(websocket, rom_array, savestate_array) {
|
function sendHello(websocket: WebSocket, rom_array: Uint8Array, savestate_array: Uint8Array) {
|
||||||
console.log('Sending hello.');
|
console.log('Sending hello.');
|
||||||
const length_rom = BigInt(rom_array.length);
|
const length_rom = BigInt(rom_array.length);
|
||||||
const length_savestate = BigInt(savestate_array.length);
|
const length_savestate = BigInt(savestate_array.length);
|
||||||
const raw_data =
|
const raw_data =
|
||||||
concatU8Array(
|
concatU8Array(
|
||||||
concatU8Array(
|
concatU8Array(
|
||||||
concatU8Array(u64ToByteArrayBigEndian(length_rom), rom_array),
|
concatU8Array(Endian.u64ToByteArrayBigEndian(length_rom), rom_array),
|
||||||
u64ToByteArrayBigEndian(length_savestate)
|
Endian.u64ToByteArrayBigEndian(length_savestate)
|
||||||
),
|
),
|
||||||
savestate_array
|
savestate_array
|
||||||
);
|
);
|
||||||
sendPacket(websocket, PACKET_ID_HELLO, raw_data);
|
sendPacket(websocket, PACKET_ID_HELLO, raw_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onWebSocketPacket(event, canvas, ctx) {
|
function onWebSocketPacket(event: MessageEvent, canvas: HTMLCanvasElement, ctx: CanvasRenderingContext2D, printingFrame: boolean, setPrintingFrame: (c: setBooleanCallback) => void) {
|
||||||
const buffer = event.data;
|
const buffer = event.data;
|
||||||
let packet_u8 = new Uint8Array(buffer);
|
let packet_u8: Uint8Array | null = new Uint8Array(buffer);
|
||||||
const id = byteArrayToU64BigEndian(packet_u8.slice(0, 8));
|
const id = Endian.byteArrayToU64BigEndian(packet_u8.slice(0, 8));
|
||||||
packet_u8 = packet_u8.slice(8, packet_u8.length);
|
packet_u8 = packet_u8.slice(8, packet_u8.length);
|
||||||
const size = byteArrayToU64BigEndian(packet_u8.slice(0, 8));
|
const size = Endian.byteArrayToU64BigEndian(packet_u8.slice(0, 8));
|
||||||
const raw_data = packet_u8.slice(8, packet_u8.length);
|
const raw_data = packet_u8.slice(8, packet_u8.length);
|
||||||
packet_u8 = null;
|
packet_u8 = null;
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case PACKET_ID_SEND_FRAME:
|
case PACKET_ID_SEND_FRAME:
|
||||||
handleSendFrame(raw_data, canvas, ctx);
|
handleSendFrame(raw_data, canvas, ctx, printingFrame, setPrintingFrame);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
console.log(`Received unknown packet ${id}`);
|
console.log(`Received unknown packet ${id}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let printing_frame = false;
|
function handleSendFrame(raw_data: Uint8Array, canvas: HTMLCanvasElement, ctx: CanvasRenderingContext2D, printingFrame: boolean, setPrintingFrame: (c: setBooleanCallback) => void) {
|
||||||
function handleSendFrame(raw_data, canvas, ctx) {
|
if (printingFrame) {
|
||||||
if (printing_frame) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
printing_frame = true;
|
setPrintingFrame(c => true);
|
||||||
let data = raw_data;
|
let data: Uint8Array | null = raw_data;
|
||||||
const stride = byteArrayToU32BigEndian(data.slice(0, 4));
|
const stride = Endian.byteArrayToU32BigEndian(data.slice(0, 4));
|
||||||
data = data.slice(4, data.length);
|
data = data.slice(4, data.length);
|
||||||
const output_buffer_size = byteArrayToU32BigEndian(data.slice(0, 8));
|
const output_buffer_size = Endian.byteArrayToU64BigEndian(data.slice(0, 8));
|
||||||
data = data.slice(8, data.length);
|
data = data.slice(8, data.length);
|
||||||
console.log(data.length / 4 / MIN_WIDTH);
|
|
||||||
const img_data = ctx.createImageData(MIN_WIDTH, MIN_HEIGHT);
|
const img_data = ctx.createImageData(MIN_WIDTH, MIN_HEIGHT);
|
||||||
const img_data_u8 = new Uint8Array(img_data.data.buffer);
|
const img_data_u8 = new Uint8Array(img_data.data.buffer);
|
||||||
for (let i = 0; i<data.length; i++) {
|
for (let i = 0; i<data.length; i++) {
|
||||||
|
@ -120,56 +136,48 @@ function handleSendFrame(raw_data, canvas, ctx) {
|
||||||
img_data_u8[i] = data[i];
|
img_data_u8[i] = data[i];
|
||||||
}
|
}
|
||||||
data = null;
|
data = null;
|
||||||
createImageBitmap(img_data).then((bitmap) => drawBitmap(bitmap, canvas, ctx));
|
createImageBitmap(img_data).then((bitmap) => drawBitmap(bitmap, canvas, ctx, printingFrame));
|
||||||
}
|
}
|
||||||
|
|
||||||
function byteArrayToU32BigEndian(input_array) {
|
function drawBitmap(bitmap: ImageBitmap, canvas: HTMLCanvasElement, ctx: CanvasRenderingContext2D, printingFrame: boolean) {
|
||||||
if (Endian.isLittleEndian()) {
|
|
||||||
input_array = input_array.reverse();
|
|
||||||
}
|
|
||||||
const buffer = input_array.buffer;
|
|
||||||
const output_u32_array = new Uint32Array(buffer);
|
|
||||||
return output_u32_array[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
function byteArrayToU64BigEndian(input_array) {
|
|
||||||
if (Endian.isLittleEndian()) {
|
|
||||||
input_array = input_array.reverse();
|
|
||||||
}
|
|
||||||
const buffer = input_array.buffer;
|
|
||||||
const output_u64_array = new BigUint64Array(buffer);
|
|
||||||
return output_u64_array[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
function drawBitmap(bitmap, canvas, ctx) {
|
|
||||||
ctx.drawImage(bitmap, 0, 0, canvas.width, canvas.height);
|
ctx.drawImage(bitmap, 0, 0, canvas.width, canvas.height);
|
||||||
printing_frame = false;
|
printingFrame = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
const screenDimensions = useScreenDimensions();
|
const screenDimensions = useScreenDimensions();
|
||||||
const emulatorDimensions = calculateSizeEmulator(screenDimensions);
|
const emulatorDimensions = calculateSizeEmulator(screenDimensions);
|
||||||
const canvasRef = React.useRef(null);
|
const canvasRef = React.useRef<HTMLCanvasElement>(null);
|
||||||
function resizeCanvas(node) {
|
function resizeCanvas() {
|
||||||
const canvas = canvasRef.current;
|
const canvas = canvasRef.current;
|
||||||
if (canvas) {
|
if (canvas == null) {
|
||||||
canvas.width = emulatorDimensions.width;
|
return;
|
||||||
canvas.height = emulatorDimensions.height;
|
|
||||||
const ctx = canvas.getContext('2d')
|
|
||||||
fillBlack(canvas, ctx);
|
|
||||||
}
|
}
|
||||||
|
if (emulatorDimensions.width === undefined || emulatorDimensions.height === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
canvas.width = emulatorDimensions.width;
|
||||||
|
canvas.height = emulatorDimensions.height;
|
||||||
|
const ctx = canvas.getContext('2d')
|
||||||
|
if (ctx == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fillBlack(canvas, ctx);
|
||||||
};
|
};
|
||||||
const [hiddenFormSelectFiles, setHiddenFormSelectFiles] = React.useState(false);
|
const [hiddenFormSelectFiles, setHiddenFormSelectFiles] = React.useState<boolean>(false);
|
||||||
|
const [printingFrame, setPrintingFrame] = React.useState<boolean>(false);
|
||||||
React.useEffect(resizeCanvas, [emulatorDimensions]);
|
React.useEffect(resizeCanvas, [emulatorDimensions]);
|
||||||
const refInputRom = React.useRef(null);
|
const refInputRom = React.useRef<HTMLInputElement | null>(null);
|
||||||
const refInputSaveState = React.useRef(null);
|
const refInputSaveState = React.useRef<HTMLInputElement | null>(null);
|
||||||
const onStartEmulation = (e) => {
|
const onStartEmulation = (e: React.MouseEvent<HTMLInputElement>) => {
|
||||||
handleClickStartEmulationButton({
|
handleClickStartEmulationButton({
|
||||||
e: e,
|
e: e,
|
||||||
setHiddenFormSelectFiles: setHiddenFormSelectFiles,
|
setHiddenFormSelectFiles: setHiddenFormSelectFiles,
|
||||||
inputRom: refInputRom.current,
|
inputRom: refInputRom.current,
|
||||||
inputSaveState: refInputSaveState.current,
|
inputSaveState: refInputSaveState.current,
|
||||||
canvas: canvasRef.current,
|
canvas: canvasRef.current,
|
||||||
|
setPrintingFrame: setPrintingFrame,
|
||||||
|
printingFrame: printingFrame,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
|
@ -198,7 +206,7 @@ function getScreenDimensions() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function useScreenDimensions() {
|
function useScreenDimensions() {
|
||||||
const [screenDimensions, setScreenDimensions] = React.useState(getScreenDimensions());
|
const [screenDimensions, setScreenDimensions] = React.useState<EmulatorDimensions>(getScreenDimensions());
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
function onResize() {
|
function onResize() {
|
||||||
|
@ -215,17 +223,25 @@ function useScreenDimensions() {
|
||||||
return screenDimensions;
|
return screenDimensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
function fillBlack(canvas, ctx) {
|
function fillBlack(canvas: HTMLCanvasElement, ctx: CanvasRenderingContext2D) {
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.rect(0, 0, canvas.width, canvas.height);
|
ctx.rect(0, 0, canvas.width, canvas.height);
|
||||||
ctx.fillStyle = 'black';
|
ctx.fillStyle = 'black';
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
}
|
}
|
||||||
|
|
||||||
function calculateSizeEmulator(screenDimensions) {
|
export interface EmulatorDimensions {
|
||||||
|
width?: number;
|
||||||
|
height?: number;
|
||||||
|
};
|
||||||
|
function calculateSizeEmulator(screenDimensions: EmulatorDimensions): EmulatorDimensions {
|
||||||
|
if (screenDimensions.width === undefined || screenDimensions.height === undefined) {
|
||||||
|
console.error(screenDimensions, 'screenDimensions has undefined fields');
|
||||||
|
return {};
|
||||||
|
}
|
||||||
const width = screenDimensions.width;
|
const width = screenDimensions.width;
|
||||||
const height = screenDimensions.height * 0.75;
|
const height = screenDimensions.height * 0.75;
|
||||||
const emulatorDimensions = {};
|
const emulatorDimensions: EmulatorDimensions = {};
|
||||||
if (width < MIN_WIDTH || height < MIN_HEIGHT) {
|
if (width < MIN_WIDTH || height < MIN_HEIGHT) {
|
||||||
return {
|
return {
|
||||||
width: MIN_WIDTH,
|
width: MIN_WIDTH,
|
|
@ -3,6 +3,11 @@ export const MIN_HEIGHT = 160;
|
||||||
export const PACKET_ID_HELLO = 0n;
|
export const PACKET_ID_HELLO = 0n;
|
||||||
export const PACKET_ID_SEND_FRAME = 1n;
|
export const PACKET_ID_SEND_FRAME = 1n;
|
||||||
export default class Constants {
|
export default class Constants {
|
||||||
|
public static MIN_WIDTH: number = MIN_WIDTH;
|
||||||
|
public static MIN_HEIGHT: number = MIN_HEIGHT;
|
||||||
|
public static PACKET_ID_HELLO: bigint = PACKET_ID_HELLO;
|
||||||
|
public static PACKET_ID_SEND_FRAME: bigint = PACKET_ID_SEND_FRAME;
|
||||||
|
|
||||||
};
|
};
|
||||||
Constants.MIN_WIDTH = MIN_WIDTH;
|
Constants.MIN_WIDTH = MIN_WIDTH;
|
||||||
Constants.MIN_HEIGHT = MIN_HEIGHT;
|
Constants.MIN_HEIGHT = MIN_HEIGHT;
|
|
@ -1,18 +0,0 @@
|
||||||
"use strict";
|
|
||||||
|
|
||||||
let littleEndian = true;
|
|
||||||
(()=>{
|
|
||||||
let buf = new ArrayBuffer(4);
|
|
||||||
let buf8 = new Uint8ClampedArray(buf);
|
|
||||||
let data = new Uint32Array(buf);
|
|
||||||
data[0] = 0xdeadbeef;
|
|
||||||
if(buf8[0] === 0xde){
|
|
||||||
littleEndian = false;
|
|
||||||
}
|
|
||||||
})()
|
|
||||||
|
|
||||||
export default class Endian {
|
|
||||||
static isLittleEndian() {
|
|
||||||
return littleEndian;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
let littleEndian = true; (()=>{ let buf = new ArrayBuffer(4); let buf8 = new
|
||||||
|
Uint8ClampedArray(buf); let data = new Uint32Array(buf); data[0] = 0xdeadbeef;
|
||||||
|
if(buf8[0] === 0xde){ littleEndian = false; } })()
|
||||||
|
|
||||||
|
export default class Endian {
|
||||||
|
static isLittleEndian() {
|
||||||
|
return littleEndian;
|
||||||
|
}
|
||||||
|
|
||||||
|
static byteArrayToU32BigEndian(inputArray: Uint8Array) {
|
||||||
|
if (Endian.isLittleEndian()) {
|
||||||
|
inputArray = inputArray.reverse();
|
||||||
|
}
|
||||||
|
const buffer = inputArray.buffer;
|
||||||
|
const outputU32Array = new Uint32Array(buffer);
|
||||||
|
return outputU32Array[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
static byteArrayToU64BigEndian(inputArray: Uint8Array) {
|
||||||
|
if (Endian.isLittleEndian()) {
|
||||||
|
inputArray = inputArray.reverse();
|
||||||
|
}
|
||||||
|
const buffer = inputArray.buffer;
|
||||||
|
const outputU64Array = new BigUint64Array(buffer);
|
||||||
|
return outputU64Array[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
static u64ToByteArrayBigEndian(inputNumber: bigint) {
|
||||||
|
const buffer = new ArrayBuffer(8);
|
||||||
|
const buffer8 = new Uint8Array(buffer);
|
||||||
|
const buffer64 = new BigUint64Array(buffer);
|
||||||
|
buffer64[0] = inputNumber;
|
||||||
|
if (Endian.isLittleEndian()) {
|
||||||
|
buffer8.reverse();
|
||||||
|
}
|
||||||
|
return buffer8;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,12 +0,0 @@
|
||||||
"use strict";
|
|
||||||
import React from 'react';
|
|
||||||
import ReactDOMClient from 'react-dom/client';
|
|
||||||
|
|
||||||
import Endian from '/endian';
|
|
||||||
import Page from '/components/page';
|
|
||||||
|
|
||||||
const body = document.querySelector('body');
|
|
||||||
const app = document.createElement('div');
|
|
||||||
body.appendChild(app);
|
|
||||||
const root = ReactDOMClient.createRoot(app);
|
|
||||||
root.render(<Page/>);
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
"use strict";
|
||||||
|
import * as React from 'react';
|
||||||
|
import * as ReactDOMClient from 'react-dom/client';
|
||||||
|
|
||||||
|
import Endian from '/endian';
|
||||||
|
import Page from '/components/page';
|
||||||
|
|
||||||
|
const body = document.querySelector('body');
|
||||||
|
if (body != null) {
|
||||||
|
fillBody(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
function fillBody(body: HTMLElement) {
|
||||||
|
const app = document.createElement('div');
|
||||||
|
body.appendChild(app);
|
||||||
|
const root = ReactDOMClient.createRoot(app);
|
||||||
|
root.render(<Page/>);
|
||||||
|
}
|
|
@ -11,8 +11,12 @@
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/preset-react": "^7.18.6",
|
"@babel/preset-react": "^7.18.6",
|
||||||
|
"@types/react": "^18.0.28",
|
||||||
|
"@types/react-dom": "^18.0.11",
|
||||||
"babel-loader": "^9.1.2",
|
"babel-loader": "^9.1.2",
|
||||||
"file-loader": "^6.2.0",
|
"file-loader": "^6.2.0",
|
||||||
|
"ts-loader": "^9.4.2",
|
||||||
|
"typescript": "^5.0.2",
|
||||||
"url-loader": "^4.1.1",
|
"url-loader": "^4.1.1",
|
||||||
"webpack": "^5.38.1",
|
"webpack": "^5.38.1",
|
||||||
"webpack-cli": "^4.7.2"
|
"webpack-cli": "^4.7.2"
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./public/js/",
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"module": "es2020",
|
||||||
|
"target": "es2020",
|
||||||
|
"jsx": "react",
|
||||||
|
"allowJs": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"strictNullChecks": true,
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {
|
||||||
|
"*": ["js-src/*"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"include": ["js-src/*.ts", "js-src/*/*.ts" ]
|
||||||
|
}
|
|
@ -1,23 +1,25 @@
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
entry: './js-src/index.jsx',
|
entry: './js-src/index.tsx',
|
||||||
mode: 'development',
|
mode: 'development',
|
||||||
output: {
|
output: {
|
||||||
filename: 'bundle.js',
|
filename: 'bundle.js',
|
||||||
path: path.resolve(__dirname, 'public/js/'),
|
path: path.resolve(__dirname, 'public/js/'),
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: [
|
extensions: [ '.js', '.jsx','.ts', '.tsx' ],
|
||||||
'.js',
|
|
||||||
'.jsx',
|
|
||||||
],
|
|
||||||
roots: [
|
roots: [
|
||||||
path.resolve(__dirname, 'js-src/')
|
path.resolve(__dirname, 'js-src/')
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.tsx?$/,
|
||||||
|
use: 'ts-loader',
|
||||||
|
exclude: /node_modules/,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
test: /\.jpe?g|png$/,
|
test: /\.jpe?g|png$/,
|
||||||
exclude: /node_modules/,
|
exclude: /node_modules/,
|
||||||
|
|
Loading…
Reference in New Issue