From fc45e52dc3cf9bdbd9bd3a3501e1d8eee4975abe Mon Sep 17 00:00:00 2001 From: MajesticWafer <123651667+MajesticWafer@users.noreply.github.com> Date: Mon, 23 Oct 2023 12:25:07 -0400 Subject: [PATCH] Add files via upload --- app-ds.js | 1 + 1 file changed, 1 insertion(+) create mode 100644 app-ds.js diff --git a/app-ds.js b/app-ds.js new file mode 100644 index 0000000..78bae9c --- /dev/null +++ b/app-ds.js @@ -0,0 +1 @@ +var VER="v20230219",isIOS=!!navigator.platform&&/iPad|iPhone|iPod/.test(navigator.platform),isMacOS=!!navigator.platform&&/Mac/.test(navigator.platform),safariVer,chromeVer;isMacOS&&navigator.maxTouchPoints>2&&(isIOS=!0,isMacOS=!1);try{!function(){var e=navigator.userAgent.toLowerCase(),n=e.match(/chrome\/([0-9]+).([0-9]+)/);n?chromeVer=[parseInt(n[1]),parseInt(n[2])]:(isIOS||isMacOS)&&(n=e.match(/version\/([0-9]+).([0-9]+)/))&&(safariVer=[parseInt(n[1]),parseInt(n[2])])}()}catch(e){console.log(e)}var isWebApp=navigator.standalone||!1,isSaveSupported=!0,isSaveNagAppeared=!1;if(isIOS)if(isWebApp)$id("ios-power-hint").hidden=!1;else{isSaveSupported=!1;var divIosHint=$id("ios-hint");divIosHint.hidden=!1,divIosHint.style="position: absolute; bottom: 20px;",$id("btn-choose-file").hidden=!0,$id("welcome").hidden=!0}function $id(e){return document.getElementById(e)}isMacOS&&navigator.userAgent.indexOf("Chrome")<0&&($id("mac-warning").hidden=!1),WebAssembly||(isIOS&&isWebApp?alert('\nYou have lockdown mode enabled that disables WebAssembly and prevents the app from running. \n\nPlease go back to Safari, click \'Aa\' button in the address bar, open "Website Settings", and disable "Lockdown Mode" for this website.\n'):alert("WebAssembly is not supported or disabled in your browser.\n\nPlease check the settings of your browser and enable WebAssembly.\n"));var optScaleMode=0,uiCurrentMode="welcome",plugins={},body=document.getElementsByTagName("body")[0],html=document.getElementsByTagName("html")[0],config={swapABXY:!1,swapTopBottom:!1,swapTopBottomL:!1,powerSave:!0,micWhenR:!0,vkEnabled:!0,muteSound:!1,useDPad:!1,lsLayout:0,turbo:!1,scaleMode:0,fwLang:1,vkScale:1},emuUseTimer33=!1,lidClosed=!1;function afterConfigUpdated(){emuUseTimer33=!1,(config.powerSave||config.turbo)&&(emuUseTimer33=!0)}function loadConfig(){var e=JSON.parse(window.localStorage.config||"{}");for(var n in e)config[n]=e[n];$id("power-save").checked=config.powerSave,$id("vk-enabled").checked=config.vkEnabled,$id("cfg-mute-sound").checked=config.muteSound,$id("vk-direction").value=config.useDPad?"1":"0",$id("cfg-turbo").checked=config.turbo,$id("cfg-ls-layout").value=config.lsLayout,$id("cfg-scale-mode").value=config.scaleMode,$id("cfg-lang").value=config.fwLang,$id("cfg-swap-abxy").checked=config.swapABXY,$id("cfg-opt").checked="1"==localStorage.simd,afterConfigUpdated(),optScaleMode=config.scaleMode}function uiSaveConfig(){config.powerSave=!!$id("power-save").checked,config.vkEnabled=!!$id("vk-enabled").checked,config.muteSound=!!$id("cfg-mute-sound").checked,config.useDPad=!!parseInt($id("vk-direction").value),config.turbo=!!$id("cfg-turbo").checked,config.lsLayout=parseInt($id("cfg-ls-layout").value),config.scaleMode=parseInt($id("cfg-scale-mode").value),config.fwLang=parseInt($id("cfg-lang").value),config.swapABXY=!!$id("cfg-swap-abxy").checked,window.localStorage.config=JSON.stringify(config),afterConfigUpdated()}function uiMenuBack(){tryInitSound(),uiSaveConfig(),uiSwitchTo(emuIsGameLoaded?"player":"welcome")}function toyEncrypt(e){for(var n=new Uint8Array(e.length),t=0;to.length)return void alert("The .sav file is too large.");o.set(t,0),t=o}localforage.setItem("sav-"+gameID,t).then((()=>{alert("Save data updated. \nPlease close and reopen this app."),setTimeout((()=>{location.reload()}),500)}))}else alert("Invalid file extension: "+n)}}loadConfig(),$id("cfg-opt").onclick=function(){if(this.checked){if(safariVer){if(!(safariVer[0]>=16&&safariVer[1]>=4||safariVer[0]>=17))return alert("iOS 16.4+ is required to enable this option."),void(this.checked=!1)}else if(chromeVer){if(chromeVer[0]<92)return alert("Chrome 92+ is required to enable this option."),void(this.checked=!1)}else alert("We don't know if your browser is supported. Please try it and disable this option if it doesn't work.");localStorage.simd="1"}else localStorage.simd="0";alert("Please restart the app to apply the change.")};var gameID="",emuKeyState=new Array(14);const emuKeyNames=["right","left","down","up","select","start","b","a","y","x","l","r","debug","lid"];for(var vkMap={},vkState={},keyNameToKeyId={},vkStickPos=[0,0,0,0,0],vkDPadRect={x:0,y:0,w:0,h:0},i=0;i=audioFifoCap);n++){var t=(audioFifoHead+audioFifoLen)%audioFifoCap;audioFifoL[t]=audioBuffer[2*n],audioFifoR[t]=audioBuffer[2*n+1],audioFifoLen++}}function emuRunFrame(){processGamepadInput();for(var e=0,n=0;n<14;n++)emuKeyState[n]&&(e|=1<{if(1!=$id("loading").hidden){$id("loading").hidden=!0,$id("loadrom").hidden=!1;var e=$id("btn-choose-file");e.onclick||(e.onclick=()=>{tryInitSound(),$id("rom").click()})}}),2e3),$id("ver-info").innerText="Ver: "+VER+" ",optScaleMode<2?ctx2d=screenCanvas.map((e=>e.getContext("2d",{alpha:!1}))):gpuInit()}function emuCopySavBuffer(){var e=Module._savGetSize();if(e>0){var n=Module._savGetPointer(0),t=new Uint8Array(e);return t.set(Module.HEAPU8.subarray(n,n+e)),t}return new Uint8Array(0)}function checkSaveGame(){if(isSaveSupported){var e=Module._savUpdateChangeFlag();if(0==e&&1==prevSaveFlag){var n=emuCopySavBuffer();n.length>0&&(localforage.setItem("sav-"+gameID,n),showMsg("Auto saving..."))}prevSaveFlag=e}}async function tryLoadROM(e){if(!e)return;if(e.size<1024)return;var n=new Uint8Array(await e.slice(0,1024).arrayBuffer());gameID="";for(var t=0;t<16;t++)gameID+=0==n[t]?" ":String.fromCharCode(n[t]);"#"==gameID[12]&&(gameID=e.name),console.log("gameID",gameID),romSize=e.size;var o=Module._prepareRomBuffer(romSize);console.log(romSize,o);const i=4194304;for(var a=0;an&&(t=(o=n)/192*256),[t,o]}function setScreenPos(e,n,t,o,i){var a="left:"+n+"px;top:"+t+"px;width:"+o+"px;height:"+i+"px;";if(0==optScaleMode&&(a+="image-rendering:pixelated;"),e.style=a,optScaleMode>=2){var r=window.devicePixelRatio||1;e.width=o*r,e.height=i*r}}function uiUpdateLayout(){if((isLandscape=isScreenLandscape())&&0!=config.lsLayout){if(1==config.lsLayout){n=(e=maxScreenSize(window.innerWidth/2,window.innerHeight))[0],t=e[1],o=0,i=0;fbSize=[[n,t],[n,t]];for(a=0;a<2;a++)setScreenPos(screenCanvas[a],o,i,fbSize[a][0],fbSize[a][1]),o+=n}else if(2==config.lsLayout){n=(e=maxScreenSize(window.innerWidth-256,window.innerHeight))[0],t=e[1],o=0,i=0;fbSize=[[n,t],[256,192]];for(a=0;a<2;a++)setScreenPos(screenCanvas[a],o,i,fbSize[a][0],fbSize[a][1]),o+=n}}else{var e,n=(e=maxScreenSize(window.innerWidth,window.innerHeight/2))[0],t=e[1],o=0;o+=(window.innerWidth-n)/2;var i=0;fbSize=[[n,t],[n,t]];for(var a=0;a<2;a++)setScreenPos(screenCanvas[a],o,i,fbSize[a][0],fbSize[a][1]),i+=t}uiAdjustVKLayout()}function uiSwitchTo(e){if(e!=uiCurrentMode){if(uiCurrentMode=e,$id("welcome").hidden=!0,$id("vk-layer").hidden=!0,$id("menu").hidden=!0,$id("player").hidden=!0,body.style="",html.style="",emuIsRunning=!1,"player"==e){body.style="touch-action: none;",html.style="position: fixed;overflow:hidden;touch-action: none;";for(var n=0;n<14;n++)emuKeyState[n]=!1;config.vkEnabled&&($id("vk-layer").hidden=!1),uiUpdateLayout(),emuIsGameLoaded&&(emuIsRunning=!0),$id("player").hidden=!1}"menu"==e&&($id("player").hidden=!1,$id("menu").hidden=!1,$id("menu-savegame").hidden=!emuIsGameLoaded),"welcome"==e&&($id("welcome").hidden=!1)}}function onScriptNodeAudioProcess(e){var n=e.outputBuffer.getChannelData(0),t=e.outputBuffer.getChannelData(1);if(!config.muteSound)for(var o=0;o{var file=fileInput.files[0];if(file){var fileNameLower=file.name.toLowerCase();if(fileNameLower.endsWith(".json")){var obj=JSON.parse(await file.text()),pluginName=obj.name||"unknown";return plugins[pluginName]=obj,obj.js&&(plugins[pluginName].handler=eval(obj.js)(obj)),void alert("plugin loaded!")}if(fileNameLower.endsWith(".gba"))alert("This is a GBA file, redirecting to the GBA player..."),window.location.href="/gba";else if(fileNameLower.endsWith(".zip"))alert("ZIP files are not supported.\nOn iOS, you can unzip it with the built-in Files app.");else if(fileNameLower.endsWith(".3ds"))alert("No, 3DS is not supported.");else{if(fileNameLower.endsWith(".nds"))return void tryLoadROM(file);alert("Unknown file type!")}}},emuLoop(),setInterval(emuTimer33,33);var stickTouchID=null,tpadTouchID=null;function isPointInRect(e,n,t){return e>=t.x&&e=t.y&&n1?1:e}function handleTouch(e){if(tryInitSound(),emuIsRunning){e.preventDefault(),e.stopPropagation();for(var n=!1,t=0,o=0,i=!1,a=vkStickPos[0],r=vkStickPos[1],d=vkStickPos[2],s=vkStickPos[3],c=.2*d,l=null,u=null,f=screenCanvas[1].getBoundingClientRect(),p=0;pr+c&&(emuKeyState[0]=!0),Ea+c&&(emuKeyState[2]=!0),S=Math.max(r-d/2,S),S=Math.min(r+d/2,S),E=Math.max(a-s/2,E),r=S,a=E=Math.min(a+s/2,E),i=!0,l=g;continue}g===tpadTouchID||isPointInRect(v.clientX,v.clientY,f)&&!m?(n=!0,t=256*clamp01((v.clientX-f.x)/f.width),o=192*clamp01((v.clientY-f.y)/f.height),u=g):m&&(vkState[m][1]=1)}for(var m in touched=n?1:0,touchX=t,touchY=o,vkState)if(vkState[m][0]!=vkState[m][1]){var C=vkMap[m];vkState[m][0]=vkState[m][1],vkState[m][1]?"menu"==m&&uiSwitchTo("menu"):"stick"==m&&(i=!0)}for(p=0;p{window.addEventListener(e,handleTouch)})),window.onmousedown=window.onmouseup=window.onmousemove=e=>{if(emuIsRunning){"mousedown"==e.type&&tryInitSound();var n=screenCanvas[1].getBoundingClientRect();e.preventDefault(),e.stopPropagation();var t=0!=e.buttons&&isPointInRect(e.clientX,e.clientY,n),o=(e.clientX-n.x)/n.width*256,i=(e.clientY-n.y)/n.height*192;touched=t?1:0,touchX=o,touchY=i}},window.onresize=window.onorientationchange=()=>{uiUpdateLayout()},window.onkeydown=window.onkeyup=e=>{if(emuIsRunning){e.preventDefault();var n="keydown"===e.type,t=convertKeyCode(e.keyCode);t>=0&&(emuKeyState[t]=n),27==e.keyCode&&uiSwitchTo("menu")}};var currentConnectedGamepad=-1,gamePadKeyMap={a:1,b:0,x:3,y:2,l:4,r:5,select:8,start:9,up:12,down:13,left:14,right:15},gamePadKeyMap2={a:0,b:1,x:2,y:3,l:4,r:5,select:8,start:9,up:12,down:13,left:14,right:15};function processGamepadInput(){var e=gamePadKeyMap;if(config.swapABXY&&(e=gamePadKeyMap2),!(currentConnectedGamepad<0)){var n=navigator.getGamepads()[currentConnectedGamepad];if(!n)return showMsg("Gamepad disconnected."),void(currentConnectedGamepad=-1);for(var t=0;t.5&&(emuKeyState[keyNameToKeyId.right]=!0),n.axes[1]<-.5&&(emuKeyState[keyNameToKeyId.up]=!0),n.axes[1]>.5&&(emuKeyState[keyNameToKeyId.down]=!0)}}}isSaveSupported&&window.addEventListener("gamepadconnected",(function(e){console.log("Gamepad connected at index %d: %s. %d buttons, %d axes.",e.gamepad.index,e.gamepad.id,e.gamepad.buttons.length,e.gamepad.axes.length),showMsg("Gamepad connected."),currentConnectedGamepad=e.gamepad.index,$id("a-gamepad").innerText="Gamepad connected"}));var isMicrophoneEnabled=!1,micPtr,micBuf,micScriptNode,micSource;function enableMicrophone(){micPtr||(micPtr=Module._realloc(0,4096),micBuf=Module.HEAPU8.subarray(micPtr,micPtr+4096)),micScriptNode&&micScriptNode.disconnect(),micSource&&micSource.disconnect(),tryInitSound(),isMicrophoneEnabled=!0,navigator.mediaDevices.getUserMedia({audio:!0,video:!1}).then((function(e){micSource=audioContext.createMediaStreamSource(e),micScriptNode=audioContext.createScriptProcessor(2048,1,1),micSource.connect(micScriptNode),micScriptNode.onaudioprocess=function(e){for(var n=e.inputBuffer.getChannelData(0),t=0,o=0;o<=2045;o+=3){var i=(n[o]+n[o+1]+n[o+2])/3;(i=Math.floor(64*i+64))>127?i=127:i<0&&(i=0),micBuf[t]=i,t++}Module._micWriteSamples(micPtr,682);for(var a=0;a<1;a++)for(n=e.outputBuffer.getChannelData(a),o=0;o<2048;o++)n[o]=0},micScriptNode.connect(audioContext.destination)}))}function isScreenLandscape(){return window.innerWidth/window.innerHeight>1.2}"https://ds.44670.org"==location.origin&&(isSaveSupported&&"serviceWorker"in navigator&&(navigator.serviceWorker.register("/sw.js").then((function(e){console.log("Registration succeeded. Scope is "+e.scope)})).catch((function(e){console.log("Registration failed with "+e)})),navigator.serviceWorker.addEventListener("message",(e=>{console.log("sw msg",e),e.data.msg&&($id("whats-new").innerText=e.data.msg)}))),function(){var e=0;window.onbeforeinstallprompt=function(n){if(!((e+=1)>2)){console.log("Before install prompt",n),n.preventDefault();var t=n;window.onclick=function(e){t.prompt(),window.onclick=null}}}}());var vertShaderSource="\n precision mediump float;\n attribute vec2 a_position; //(0,0)-(1,1)\n varying vec2 v_texCoord; //(0,0)-(1,1)\n \n void main() {\n // Convert a_position to gl_Position\n gl_Position = vec4(a_position.x * 2.0 - 1.0, 1.0 - a_position.y * 2.0, 0, 1);\n v_texCoord = a_position;\n }\n",fragShaderSource="\n\n\n \n#ifdef GL_ES\n#ifdef GL_FRAGMENT_PRECISION_HIGH\nprecision highp float;\n#else\nprecision mediump float;\n#endif\n#define COMPAT_PRECISION mediump\n#else\n#define COMPAT_PRECISION\n#endif\n\n#if __VERSION__ >= 130\n#define COMPAT_VARYING in\n#define COMPAT_TEXTURE texture\nout COMPAT_PRECISION vec4 FragColor;\n#else\n#define COMPAT_VARYING varying\n#define FragColor gl_FragColor\n#define COMPAT_TEXTURE texture2D\n#endif\n\nprecision mediump float;\nuniform sampler2D u_image; \nvarying vec2 v_texCoord; \nuniform vec2 u_outResolution;\nuniform vec2 u_inResolution;\n\n#define Source u_image\n#define vTexCoord v_texCoord\n\n#define SourceSize vec4(u_inResolution, 1.0 / u_inResolution) \n#define OutSize vec4(u_outResolution, 1.0 / u_outResolution)\n\n#define BLEND_NONE 0\n#define BLEND_NORMAL 1\n#define BLEND_DOMINANT 2\n#define LUMINANCE_WEIGHT 1.0\n#define EQUAL_COLOR_TOLERANCE 30.0/255.0\n#define STEEP_DIRECTION_THRESHOLD 2.2\n#define DOMINANT_DIRECTION_THRESHOLD 3.6\n\nfloat DistYCbCr(vec3 pixA, vec3 pixB)\n{\n const vec3 w = vec3(0.2627, 0.6780, 0.0593);\n const float scaleB = 0.5 / (1.0 - w.b);\n const float scaleR = 0.5 / (1.0 - w.r);\n vec3 diff = pixA - pixB;\n float Y = dot(diff.rgb, w);\n float Cb = scaleB * (diff.b - Y);\n float Cr = scaleR * (diff.r - Y);\n\n return sqrt(((LUMINANCE_WEIGHT * Y) * (LUMINANCE_WEIGHT * Y)) + (Cb * Cb) + (Cr * Cr));\n}\n\nbool IsPixEqual(const vec3 pixA, const vec3 pixB)\n{\n return (DistYCbCr(pixA, pixB) < EQUAL_COLOR_TOLERANCE);\n}\n\nfloat get_left_ratio(vec2 center, vec2 origin, vec2 direction, vec2 scale)\n{\n vec2 P0 = center - origin;\n vec2 proj = direction * (dot(P0, direction) / dot(direction, direction));\n vec2 distv = P0 - proj;\n vec2 orth = vec2(-direction.y, direction.x);\n float side = sign(dot(P0, orth));\n float v = side * length(distv * scale);\n\n// return step(0, v);\n return smoothstep(-sqrt(2.0)/2.0, sqrt(2.0)/2.0, v);\n}\n\n#define eq(a,b) (a == b)\n#define neq(a,b) (a != b)\n\n#define P(x,y) COMPAT_TEXTURE(Source, coord + SourceSize.zw * vec2(x, y)).rgb\n\nvoid main()\n{\n //---------------------------------------\n // Input Pixel Mapping: -|x|x|x|-\n // x|A|B|C|x\n // x|D|E|F|x\n // x|G|H|I|x\n // -|x|x|x|-\n\n vec2 scale = OutSize.xy * SourceSize.zw;\n vec2 pos = fract(vTexCoord * SourceSize.xy) - vec2(0.5, 0.5);\n vec2 coord = vTexCoord - pos * SourceSize.zw;\n\n vec3 A = P(-1.,-1.);\n vec3 B = P( 0.,-1.);\n vec3 C = P( 1.,-1.);\n vec3 D = P(-1., 0.);\n vec3 E = P( 0., 0.);\n vec3 F = P( 1., 0.);\n vec3 G = P(-1., 1.);\n vec3 H = P( 0., 1.);\n vec3 I = P( 1., 1.);\n\n // blendResult Mapping: x|y|\n // w|z|\n ivec4 blendResult = ivec4(BLEND_NONE,BLEND_NONE,BLEND_NONE,BLEND_NONE);\n\n // Preprocess corners\n // Pixel Tap Mapping: -|-|-|-|-\n // -|-|B|C|-\n // -|D|E|F|x\n // -|G|H|I|x\n // -|-|x|x|-\n if (!((eq(E,F) && eq(H,I)) || (eq(E,H) && eq(F,I))))\n {\n float dist_H_F = DistYCbCr(G, E) + DistYCbCr(E, C) + DistYCbCr(P(0,2), I) + DistYCbCr(I, P(2.,0.)) + (4.0 * DistYCbCr(H, F));\n float dist_E_I = DistYCbCr(D, H) + DistYCbCr(H, P(1,2)) + DistYCbCr(B, F) + DistYCbCr(F, P(2.,1.)) + (4.0 * DistYCbCr(E, I));\n bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_H_F) < dist_E_I;\n blendResult.z = ((dist_H_F < dist_E_I) && neq(E,F) && neq(E,H)) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE;\n }\n\n\n // Pixel Tap Mapping: -|-|-|-|-\n // -|A|B|-|-\n // x|D|E|F|-\n // x|G|H|I|-\n // -|x|x|-|-\n if (!((eq(D,E) && eq(G,H)) || (eq(D,G) && eq(E,H))))\n {\n float dist_G_E = DistYCbCr(P(-2.,1.) , D) + DistYCbCr(D, B) + DistYCbCr(P(-1.,2.), H) + DistYCbCr(H, F) + (4.0 * DistYCbCr(G, E));\n float dist_D_H = DistYCbCr(P(-2.,0.) , G) + DistYCbCr(G, P(0.,2.)) + DistYCbCr(A, E) + DistYCbCr(E, I) + (4.0 * DistYCbCr(D, H));\n bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_D_H) < dist_G_E;\n blendResult.w = ((dist_G_E > dist_D_H) && neq(E,D) && neq(E,H)) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE;\n }\n\n // Pixel Tap Mapping: -|-|x|x|-\n // -|A|B|C|x\n // -|D|E|F|x\n // -|-|H|I|-\n // -|-|-|-|-\n if (!((eq(B,C) && eq(E,F)) || (eq(B,E) && eq(C,F))))\n {\n float dist_E_C = DistYCbCr(D, B) + DistYCbCr(B, P(1.,-2.)) + DistYCbCr(H, F) + DistYCbCr(F, P(2.,-1.)) + (4.0 * DistYCbCr(E, C));\n float dist_B_F = DistYCbCr(A, E) + DistYCbCr(E, I) + DistYCbCr(P(0.,-2.), C) + DistYCbCr(C, P(2.,0.)) + (4.0 * DistYCbCr(B, F));\n bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_B_F) < dist_E_C;\n blendResult.y = ((dist_E_C > dist_B_F) && neq(E,B) && neq(E,F)) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE;\n }\n\n // Pixel Tap Mapping: -|x|x|-|-\n // x|A|B|C|-\n // x|D|E|F|-\n // -|G|H|-|-\n // -|-|-|-|-\n if (!((eq(A,B) && eq(D,E)) || (eq(A,D) && eq(B,E))))\n {\n float dist_D_B = DistYCbCr(P(-2.,0.), A) + DistYCbCr(A, P(0.,-2.)) + DistYCbCr(G, E) + DistYCbCr(E, C) + (4.0 * DistYCbCr(D, B));\n float dist_A_E = DistYCbCr(P(-2.,-1.), D) + DistYCbCr(D, H) + DistYCbCr(P(-1.,-2.), B) + DistYCbCr(B, F) + (4.0 * DistYCbCr(A, E));\n bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_D_B) < dist_A_E;\n blendResult.x = ((dist_D_B < dist_A_E) && neq(E,D) && neq(E,B)) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE;\n }\n\n vec3 res = E;\n\n // Pixel Tap Mapping: -|-|-|-|-\n // -|-|B|C|-\n // -|D|E|F|x\n // -|G|H|I|x\n // -|-|x|x|-\n if(blendResult.z != BLEND_NONE)\n {\n float dist_F_G = DistYCbCr(F, G);\n float dist_H_C = DistYCbCr(H, C);\n bool doLineBlend = (blendResult.z == BLEND_DOMINANT ||\n !((blendResult.y != BLEND_NONE && !IsPixEqual(E, G)) || (blendResult.w != BLEND_NONE && !IsPixEqual(E, C)) ||\n (IsPixEqual(G, H) && IsPixEqual(H, I) && IsPixEqual(I, F) && IsPixEqual(F, C) && !IsPixEqual(E, I))));\n\n vec2 origin = vec2(0.0, 1.0 / sqrt(2.0));\n vec2 direction = vec2(1.0, -1.0);\n if(doLineBlend)\n {\n bool haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_F_G <= dist_H_C) && neq(E,G) && neq(D,G);\n bool haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_H_C <= dist_F_G) && neq(E,C) && neq(B,C);\n origin = haveShallowLine? vec2(0.0, 0.25) : vec2(0.0, 0.5);\n direction.x += haveShallowLine? 1.0: 0.0;\n direction.y -= haveSteepLine? 1.0: 0.0;\n }\n\n vec3 blendPix = mix(H,F, step(DistYCbCr(E, F), DistYCbCr(E, H)));\n res = mix(res, blendPix, get_left_ratio(pos, origin, direction, scale));\n }\n\n // Pixel Tap Mapping: -|-|-|-|-\n // -|A|B|-|-\n // x|D|E|F|-\n // x|G|H|I|-\n // -|x|x|-|-\n if(blendResult.w != BLEND_NONE)\n {\n float dist_H_A = DistYCbCr(H, A);\n float dist_D_I = DistYCbCr(D, I);\n bool doLineBlend = (blendResult.w == BLEND_DOMINANT ||\n !((blendResult.z != BLEND_NONE && !IsPixEqual(E, A)) || (blendResult.x != BLEND_NONE && !IsPixEqual(E, I)) ||\n (IsPixEqual(A, D) && IsPixEqual(D, G) && IsPixEqual(G, H) && IsPixEqual(H, I) && !IsPixEqual(E, G))));\n\n vec2 origin = vec2(-1.0 / sqrt(2.0), 0.0);\n vec2 direction = vec2(1.0, 1.0);\n if(doLineBlend)\n {\n bool haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_H_A <= dist_D_I) && neq(E,A) && neq(B,A);\n bool haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_D_I <= dist_H_A) && neq(E,I) && neq(F,I);\n origin = haveShallowLine? vec2(-0.25, 0.0) : vec2(-0.5, 0.0);\n direction.y += haveShallowLine? 1.0: 0.0;\n direction.x += haveSteepLine? 1.0: 0.0;\n }\n origin = origin;\n direction = direction;\n\n vec3 blendPix = mix(H,D, step(DistYCbCr(E, D), DistYCbCr(E, H)));\n res = mix(res, blendPix, get_left_ratio(pos, origin, direction, scale));\n }\n\n // Pixel Tap Mapping: -|-|x|x|-\n // -|A|B|C|x\n // -|D|E|F|x\n // -|-|H|I|-\n // -|-|-|-|-\n if(blendResult.y != BLEND_NONE)\n {\n float dist_B_I = DistYCbCr(B, I);\n float dist_F_A = DistYCbCr(F, A);\n bool doLineBlend = (blendResult.y == BLEND_DOMINANT ||\n !((blendResult.x != BLEND_NONE && !IsPixEqual(E, I)) || (blendResult.z != BLEND_NONE && !IsPixEqual(E, A)) ||\n (IsPixEqual(I, F) && IsPixEqual(F, C) && IsPixEqual(C, B) && IsPixEqual(B, A) && !IsPixEqual(E, C))));\n\n vec2 origin = vec2(1.0 / sqrt(2.0), 0.0);\n vec2 direction = vec2(-1.0, -1.0);\n\n if(doLineBlend)\n {\n bool haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_B_I <= dist_F_A) && neq(E,I) && neq(H,I);\n bool haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_F_A <= dist_B_I) && neq(E,A) && neq(D,A);\n origin = haveShallowLine? vec2(0.25, 0.0) : vec2(0.5, 0.0);\n direction.y -= haveShallowLine? 1.0: 0.0;\n direction.x -= haveSteepLine? 1.0: 0.0;\n }\n\n vec3 blendPix = mix(F,B, step(DistYCbCr(E, B), DistYCbCr(E, F)));\n res = mix(res, blendPix, get_left_ratio(pos, origin, direction, scale));\n }\n\n // Pixel Tap Mapping: -|x|x|-|-\n // x|A|B|C|-\n // x|D|E|F|-\n // -|G|H|-|-\n // -|-|-|-|-\n if(blendResult.x != BLEND_NONE)\n {\n float dist_D_C = DistYCbCr(D, C);\n float dist_B_G = DistYCbCr(B, G);\n bool doLineBlend = (blendResult.x == BLEND_DOMINANT ||\n !((blendResult.w != BLEND_NONE && !IsPixEqual(E, C)) || (blendResult.y != BLEND_NONE && !IsPixEqual(E, G)) ||\n (IsPixEqual(C, B) && IsPixEqual(B, A) && IsPixEqual(A, D) && IsPixEqual(D, G) && !IsPixEqual(E, A))));\n\n vec2 origin = vec2(0.0, -1.0 / sqrt(2.0));\n vec2 direction = vec2(-1.0, 1.0);\n if(doLineBlend)\n {\n bool haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_D_C <= dist_B_G) && neq(E,C) && neq(F,C);\n bool haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_B_G <= dist_D_C) && neq(E,G) && neq(H,G);\n origin = haveShallowLine? vec2(0.0, -0.25) : vec2(0.0, -0.5);\n direction.x -= haveShallowLine? 1.0: 0.0;\n direction.y += haveSteepLine? 1.0: 0.0;\n }\n\n vec3 blendPix = mix(D,B, step(DistYCbCr(E, B), DistYCbCr(E, D)));\n res = mix(res, blendPix, get_left_ratio(pos, origin, direction, scale));\n }\n\n \tFragColor = vec4(res, 1.0);\n} ";function gpuInitWithCanvas(e){var n=e.getContext("webgl");if(e.gl=n,!n)return alert("Unable to initialize WebGL. Your browser or machine may not support it."),null;n.viewport(0,0,e.width,e.height),program=n.createProgram();var t=n.createShader(n.VERTEX_SHADER),o=n.createShader(n.FRAGMENT_SHADER);if(n.shaderSource(t,vertShaderSource),n.shaderSource(o,fragShaderSource),n.compileShader(t),n.compileShader(o),n.getShaderParameter(t,n.COMPILE_STATUS))if(n.getShaderParameter(o,n.COMPILE_STATUS)){if(n.attachShader(program,t),n.attachShader(program,o),n.linkProgram(program),n.getProgramParameter(program,n.LINK_STATUS)){n.useProgram(program);var i=n.createTexture();n.bindTexture(n.TEXTURE_2D,i),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_S,n.CLAMP_TO_EDGE),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_T,n.CLAMP_TO_EDGE),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MIN_FILTER,n.NEAREST),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MAG_FILTER,n.NEAREST);var a=new Float32Array([0,0,1,0,0,1,0,1,1,0,1,1]),r=n.createBuffer();n.bindBuffer(n.ARRAY_BUFFER,r),n.bufferData(n.ARRAY_BUFFER,a,n.STATIC_DRAW);var d=n.getAttribLocation(program,"a_position");n.enableVertexAttribArray(d),n.vertexAttribPointer(d,2,n.FLOAT,!1,0,0),e.outResolutionUniformLocation=n.getUniformLocation(program,"u_outResolution");var s=n.getUniformLocation(program,"u_inResolution");return n.uniform2f(s,256,192),n}alert("Error in program: "+n.getProgramInfoLog(program))}else alert("Error in fragment shader: "+n.getShaderInfoLog(o));else alert("Error in vertex shader: "+n.getShaderInfoLog(t))}function gpuDraw(e,n){var t=e.gl;t.texImage2D(t.TEXTURE_2D,0,t.RGBA,t.RGBA,t.UNSIGNED_BYTE,n),t.viewport(0,0,e.width,e.height),t.uniform2f(e.outResolutionUniformLocation,e.width,e.height),t.drawArrays(t.TRIANGLES,0,6)}function gpuInit(){gpuInitWithCanvas(screenCanvas[0])&&gpuInitWithCanvas(screenCanvas[1])}var DP_BASE_PATH="/dssav",DP_EXT=".4dsaz";function dpGetCurrentDayInt(){var e=new Date;return 1e4*e.getFullYear()+100*(e.getMonth()+1)+e.getDate()}function dpIsConnected(){return!!localStorage["d-token"]}async function dpIDHash(e){if(!localStorage["d-id"])throw"Not connected";var n=localStorage["d-id"]+","+e,t=await window.crypto.subtle.digest("SHA-256",new TextEncoder("utf-8").encode(n));return Array.from(new Uint8Array(t)).map((e=>e.toString(16).padStart(2,"0"))).join("").substring(0,8)}async function dpGameLoaded(){if(dpIsConnected()){var e=await dpIDHash(gameID);$id("span-cloud-id").innerText=e}}async function dpConnect(){var e="https://www.dropbox.com/oauth2/authorize?client_id=zro5k6xlnsxu4gz&response_type=code&token_access_type=offline";e+="&redirect_uri="+encodeURIComponent(location.origin),location.href=e}async function dpCheckUser(){var e=await fetch("https://api.dropboxapi.com/2/check/user",{method:"POST",headers:{Authorization:"Bearer "+localStorage["d-token"],"Content-Type":"application/json"},body:JSON.stringify({query:"foo"})}),n=await e.text();console.log(n)}async function dpUploadFile(e,n,t){t=t||"overwrite";for(var o=JSON.stringify({autorename:!0,mode:t,mute:!0,strict_conflict:!1,path:e}),i=new Blob([n],{type:"application/octet-stream"}),a=0;a<2;a++){var r=await fetch("https://content.dropboxapi.com/2/files/upload",{method:"POST",headers:{Authorization:"Bearer "+localStorage["d-token"],"Dropbox-API-Arg":o,"Content-Type":"application/octet-stream"},body:i});if(console.log("status: ",r.status),200!=r.status){if(401==r.status){if(!await dpRefreshToken())throw"Unable to refresh token";continue}throw"Upload failed, unknown http status: "+r.status}var d=await r.json();return console.log(d),d}return!1}async function dpDownloadFile(e){for(var n=JSON.stringify({path:e}),t=0;t<2;t++){var o=await fetch("https://content.dropboxapi.com/2/files/download",{method:"POST",headers:{Authorization:"Bearer "+localStorage["d-token"],"Dropbox-API-Arg":n}});if(console.log("status: ",o.status),200!=o.status){if(401==o.status){if(!await dpRefreshToken())throw"Unable to refresh token";continue}throw"Download failed, unknown http status: "+o.status}var i=JSON.parse(o.headers.get("dropbox-api-result"));console.log(i);var a=await o.arrayBuffer();return new Uint8Array(a)}return!1}async function dpOnLoad(){if(location.search.startsWith("?code=")){var e=location.search.slice(6),n=await fetch("https://c.44670.org/d",{method:"POST",body:"1,"+location.origin+","+e}),t=await n.json();t.error?alert(t.error):(localStorage["d-token"]=t.token,localStorage["d-token-r"]=t.tokenr,localStorage["d-id"]=t.id,alert("Dropbox connected."),location.href=location.origin)}document.getElementById("btn-dp-connect").innerText=(dpIsConnected()?"Disconnect":"Connect")+" Dropbox"}async function dpRefreshToken(){if(console.log("Refreshing token..."),!localStorage["d-token-r"])throw"No refresh token";var e=await fetch("https://c.44670.org/d",{method:"POST",body:"2,"+location.origin+","+localStorage["d-token-r"]}),n=await e.json();return n.error?(alert("Failed to update DropBox token: "+n.error),!1):(localStorage["d-token"]=n.token,!0)}async function dpGetPath(e,n){var t=await dpIDHash(e);return DP_BASE_PATH+"/"+t+"/"+n+DP_EXT}async function dpTryUploadCloudSave(e,n,t,o){if(!dpIsConnected())return!1;var i=await dpGetPath(e,n);try{return await dpUploadFile(i,t,o)}catch(e){return alert("Failed to upload cloud save: "+e),!1}return!1}async function dpTryAutoBackup(){if(!dpIsConnected())return!1;var e=""+dpGetCurrentDayInt();return localStorage["d-last-"+gameID]!=e&&(!!await dpTryUploadCloudSave(gameID,"auto-"+dpGetCurrentDayInt(),await emuBackupCloudSav(),"add")&&(localStorage["d-last-"+gameID]=e,!0))}function dpOnConnectButtonClicked(){dpIsConnected()?confirm("Are you sure to disconnect from Dropbox?")&&(localStorage["d-token"]="",localStorage["d-token-r"]="",localStorage["d-id"]="",alert("Dropbox disconnected."),location.href=location.origin):dpConnect()}async function dpManualBtn(e){if(dpIsConnected())if(gameID)try{if(e){await dpTryUploadCloudSave(gameID,"manual",await emuBackupCloudSav(),"overwrite")?alert("Uploaded successfully."):alert("Failed to upload.")}else{var n=await dpGetPath(gameID,"manual"),t=await dpDownloadFile(n);if(!t)return void alert("Failed to download.");if(t.length<1)return void alert("No cloud save found.");await emuRestoreCloudSav(t)?(alert("Restored successfully."),setTimeout((function(){location.reload()}),1e3)):alert("Failed to restore.")}}catch(e){return void alert("Error:"+e)}else alert("Please load a game first.");else alert("Please connect to Dropbox first.")}dpOnLoad(); \ No newline at end of file