From 9650bad8f80df3a145413a67d4d4c54d09c31e62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Magalh=C3=A3es?= <joamag@gmail.com> Date: Thu, 23 Jun 2022 15:16:35 +0100 Subject: [PATCH] feat: retina canvas support Also added error icon --- examples/web/index.css | 2 ++ examples/web/index.ts | 58 ++++++++++++++++++++++++++++++++----- examples/web/res/storm.png | Bin 0 -> 1889 bytes 3 files changed, 53 insertions(+), 7 deletions(-) create mode 100644 examples/web/res/storm.png diff --git a/examples/web/index.css b/examples/web/index.css index 5a483d5..3145e88 100644 --- a/examples/web/index.css +++ b/examples/web/index.css @@ -88,6 +88,8 @@ p { border: 2px solid #50cb93; margin-top: 76px; max-width: 100%; + width: 640px; + height: 320px; padding: 8px 8px 8px 8px; } diff --git a/examples/web/index.ts b/examples/web/index.ts index 4911362..2be3cc5 100644 --- a/examples/web/index.ts +++ b/examples/web/index.ts @@ -3,7 +3,6 @@ import info from "./package.json"; const PIXEL_SET_COLOR = 0x50cb93ff; const PIXEL_UNSET_COLOR = 0x1b1a17ff; -const PIXEL_ERROR_COLOR = 0xe63946ff; const LOGIC_HZ = 600; const VISUAL_HZ = 60; @@ -179,7 +178,11 @@ const main = async () => { // system and the machine state (to be able to recover) // also sets the default color on screen to indicate the issue if (isPanic) { - clearCanvas(); + clearCanvas(undefined, { + // @ts-ignore: ts(2580) + image: require("./res/storm.png"), + imageScale: 0.4 + }); await wasm(); await start({ restore: false }); @@ -649,6 +652,10 @@ const initCanvas = async () => { state.canvasScaled = document.getElementById( "chip-canvas" ) as HTMLCanvasElement; + state.canvasScaled.width = + state.canvasScaled.width * window.devicePixelRatio; + state.canvasScaled.height = + state.canvasScaled.height * window.devicePixelRatio; state.canvasScaledCtx = state.canvasScaled.getContext("2d"); state.canvasScaledCtx.scale( @@ -675,12 +682,49 @@ const updateCanvas = (pixels: Uint8Array) => { state.canvasScaledCtx.drawImage(state.canvas, 0, 0); }; -const clearCanvas = (color = PIXEL_UNSET_COLOR) => { - for (let i = 0; i < DISPLAY_WIDTH * DISPLAY_HEIGHT; i++) { - state.videoBuff.setUint32(i * 4, color); +const clearCanvas = ( + color = PIXEL_UNSET_COLOR, + { image = null as string, imageScale = 1 } = {} +) => { + state.canvasScaledCtx.fillStyle = `#${color.toString(16).toUpperCase()}`; + state.canvasScaledCtx.fillRect( + 0, + 0, + state.canvasScaled.width, + state.canvasScaled.height + ); + + // in case an image was requested then uses that to load + // an image at the center of the screen + if (image) { + const img = new Image(); + img.onload = () => { + const [imgWidth, imgHeight] = [ + img.width * imageScale, + img.height * imageScale + ]; + const [x0, y0] = [ + state.canvasScaled.width / 2 - imgWidth / 2, + state.canvasScaled.height / 2 - imgHeight / 2 + ]; + state.canvasScaledCtx.setTransform(1, 0, 0, 1, 0, 0); + try { + state.canvasScaledCtx.drawImage( + img, + x0, + y0, + imgWidth, + imgHeight + ); + } finally { + state.canvasScaledCtx.scale( + state.canvasScaled.width / state.canvas.width, + state.canvasScaled.height / state.canvas.height + ); + } + }; + img.src = image; } - state.canvasCtx.putImageData(state.image, 0, 0); - state.canvasScaledCtx.drawImage(state.canvas, 0, 0); }; const showToast = async (message: string, error = false, timeout = 3500) => { diff --git a/examples/web/res/storm.png b/examples/web/res/storm.png new file mode 100644 index 0000000000000000000000000000000000000000..afcff7338dad180df01cfab7bffc39a85ffc50e4 GIT binary patch literal 1889 zcmeAS@N?(olHy`uVBq!ia0y~yU;;9k7&w@L)Zt|+Cx8@lv6E*A2M5RPhyD+MT+RZI z$YP-K>mbbNq%pe!C@5Lt8c`CQpH@<ySd_|8US6)3nU`IhoLG>mmtT}V`<;yx0|TRb zfKQ0)|NsA8Ts%5ECR9~6<mMJTJG(cPc{Y{0R%R$zS=u@}xHvdCm!~P%+dG+?TiMw< z+S)o6CCb^@*cT+oSzFmzm|JH=%GldGTUywdn3&tyIojJf#RW>o_(_C#hy}Weg?UM6 zY3leoiDpL0sH<yw+KWW`h?|>R12q~On<*=+I+_bAC@7if@%j4&`TGS+NJwd`@&p8g z3J3`L`37-w^N0$u0e!^A%EZpb#LvSbBFHKx%q}U)E-5K3Bf%~wD=#n2p`@gus=%eD zz@??7tFOTebcwk>zlDXhy_uk=ov^2)LV$~CU|?ueWL#{BL0oKdc2+@tUTINbMR|Tu zRaIk6byIy^TSHZPLw#FAeS1@FZd+?_d$CG;TVH2;S7&=KFnp#rYAo*7UEZ&Iexv!d z?UuK9TRlH&_x-Zd-y6>VZ@EOtI>!KAX<icK7tFxK!O0~cCaz~-YGvaV5E>qpl2Xv# z-rKie*|N3k4;?>s{`~o?SFhc;`QYKh=WjoK`uyeRuU~)vzT;9`!@$7m>FMGaQgQ3; z9p8MPM2X{xZp+X3Yz<l_<+x%M3wLM7`q#=HZ*)}6gqk|aIfdK;H(!{w@8yjR8-Fe@ zt}<F~e0}S@Cp*s<|G!imwpRAW`E_^KG-Ut&#g)x2k<BE)z~sQd!N91%z|z1#6el2{ z*zo22H4Squ(wrHXXWGn*u?S@BE<Ce~IPJ)`e9L86d-Fko@=BL|TP@OzZ8NiVm}l&k zh>7x8wp!poiA=Gk?aMjg3```t5ZMZluNoL)8W{u}1l`y3rCodb-`M(rsN7l?hOgHW z)O7yM?_^xR;hiYD9&DDP2GfJ}Gs`Z_(DPh8drkO5uIrCytlgCN!sFK2Gjc2!;yCo? zX`a0De2Em}5yRQ3cP|9p^1ZFiz=$5o=zI)UEEYJ>oAN8hApTlT@XIH~Yqeq$wfihX zuU-87@=0>x-mNc6v@@oCt!Te=a&46;(~9GU{8LLyjOW&9y}vH+c%QV01zLV!-pl_I zg0q<<bQ;ce+#o7Bpg8$}1-rq;H4Vy460=T+YdzRRdXivq;AGt69k-X?Dz7lYD${)Z z<ErfYlkaCco>yvHI=yVO?Df~852P_e62%!99A%*cx6UV2s@{~Cc>2~Yj%~M2x>zNb zrixFyoOkV;Lc_Vw2|v9z*(ou8na8I8e3Dzwo6~wa%kP$aQ(&lJCKyLdXvwq3f#I(E z$+yu5?}{IM{rY6eNA}8}20Ol6R1~b<VBKG~FuIfBSM<sEa~~x9a@;>nM(3YG;hDN$ z;)b)WTXXZ@I^D;TPB1)#o^Supj^#MVm9WHjTXQ8wD#O%`?&4yGzh@6^d#reNW<n5y zGxr0}MES>x&!;ziM)w<P7Qh}2$<hb5Z*TppWp}i_<k;UY&E`xJXMTAlS|42=@s{m& zX2&`*QboWCH~pVqlwWWr$Vb;stEm&N5oI9VZ4yoPS;s!#`w(@ri~$HdUHx3vIVCg! E0K_r{ssI20 literal 0 HcmV?d00001 -- GitLab