diff --git a/CHANGES.md b/CHANGES.md index ac3b24c..06e6fe5 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,18 @@ # Changes -# 4.0.11 +# 4.0.12 +- Fix scroll bar css (Thanks to [@allancoding](https://github.com/allancoding)) +- Flip the context menu instead of going off the page +- Add hooks for save files (Thanks to [@gantoine](https://github.com/gantoine)) +- Add class for each virtual gamepad button +- Add `EJS_forceLegacyCores` option +- Add `EJS_noAutoFocus` (this is only for advanced developers, not likely an option you will use) +- Added supported Amiga file extensions (Thanks to [@michael-j-green](https://github.com/michael-j-green)) +- Display the file name of the ROM/disk when using M3U lists (Thanks to [@michael-j-green](https://github.com/michael-j-green)) +- Added vsync option +- Added advanced shader configuration support (Thanks to [@n-at](https://github.com/n-at)) + +# 4.0.11 [View Tree](https://github.com/EmulatorJS/EmulatorJS/tree/cafd80d023afa9562c7054e89a4240f3381d64ff) - Added the ability to disable localstorage using `EJS_disableLocalStorage`. (Thanks to [@n-at](https://github.com/n-at)) - Added the ability to trigger `EJS_emulator.displayMessage` with a duration. (Thanks to [@allancoding](https://github.com/allancoding)) - `EJS_emulator.gameManager.getState` now returns a Uint8Array instead of a promise. diff --git a/data/GameManager.js b/data/GameManager.js index 095a92f..edace7a 100644 --- a/data/GameManager.js +++ b/data/GameManager.js @@ -29,7 +29,8 @@ class EJS_GameManager { setRewindGranularity: this.Module.cwrap('set_rewind_granularity', 'null', ['number']), toggleSlowMotion: this.Module.cwrap('toggle_slow_motion', 'null', ['number']), setSlowMotionRatio: this.Module.cwrap('set_sm_ratio', 'null', ['number']), - getFrameNum: this.Module.cwrap('get_current_frame_count', 'number', ['']) + getFrameNum: this.Module.cwrap('get_current_frame_count', 'number', ['']), + setVSync: this.Module.cwrap('set_vsync', 'null', ['number']) } this.writeFile("/home/web_user/retroarch/userdata/config/Beetle PSX HW/Beetle PSX HW.opt", 'beetle_psx_hw_renderer = "software"\n'); this.writeFile("/home/web_user/retroarch/userdata/config/MAME 2003 (0.78)/MAME 2003 (0.78).opt", 'mame2003_skip_disclaimer = "enabled"\nmame2003_skip_warnings = "enabled"\n'); @@ -118,10 +119,13 @@ class EJS_GameManager { "savefile_directory = \"/data/saves\"\n"; } initShaders() { - if (!window.EJS_SHADERS) return; + if (!this.EJS.config.shaders) return; this.mkdir("/shader"); - for (const shader in window.EJS_SHADERS) { - this.FS.writeFile('/shader/'+shader, window.EJS_SHADERS[shader]); + for (const shaderFileName in this.EJS.config.shaders) { + const shader = this.EJS.config.shaders[shaderFileName]; + if (typeof shader === 'string') { + this.FS.writeFile(`/shader/${shaderFileName}`, shader); + } } } clearEJSResetTimer() { @@ -306,6 +310,9 @@ class EJS_GameManager { }, null, false, {responseType: "arraybuffer", method: "GET"}); }) } + setVSync(enabled) { + this.functions.setVSync(enabled); + } toggleMainLoop(playing) { this.functions.toggleMainLoop(playing); } diff --git a/data/emulator.css b/data/emulator.css index 18a6043..68e362a 100644 --- a/data/emulator.css +++ b/data/emulator.css @@ -287,8 +287,11 @@ .ejs_svg_rotate { transform: rotate(90deg); } +.ejs_small_screen .ejs_settings_parent::before { + border: none; +} .ejs_small_screen .ejs_settings_parent::after { - right: 15px; + border: none; } .ejs_small_screen .ejs_settings_center_right { right: -35% @@ -374,12 +377,15 @@ .ejs_big_screen .ejs_settings_parent { right: -3px; } -.ejs_big_screen .ejs_settings_parent::after { +/* .ejs_big_screen .ejs_settings_parent::after { right: 15px; -} +} */ .ejs_big_screen .ejs_settings_text { display: none; } +.ejs_big_screen .ejs_disks_text { + display: none; +} .ejs_big_screen .ejs_menu_bar_spacer { flex:1; } @@ -764,8 +770,11 @@ .ejs_settings_parent { animation: ejs_settings_parent_animation .2s ease; - background: rgba(16,16,16,0.9); + background: rgba(29, 29, 29, 0.9); border-radius: 4px; + border-width: 1px; + border-style: solid; + border-color: rgba(49, 49, 49, 0.9); bottom: 100%; box-shadow: 0 1px 2px rgba(0,0,0,0.15); color: #4f5b5f; @@ -775,15 +784,36 @@ text-align: left; white-space: nowrap; z-index: 9999; + backdrop-filter: blur(8px); + -webkit-backdrop-filter: blur(8px); } -.ejs_settings_parent::after { - border: 4px solid transparent; - border-top-color: rgba(16,16,16,0.9); +/* .ejs_settings_parent::after { + border: 5px solid transparent; + border-top-color: rgba(119, 119, 119, 0.9); content: ''; height: 0; position: absolute; top: 100%; width: 0; +} */ +.ejs_settings_parent::before, .ejs_settings_parent::after { + position: absolute; + right: 15px; + width: 0; + height: 0; + content: ''; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top-width: 5px; + border-top-style: solid; +} +.ejs_settings_parent::before { + top: calc(100% + 1px); + border-top-color: rgba(49, 49, 49, 0.9); +} +.ejs_settings_parent::after { + top: 100%; + border-top-color: rgba(29, 29, 29, 0.9); } .ejs_settings_transition { overflow: hidden; diff --git a/data/emulator.js b/data/emulator.js index cacb446..b1596df 100644 --- a/data/emulator.js +++ b/data/emulator.js @@ -1,5 +1,5 @@ class EmulatorJS { - version = 12; //Increase by 1 when cores are updated + version = 13; //Increase by 1 when cores are updated getCore(generic) { const core = this.config.system; /*todo: @@ -269,8 +269,8 @@ class EmulatorJS { }) } constructor(element, config) { - this.ejs_version = "4.0.11"; - this.ejs_num_version = 401.1; + this.ejs_version = "4.0.12"; + this.ejs_num_version = 401.2; this.debug = (window.EJS_DEBUG_XX === true); if (this.debug || (window.location && ['localhost', '127.0.0.1'].includes(location.hostname))) this.checkForUpdates(); this.netplayEnabled = (window.EJS_DEBUG_XX === true) && (window.EJS_EXPERIMENTAL_NETPLAY === true); @@ -952,7 +952,7 @@ class EmulatorJS { const altName = this.getBaseFileName(true); let disableCue = false; - if (['pcsx_rearmed', 'genesis_plus_gx', 'picodrive', 'mednafen_pce', 'smsplus', 'vice_x64', 'vice_x64sc', 'vice_x128', 'vice_xvic', 'vice_xplus4', 'vice_xpet'].includes(this.getCore()) && this.config.disableCue === undefined) { + if (['pcsx_rearmed', 'genesis_plus_gx', 'picodrive', 'mednafen_pce', 'smsplus', 'vice_x64', 'vice_x64sc', 'vice_x128', 'vice_xvic', 'vice_xplus4', 'vice_xpet', 'puae'].includes(this.getCore()) && this.config.disableCue === undefined) { disableCue = true; } else { disableCue = this.config.disableCue; @@ -1129,6 +1129,11 @@ class EmulatorJS { } this.Module.resumeMainLoop(); this.checkSupportedOpts(); + this.setupDisksMenu(); + // hide the disks menu if the disk count is not greater than 1 + if (!(this.gameManager.getDiskCount() > 1)) { + this.diskParent.style.display = 'none'; + } this.setupSettingsMenu(); this.loadSettings(); this.updateCheatUI(); @@ -1580,7 +1585,7 @@ class EmulatorJS { let timeout = null; let ignoreEvents = false; const hide = () => { - if (this.paused || this.settingsMenuOpen) return; + if (this.paused || this.settingsMenuOpen || this.disksMenuOpen) return; this.elements.menu.classList.add("ejs_menu_bar_hidden"); } @@ -1882,6 +1887,30 @@ class EmulatorJS { } }); + this.diskParent = this.createElement("div"); + this.diskParent.id = "ejs_disksMenu"; + this.disksMenuOpen = false; + const diskButton = addButton("Disks", '', () => { + this.disksMenuOpen = !this.disksMenuOpen; + diskButton[1].classList.toggle("ejs_svg_rotate", this.disksMenuOpen); + this.disksMenu.style.display = this.disksMenuOpen ? "" : "none"; + diskButton[2].classList.toggle("ejs_disks_text", this.disksMenuOpen); + }, this.diskParent, true); + this.elements.menu.appendChild(this.diskParent); + this.closeDisksMenu = () => { + if (!this.disksMenu) return; + this.disksMenuOpen = false; + diskButton[1].classList.toggle("ejs_svg_rotate", this.disksMenuOpen); + diskButton[2].classList.toggle("ejs_disks_text", this.disksMenuOpen); + this.disksMenu.style.display = "none"; + } + this.addEventListener(this.elements.parent, "mousedown touchstart", (e) => { + if (this.isChild(this.disksMenu, e.target)) return; + if (e.pointerType === "touch") return; + if (e.target === diskButton[0] || e.target === diskButton[2]) return; + this.closeDisksMenu(); + }) + this.settingParent = this.createElement("div"); this.settingsMenuOpen = false; const settingButton = addButton("Settings", '', () => { @@ -1904,6 +1933,7 @@ class EmulatorJS { if (e.target === settingButton[0] || e.target === settingButton[2]) return; this.closeSettingsMenu(); }) + this.addEventListener(this.canvas, "click", (e) => { if (e.pointerType === "touch") return; if (!this.paused) { @@ -3853,15 +3883,7 @@ class EmulatorJS { this.saveSettings(); if (this.debug) console.log(option, value); if (option === "shader") { - try { - this.Module.FS.unlink("/shader/shader.glslp"); - } catch(e) {} - if (value === "disabled") { - this.gameManager.toggleShader(0); - return; - } - this.Module.FS.writeFile("/shader/shader.glslp", window.EJS_SHADERS[value]); - this.gameManager.toggleShader(1); + this.enableShader(value); return; } else if (option === "disk") { this.gameManager.setCurrentDisk(value); @@ -3912,10 +3934,197 @@ class EmulatorJS { } else { this.isPointerCapture = false; } + } else if (option === "vsync") { + this.gameManager.setVSync(value === "enabled"); } this.gameManager.setVariable(option, value); this.saveSettings(); } + setupDisksMenu() { + this.disksMenu = this.createElement("div"); + this.disksMenu.classList.add("ejs_settings_parent"); + const nested = this.createElement("div"); + nested.classList.add("ejs_settings_transition"); + this.disks = {}; + + const home = this.createElement("div"); + home.style.overflow = "auto"; + const menus = []; + this.handleDisksResize = () => { + let needChange = false; + if (this.disksMenu.style.display !== "") { + this.disksMenu.style.opacity = "0"; + this.disksMenu.style.display = ""; + needChange = true; + } + let height = this.elements.parent.getBoundingClientRect().height; + let w2 = this.diskParent.parentElement.getBoundingClientRect().width; + let disksX = this.diskParent.getBoundingClientRect().x; + if (w2 > window.innerWidth) disksX += (w2 - window.innerWidth); + const onTheRight = disksX > (w2-15)/2; + if (height > 375) height = 375; + home.style['max-height'] = (height - 95) + "px"; + nested.style['max-height'] = (height - 95) + "px"; + for (let i=0; i { + this.disks[title] = newValue; + funcs.forEach(e => e(title)); + } + let allOpts = {}; + + const addToMenu = (title, id, options, defaultOption) => { + const span = this.createElement("span"); + span.innerText = title; + + const current = this.createElement("div"); + current.innerText = ""; + current.classList.add("ejs_settings_main_bar_selected"); + span.appendChild(current); + + const menu = this.createElement("div"); + menus.push(menu); + menu.style.overflow = "auto"; + menu.setAttribute("hidden", ""); + const button = this.createElement("button"); + const goToHome = () => { + const homeSize = this.getElementSize(home); + nested.style.width = (homeSize.width+20) + "px"; + nested.style.height = homeSize.height + "px"; + menu.setAttribute("hidden", ""); + home.removeAttribute("hidden"); + } + this.addEventListener(button, "click", goToHome); + + button.type = "button"; + button.classList.add("ejs_back_button"); + menu.appendChild(button); + const pageTitle = this.createElement("span"); + pageTitle.innerText = title; + pageTitle.classList.add("ejs_menu_text_a"); + button.appendChild(pageTitle); + + const optionsMenu = this.createElement("div"); + optionsMenu.classList.add("ejs_setting_menu"); + + let buttons = []; + let opts = options; + if (Array.isArray(options)) { + opts = {}; + for (let i=0; i { + if (id !== title) return; + for (let j=0; j { + this.disks[id] = opt; + for (let j=0; j 1) { + const diskLabels = {}; + let isM3U = false; + let disks = {}; + if (this.fileName.split(".").pop() === "m3u") { + disks = this.gameManager.Module.FS.readFile(this.fileName, { encoding: 'utf8' }).split("\n"); + isM3U = true; + } + for (let i=0; i= 2) { + // has a label - use that instead + diskLabel = diskLabelValues[1]; + } + diskLabels[i.toString()] = diskLabel; + } + } + addToMenu(this.localization("Disk"), "disk", diskLabels, this.gameManager.getCurrentDisk().toString()); + } + + this.disksMenu.appendChild(nested); + + this.diskParent.appendChild(this.disksMenu); + this.diskParent.style.position = "relative"; + + const homeSize = this.getElementSize(home); + nested.style.width = (homeSize.width+20) + "px"; + nested.style.height = homeSize.height + "px"; + + this.disksMenu.style.display = "none"; + + if (this.debug) { + console.log("Available core options", allOpts); + } + + if (this.config.defaultOptions) { + for (const k in this.config.defaultOptions) { + this.changeDiskOption(k, this.config.defaultOptions[k]); + } + } + } setupSettingsMenu() { this.settingsMenu = this.createElement("div"); this.settingsMenu.classList.add("ejs_settings_parent"); @@ -4006,8 +4215,6 @@ class EmulatorJS { const optionsMenu = this.createElement("div"); optionsMenu.classList.add("ejs_setting_menu"); - //optionsMenu.style["max-height"] = "385px"; - //optionsMenu.style.overflow = "auto"; let buttons = []; let opts = options; @@ -4064,28 +4271,35 @@ class EmulatorJS { nested.appendChild(menu); } - //addToMenu("Test", 'test', {a:1, b:2, c:3}, 2); - //addToMenu("Test2", 'test_2', [4, 5, 6]); - //addToMenu("Testertthgfd", 'booger', [7, 8, 9]); - - if (this.gameManager.getDiskCount() > 1) { - const diskLabels = {}; - for (let i=0; i { + this.Module.FS.writeFile(`/shader/${resource.name}`, resource.type === 'base64' ? atob(resource.value) : resource.value, {}, 'w+'); + }); + } + } + + this.gameManager.toggleShader(1); + } + collectScreenRecordingMediaTracks(canvasEl, fps) { let videoTrack = null; const videoTracks = canvasEl.captureStream(fps).getVideoTracks(); diff --git a/data/loader.js b/data/loader.js index 582043d..2603446 100644 --- a/data/loader.js +++ b/data/loader.js @@ -113,6 +113,7 @@ config.disableLocalStorage = window.EJS_disableLocalStorage; config.forceLegacyCores = window.EJS_forceLegacyCores; config.noAutoFocus = window.EJS_noAutoFocus; + config.shaders = Object.assign({}, window.EJS_SHADERS, window.EJS_shaders ? window.EJS_shaders : {}); if (typeof window.EJS_language === "string" && window.EJS_language !== "en-US") { try { diff --git a/data/localization/Translate.html b/data/localization/Translate.html index beeb2b5..e1ef1c5 100644 --- a/data/localization/Translate.html +++ b/data/localization/Translate.html @@ -2,7 +2,7 @@ - EmulalorJS | Translate Languages + EmulatorJS | Translate Languages @@ -345,4 +345,4 @@ console.log(data7); } - \ No newline at end of file + diff --git a/data/localization/de-GER.json b/data/localization/de-GER.json index 57bedc6..07aac89 100644 --- a/data/localization/de-GER.json +++ b/data/localization/de-GER.json @@ -9,40 +9,40 @@ "7": "7", "8": "8", "9": "9", - "Restart": "Neu starten", + "Restart": "Neustart", "Pause": "Pause", "Play": "Spielen", - "Save State": "Sicherer Staat", - "Load State": "Ladezustand", - "Control Settings": "Kontrolleinstellungen", - "Cheats": "Betrüger", + "Save State": "Zustand speichern", + "Load State": "Zustand laden", + "Control Settings": "Steuerung", + "Cheats": "Cheats", "Cache Manager": "Cache-Manager", - "Export Save File": "Speichern Sie die Datei exportieren", - "Import Save File": "Speicherdatei importieren", - "Netplay": "Spiel am Netz", + "Export Save File": "Speicherstand exportieren", + "Import Save File": "Speicherstand importieren", + "Netplay": "Onlinespiel", "Mute": "Stumm", "Unmute": "Stummschaltung aufheben", "Settings": "Einstellungen", "Enter Fullscreen": "Vollbildmodus aktivieren", - "Exit Fullscreen": "Beenden Sie den Vollbildmodus", + "Exit Fullscreen": "Vollbildmodus verlassen", "Reset": "Zurücksetzen", - "Clear": "Klar", + "Clear": "Löschen", "Close": "Schließen", - "QUICK SAVE STATE": "SCHNELLER SPEICHERENZUSTAND", - "QUICK LOAD STATE": "SCHNELLER LADEZUSTAND", + "QUICK SAVE STATE": "SCHNELLSPEICHERN", + "QUICK LOAD STATE": "SCHNELLLADEN", "CHANGE STATE SLOT": "STATUS-SLOT ÄNDERN", - "FAST FORWARD": "SCHNELLER VORLAUF", + "FAST FORWARD": "VORSPULEN", "Player": "Spieler", "Connected Gamepad": "Verbundenes Gamepad", "Gamepad": "Gamepad", "Keyboard": "Tastatur", - "Set": "Satz", + "Set": "Setzen", "Add Cheat": "Cheat hinzufügen", - "Create a Room": "Erstellen Sie einen Raum", + "Create a Room": "Raum erstellen", "Rooms": "Räume", "Start Game": "Spiel beginnen", "Loading...": "Wird geladen...", - "Download Game Core": "Laden Sie Game Core herunter", + "Download Game Core": "Game Core herunterladen", "Decompress Game Core": "Game Core entpacken", "Download Game Data": "Spieldaten herunterladen", "Decompress Game Data": "Spieldaten entpacken", @@ -57,16 +57,16 @@ "FPS": "FPS", "show": "zeigen", "hide": "verstecken", - "Fast Forward Ratio": "Schnellvorlaufverhältnis", - "Fast Forward": "Schneller Vorlauf", - "Enabled": "Ermöglicht", - "Save State Slot": "Status-Slot speichern", - "Save State Location": "Bundeslandstandort speichern", + "Fast Forward Ratio": "Vorspulgeschwindigkeit", + "Fast Forward": "Vorspulen", + "Enabled": "Aktiviert", + "Save State Slot": "Speicherplatz", + "Save State Location": "Speicherort", "Download": "Herunterladen", "Keep in Browser": "Im Browser behalten", "Auto": "Auto", "NTSC": "NTSC", - "PAL": "KUMPEL", + "PAL": "PAL", "Dendy": "Dendy", "8:7 PAR": "8:7 PAR", "4:3": "4:3", @@ -77,59 +77,59 @@ "Player 1": "Spieler 1", "Player 2": "Spieler 2", "Both": "Beide", - "SAVED STATE TO SLOT": "STATUS FÜR SLOT GESPEICHERT", - "LOADED STATE FROM SLOT": "GELADENER STATUS VON SLOT", - "SET SAVE STATE SLOT TO": "SAVE STATE SLOT EINSTELLEN AUF", + "SAVED STATE TO SLOT": "STATUS IN SLOT SPEICHERN", + "LOADED STATE FROM SLOT": "STATUS VON SLOT GELADEN", + "SET SAVE STATE SLOT TO": "SPEICHERPLATZ ÄNDERN", "Network Error": "Netzwerkfehler", - "Submit": "Einreichen", + "Submit": "Abschicken", "Description": "Beschreibung", "Code": "Code", "Add Cheat Code": "Cheat-Code hinzufügen", - "Leave Room": "Zimmer verlassen", + "Leave Room": "Raum verlassen", "Password": "Passwort", "Password (optional)": "Passwort (optional)", "Max Players": "Maximale Spieleranzahl", "Room Name": "Raumname", - "Join": "Verbinden", + "Join": "Beitreten", "Player Name": "Spielername", - "Set Player Name": "Legen Sie den Spielernamen fest", + "Set Player Name": "Spielernamen festlegen", "Left Handed Mode": "Linkshänder-Modus", "Virtual Gamepad": "Virtuelles Gamepad", "Disk": "Scheibe", - "Press Keyboard": "Drücken Sie Tastatur", + "Press Keyboard": "Taste drücken", "INSERT COIN": "MÜNZE EINWERFEN", "Remove": "Entfernen", - "SAVE LOADED FROM BROWSER": "SPEICHERN VOM BROWSER GELADEN", - "SAVE SAVED TO BROWSER": "SPEICHERN IM BROWSER GESPEICHERT", + "SAVE LOADED FROM BROWSER": "SPEICHERSTAND VOM BROWSER GELADEN", + "SAVE SAVED TO BROWSER": "SPEICHERSTAND IM BROWSER GESPEICHERT", "Join the discord": "Treten Sie dem Discord bei", "View on GitHub": "Auf GitHub ansehen", "Failed to start game": "Das Spiel konnte nicht gestartet werden", - "Download Game BIOS": "Laden Sie das Spiel-BIOS herunter", - "Decompress Game BIOS": "Dekomprimieren Sie das Spiel-BIOS", - "Download Game Parent": "Laden Sie Game Parent herunter", - "Decompress Game Parent": "Dekomprimieren Sie das übergeordnete Spiel", - "Download Game Patch": "Laden Sie den Spiel-Patch herunter", - "Decompress Game Patch": "Dekomprimieren Sie den Spiel-Patch", + "Download Game BIOS": "Spiel-BIOS herunterladen", + "Decompress Game BIOS": "Spiel-BIOS entpacken", + "Download Game Parent": "Game Parent herunterladen", + "Decompress Game Parent": "Game Parent entpacken", + "Download Game Patch": "Spiel-Patch herunterladen", + "Decompress Game Patch": "Spiel-Patch entpacken", "Download Game State": "Spielstatus herunterladen", "Check console": "Überprüfen Sie die Konsole", "Error for site owner": "Fehler für Websitebesitzer", "EmulatorJS": "EmulatorJS", "Clear All": "Alles löschen", - "Take Screenshot": "Einen Screenshot machen", + "Take Screenshot": "Screenshot aufnehmen", "Quick Save": "Schnellspeichern", "Quick Load": "Schnell laden", "REWIND": "ZURÜCKSPULEN", - "Rewind Enabled (requires restart)": "Rücklauf aktiviert (Neustart erforderlich)", - "Rewind Granularity": "Granularität zurückspulen", - "Slow Motion Ratio": "Zeitlupenverhältnis", + "Rewind Enabled (requires restart)": "Zurückspulen aktiviert (Neustart erforderlich)", + "Rewind Granularity": "Zurückspulgeschwindigkeit", + "Slow Motion Ratio": "Zeitlupengeschwindigkeit", "Slow Motion": "Zeitlupe", - "Home": "Heim", + "Home": "Zurück", "EmulatorJS License": "EmulatorJS-Lizenz", "RetroArch License": "RetroArch-Lizenz", "SLOW MOTION": "ZEITLUPE", "A": "A", "B": "B", - "SELECT": "WÄHLEN", + "SELECT": "SELECT", "START": "START", "UP": "HOCH", "DOWN": "RUNTER", @@ -140,12 +140,12 @@ "L": "L", "R": "R", "Z": "Z", - "STICK UP": "Bleiben Sie dran", - "STICK DOWN": "HALTE DICH", - "STICK LEFT": "LINKS STEHEN", - "STICK RIGHT": "HALTEN SIE SICH NACH RECHTS", - "C-PAD UP": "C-PAD nach oben", - "C-PAD DOWN": "C-PAD NACH UNTEN", + "STICK UP": "STICK NACH OBEN", + "STICK DOWN": "STICK NOCH UNTEN", + "STICK LEFT": "STICK LINKS", + "STICK RIGHT": "STICK RECHTS", + "C-PAD UP": "C-PAD HOCH", + "C-PAD DOWN": "C-PAD RUNTER", "C-PAD LEFT": "C-PAD LINKS", "C-PAD RIGHT": "C-PAD RECHTS", "MICROPHONE": "MIKROFON", @@ -171,83 +171,83 @@ "COLOR": "FARBE", "B/W": "S/W", "PAUSE": "PAUSE", - "OPTION": "MÖGLICHKEIT", + "OPTION": "EINSTELLUNGEN", "OPTION 1": "OPTION 1", "OPTION 2": "OPTION 2", "L2": "L2", "R2": "R2", "L3": "L3", "R3": "R3", - "L STICK UP": "L BLEIB DURCH", - "L STICK DOWN": "L HALTE DICH", + "L STICK UP": "L STICK NACH OBEN", + "L STICK DOWN": "L STICK NACH UNTEN", "L STICK LEFT": "L STICK LINKS", - "L STICK RIGHT": "L HALTE NACH RECHTS", - "R STICK UP": "R HALTEN SIE SICH AUF", - "R STICK DOWN": "R HALTEN SIE SICH NACH UNTEN", + "L STICK RIGHT": "L STICK RECHTS", + "R STICK UP": "R STICK NACH OBEN", + "R STICK DOWN": "R STICK NACH UNTEN", "R STICK LEFT": "R STICK LINKS", - "R STICK RIGHT": "R STICK NACH RECHTS", + "R STICK RIGHT": "R STICK RECHTS", "Start": "Start", - "Select": "Wählen", + "Select": "Select", "Fast": "Schnell", "Slow": "Langsam", - "a": "A", - "b": "B", - "c": "C", - "d": "D", + "a": "a", + "b": "b", + "c": "c", + "d": "d", "e": "e", "f": "F", - "g": "G", - "h": "H", - "i": "ich", + "g": "g", + "h": "h", + "i": "i", "j": "J", "k": "k", "l": "l", - "m": "M", - "n": "N", - "o": "Ö", - "p": "P", - "q": "Q", - "r": "R", - "s": "S", - "t": "T", + "m": "m", + "n": "n", + "o": "o", + "p": "p", + "q": "q", + "r": "r", + "s": "s", + "t": "t", "u": "u", "v": "v", "w": "w", - "x": "X", - "y": "j", + "x": "x", + "y": "y", "z": "z", - "enter": "eingeben", - "escape": "Flucht", - "space": "Raum", + "enter": "ENTER", + "escape": "ESC", + "space": "Leertaste", "tab": "Tab", "backspace": "Rücktaste", - "delete": "löschen", + "delete": "ENTF", "arrowup": "Pfeil nach oben", "arrowdown": "Pfeil nach unten", "arrowleft": "Pfeil nach links", "arrowright": "Pfeil nach rechts", - "f1": "f1", - "f2": "f2", - "f3": "f3", - "f4": "f4", - "f5": "f5", - "f6": "f6", - "f7": "f7", - "f8": "f8", - "f9": "f9", - "f10": "f10", - "f11": "f11", - "f12": "f12", - "shift": "Schicht", - "control": "Kontrolle", + "f1": "F1", + "f2": "F2", + "f3": "F3", + "f4": "F4", + "f5": "F5", + "f6": "F6", + "f7": "F7", + "f8": "F8", + "f9": "F9", + "f10": "F10", + "f11": "F11", + "f12": "F12", + "shift": "Shift", + "control": "strg", "alt": "alt", "meta": "Meta", - "capslock": "Feststelltaste", - "insert": "einfügen", - "home": "heim", - "end": "Ende", - "pageup": "Seite nach oben", - "pagedown": "Bild nach unten", + "capslock": "capslock", + "insert": "einf", + "home": "pos1", + "end": "ende", + "pageup": "bild hoch", + "pagedown": "bild runter", "!": "!", "@": "@", "#": "#", @@ -282,15 +282,15 @@ "RIGHT_STICK_Y": "RIGHT_STICK_Y", "LEFT_TRIGGER": "LINKER TRIGGER", "RIGHT_TRIGGER": "RIGHT_TRIGGER", - "A_BUTTON": "EIN KNOPF", + "A_BUTTON": "A_BUTTON", "B_BUTTON": "B_BUTTON", "X_BUTTON": "X_BUTTON", "Y_BUTTON": "Y_BUTTON", - "START_BUTTON": "START KNOPF", - "SELECT_BUTTON": "AUSWAHLKNOPF", - "L1_BUTTON": "L1_TASTE", + "START_BUTTON": "START", + "SELECT_BUTTON": "SELECT", + "L1_BUTTON": "L1_BUTTON", "R1_BUTTON": "R1_BUTTON", - "L2_BUTTON": "L2_TASTE", + "L2_BUTTON": "L2_BUTTON", "R2_BUTTON": "R2_BUTTON", "LEFT_THUMB_BUTTON": "LEFT_THUMB_BUTTON", "RIGHT_THUMB_BUTTON": "RIGHT_THUMB_BUTTON", @@ -298,4 +298,4 @@ "DPAD_DOWN": "DPAD_DOWN", "DPAD_LEFT": "DPAD_LEFT", "DPAD_RIGHT": "DPAD_RIGHT" -} \ No newline at end of file +} diff --git a/data/localization/vi-VN.json b/data/localization/vi-VN.json new file mode 100644 index 0000000..ced065a --- /dev/null +++ b/data/localization/vi-VN.json @@ -0,0 +1,302 @@ +{ + "0": "0", + "1": "1", + "2": "2", + "3": "3", + "4": "4", + "5": "5", + "6": "6", + "7": "7", + "8": "8", + "9": "9", + "Restart": "Chạy lại", + "Pause": "Tạm dừng", + "Play": "Chơi", + "Save State": "Lưu State", + "Load State": "Nạp State", + "Control Settings": "Cài đặt điều khiển", + "Cheats": "Gian lận xíu", + "Cache Manager": "Bộ nhớ đệm", + "Export Save File": "Xuất tệp lưu", + "Import Save File": "Nhập tệp lưu ", + "Netplay": "Chơi qua mạng", + "Mute": "Tắt âm", + "Unmute": "Mở âm", + "Settings": "Cài đặt", + "Enter Fullscreen": "Toàn màn hình", + "Exit Fullscreen": "Thoát toàn màn hình", + "Context Menu": "Menu chuột phải", + "Reset": "Đặt lại", + "Clear": "Xoá", + "Close": "Đóng", + "QUICK SAVE STATE": "LƯU NHANH", + "QUICK LOAD STATE": "NẠP NHANH", + "CHANGE STATE SLOT": "ĐỔI NHANH", + "FAST FORWARD": "TIẾN NHANH ", + "Player": "Người chơi", + "Connected Gamepad": "Bảng điều khiển đã kết nối", + "Gamepad": "Bảng điều khiển ", + "Keyboard": "Bàn phím", + "Set": "Đặt", + "Add Cheat": "Thêm mật mã", + "Create a Room": "Tạo phòng", + "Rooms": "Các phòng", + "Start Game": "Bắt đầu chơi", + "Loading...": "Đang nạp...", + "Download Game Core": "Tải xuống nhân trò chơi", + "Decompress Game Core": "Giải nén nhân trò chơi", + "Download Game Data": "Tải xuống dữ liệu trò chơi", + "Decompress Game Data": "Giải nén dữ liệu trò chơi ", + "Shaders": "Shaders", + "Disabled": "Vô hiệu", + "2xScaleHQ": "2xScaleHQ", + "4xScaleHQ": "4xScaleHQ", + "CRT easymode": "CRT chế độ dễ", + "CRT aperture": "CRT aperture", + "CRT geom": "CRT geom", + "CRT mattias": "CRT mattias", + "FPS": "FPS", + "show": "hiện", + "hide": "ẩn", + "Fast Forward Ratio": "Tỷ lệ tiến nhanh", + "Fast Forward": "Tiến nhanh", + "Enabled": "Cho phép", + "Save State Slot": "Lưu trạng thái thẻ", + "Save State Location": "Lưu trạng thái vị trí", + "Download": "Tải về", + "Keep in Browser": "Giữ ở trình duyệt", + "Auto": "Auto", + "NTSC": "NTSC", + "PAL": "PAL", + "Dendy": "Dendy", + "8:7 PAR": "8:7 PAR", + "4:3": "4:3", + "Low": "Thấp", + "High": "Cao", + "Very High": "Rất cao", + "None": "Không gì", + "Player 1": "Game thủ 1", + "Player 2": "Game thủ 2", + "Both": "Cả hai", + "SAVED STATE TO SLOT": "SAVED STATE TO SLOT", + "LOADED STATE FROM SLOT": "LOADED STATE FROM SLOT", + "SET SAVE STATE SLOT TO": "SET SAVE STATE SLOT TO", + "Network Error": "Mạng bị lỗi", + "Submit": "Gửi đi", + "Description": "Mô tả", + "Code": "Mã", + "Add Cheat Code": "Thêm mã gian lận", + "Leave Room": "Rời phòng", + "Password": "Mật khẩu", + "Password (optional)": "Mật khẩu (tùy chọn)", + "Max Players": "Người chơi tối đa", + "Room Name": "Tên phòng", + "Join": "Tham gia", + "Player Name": "Tên người chơi", + "Set Player Name": "Đặt tên người chơi", + "Left Handed Mode": "Chế độ tay trái", + "Virtual Gamepad": "Bàn phím ảo", + "Disk": "Đĩa", + "Press Keyboard": "Bàn phím", + "INSERT COIN": "THÊM XU", + "Remove": "Loại bỏ", + "SAVE LOADED FROM BROWSER": "SAVE LOADED FROM BROWSER", + "SAVE SAVED TO BROWSER": "SAVE SAVED TO BROWSER", + "Join the discord": "Tham gia thảo luận", + "View on GitHub": "Xem trên GitHub", + "Failed to start game": "Thất bại khởi động game", + "Download Game BIOS": "Tải Game BIOS", + "Decompress Game BIOS": "Giải nén Game BIOS", + "Download Game Parent": "Tải Game cha", + "Decompress Game Parent": "Giải nén Game cha", + "Download Game Patch": "Tải vá Game ", + "Decompress Game Patch": "Giải nén Game vá", + "Download Game State": "Tải trạng thái Game", + "Check console": "Kiểm tra log console", + "Error for site owner": "Lỗi sở hữu trang chủ", + "EmulatorJS": "EmulatorJS", + "Clear All": "Xóa hết", + "Take Screenshot": "Chụp màn hình", + "Quick Save": "Lưu nhanh", + "Quick Load": "Nạp nhanh", + "REWIND": "REWIND", + "Rewind Enabled (requires restart)": "Cho phép quay lui (cần khởi động lại)", + "Rewind Granularity": "Rewind Granularity", + "Slow Motion Ratio": "Tỷ lệ chuyển động chậm", + "Slow Motion": "chuyển động chậm", + "Home": "Nhà", + "EmulatorJS License": "Giấy phép EmulatorJS", + "RetroArch License": "Giấy phép RetroArch ", + "SLOW MOTION": "CHUYỂN ĐỘNG CHẬM", + "A": "A", + "B": "B", + "SELECT": "SELECT", + "START": "START", + "UP": "UP", + "DOWN": "DOWN", + "LEFT": "LEFT", + "RIGHT": "RIGHT", + "X": "X", + "Y": "Y", + "L": "L", + "R": "R", + "Z": "Z", + "STICK UP": "STICK UP", + "STICK DOWN": "STICK DOWN", + "STICK LEFT": "STICK LEFT", + "STICK RIGHT": "STICK RIGHT", + "C-PAD UP": "C-PAD UP", + "C-PAD DOWN": "C-PAD DOWN", + "C-PAD LEFT": "C-PAD LEFT", + "C-PAD RIGHT": "C-PAD RIGHT", + "MICROPHONE": "MICROPHONE", + "BUTTON 1 / START": "BUTTON 1 / START", + "BUTTON 2": "BUTTON 2", + "BUTTON": "BUTTON", + "LEFT D-PAD UP": "LEFT D-PAD UP", + "LEFT D-PAD DOWN": "LEFT D-PAD DOWN", + "LEFT D-PAD LEFT": "LEFT D-PAD LEFT", + "LEFT D-PAD RIGHT": "LEFT D-PAD RIGHT", + "RIGHT D-PAD UP": "RIGHT D-PAD UP", + "RIGHT D-PAD DOWN": "RIGHT D-PAD DOWN", + "RIGHT D-PAD LEFT": "RIGHT D-PAD LEFT", + "RIGHT D-PAD RIGHT": "RIGHT D-PAD RIGHT", + "C": "C", + "MODE": "MODE", + "FIRE": "FIRE", + "RESET": "RESET", + "LEFT DIFFICULTY A": "LEFT DIFFICULTY A", + "LEFT DIFFICULTY B": "LEFT DIFFICULTY B", + "RIGHT DIFFICULTY A": "RIGHT DIFFICULTY A", + "RIGHT DIFFICULTY B": "RIGHT DIFFICULTY B", + "COLOR": "COLOR", + "B/W": "B/W", + "PAUSE": "PAUSE", + "OPTION": "OPTION", + "OPTION 1": "OPTION 1", + "OPTION 2": "OPTION 2", + "L2": "L2", + "R2": "R2", + "L3": "L3", + "R3": "R3", + "L STICK UP": "L STICK UP", + "L STICK DOWN": "L STICK DOWN", + "L STICK LEFT": "L STICK LEFT", + "L STICK RIGHT": "L STICK RIGHT", + "R STICK UP": "R STICK UP", + "R STICK DOWN": "R STICK DOWN", + "R STICK LEFT": "R STICK LEFT", + "R STICK RIGHT": "R STICK RIGHT", + "Start": "Start", + "Select": "Select", + "Fast": "Fast", + "Slow": "Slow", + "a": "a", + "b": "b", + "c": "c", + "d": "d", + "e": "e", + "f": "f", + "g": "g", + "h": "h", + "i": "i", + "j": "j", + "k": "k", + "l": "l", + "m": "m", + "n": "n", + "o": "o", + "p": "p", + "q": "q", + "r": "r", + "s": "s", + "t": "t", + "u": "u", + "v": "v", + "w": "w", + "x": "x", + "y": "y", + "z": "z", + "enter": "enter", + "escape": "escape", + "space": "space", + "tab": "tab", + "backspace": "backspace", + "delete": "delete", + "arrowup": "arrowup", + "arrowdown": "arrowdown", + "arrowleft": "arrowleft", + "arrowright": "arrowright", + "f1": "f1", + "f2": "f2", + "f3": "f3", + "f4": "f4", + "f5": "f5", + "f6": "f6", + "f7": "f7", + "f8": "f8", + "f9": "f9", + "f10": "f10", + "f11": "f11", + "f12": "f12", + "shift": "shift", + "control": "control", + "alt": "alt", + "meta": "meta", + "capslock": "capslock", + "insert": "insert", + "home": "home", + "end": "end", + "pageup": "pageup", + "pagedown": "pagedown", + "!": "!", + "@": "@", + "#": "#", + "$": "$", + "%": "%", + "^": "^", + "&": "&", + "*": "*", + "(": "(", + ")": ")", + "-": "-", + "_": "_", + "+": "+", + "=": "=", + "[": "[", + "]": "]", + "{": "{", + "}": "}", + ";": ";", + ":": ":", + "'": "'", + "\"": "\"", + ",": ",", + ".": ".", + "<": "<", + ">": ">", + "/": "/", + "?": "?", + "LEFT_STICK_X": "LEFT_STICK_X", + "LEFT_STICK_Y": "LEFT_STICK_Y", + "RIGHT_STICK_X": "RIGHT_STICK_X", + "RIGHT_STICK_Y": "RIGHT_STICK_Y", + "LEFT_TRIGGER": "LEFT_TRIGGER", + "RIGHT_TRIGGER": "RIGHT_TRIGGER", + "A_BUTTON": "A_BUTTON", + "B_BUTTON": "B_BUTTON", + "X_BUTTON": "X_BUTTON", + "Y_BUTTON": "Y_BUTTON", + "START_BUTTON": "START_BUTTON", + "SELECT_BUTTON": "SELECT_BUTTON", + "L1_BUTTON": "L1_BUTTON", + "R1_BUTTON": "R1_BUTTON", + "L2_BUTTON": "L2_BUTTON", + "R2_BUTTON": "R2_BUTTON", + "LEFT_THUMB_BUTTON": "LEFT_THUMB_BUTTON", + "RIGHT_THUMB_BUTTON": "RIGHT_THUMB_BUTTON", + "DPAD_UP": "DPAD_UP", + "DPAD_DOWN": "DPAD_DOWN", + "DPAD_LEFT": "DPAD_LEFT", + "DPAD_RIGHT": "DPAD_RIGHT" +} diff --git a/data/shaders.js b/data/shaders.js index 30e5baf..eed288f 100644 --- a/data/shaders.js +++ b/data/shaders.js @@ -1,14 +1,236 @@ +/** + * Shader configuration format: + * + * Default format, shader code in string: + * "shader_name": "...", + * + * Advanced format, shader code in multiple files: + * "shader_name": { + * //main shader file + * "shader": { + * "type": "text|base64", //value type, "text" - plain text, "base64" - encoded with Base64 + * "value": "...", //main shader file value + * }, + * //additional resources + * "resources": [ + * { + * "name": "resource_file_name", //file name of resource. Note: all files will be placed in the same directory + * "type": "text|base64", //resource value type, see "type" of main shader file + * "value": "...", //resource file value + * }, + * ... + * ], + * } + */ window.EJS_SHADERS = { - "2xScaleHQ.glslp": "shaders = 1\n\nshader0 = \"2xScaleHQ.glsl\"\nfilter_linear0 = false\nscale_type_0 = source\n", - "4xScaleHQ.glslp": "shaders = 1\n\nshader0 = \"4xScaleHQ.glsl\"\nfilter_linear0 = false\nscale_type_0 = source\n", - "crt-easymode.glslp": "shaders = 1\n\nshader0 = crt-easymode.glsl\nfilter_linear0 = false\nscale_type_0 = source\n", - "crt-aperture.glslp": "shaders = 1\n\nshader0 = crt-aperture.glsl\nfilter_linear0 = false\n", - "crt-geom.glslp": "shaders = 1\n\nshader0 = crt-geom.glsl\nfilter_linear0 = false\nscale_type_0 = source\n", - "crt-mattias.glslp": "\nshaders = 1\nshader0 = crt-mattias.glsl\nfilter_linear0 = false\n", - "2xScaleHQ.glsl": "/*\n2xGLSLHqFilter shader\n\nCopyright (C) 2005 guest(r) - guest.r@gmail.com\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n*/\n\n#if defined(VERTEX)\n\n#if __VERSION__ >= 130\n#define COMPAT_VARYING out\n#define COMPAT_ATTRIBUTE in\n#define COMPAT_TEXTURE texture\n#else\n#define COMPAT_VARYING varying \n#define COMPAT_ATTRIBUTE attribute \n#define COMPAT_TEXTURE texture2D\n#endif\n\n#ifdef GL_ES\n#define COMPAT_PRECISION mediump\n#else\n#define COMPAT_PRECISION\n#endif\n\nCOMPAT_ATTRIBUTE vec4 VertexCoord;\nCOMPAT_ATTRIBUTE vec4 COLOR;\nCOMPAT_ATTRIBUTE vec4 TexCoord;\nCOMPAT_VARYING vec4 COL0;\nCOMPAT_VARYING vec4 TEX0;\nCOMPAT_VARYING vec4 t1;\nCOMPAT_VARYING vec4 t2;\nCOMPAT_VARYING vec4 t3;\nCOMPAT_VARYING vec4 t4;\n\nvec4 _oPosition1; \nuniform mat4 MVPMatrix;\nuniform COMPAT_PRECISION int FrameDirection;\nuniform COMPAT_PRECISION int FrameCount;\nuniform COMPAT_PRECISION vec2 OutputSize;\nuniform COMPAT_PRECISION vec2 TextureSize;\nuniform COMPAT_PRECISION vec2 InputSize;\n\n// compatibility #defines\n#define vTexCoord TEX0.xy\n#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize\n#define OutSize vec4(OutputSize, 1.0 / OutputSize)\n\nvoid main()\n{\ngl_Position = MVPMatrix * VertexCoord;\nTEX0.xy = TexCoord.xy;\nfloat x = 0.5 * SourceSize.z;\nfloat y = 0.5 * SourceSize.w;\nvec2 dg1 = vec2( x, y);\nvec2 dg2 = vec2(-x, y);\nvec2 dx = vec2(x, 0.0);\nvec2 dy = vec2(0.0, y);\nt1 = vec4(vTexCoord - dg1, vTexCoord - dy);\nt2 = vec4(vTexCoord - dg2, vTexCoord + dx);\nt3 = vec4(vTexCoord + dg1, vTexCoord + dy);\nt4 = vec4(vTexCoord + dg2, vTexCoord - dx);\n}\n\n#elif defined(FRAGMENT)\n\n#if __VERSION__ >= 130\n#define COMPAT_VARYING in\n#define COMPAT_TEXTURE texture\nout vec4 FragColor;\n#else\n#define COMPAT_VARYING varying\n#define FragColor gl_FragColor\n#define COMPAT_TEXTURE texture2D\n#endif\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\nuniform COMPAT_PRECISION int FrameDirection;\nuniform COMPAT_PRECISION int FrameCount;\nuniform COMPAT_PRECISION vec2 OutputSize;\nuniform COMPAT_PRECISION vec2 TextureSize;\nuniform COMPAT_PRECISION vec2 InputSize;\nuniform sampler2D Texture;\nCOMPAT_VARYING vec4 TEX0;\nCOMPAT_VARYING vec4 t1;\nCOMPAT_VARYING vec4 t2;\nCOMPAT_VARYING vec4 t3;\nCOMPAT_VARYING vec4 t4;\n\n// compatibility #defines\n#define Source Texture\n#define vTexCoord TEX0.xy\n\n#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize\n#define OutSize vec4(OutputSize, 1.0 / OutputSize)\n\nfloat mx = 0.325; // start smoothing wt.\nfloat k = -0.250; // wt. decrease factor\nfloat max_w = 0.25; // max filter weight\nfloat min_w =-0.05; // min filter weight\nfloat lum_add = 0.25; // affects smoothing\nvec3 dt = vec3(1.0);\n\nvoid main()\n{\nvec3 c00 = COMPAT_TEXTURE(Source, t1.xy).xyz; \nvec3 c10 = COMPAT_TEXTURE(Source, t1.zw).xyz; \nvec3 c20 = COMPAT_TEXTURE(Source, t2.xy).xyz; \nvec3 c01 = COMPAT_TEXTURE(Source, t4.zw).xyz; \nvec3 c11 = COMPAT_TEXTURE(Source, vTexCoord).xyz; \nvec3 c21 = COMPAT_TEXTURE(Source, t2.zw).xyz; \nvec3 c02 = COMPAT_TEXTURE(Source, t4.xy).xyz; \nvec3 c12 = COMPAT_TEXTURE(Source, t3.zw).xyz; \nvec3 c22 = COMPAT_TEXTURE(Source, t3.xy).xyz; \n\nfloat md1 = dot(abs(c00 - c22), dt);\nfloat md2 = dot(abs(c02 - c20), dt);\n\nfloat w1 = dot(abs(c22 - c11), dt) * md2;\nfloat w2 = dot(abs(c02 - c11), dt) * md1;\nfloat w3 = dot(abs(c00 - c11), dt) * md2;\nfloat w4 = dot(abs(c20 - c11), dt) * md1;\n\nfloat t1 = w1 + w3;\nfloat t2 = w2 + w4;\nfloat ww = max(t1, t2) + 0.0001;\n\nc11 = (w1 * c00 + w2 * c20 + w3 * c22 + w4 * c02 + ww * c11) / (t1 + t2 + ww);\n\nfloat lc1 = k / (0.12 * dot(c10 + c12 + c11, dt) + lum_add);\nfloat lc2 = k / (0.12 * dot(c01 + c21 + c11, dt) + lum_add);\n\nw1 = clamp(lc1 * dot(abs(c11 - c10), dt) + mx, min_w, max_w);\nw2 = clamp(lc2 * dot(abs(c11 - c21), dt) + mx, min_w, max_w);\nw3 = clamp(lc1 * dot(abs(c11 - c12), dt) + mx, min_w, max_w);\nw4 = clamp(lc2 * dot(abs(c11 - c01), dt) + mx, min_w, max_w);\nFragColor = vec4(w1 * c10 + w2 * c21 + w3 * c12 + w4 * c01 + (1.0 - w1 - w2 - w3 - w4) * c11, 1.0);\n} \n#endif\n", - "4xScaleHQ.glsl": "/*\n4xGLSLHqFilter shader\n\nCopyright (C) 2005 guest(r) - guest.r@gmail.com\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n*/\n\n#if defined(VERTEX)\n\n#if __VERSION__ >= 130\n#define COMPAT_VARYING out\n#define COMPAT_ATTRIBUTE in\n#define COMPAT_TEXTURE texture\n#else\n#define COMPAT_VARYING varying \n#define COMPAT_ATTRIBUTE attribute \n#define COMPAT_TEXTURE texture2D\n#endif\n\n#ifdef GL_ES\n#define COMPAT_PRECISION mediump\n#else\n#define COMPAT_PRECISION\n#endif\n\nCOMPAT_ATTRIBUTE vec4 VertexCoord;\nCOMPAT_ATTRIBUTE vec4 COLOR;\nCOMPAT_ATTRIBUTE vec4 TexCoord;\nCOMPAT_VARYING vec4 COL0;\nCOMPAT_VARYING vec4 TEX0;\nCOMPAT_VARYING vec4 t1;\nCOMPAT_VARYING vec4 t2;\nCOMPAT_VARYING vec4 t3;\nCOMPAT_VARYING vec4 t4;\nCOMPAT_VARYING vec4 t5;\nCOMPAT_VARYING vec4 t6;\n\nvec4 _oPosition1; \nuniform mat4 MVPMatrix;\nuniform COMPAT_PRECISION int FrameDirection;\nuniform COMPAT_PRECISION int FrameCount;\nuniform COMPAT_PRECISION vec2 OutputSize;\nuniform COMPAT_PRECISION vec2 TextureSize;\nuniform COMPAT_PRECISION vec2 InputSize;\n\n// compatibility #defines\n#define vTexCoord TEX0.xy\n#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize\n#define OutSize vec4(OutputSize, 1.0 / OutputSize)\n\nvoid main()\n{\ngl_Position = MVPMatrix * VertexCoord;\nTEX0.xy = TexCoord.xy;\nfloat x = 0.5 * SourceSize.z;\nfloat y = 0.5 * SourceSize.w;\nvec2 dg1 = vec2( x, y);\nvec2 dg2 = vec2(-x, y);\nvec2 sd1 = dg1 * 0.5;\nvec2 sd2 = dg2 * 0.5;\nvec2 ddx = vec2(x, 0.0);\nvec2 ddy = vec2(0.0, y);\nt1 = vec4(vTexCoord - sd1, vTexCoord - ddy);\nt2 = vec4(vTexCoord - sd2, vTexCoord + ddx);\nt3 = vec4(vTexCoord + sd1, vTexCoord + ddy);\nt4 = vec4(vTexCoord + sd2, vTexCoord - ddx);\nt5 = vec4(vTexCoord - dg1, vTexCoord - dg2);\nt6 = vec4(vTexCoord + dg1, vTexCoord + dg2);\n}\n\n#elif defined(FRAGMENT)\n\n#if __VERSION__ >= 130\n#define COMPAT_VARYING in\n#define COMPAT_TEXTURE texture\nout vec4 FragColor;\n#else\n#define COMPAT_VARYING varying\n#define FragColor gl_FragColor\n#define COMPAT_TEXTURE texture2D\n#endif\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\nuniform COMPAT_PRECISION int FrameDirection;\nuniform COMPAT_PRECISION int FrameCount;\nuniform COMPAT_PRECISION vec2 OutputSize;\nuniform COMPAT_PRECISION vec2 TextureSize;\nuniform COMPAT_PRECISION vec2 InputSize;\nuniform sampler2D Texture;\nCOMPAT_VARYING vec4 TEX0;\nCOMPAT_VARYING vec4 t1;\nCOMPAT_VARYING vec4 t2;\nCOMPAT_VARYING vec4 t3;\nCOMPAT_VARYING vec4 t4;\nCOMPAT_VARYING vec4 t5;\nCOMPAT_VARYING vec4 t6;\n\n// compatibility #defines\n#define Source Texture\n#define vTexCoord TEX0.xy\n\n#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize\n#define OutSize vec4(OutputSize, 1.0 / OutputSize)\n\nfloat mx = 1.0; // start smoothing wt.\nfloat k = -1.10; // wt. decrease factor\nfloat max_w = 0.75; // max filter weight\nfloat min_w = 0.03; // min filter weight\nfloat lum_add = 0.33; // affects smoothing\nvec3 dt = vec3(1.0);\n\nvoid main()\n{\nvec3 c = COMPAT_TEXTURE(Source, vTexCoord).xyz;\nvec3 i1 = COMPAT_TEXTURE(Source, t1.xy).xyz; \nvec3 i2 = COMPAT_TEXTURE(Source, t2.xy).xyz; \nvec3 i3 = COMPAT_TEXTURE(Source, t3.xy).xyz; \nvec3 i4 = COMPAT_TEXTURE(Source, t4.xy).xyz; \nvec3 o1 = COMPAT_TEXTURE(Source, t5.xy).xyz; \nvec3 o3 = COMPAT_TEXTURE(Source, t6.xy).xyz; \nvec3 o2 = COMPAT_TEXTURE(Source, t5.zw).xyz;\nvec3 o4 = COMPAT_TEXTURE(Source, t6.zw).xyz;\nvec3 s1 = COMPAT_TEXTURE(Source, t1.zw).xyz; \nvec3 s2 = COMPAT_TEXTURE(Source, t2.zw).xyz; \nvec3 s3 = COMPAT_TEXTURE(Source, t3.zw).xyz; \nvec3 s4 = COMPAT_TEXTURE(Source, t4.zw).xyz; \n\nfloat ko1=dot(abs(o1-c),dt);\nfloat ko2=dot(abs(o2-c),dt);\nfloat ko3=dot(abs(o3-c),dt);\nfloat ko4=dot(abs(o4-c),dt);\n\nfloat k1=min(dot(abs(i1-i3),dt),max(ko1,ko3));\nfloat k2=min(dot(abs(i2-i4),dt),max(ko2,ko4));\n\nfloat w1 = k2; if(ko3= 130\n #define COMPAT_VARYING out\n #define COMPAT_ATTRIBUTE in\n #define COMPAT_TEXTURE texture\n #else\n #define COMPAT_VARYING varying\n #define COMPAT_ATTRIBUTE attribute\n #define COMPAT_TEXTURE texture2D\n #endif\n \n #ifdef GL_ES\n #define COMPAT_PRECISION mediump\n #else\n #define COMPAT_PRECISION\n #endif\n COMPAT_VARYING float _frame_rotation;\n struct input_dummy {\n vec2 _video_size;\n vec2 _texture_size;\n vec2 _output_dummy_size;\n float _frame_count;\n float _frame_direction;\n float _frame_rotation;\n };\n vec4 _oPosition1;\n vec4 _r0005;\n COMPAT_ATTRIBUTE vec4 VertexCoord;\n COMPAT_ATTRIBUTE vec4 TexCoord;\n COMPAT_VARYING vec4 TEX0;\n \n uniform mat4 MVPMatrix;\n uniform int FrameDirection;\n uniform int FrameCount;\n uniform COMPAT_PRECISION vec2 OutputSize;\n uniform COMPAT_PRECISION vec2 TextureSize;\n uniform COMPAT_PRECISION vec2 InputSize;\n void main()\n {\n vec2 _oTex;\n _r0005 = VertexCoord.x*MVPMatrix[0];\n _r0005 = _r0005 + VertexCoord.y*MVPMatrix[1];\n _r0005 = _r0005 + VertexCoord.z*MVPMatrix[2];\n _r0005 = _r0005 + VertexCoord.w*MVPMatrix[3];\n _oPosition1 = _r0005;\n _oTex = TexCoord.xy;\n gl_Position = _r0005;\n TEX0.xy = TexCoord.xy;\n }\n #elif defined(FRAGMENT)\n \n #if __VERSION__ >= 130\n #define COMPAT_VARYING in\n #define COMPAT_TEXTURE texture\n out vec4 FragColor;\n #else\n #define COMPAT_VARYING varying\n #define FragColor gl_FragColor\n #define COMPAT_TEXTURE texture2D\n #endif\n \n #ifdef GL_ES\n #ifdef GL_FRAGMENT_PRECISION_HIGH\n precision highp float;\n #else\n precision mediump float;\n #endif\n #define COMPAT_PRECISION mediump\n #else\n #define COMPAT_PRECISION\n #endif\n COMPAT_VARYING float _frame_rotation;\n struct input_dummy {\n vec2 _video_size;\n vec2 _texture_size;\n vec2 _output_dummy_size;\n float _frame_count;\n float _frame_direction;\n float _frame_rotation;\n };\n vec4 _ret_0;\n float _TMP30;\n float _TMP29;\n float _TMP28;\n float _TMP13;\n float _TMP32;\n float _TMP11;\n float _TMP10;\n float _TMP31;\n float _TMP9;\n float _TMP8;\n float _TMP15;\n float _TMP14;\n float _TMP33;\n vec4 _TMP34;\n vec4 _TMP27;\n vec4 _TMP25;\n vec4 _TMP23;\n vec4 _TMP21;\n vec4 _TMP26;\n vec4 _TMP24;\n vec4 _TMP22;\n vec4 _TMP20;\n float _TMP4;\n vec4 _TMP3;\n vec4 _TMP2;\n float _TMP19;\n float _TMP18;\n float _TMP17;\n float _TMP16;\n vec4 _TMP1;\n vec2 _TMP0;\n uniform sampler2D Texture;\n input_dummy _IN1;\n float _TMP43;\n float _x_step0044;\n float _curve0044;\n float _a0048;\n float _val0052;\n float _a0052;\n vec4 _TMP57;\n vec4 _x0072;\n vec2 _c0086;\n vec4 _x0088;\n vec4 _x0094;\n vec2 _c0098;\n vec4 _x0100;\n vec2 _c0104;\n vec4 _x0106;\n vec4 _sample_min0110;\n vec4 _sample_max0110;\n vec4 _r0112;\n vec4 _TMP117;\n vec2 _co0124;\n vec2 _c0126;\n vec4 _x0128;\n vec4 _x0134;\n vec2 _c0138;\n vec4 _x0140;\n vec2 _c0144;\n vec4 _x0146;\n vec4 _sample_min0150;\n vec4 _sample_max0150;\n vec4 _r0152;\n vec4 _TMP157;\n float _TMP163;\n float _x_step0164;\n float _curve0164;\n float _a0168;\n float _val0172;\n float _a0172;\n float _TMP183;\n float _TMP189;\n float _x0190;\n float _a0196;\n float _x0198;\n vec2 _x0200;\n float _x0208;\n COMPAT_VARYING vec4 TEX0;\n \n uniform COMPAT_PRECISION vec2 OutputSize;\n uniform COMPAT_PRECISION vec2 TextureSize;\n uniform COMPAT_PRECISION vec2 InputSize;\n void main()\n {\n vec2 _dx1;\n vec2 _dy;\n vec2 _pix_co;\n vec2 _tex_co;\n vec2 _dist;\n vec3 _col2;\n vec3 _col21;\n vec4 _coeffs1;\n float _luma;\n float _bright;\n float _scan_weight;\n vec2 _mod_fac;\n int _dot_no;\n vec3 _mask_weight;\n vec3 _TMP37;\n _dx1 = vec2(1.00000000E+00/TextureSize.x, 0.00000000E+00);\n _dy = vec2(0.00000000E+00, 1.00000000E+00/TextureSize.y);\n _pix_co = TEX0.xy*TextureSize - vec2( 5.00000000E-01, 5.00000000E-01);\n _TMP0 = floor(_pix_co);\n _tex_co = (_TMP0 + vec2( 5.00000000E-01, 5.00000000E-01))/TextureSize;\n _dist = fract(_pix_co);\n _x_step0044 = float((_dist.x >= 5.00000000E-01));\n _a0048 = 2.50000000E-01 - (_dist.x - _x_step0044)*(_dist.x - _x_step0044);\n _TMP33 = inversesqrt(_a0048);\n _TMP14 = 1.00000000E+00/_TMP33;\n _a0052 = 5.00000000E-01 - _dist.x;\n _val0052 = float((_a0052 > 0.00000000E+00));\n _TMP15 = _val0052 - float((_a0052 < 0.00000000E+00));\n _curve0044 = 5.00000000E-01 - _TMP14*_TMP15;\n _TMP43 = _dist.x + 2.50000000E-01*(_curve0044 - _dist.x);\n _coeffs1 = 3.14159274E+00*vec4(1.00000000E+00 + _TMP43, _TMP43, 1.00000000E+00 - _TMP43, 2.00000000E+00 - _TMP43);\n _TMP1 = abs(_coeffs1);\n _TMP57 = max(_TMP1, vec4( 9.99999975E-06, 9.99999975E-06, 9.99999975E-06, 9.99999975E-06));\n _TMP16 = sin(_TMP57.x);\n _TMP17 = sin(_TMP57.y);\n _TMP18 = sin(_TMP57.z);\n _TMP19 = sin(_TMP57.w);\n _TMP2 = vec4(_TMP16, _TMP17, _TMP18, _TMP19);\n _x0072 = _TMP57/2.00000000E+00;\n _TMP16 = sin(_x0072.x);\n _TMP17 = sin(_x0072.y);\n _TMP18 = sin(_x0072.z);\n _TMP19 = sin(_x0072.w);\n _TMP3 = vec4(_TMP16, _TMP17, _TMP18, _TMP19);\n _coeffs1 = ((2.00000000E+00*_TMP2)*_TMP3)/(_TMP57*_TMP57);\n _TMP4 = dot(_coeffs1, vec4( 1.00000000E+00, 1.00000000E+00, 1.00000000E+00, 1.00000000E+00));\n _coeffs1 = _coeffs1/_TMP4;\n _c0086 = _tex_co - _dx1;\n _TMP20 = COMPAT_TEXTURE(Texture, _c0086);\n _x0088 = vec4( 1.00000000E+00, 1.00000000E+00, 1.00000000E+00, 1.00000000E+00) + (_TMP20 - vec4( 1.00000000E+00, 1.00000000E+00, 1.00000000E+00, 1.00000000E+00));\n _TMP21 = _TMP20*_x0088;\n _TMP22 = COMPAT_TEXTURE(Texture, _tex_co);\n _x0094 = vec4( 1.00000000E+00, 1.00000000E+00, 1.00000000E+00, 1.00000000E+00) + (_TMP22 - vec4( 1.00000000E+00, 1.00000000E+00, 1.00000000E+00, 1.00000000E+00));\n _TMP23 = _TMP22*_x0094;\n _c0098 = _tex_co + _dx1;\n _TMP24 = COMPAT_TEXTURE(Texture, _c0098);\n _x0100 = vec4( 1.00000000E+00, 1.00000000E+00, 1.00000000E+00, 1.00000000E+00) + (_TMP24 - vec4( 1.00000000E+00, 1.00000000E+00, 1.00000000E+00, 1.00000000E+00));\n _TMP25 = _TMP24*_x0100;\n _c0104 = _tex_co + 2.00000000E+00*_dx1;\n _TMP26 = COMPAT_TEXTURE(Texture, _c0104);\n _x0106 = vec4( 1.00000000E+00, 1.00000000E+00, 1.00000000E+00, 1.00000000E+00) + (_TMP26 - vec4( 1.00000000E+00, 1.00000000E+00, 1.00000000E+00, 1.00000000E+00));\n _TMP27 = _TMP26*_x0106;\n _r0112 = _coeffs1.x*_TMP21;\n _r0112 = _r0112 + _coeffs1.y*_TMP23;\n _r0112 = _r0112 + _coeffs1.z*_TMP25;\n _r0112 = _r0112 + _coeffs1.w*_TMP27;\n _sample_min0110 = min(_TMP23, _TMP25);\n _sample_max0110 = max(_TMP23, _TMP25);\n _TMP34 = min(_sample_max0110, _r0112);\n _TMP117 = max(_sample_min0110, _TMP34);\n _co0124 = _tex_co + _dy;\n _c0126 = _co0124 - _dx1;\n _TMP20 = COMPAT_TEXTURE(Texture, _c0126);\n _x0128 = vec4( 1.00000000E+00, 1.00000000E+00, 1.00000000E+00, 1.00000000E+00) + (_TMP20 - vec4( 1.00000000E+00, 1.00000000E+00, 1.00000000E+00, 1.00000000E+00));\n _TMP21 = _TMP20*_x0128;\n _TMP22 = COMPAT_TEXTURE(Texture, _co0124);\n _x0134 = vec4( 1.00000000E+00, 1.00000000E+00, 1.00000000E+00, 1.00000000E+00) + (_TMP22 - vec4( 1.00000000E+00, 1.00000000E+00, 1.00000000E+00, 1.00000000E+00));\n _TMP23 = _TMP22*_x0134;\n _c0138 = _co0124 + _dx1;\n _TMP24 = COMPAT_TEXTURE(Texture, _c0138);\n _x0140 = vec4( 1.00000000E+00, 1.00000000E+00, 1.00000000E+00, 1.00000000E+00) + (_TMP24 - vec4( 1.00000000E+00, 1.00000000E+00, 1.00000000E+00, 1.00000000E+00));\n _TMP25 = _TMP24*_x0140;\n _c0144 = _co0124 + 2.00000000E+00*_dx1;\n _TMP26 = COMPAT_TEXTURE(Texture, _c0144);\n _x0146 = vec4( 1.00000000E+00, 1.00000000E+00, 1.00000000E+00, 1.00000000E+00) + (_TMP26 - vec4( 1.00000000E+00, 1.00000000E+00, 1.00000000E+00, 1.00000000E+00));\n _TMP27 = _TMP26*_x0146;\n _r0152 = _coeffs1.x*_TMP21;\n _r0152 = _r0152 + _coeffs1.y*_TMP23;\n _r0152 = _r0152 + _coeffs1.z*_TMP25;\n _r0152 = _r0152 + _coeffs1.w*_TMP27;\n _sample_min0150 = min(_TMP23, _TMP25);\n _sample_max0150 = max(_TMP23, _TMP25);\n _TMP34 = min(_sample_max0150, _r0152);\n _TMP157 = max(_sample_min0150, _TMP34);\n _x_step0164 = float((_dist.y >= 5.00000000E-01));\n _a0168 = 2.50000000E-01 - (_dist.y - _x_step0164)*(_dist.y - _x_step0164);\n _TMP33 = inversesqrt(_a0168);\n _TMP14 = 1.00000000E+00/_TMP33;\n _a0172 = 5.00000000E-01 - _dist.y;\n _val0172 = float((_a0172 > 0.00000000E+00));\n _TMP15 = _val0172 - float((_a0172 < 0.00000000E+00));\n _curve0164 = 5.00000000E-01 - _TMP14*_TMP15;\n _TMP163 = _dist.y + (_curve0164 - _dist.y);\n _col2 = _TMP117.xyz + _TMP163*(_TMP157.xyz - _TMP117.xyz);\n _luma = dot(vec3( 2.12599993E-01, 7.15200007E-01, 7.22000003E-02), _col2);\n _TMP8 = max(_col2.y, _col2.z);\n _TMP9 = max(_col2.x, _TMP8);\n _bright = (_TMP9 + _luma)/2.00000000E+00;\n _TMP31 = min(6.49999976E-01, _bright);\n _TMP183 = max(3.49999994E-01, _TMP31);\n _x0190 = _bright*1.50000000E+00;\n _TMP31 = min(1.50000000E+00, _x0190);\n _TMP189 = max(1.50000000E+00, _TMP31);\n _a0196 = TEX0.y*2.00000000E+00*3.14159274E+00*TextureSize.y;\n _TMP10 = cos(_a0196);\n _x0198 = _TMP10*5.00000000E-01 + 5.00000000E-01;\n _TMP11 = pow(_x0198, _TMP189);\n _scan_weight = 1.00000000E+00 - _TMP11;\n _x0200 = (TEX0.xy*OutputSize*TextureSize)/InputSize;\n _mod_fac = floor(_x0200);\n _x0208 = _mod_fac.x/3.00000000E+00;\n _TMP32 = floor(_x0208);\n _TMP13 = _mod_fac.x - 3.00000000E+00*_TMP32;\n _dot_no = int(_TMP13);\n if (_dot_no == 0) {\n _mask_weight = vec3( 1.00000000E+00, 6.99999988E-01, 6.99999988E-01);\n } else {\n if (_dot_no == 1) {\n _mask_weight = vec3( 6.99999988E-01, 1.00000000E+00, 6.99999988E-01);\n } else {\n _mask_weight = vec3( 6.99999988E-01, 6.99999988E-01, 1.00000000E+00);\n }\n }\n if (InputSize.y >= 4.00000000E+02) {\n _scan_weight = 1.00000000E+00;\n }\n _col21 = _col2.xyz;\n _col2 = _col2*vec3(_scan_weight, _scan_weight, _scan_weight);\n _col2 = _col2 + _TMP183*(_col21 - _col2);\n _col2 = _col2*_mask_weight;\n _TMP28 = pow(_col2.x, 5.55555582E-01);\n _TMP29 = pow(_col2.y, 5.55555582E-01);\n _TMP30 = pow(_col2.z, 5.55555582E-01);\n _col2 = vec3(_TMP28, _TMP29, _TMP30);\n _TMP37 = _col2*1.20000005E+00;\n _ret_0 = vec4(_TMP37.x, _TMP37.y, _TMP37.z, 1.00000000E+00);\n FragColor = _ret_0;\n return;\n }\n #endif\n", - "crt-aperture.glsl": "\n/*\nCRT Shader by EasyMode\nLicense: GPL\n*/\n/*\n#pragma parameter SHARPNESS_IMAGE \"Sharpness Image\" 1.0 1.0 5.0 1.0\n#pragma parameter SHARPNESS_EDGES \"Sharpness Edges\" 3.0 1.0 5.0 1.0\n#pragma parameter GLOW_WIDTH \"Glow Width\" 0.5 0.05 0.65 0.05\n#pragma parameter GLOW_HEIGHT \"Glow Height\" 0.5 0.05 0.65 0.05\n#pragma parameter GLOW_HALATION \"Glow Halation\" 0.1 0.0 1.0 0.01\n#pragma parameter GLOW_DIFFUSION \"Glow Diffusion\" 0.05 0.0 1.0 0.01\n#pragma parameter MASK_COLORS \"Mask Colors\" 2.0 2.0 3.0 1.0\n#pragma parameter MASK_STRENGTH \"Mask Strength\" 0.3 0.0 1.0 0.05\n#pragma parameter MASK_SIZE \"Mask Size\" 1.0 1.0 9.0 1.0\n#pragma parameter SCANLINE_SIZE_MIN \"Scanline Size Min.\" 0.5 0.5 1.5 0.05\n#pragma parameter SCANLINE_SIZE_MAX \"Scanline Size Max.\" 1.5 0.5 1.5 0.05\n#pragma parameter GAMMA_INPUT \"Gamma Input\" 2.4 1.0 5.0 0.1\n#pragma parameter GAMMA_OUTPUT \"Gamma Output\" 2.4 1.0 5.0 0.1\n#pragma parameter BRIGHTNESS \"Brightness\" 1.5 0.0 2.0 0.05\n* */\n\n#define Coord TEX0\n\n#if defined(VERTEX)\n\n#if __VERSION__ >= 130\n#define OUT out\n#define IN in\n#define tex2D texture\n#else\n#define OUT varying \n#define IN attribute \n#define tex2D texture2D\n#endif\n\n#ifdef GL_ES\n#define PRECISION mediump\n#else\n#define PRECISION\n#endif\n\nIN vec4 VertexCoord;\nIN vec4 Color;\nIN vec2 TexCoord;\nOUT vec4 color;\nOUT vec2 Coord;\n\nuniform mat4 MVPMatrix;\nuniform PRECISION int FrameDirection;\nuniform PRECISION int FrameCount;\nuniform PRECISION vec2 OutputSize;\nuniform PRECISION vec2 TextureSize;\nuniform PRECISION vec2 InputSize;\n\nvoid main()\n{\ngl_Position = MVPMatrix * VertexCoord;\ncolor = Color;\nCoord = TexCoord;\n}\n\n#elif defined(FRAGMENT)\n\n#if __VERSION__ >= 130\n#define IN in\n#define tex2D texture\nout vec4 FragColor;\n#else\n#define IN varying\n#define FragColor gl_FragColor\n#define tex2D texture2D\n#endif\n\n#ifdef GL_ES\n#ifdef GL_FRAGMENT_PRECISION_HIGH\nprecision highp float;\n#else\nprecision mediump float;\n#endif\n#define PRECISION mediump\n#else\n#define PRECISION\n#endif\n\nuniform PRECISION int FrameDirection;\nuniform PRECISION int FrameCount;\nuniform PRECISION vec2 OutputSize;\nuniform PRECISION vec2 TextureSize;\nuniform PRECISION vec2 InputSize;\nuniform sampler2D Texture;\nIN vec2 Coord;\n\n#ifdef PARAMETER_UNIFORM\nuniform PRECISION float SHARPNESS_IMAGE;\nuniform PRECISION float SHARPNESS_EDGES;\nuniform PRECISION float GLOW_WIDTH;\nuniform PRECISION float GLOW_HEIGHT;\nuniform PRECISION float GLOW_HALATION;\nuniform PRECISION float GLOW_DIFFUSION;\nuniform PRECISION float MASK_COLORS;\nuniform PRECISION float MASK_STRENGTH;\nuniform PRECISION float MASK_SIZE;\nuniform PRECISION float SCANLINE_SIZE_MIN;\nuniform PRECISION float SCANLINE_SIZE_MAX;\nuniform PRECISION float GAMMA_INPUT;\nuniform PRECISION float GAMMA_OUTPUT;\nuniform PRECISION float BRIGHTNESS;\n#else\n#define SHARPNESS_IMAGE 1.0\n#define SHARPNESS_EDGES 3.0\n#define GLOW_WIDTH 0.5\n#define GLOW_HEIGHT 0.5\n#define GLOW_HALATION 0.1\n#define GLOW_DIFFUSION 0.05\n#define MASK_COLORS 2.0\n#define MASK_STRENGTH 0.3\n#define MASK_SIZE 1.0\n#define SCANLINE_SIZE_MIN 0.5\n#define SCANLINE_SIZE_MAX 1.5\n#define GAMMA_INPUT 2.4\n#define GAMMA_OUTPUT 2.4\n#define BRIGHTNESS 1.5\n#endif\n\n#define FIX(c) max(abs(c), 1e-5)\n#define PI 3.141592653589\n#define saturate(c) clamp(c, 0.0, 1.0)\n#define TEX2D(c) pow(tex2D(tex, c).rgb, vec3(GAMMA_INPUT))\n\nmat3 get_color_matrix(sampler2D tex, vec2 co, vec2 dx)\n{\nreturn mat3(TEX2D(co - dx), TEX2D(co), TEX2D(co + dx));\n}\n\nvec3 blur(mat3 m, float dist, float rad)\n{\nvec3 x = vec3(dist - 1.0, dist, dist + 1.0) / rad;\nvec3 w = exp2(x * x * -1.0);\n\nreturn (m[0] * w.x + m[1] * w.y + m[2] * w.z) / (w.x + w.y + w.z);\n}\n\nvec3 filter_gaussian(sampler2D tex, vec2 co, vec2 tex_size)\n{\nvec2 dx = vec2(1.0 / tex_size.x, 0.0);\nvec2 dy = vec2(0.0, 1.0 / tex_size.y);\nvec2 pix_co = co * tex_size;\nvec2 tex_co = (floor(pix_co) + 0.5) / tex_size;\nvec2 dist = (fract(pix_co) - 0.5) * -1.0;\n\nmat3 line0 = get_color_matrix(tex, tex_co - dy, dx);\nmat3 line1 = get_color_matrix(tex, tex_co, dx);\nmat3 line2 = get_color_matrix(tex, tex_co + dy, dx);\nmat3 column = mat3(blur(line0, dist.x, GLOW_WIDTH),\n blur(line1, dist.x, GLOW_WIDTH),\n blur(line2, dist.x, GLOW_WIDTH));\n\nreturn blur(column, dist.y, GLOW_HEIGHT);\n}\n\nvec3 filter_lanczos(sampler2D tex, vec2 co, vec2 tex_size, float sharp)\n{\ntex_size.x *= sharp;\n\nvec2 dx = vec2(1.0 / tex_size.x, 0.0);\nvec2 pix_co = co * tex_size - vec2(0.5, 0.0);\nvec2 tex_co = (floor(pix_co) + vec2(0.5, 0.0)) / tex_size;\nvec2 dist = fract(pix_co);\nvec4 coef = PI * vec4(dist.x + 1.0, dist.x, dist.x - 1.0, dist.x - 2.0);\n\ncoef = FIX(coef);\ncoef = 2.0 * sin(coef) * sin(coef / 2.0) / (coef * coef);\ncoef /= dot(coef, vec4(1.0));\n\nvec4 col1 = vec4(TEX2D(tex_co), 1.0);\nvec4 col2 = vec4(TEX2D(tex_co + dx), 1.0);\n\nreturn (mat4(col1, col1, col2, col2) * coef).rgb;\n}\n\nvec3 get_scanline_weight(float x, vec3 col)\n{\nvec3 beam = mix(vec3(SCANLINE_SIZE_MIN), vec3(SCANLINE_SIZE_MAX), col);\nvec3 x_mul = 2.0 / beam;\nvec3 x_offset = x_mul * 0.5;\n\nreturn smoothstep(0.0, 1.0, 1.0 - abs(x * x_mul - x_offset)) * x_offset;\n}\n\nvec3 get_mask_weight(float x)\n{\nfloat i = mod(floor(x * OutputSize.x * TextureSize.x / (InputSize.x * MASK_SIZE)), MASK_COLORS);\n\nif (i == 0.0) return mix(vec3(1.0, 0.0, 1.0), vec3(1.0, 0.0, 0.0), MASK_COLORS - 2.0);\nelse if (i == 1.0) return vec3(0.0, 1.0, 0.0);\nelse return vec3(0.0, 0.0, 1.0);\n}\n\nvoid main()\n{\nvec3 col_glow = filter_gaussian(Texture, Coord, TextureSize);\nvec3 col_soft = filter_lanczos(Texture, Coord, TextureSize, SHARPNESS_IMAGE);\nvec3 col_sharp = filter_lanczos(Texture, Coord, TextureSize, SHARPNESS_EDGES);\nvec3 col = sqrt(col_sharp * col_soft);\n\ncol *= get_scanline_weight(fract(Coord.y * TextureSize.y), col_soft);\ncol_glow = saturate(col_glow - col);\ncol += col_glow * col_glow * GLOW_HALATION;\ncol = mix(col, col * get_mask_weight(Coord.x) * MASK_COLORS, MASK_STRENGTH);\ncol += col_glow * GLOW_DIFFUSION;\ncol = pow(col * BRIGHTNESS, vec3(1.0 / GAMMA_OUTPUT));\n\nFragColor = vec4(col, 1.0);\n}\n\n#endif\n", - "crt-geom.glsl": "\n/*\nCRT-interlaced\n\nCopyright (C) 2010-2012 cgwg, Themaister and DOLLS\n\nThis program is free software; you can redistribute it and/or modify it\nunder the terms of the GNU General Public License as published by the Free\nSoftware Foundation; either version 2 of the License, or (at your option)\nany later version.\n\n(cgwg gave their consent to have the original version of this shader\ndistributed under the GPL in this message:\n\nhttp://board.byuu.org/viewtopic.php?p=26075#p26075\n\n\"Feel free to distribute my shaders under the GPL. After all, the\nbarrel distortion code was taken from the Curvature shader, which is\nunder the GPL.\"\n)\nThis shader variant is pre-configured with screen curvature\n*/\n/*\n#pragma parameter CRTgamma \"CRTGeom Target Gamma\" 2.4 0.1 5.0 0.1\n#pragma parameter monitorgamma \"CRTGeom Monitor Gamma\" 2.2 0.1 5.0 0.1\n#pragma parameter d \"CRTGeom Distance\" 1.6 0.1 3.0 0.1\n#pragma parameter CURVATURE \"CRTGeom Curvature Toggle\" 1.0 0.0 1.0 1.0\n#pragma parameter R \"CRTGeom Curvature Radius\" 2.0 0.1 10.0 0.1\n#pragma parameter cornersize \"CRTGeom Corner Size\" 0.03 0.001 1.0 0.005\n#pragma parameter cornersmooth \"CRTGeom Corner Smoothness\" 1000.0 80.0 2000.0 100.0\n#pragma parameter x_tilt \"CRTGeom Horizontal Tilt\" 0.0 -0.5 0.5 0.05\n#pragma parameter y_tilt \"CRTGeom Vertical Tilt\" 0.0 -0.5 0.5 0.05\n#pragma parameter overscan_x \"CRTGeom Horiz. Overscan %\" 100.0 -125.0 125.0 1.0\n#pragma parameter overscan_y \"CRTGeom Vert. Overscan %\" 100.0 -125.0 125.0 1.0\n#pragma parameter DOTMASK \"CRTGeom Dot Mask Toggle\" 0.3 0.0 0.3 0.3\n#pragma parameter SHARPER \"CRTGeom Sharpness\" 1.0 1.0 3.0 1.0\n#pragma parameter scanline_weight \"CRTGeom Scanline Weight\" 0.3 0.1 0.5 0.05\n*/\n\n#ifndef PARAMETER_UNIFORM\n#define CRTgamma 2.4\n#define monitorgamma 2.2\n#define d 1.6\n#define CURVATURE 1.0\n#define R 2.0\n#define cornersize 0.03\n#define cornersmooth 1000.0\n#define x_tilt 0.0\n#define y_tilt 0.0\n#define overscan_x 100.0\n#define overscan_y 100.0\n#define DOTMASK 0.3\n#define SHARPER 1.0\n#define scanline_weight 0.3\n#endif\n\n#if defined(VERTEX)\n\n#if __VERSION__ >= 130\n#define COMPAT_VARYING out\n#define COMPAT_ATTRIBUTE in\n#define COMPAT_TEXTURE texture\n#else\n#define COMPAT_VARYING varying \n#define COMPAT_ATTRIBUTE attribute \n#define COMPAT_TEXTURE texture2D\n#endif\n\n#ifdef GL_ES\n#define COMPAT_PRECISION mediump\n#else\n#define COMPAT_PRECISION\n#endif\n\nCOMPAT_ATTRIBUTE vec4 VertexCoord;\nCOMPAT_ATTRIBUTE vec4 COLOR;\nCOMPAT_ATTRIBUTE vec4 TexCoord;\nCOMPAT_VARYING vec4 COL0;\nCOMPAT_VARYING vec4 TEX0;\n\nvec4 _oPosition1; \nuniform mat4 MVPMatrix;\nuniform COMPAT_PRECISION int FrameDirection;\nuniform COMPAT_PRECISION int FrameCount;\nuniform COMPAT_PRECISION vec2 OutputSize;\nuniform COMPAT_PRECISION vec2 TextureSize;\nuniform COMPAT_PRECISION vec2 InputSize;\n\nCOMPAT_VARYING vec2 overscan;\nCOMPAT_VARYING vec2 aspect;\nCOMPAT_VARYING vec3 stretch;\nCOMPAT_VARYING vec2 sinangle;\nCOMPAT_VARYING vec2 cosangle;\nCOMPAT_VARYING vec2 one;\nCOMPAT_VARYING float mod_factor;\nCOMPAT_VARYING vec2 ilfac;\n\n#ifdef PARAMETER_UNIFORM\nuniform COMPAT_PRECISION float CRTgamma;\nuniform COMPAT_PRECISION float monitorgamma;\nuniform COMPAT_PRECISION float d;\nuniform COMPAT_PRECISION float CURVATURE;\nuniform COMPAT_PRECISION float R;\nuniform COMPAT_PRECISION float cornersize;\nuniform COMPAT_PRECISION float cornersmooth;\nuniform COMPAT_PRECISION float x_tilt;\nuniform COMPAT_PRECISION float y_tilt;\nuniform COMPAT_PRECISION float overscan_x;\nuniform COMPAT_PRECISION float overscan_y;\nuniform COMPAT_PRECISION float DOTMASK;\nuniform COMPAT_PRECISION float SHARPER;\nuniform COMPAT_PRECISION float scanline_weight;\n#endif\n\n#define FIX(c) max(abs(c), 1e-5);\n\nfloat intersect(vec2 xy)\n{\nfloat A = dot(xy,xy)+d*d;\nfloat B = 2.0*(R*(dot(xy,sinangle)-d*cosangle.x*cosangle.y)-d*d);\nfloat C = d*d + 2.0*R*d*cosangle.x*cosangle.y;\nreturn (-B-sqrt(B*B-4.0*A*C))/(2.0*A);\n}\n\nvec2 bkwtrans(vec2 xy)\n{\nfloat c = intersect(xy);\nvec2 point = vec2(c)*xy;\npoint -= vec2(-R)*sinangle;\npoint /= vec2(R);\nvec2 tang = sinangle/cosangle;\nvec2 poc = point/cosangle;\nfloat A = dot(tang,tang)+1.0;\nfloat B = -2.0*dot(poc,tang);\nfloat C = dot(poc,poc)-1.0;\nfloat a = (-B+sqrt(B*B-4.0*A*C))/(2.0*A);\nvec2 uv = (point-a*sinangle)/cosangle;\nfloat r = R*acos(a);\nreturn uv*r/sin(r/R);\n}\n\nvec2 fwtrans(vec2 uv)\n{\nfloat r = FIX(sqrt(dot(uv,uv)));\nuv *= sin(r/R)/r;\nfloat x = 1.0-cos(r/R);\nfloat D = d/R + x*cosangle.x*cosangle.y+dot(uv,sinangle);\nreturn d*(uv*cosangle-x*sinangle)/D;\n}\n\nvec3 maxscale()\n{\nvec2 c = bkwtrans(-R * sinangle / (1.0 + R/d*cosangle.x*cosangle.y));\nvec2 a = vec2(0.5,0.5)*aspect;\nvec2 lo = vec2(fwtrans(vec2(-a.x,c.y)).x, fwtrans(vec2(c.x,-a.y)).y)/aspect;\nvec2 hi = vec2(fwtrans(vec2(+a.x,c.y)).x, fwtrans(vec2(c.x,+a.y)).y)/aspect;\nreturn vec3((hi+lo)*aspect*0.5,max(hi.x-lo.x,hi.y-lo.y));\n}\n\nvoid main()\n{\n// START of parameters\n\n// gamma of simulated CRT\n//\tCRTgamma = 1.8;\n// gamma of display monitor (typically 2.2 is correct)\n//\tmonitorgamma = 2.2;\n// overscan (e.g. 1.02 for 2% overscan)\noverscan = vec2(1.00,1.00);\n// aspect ratio\naspect = vec2(1.0, 0.75);\n// lengths are measured in units of (approximately) the width\n// of the monitor simulated distance from viewer to monitor\n//\td = 2.0;\n// radius of curvature\n//\tR = 1.5;\n// tilt angle in radians\n// (behavior might be a bit wrong if both components are\n// nonzero)\nconst vec2 angle = vec2(0.0,0.0);\n// size of curved corners\n//\tcornersize = 0.03;\n// border smoothness parameter\n// decrease if borders are too aliased\n//\tcornersmooth = 1000.0;\n\n// END of parameters\n\nvec4 _oColor;\nvec2 _otexCoord;\ngl_Position = VertexCoord.x * MVPMatrix[0] + VertexCoord.y * MVPMatrix[1] + VertexCoord.z * MVPMatrix[2] + VertexCoord.w * MVPMatrix[3];\n_oPosition1 = gl_Position;\n_oColor = COLOR;\n_otexCoord = TexCoord.xy;\nCOL0 = COLOR;\nTEX0.xy = TexCoord.xy;\n\n// Precalculate a bunch of useful values we'll need in the fragment\n// shader.\nsinangle = sin(vec2(x_tilt, y_tilt)) + vec2(0.001);//sin(vec2(max(abs(x_tilt), 1e-3), max(abs(y_tilt), 1e-3)));\ncosangle = cos(vec2(x_tilt, y_tilt)) + vec2(0.001);//cos(vec2(max(abs(x_tilt), 1e-3), max(abs(y_tilt), 1e-3)));\nstretch = maxscale();\n\nilfac = vec2(1.0,clamp(floor(InputSize.y/200.0), 1.0, 2.0));\n\n// The size of one texel, in texture-coordinates.\nvec2 sharpTextureSize = vec2(SHARPER * TextureSize.x, TextureSize.y);\none = ilfac / sharpTextureSize;\n\n// Resulting X pixel-coordinate of the pixel we're drawing.\nmod_factor = TexCoord.x * TextureSize.x * OutputSize.x / InputSize.x;\n\n}\n\n#elif defined(FRAGMENT)\n\n#if __VERSION__ >= 130\n#define COMPAT_VARYING in\n#define COMPAT_TEXTURE texture\nout vec4 FragColor;\n#else\n#define COMPAT_VARYING varying\n#define FragColor gl_FragColor\n#define COMPAT_TEXTURE texture2D\n#endif\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\nstruct output_dummy {\nvec4 _color;\n};\n\nuniform COMPAT_PRECISION int FrameDirection;\nuniform COMPAT_PRECISION int FrameCount;\nuniform COMPAT_PRECISION vec2 OutputSize;\nuniform COMPAT_PRECISION vec2 TextureSize;\nuniform COMPAT_PRECISION vec2 InputSize;\nuniform sampler2D Texture;\nCOMPAT_VARYING vec4 TEX0;\n\n// Comment the next line to disable interpolation in linear gamma (and\n// gain speed).\n#define LINEAR_PROCESSING\n\n// Enable screen curvature.\n// #define CURVATURE\n\n// Enable 3x oversampling of the beam profile\n#define OVERSAMPLE\n\n// Use the older, purely gaussian beam profile\n//#define USEGAUSSIAN\n\n// Macros.\n#define FIX(c) max(abs(c), 1e-5);\n#define PI 3.141592653589\n\n#ifdef LINEAR_PROCESSING\n# define TEX2D(c) pow(COMPAT_TEXTURE(Texture, (c)), vec4(CRTgamma))\n#else\n# define TEX2D(c) COMPAT_TEXTURE(Texture, (c))\n#endif\n\nCOMPAT_VARYING vec2 one;\nCOMPAT_VARYING float mod_factor;\nCOMPAT_VARYING vec2 ilfac;\nCOMPAT_VARYING vec2 overscan;\nCOMPAT_VARYING vec2 aspect;\nCOMPAT_VARYING vec3 stretch;\nCOMPAT_VARYING vec2 sinangle;\nCOMPAT_VARYING vec2 cosangle;\n\n#ifdef PARAMETER_UNIFORM\nuniform COMPAT_PRECISION float CRTgamma;\nuniform COMPAT_PRECISION float monitorgamma;\nuniform COMPAT_PRECISION float d;\nuniform COMPAT_PRECISION float CURVATURE;\nuniform COMPAT_PRECISION float R;\nuniform COMPAT_PRECISION float cornersize;\nuniform COMPAT_PRECISION float cornersmooth;\nuniform COMPAT_PRECISION float x_tilt;\nuniform COMPAT_PRECISION float y_tilt;\nuniform COMPAT_PRECISION float overscan_x;\nuniform COMPAT_PRECISION float overscan_y;\nuniform COMPAT_PRECISION float DOTMASK;\nuniform COMPAT_PRECISION float SHARPER;\nuniform COMPAT_PRECISION float scanline_weight;\n#endif\n\nfloat intersect(vec2 xy)\n{\nfloat A = dot(xy,xy)+d*d;\nfloat B = 2.0*(R*(dot(xy,sinangle)-d*cosangle.x*cosangle.y)-d*d);\nfloat C = d*d + 2.0*R*d*cosangle.x*cosangle.y;\nreturn (-B-sqrt(B*B-4.0*A*C))/(2.0*A);\n}\n\nvec2 bkwtrans(vec2 xy)\n{\nfloat c = intersect(xy);\nvec2 point = vec2(c)*xy;\npoint -= vec2(-R)*sinangle;\npoint /= vec2(R);\nvec2 tang = sinangle/cosangle;\nvec2 poc = point/cosangle;\nfloat A = dot(tang,tang)+1.0;\nfloat B = -2.0*dot(poc,tang);\nfloat C = dot(poc,poc)-1.0;\nfloat a = (-B+sqrt(B*B-4.0*A*C))/(2.0*A);\nvec2 uv = (point-a*sinangle)/cosangle;\nfloat r = FIX(R*acos(a));\nreturn uv*r/sin(r/R);\n}\n\nvec2 transform(vec2 coord)\n{\ncoord *= TextureSize / InputSize;\ncoord = (coord-vec2(0.5))*aspect*stretch.z+stretch.xy;\nreturn (bkwtrans(coord)/vec2(overscan_x / 100.0, overscan_y / 100.0)/aspect+vec2(0.5)) * InputSize / TextureSize;\n}\n\nfloat corner(vec2 coord)\n{\ncoord *= TextureSize / InputSize;\ncoord = (coord - vec2(0.5)) * vec2(overscan_x / 100.0, overscan_y / 100.0) + vec2(0.5);\ncoord = min(coord, vec2(1.0)-coord) * aspect;\nvec2 cdist = vec2(cornersize);\ncoord = (cdist - min(coord,cdist));\nfloat dist = sqrt(dot(coord,coord));\nreturn clamp((cdist.x-dist)*cornersmooth,0.0, 1.0);\n}\n\n// Calculate the influence of a scanline on the current pixel.\n//\n// 'distance' is the distance in texture coordinates from the current\n// pixel to the scanline in question.\n// 'color' is the colour of the scanline at the horizontal location of\n// the current pixel.\nvec4 scanlineWeights(float distance, vec4 color)\n{\n// \"wid\" controls the width of the scanline beam, for each RGB\n// channel The \"weights\" lines basically specify the formula\n// that gives you the profile of the beam, i.e. the intensity as\n// a function of distance from the vertical center of the\n// scanline. In this case, it is gaussian if width=2, and\n// becomes nongaussian for larger widths. Ideally this should\n// be normalized so that the integral across the beam is\n// independent of its width. That is, for a narrower beam\n// \"weights\" should have a higher peak at the center of the\n// scanline than for a wider beam.\n#ifdef USEGAUSSIAN\nvec4 wid = 0.3 + 0.1 * pow(color, vec4(3.0));\nvec4 weights = vec4(distance / wid);\nreturn 0.4 * exp(-weights * weights) / wid;\n#else\nvec4 wid = 2.0 + 2.0 * pow(color, vec4(4.0));\nvec4 weights = vec4(distance / scanline_weight);\nreturn 1.4 * exp(-pow(weights * inversesqrt(0.5 * wid), wid)) / (0.6 + 0.2 * wid);\n#endif\n}\n\nvoid main()\n{\n// Here's a helpful diagram to keep in mind while trying to\n// understand the code:\n//\n// | | | | |\n// -------------------------------\n// | | | | |\n// | 01 | 11 | 21 | 31 | <-- current scanline\n// | | @ | | |\n// -------------------------------\n// | | | | |\n// | 02 | 12 | 22 | 32 | <-- next scanline\n// | | | | |\n// -------------------------------\n// | | | | |\n//\n// Each character-cell represents a pixel on the output\n// surface, \"@\" represents the current pixel (always somewhere\n// in the bottom half of the current scan-line, or the top-half\n// of the next scanline). The grid of lines represents the\n// edges of the texels of the underlying texture.\n\n// Texture coordinates of the texel containing the active pixel.\nvec2 xy = (CURVATURE > 0.5) ? transform(TEX0.xy) : TEX0.xy;\n\nfloat cval = corner(xy);\n\n// Of all the pixels that are mapped onto the texel we are\n// currently rendering, which pixel are we currently rendering?\nvec2 ilvec = vec2(0.0,ilfac.y > 1.5 ? mod(float(FrameCount),2.0) : 0.0);\nvec2 ratio_scale = (xy * TextureSize - vec2(0.5) + ilvec)/ilfac;\n#ifdef OVERSAMPLE\nfloat filter_ = InputSize.y/OutputSize.y;//fwidth(ratio_scale.y);\n#endif\nvec2 uv_ratio = fract(ratio_scale);\n\n// Snap to the center of the underlying texel.\nxy = (floor(ratio_scale)*ilfac + vec2(0.5) - ilvec) / TextureSize;\n\n// Calculate Lanczos scaling coefficients describing the effect\n// of various neighbour texels in a scanline on the current\n// pixel.\nvec4 coeffs = PI * vec4(1.0 + uv_ratio.x, uv_ratio.x, 1.0 - uv_ratio.x, 2.0 - uv_ratio.x);\n\n// Prevent division by zero.\ncoeffs = FIX(coeffs);\n\n// Lanczos2 kernel.\ncoeffs = 2.0 * sin(coeffs) * sin(coeffs / 2.0) / (coeffs * coeffs);\n\n// Normalize.\ncoeffs /= dot(coeffs, vec4(1.0));\n\n// Calculate the effective colour of the current and next\n// scanlines at the horizontal location of the current pixel,\n// using the Lanczos coefficients above.\nvec4 col = clamp(mat4(\n TEX2D(xy + vec2(-one.x, 0.0)),\n TEX2D(xy),\n TEX2D(xy + vec2(one.x, 0.0)),\n TEX2D(xy + vec2(2.0 * one.x, 0.0))) * coeffs,\n 0.0, 1.0);\nvec4 col2 = clamp(mat4(\n TEX2D(xy + vec2(-one.x, one.y)),\n TEX2D(xy + vec2(0.0, one.y)),\n TEX2D(xy + one),\n TEX2D(xy + vec2(2.0 * one.x, one.y))) * coeffs,\n 0.0, 1.0);\n\n#ifndef LINEAR_PROCESSING\ncol = pow(col , vec4(CRTgamma));\ncol2 = pow(col2, vec4(CRTgamma));\n#endif\n\n// Calculate the influence of the current and next scanlines on\n// the current pixel.\nvec4 weights = scanlineWeights(uv_ratio.y, col);\nvec4 weights2 = scanlineWeights(1.0 - uv_ratio.y, col2);\n#ifdef OVERSAMPLE\nuv_ratio.y =uv_ratio.y+1.0/3.0*filter_;\nweights = (weights+scanlineWeights(uv_ratio.y, col))/3.0;\nweights2=(weights2+scanlineWeights(abs(1.0-uv_ratio.y), col2))/3.0;\nuv_ratio.y =uv_ratio.y-2.0/3.0*filter_;\nweights=weights+scanlineWeights(abs(uv_ratio.y), col)/3.0;\nweights2=weights2+scanlineWeights(abs(1.0-uv_ratio.y), col2)/3.0;\n#endif\n\nvec3 mul_res = (col * weights + col2 * weights2).rgb * vec3(cval);\n\n// dot-mask emulation:\n// Output pixels are alternately tinted green and magenta.\nvec3 dotMaskWeights = mix(\nvec3(1.0, 1.0 - DOTMASK, 1.0),\nvec3(1.0 - DOTMASK, 1.0, 1.0 - DOTMASK),\nfloor(mod(mod_factor, 2.0))\n);\n\nmul_res *= dotMaskWeights;\n\n// Convert the image gamma for display on our output device.\nmul_res = pow(mul_res, vec3(1.0 / monitorgamma));\n\n// Color the texel.\noutput_dummy _OUT;\n_OUT._color = vec4(mul_res, 1.0);\nFragColor = _OUT._color;\nreturn;\n} \n#endif\n\n", - "crt-mattias.glsl": "\n#pragma parameter CURVATURE \"Curvature\" 0.5 0.0 1.0 0.05\n#pragma parameter SCANSPEED \"Scanline Crawl Speed\" 1.0 0.0 10.0 0.5\n#if defined(VERTEX)\n#if __VERSION__ >= 130\n#define COMPAT_VARYING out\n#define COMPAT_ATTRIBUTE in\n#define COMPAT_TEXTURE texture\n#else\n#define COMPAT_VARYING varying \n#define COMPAT_ATTRIBUTE attribute \n#define COMPAT_TEXTURE texture2D\n#endif\n\n#ifdef GL_ES\n#define COMPAT_PRECISION mediump\n#else\n#define COMPAT_PRECISION\n#endif\n\nCOMPAT_ATTRIBUTE vec4 VertexCoord;\nCOMPAT_ATTRIBUTE vec4 COLOR;\nCOMPAT_ATTRIBUTE vec4 TexCoord;\nCOMPAT_VARYING vec4 COL0;\nCOMPAT_VARYING vec4 TEX0;\n\nvec4 _oPosition1; \nuniform mat4 MVPMatrix;\nuniform COMPAT_PRECISION int FrameDirection;\nuniform COMPAT_PRECISION int FrameCount;\nuniform COMPAT_PRECISION vec2 OutputSize;\nuniform COMPAT_PRECISION vec2 TextureSize;\nuniform COMPAT_PRECISION vec2 InputSize;\n\n#define vTexCoord TEX0.xy\n#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize\n#define OutSize vec4(OutputSize, 1.0 / OutputSize)\n\nvoid main()\n{\n gl_Position = MVPMatrix * VertexCoord;\n TEX0.xy = TexCoord.xy;\n}\n\n#elif defined(FRAGMENT)\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\nuniform COMPAT_PRECISION int FrameDirection;\nuniform COMPAT_PRECISION int FrameCount;\nuniform COMPAT_PRECISION vec2 OutputSize;\nuniform COMPAT_PRECISION vec2 TextureSize;\nuniform COMPAT_PRECISION vec2 InputSize;\nuniform sampler2D Texture;\nCOMPAT_VARYING vec4 TEX0;\n\n// compatibility #defines\n#define Source Texture\n#define vTexCoord TEX0.xy\n\n#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize\n#define OutSize vec4(OutputSize, 1.0 / OutputSize)\n\n#ifdef PARAMETER_UNIFORM\nuniform COMPAT_PRECISION float CURVATURE, SCANSPEED;\n#else\n#define CURVATURE 0.5\n#define SCANSPEED 1.0\n#endif\n\n#define iChannel0 Texture\n#define iTime (float(FrameCount) / 60.0)\n#define iResolution OutputSize.xy\n#define fragCoord gl_FragCoord.xy\n\nvec3 sample_( sampler2D tex, vec2 tc )\n{\n vec3 s = pow(COMPAT_TEXTURE(tex,tc).rgb, vec3(2.2));\n return s;\n}\n\nvec3 blur(sampler2D tex, vec2 tc, float offs)\n{\n vec4 xoffs = offs * vec4(-2.0, -1.0, 1.0, 2.0) / (iResolution.x * TextureSize.x / InputSize.x);\n vec4 yoffs = offs * vec4(-2.0, -1.0, 1.0, 2.0) / (iResolution.y * TextureSize.y / InputSize.y);\n tc = tc * InputSize / TextureSize;\n \n vec3 color = vec3(0.0, 0.0, 0.0);\n color += sample_(tex,tc + vec2(xoffs.x, yoffs.x)) * 0.00366;\n color += sample_(tex,tc + vec2(xoffs.y, yoffs.x)) * 0.01465;\n color += sample_(tex,tc + vec2( 0.0, yoffs.x)) * 0.02564;\n color += sample_(tex,tc + vec2(xoffs.z, yoffs.x)) * 0.01465;\n color += sample_(tex,tc + vec2(xoffs.w, yoffs.x)) * 0.00366;\n \n color += sample_(tex,tc + vec2(xoffs.x, yoffs.y)) * 0.01465;\n color += sample_(tex,tc + vec2(xoffs.y, yoffs.y)) * 0.05861;\n color += sample_(tex,tc + vec2( 0.0, yoffs.y)) * 0.09524;\n color += sample_(tex,tc + vec2(xoffs.z, yoffs.y)) * 0.05861;\n color += sample_(tex,tc + vec2(xoffs.w, yoffs.y)) * 0.01465;\n \n color += sample_(tex,tc + vec2(xoffs.x, 0.0)) * 0.02564;\n color += sample_(tex,tc + vec2(xoffs.y, 0.0)) * 0.09524;\n color += sample_(tex,tc + vec2( 0.0, 0.0)) * 0.15018;\n color += sample_(tex,tc + vec2(xoffs.z, 0.0)) * 0.09524;\n color += sample_(tex,tc + vec2(xoffs.w, 0.0)) * 0.02564;\n \n color += sample_(tex,tc + vec2(xoffs.x, yoffs.z)) * 0.01465;\n color += sample_(tex,tc + vec2(xoffs.y, yoffs.z)) * 0.05861;\n color += sample_(tex,tc + vec2( 0.0, yoffs.z)) * 0.09524;\n color += sample_(tex,tc + vec2(xoffs.z, yoffs.z)) * 0.05861;\n color += sample_(tex,tc + vec2(xoffs.w, yoffs.z)) * 0.01465;\n \n color += sample_(tex,tc + vec2(xoffs.x, yoffs.w)) * 0.00366;\n color += sample_(tex,tc + vec2(xoffs.y, yoffs.w)) * 0.01465;\n color += sample_(tex,tc + vec2( 0.0, yoffs.w)) * 0.02564;\n color += sample_(tex,tc + vec2(xoffs.z, yoffs.w)) * 0.01465;\n color += sample_(tex,tc + vec2(xoffs.w, yoffs.w)) * 0.00366;\n\n return color;\n}\n\nfloat rand(vec2 co)\n{\n float a = 12.9898;\n float b = 78.233;\n float c = 43758.5453;\n float dt= dot(co.xy ,vec2(a,b));\n float sn= mod(dt,3.14);\n return fract(sin(sn) * c);\n}\n\nvec2 curve(vec2 uv)\n{\n uv = (uv - 0.5) * 2.0;\n uv *= 1.1;\t\n uv.x *= 1.0 + pow((abs(uv.y) / 5.0), 2.0);\n uv.y *= 1.0 + pow((abs(uv.x) / 4.0), 2.0);\n uv = (uv / 2.0) + 0.5;\n uv = uv *0.92 + 0.04;\n return uv;\n}\n\nvoid main()\n{\n vec2 q = (vTexCoord.xy * TextureSize.xy / InputSize.xy);//fragCoord.xy / iResolution.xy;\n vec2 uv = q;\n uv = mix( uv, curve( uv ), CURVATURE ) * InputSize.xy / TextureSize.xy;\n vec3 col;\n float x = sin(0.1*iTime+uv.y*21.0)*sin(0.23*iTime+uv.y*29.0)*sin(0.3+0.11*iTime+uv.y*31.0)*0.0017;\n float o =2.0*mod(fragCoord.y,2.0)/iResolution.x;\n x+=o;\n uv = uv * TextureSize / InputSize;\n col.r = 1.0*blur(iChannel0,vec2(uv.x+0.0009,uv.y+0.0009),1.2).x+0.005;\n col.g = 1.0*blur(iChannel0,vec2(uv.x+0.000,uv.y-0.0015),1.2).y+0.005;\n col.b = 1.0*blur(iChannel0,vec2(uv.x-0.0015,uv.y+0.000),1.2).z+0.005;\n col.r += 0.2*blur(iChannel0,vec2(uv.x+0.0009,uv.y+0.0009),2.25).x-0.005;\n col.g += 0.2*blur(iChannel0,vec2(uv.x+0.000,uv.y-0.0015),1.75).y-0.005;\n col.b += 0.2*blur(iChannel0,vec2(uv.x-0.0015,uv.y+0.000),1.25).z-0.005;\n float ghs = 0.05;\n col.r += ghs*(1.0-0.299)*blur(iChannel0,0.75*vec2(0.01, -0.027)+vec2(uv.x+0.001,uv.y+0.001),7.0).x;\n col.g += ghs*(1.0-0.587)*blur(iChannel0,0.75*vec2(-0.022, -0.02)+vec2(uv.x+0.000,uv.y-0.002),5.0).y;\n col.b += ghs*(1.0-0.114)*blur(iChannel0,0.75*vec2(-0.02, -0.0)+vec2(uv.x-0.002,uv.y+0.000),3.0).z;\n \n \n\n col = clamp(col*0.4+0.6*col*col*1.0,0.0,1.0);\n float vig = (0.0 + 1.0*16.0*uv.x*uv.y*(1.0-uv.x)*(1.0-uv.y));\n vig = pow(vig,0.3);\n col *= vec3(vig);\n\n col *= vec3(0.95,1.05,0.95);\n col = mix( col, col * col, 0.3) * 3.8;\n\n float scans = clamp( 0.35+0.15*sin(3.5*(iTime * SCANSPEED)+uv.y*iResolution.y*1.5), 0.0, 1.0);\n \n float s = pow(scans,0.9);\n col = col*vec3( s) ;\n\n col *= 1.0+0.0015*sin(300.0*iTime);\n \n col*=1.0-0.15*vec3(clamp((mod(fragCoord.x+o, 2.0)-1.0)*2.0,0.0,1.0));\n col *= vec3( 1.0 ) - 0.25*vec3( rand( uv+0.0001*iTime), rand( uv+0.0001*iTime + 0.3 ), rand( uv+0.0001*iTime+ 0.5 ) );\n col = pow(col, vec3(0.45));\n\n if (uv.x < 0.0 || uv.x > 1.0)\n col *= 0.0;\n if (uv.y < 0.0 || uv.y > 1.0)\n col *= 0.0;\n \n\n float comp = smoothstep( 0.1, 0.9, sin(iTime) );\n\n FragColor = vec4(col,1.0);\n} \n#endif\n" -} + //https://github.com/libretro/glsl-shaders/blob/master/scalehq/2xScaleHQ.glslp + "2xScaleHQ.glslp": { + "shader": { + "type": "text", + "value": "shaders = 1\n\nshader0 = \"2xScaleHQ.glsl\"\nfilter_linear0 = false\nscale_type_0 = source\n", + }, + "resources": [ + { + "name": "2xScaleHQ.glsl", + "type": "base64", + "value": "LyoKICAgMnhHTFNMSHFGaWx0ZXIgc2hhZGVyCiAgIAogICBDb3B5cmlnaHQgKEMpIDIwMDUgZ3Vlc3QocikgLSBndWVzdC5yQGdtYWlsLmNvbQoKICAgVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vcgogICBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZQogICBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyIHZlcnNpb24gMgogICBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi4KCiAgIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLAogICBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZgogICBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlCiAgIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuCgogICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZQogICBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZQogICBGb3VuZGF0aW9uLCBJbmMuLCA1OSBUZW1wbGUgUGxhY2UgLSBTdWl0ZSAzMzAsIEJvc3RvbiwgTUEgIDAyMTExLTEzMDcsIFVTQS4KKi8KCiNpZiBkZWZpbmVkKFZFUlRFWCkKCiNpZiBfX1ZFUlNJT05fXyA+PSAxMzAKI2RlZmluZSBDT01QQVRfVkFSWUlORyBvdXQKI2RlZmluZSBDT01QQVRfQVRUUklCVVRFIGluCiNkZWZpbmUgQ09NUEFUX1RFWFRVUkUgdGV4dHVyZQojZWxzZQojZGVmaW5lIENPTVBBVF9WQVJZSU5HIHZhcnlpbmcgCiNkZWZpbmUgQ09NUEFUX0FUVFJJQlVURSBhdHRyaWJ1dGUgCiNkZWZpbmUgQ09NUEFUX1RFWFRVUkUgdGV4dHVyZTJECiNlbmRpZgoKI2lmZGVmIEdMX0VTCiNkZWZpbmUgQ09NUEFUX1BSRUNJU0lPTiBtZWRpdW1wCiNlbHNlCiNkZWZpbmUgQ09NUEFUX1BSRUNJU0lPTgojZW5kaWYKCkNPTVBBVF9BVFRSSUJVVEUgdmVjNCBWZXJ0ZXhDb29yZDsKQ09NUEFUX0FUVFJJQlVURSB2ZWM0IENPTE9SOwpDT01QQVRfQVRUUklCVVRFIHZlYzQgVGV4Q29vcmQ7CkNPTVBBVF9WQVJZSU5HIHZlYzQgQ09MMDsKQ09NUEFUX1ZBUllJTkcgdmVjNCBURVgwOwpDT01QQVRfVkFSWUlORyB2ZWM0IHQxOwpDT01QQVRfVkFSWUlORyB2ZWM0IHQyOwpDT01QQVRfVkFSWUlORyB2ZWM0IHQzOwpDT01QQVRfVkFSWUlORyB2ZWM0IHQ0OwoKdmVjNCBfb1Bvc2l0aW9uMTsgCnVuaWZvcm0gbWF0NCBNVlBNYXRyaXg7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBpbnQgRnJhbWVEaXJlY3Rpb247CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBpbnQgRnJhbWVDb3VudDsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIHZlYzIgT3V0cHV0U2l6ZTsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIHZlYzIgVGV4dHVyZVNpemU7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiB2ZWMyIElucHV0U2l6ZTsKCi8vIGNvbXBhdGliaWxpdHkgI2RlZmluZXMKI2RlZmluZSB2VGV4Q29vcmQgVEVYMC54eQojZGVmaW5lIFNvdXJjZVNpemUgdmVjNChUZXh0dXJlU2l6ZSwgMS4wIC8gVGV4dHVyZVNpemUpIC8vZWl0aGVyIFRleHR1cmVTaXplIG9yIElucHV0U2l6ZQojZGVmaW5lIE91dFNpemUgdmVjNChPdXRwdXRTaXplLCAxLjAgLyBPdXRwdXRTaXplKQoKdm9pZCBtYWluKCkKewogICAgZ2xfUG9zaXRpb24gPSBNVlBNYXRyaXggKiBWZXJ0ZXhDb29yZDsKICAgIFRFWDAueHkgPSBUZXhDb29yZC54eTsKICAgZmxvYXQgeCA9IDAuNSAqIFNvdXJjZVNpemUuejsKICAgZmxvYXQgeSA9IDAuNSAqIFNvdXJjZVNpemUudzsKICAgdmVjMiBkZzEgPSB2ZWMyKCB4LCB5KTsKICAgdmVjMiBkZzIgPSB2ZWMyKC14LCB5KTsKICAgdmVjMiBkeCA9IHZlYzIoeCwgMC4wKTsKICAgdmVjMiBkeSA9IHZlYzIoMC4wLCB5KTsKICAgdDEgPSB2ZWM0KHZUZXhDb29yZCAtIGRnMSwgdlRleENvb3JkIC0gZHkpOwogICB0MiA9IHZlYzQodlRleENvb3JkIC0gZGcyLCB2VGV4Q29vcmQgKyBkeCk7CiAgIHQzID0gdmVjNCh2VGV4Q29vcmQgKyBkZzEsIHZUZXhDb29yZCArIGR5KTsKICAgdDQgPSB2ZWM0KHZUZXhDb29yZCArIGRnMiwgdlRleENvb3JkIC0gZHgpOwp9CgojZWxpZiBkZWZpbmVkKEZSQUdNRU5UKQoKI2lmIF9fVkVSU0lPTl9fID49IDEzMAojZGVmaW5lIENPTVBBVF9WQVJZSU5HIGluCiNkZWZpbmUgQ09NUEFUX1RFWFRVUkUgdGV4dHVyZQpvdXQgdmVjNCBGcmFnQ29sb3I7CiNlbHNlCiNkZWZpbmUgQ09NUEFUX1ZBUllJTkcgdmFyeWluZwojZGVmaW5lIEZyYWdDb2xvciBnbF9GcmFnQ29sb3IKI2RlZmluZSBDT01QQVRfVEVYVFVSRSB0ZXh0dXJlMkQKI2VuZGlmCgojaWZkZWYgR0xfRVMKI2lmZGVmIEdMX0ZSQUdNRU5UX1BSRUNJU0lPTl9ISUdICnByZWNpc2lvbiBoaWdocCBmbG9hdDsKI2Vsc2UKcHJlY2lzaW9uIG1lZGl1bXAgZmxvYXQ7CiNlbmRpZgojZGVmaW5lIENPTVBBVF9QUkVDSVNJT04gbWVkaXVtcAojZWxzZQojZGVmaW5lIENPTVBBVF9QUkVDSVNJT04KI2VuZGlmCgp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gaW50IEZyYW1lRGlyZWN0aW9uOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gaW50IEZyYW1lQ291bnQ7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiB2ZWMyIE91dHB1dFNpemU7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiB2ZWMyIFRleHR1cmVTaXplOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gdmVjMiBJbnB1dFNpemU7CnVuaWZvcm0gc2FtcGxlcjJEIFRleHR1cmU7CkNPTVBBVF9WQVJZSU5HIHZlYzQgVEVYMDsKQ09NUEFUX1ZBUllJTkcgdmVjNCB0MTsKQ09NUEFUX1ZBUllJTkcgdmVjNCB0MjsKQ09NUEFUX1ZBUllJTkcgdmVjNCB0MzsKQ09NUEFUX1ZBUllJTkcgdmVjNCB0NDsKCi8vIGNvbXBhdGliaWxpdHkgI2RlZmluZXMKI2RlZmluZSBTb3VyY2UgVGV4dHVyZQojZGVmaW5lIHZUZXhDb29yZCBURVgwLnh5CgojZGVmaW5lIFNvdXJjZVNpemUgdmVjNChUZXh0dXJlU2l6ZSwgMS4wIC8gVGV4dHVyZVNpemUpIC8vZWl0aGVyIFRleHR1cmVTaXplIG9yIElucHV0U2l6ZQojZGVmaW5lIE91dFNpemUgdmVjNChPdXRwdXRTaXplLCAxLjAgLyBPdXRwdXRTaXplKQoKZmxvYXQgbXggPSAwLjMyNTsgICAgICAvLyBzdGFydCBzbW9vdGhpbmcgd3QuCmZsb2F0IGsgPSAtMC4yNTA7ICAgICAgLy8gd3QuIGRlY3JlYXNlIGZhY3RvcgpmbG9hdCBtYXhfdyA9IDAuMjU7ICAgIC8vIG1heCBmaWx0ZXIgd2VpZ2h0CmZsb2F0IG1pbl93ID0tMC4wNTsgICAgLy8gbWluIGZpbHRlciB3ZWlnaHQKZmxvYXQgbHVtX2FkZCA9IDAuMjU7ICAvLyBhZmZlY3RzIHNtb290aGluZwp2ZWMzIGR0ID0gdmVjMygxLjApOwoKdm9pZCBtYWluKCkKewogICB2ZWMzIGMwMCA9IENPTVBBVF9URVhUVVJFKFNvdXJjZSwgdDEueHkpLnh5ejsgCiAgIHZlYzMgYzEwID0gQ09NUEFUX1RFWFRVUkUoU291cmNlLCB0MS56dykueHl6OyAKICAgdmVjMyBjMjAgPSBDT01QQVRfVEVYVFVSRShTb3VyY2UsIHQyLnh5KS54eXo7IAogICB2ZWMzIGMwMSA9IENPTVBBVF9URVhUVVJFKFNvdXJjZSwgdDQuencpLnh5ejsgCiAgIHZlYzMgYzExID0gQ09NUEFUX1RFWFRVUkUoU291cmNlLCB2VGV4Q29vcmQpLnh5ejsgCiAgIHZlYzMgYzIxID0gQ09NUEFUX1RFWFRVUkUoU291cmNlLCB0Mi56dykueHl6OyAKICAgdmVjMyBjMDIgPSBDT01QQVRfVEVYVFVSRShTb3VyY2UsIHQ0Lnh5KS54eXo7IAogICB2ZWMzIGMxMiA9IENPTVBBVF9URVhUVVJFKFNvdXJjZSwgdDMuencpLnh5ejsgCiAgIHZlYzMgYzIyID0gQ09NUEFUX1RFWFRVUkUoU291cmNlLCB0My54eSkueHl6OyAKCiAgIGZsb2F0IG1kMSA9IGRvdChhYnMoYzAwIC0gYzIyKSwgZHQpOwogICBmbG9hdCBtZDIgPSBkb3QoYWJzKGMwMiAtIGMyMCksIGR0KTsKCiAgIGZsb2F0IHcxID0gZG90KGFicyhjMjIgLSBjMTEpLCBkdCkgKiBtZDI7CiAgIGZsb2F0IHcyID0gZG90KGFicyhjMDIgLSBjMTEpLCBkdCkgKiBtZDE7CiAgIGZsb2F0IHczID0gZG90KGFicyhjMDAgLSBjMTEpLCBkdCkgKiBtZDI7CiAgIGZsb2F0IHc0ID0gZG90KGFicyhjMjAgLSBjMTEpLCBkdCkgKiBtZDE7CgogICBmbG9hdCB0MSA9IHcxICsgdzM7CiAgIGZsb2F0IHQyID0gdzIgKyB3NDsKICAgZmxvYXQgd3cgPSBtYXgodDEsIHQyKSArIDAuMDAwMTsKCiAgIGMxMSA9ICh3MSAqIGMwMCArIHcyICogYzIwICsgdzMgKiBjMjIgKyB3NCAqIGMwMiArIHd3ICogYzExKSAvICh0MSArIHQyICsgd3cpOwoKICAgZmxvYXQgbGMxID0gayAvICgwLjEyICogZG90KGMxMCArIGMxMiArIGMxMSwgZHQpICsgbHVtX2FkZCk7CiAgIGZsb2F0IGxjMiA9IGsgLyAoMC4xMiAqIGRvdChjMDEgKyBjMjEgKyBjMTEsIGR0KSArIGx1bV9hZGQpOwoKICAgdzEgPSBjbGFtcChsYzEgKiBkb3QoYWJzKGMxMSAtIGMxMCksIGR0KSArIG14LCBtaW5fdywgbWF4X3cpOwogICB3MiA9IGNsYW1wKGxjMiAqIGRvdChhYnMoYzExIC0gYzIxKSwgZHQpICsgbXgsIG1pbl93LCBtYXhfdyk7CiAgIHczID0gY2xhbXAobGMxICogZG90KGFicyhjMTEgLSBjMTIpLCBkdCkgKyBteCwgbWluX3csIG1heF93KTsKICAgdzQgPSBjbGFtcChsYzIgKiBkb3QoYWJzKGMxMSAtIGMwMSksIGR0KSArIG14LCBtaW5fdywgbWF4X3cpOwogICBGcmFnQ29sb3IgPSB2ZWM0KHcxICogYzEwICsgdzIgKiBjMjEgKyB3MyAqIGMxMiArIHc0ICogYzAxICsgKDEuMCAtIHcxIC0gdzIgLSB3MyAtIHc0KSAqIGMxMSwgMS4wKTsKfSAKI2VuZGlmCg==", + } + ], + }, + + //https://github.com/libretro/glsl-shaders/blob/master/scalehq/4xScaleHQ.glslp + "4xScaleHQ.glslp": { + "shader": { + "type": "text", + "value": "shaders = 1\n\nshader0 = \"4xScaleHQ.glsl\"\nfilter_linear0 = false\nscale_type_0 = source\n", + }, + "resources": [ + { + "name": "4xScaleHQ.glsl", + "type": "base64", + "value": "LyoKICAgNHhHTFNMSHFGaWx0ZXIgc2hhZGVyCiAgIAogICBDb3B5cmlnaHQgKEMpIDIwMDUgZ3Vlc3QocikgLSBndWVzdC5yQGdtYWlsLmNvbQoKICAgVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vcgogICBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZQogICBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyIHZlcnNpb24gMgogICBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi4KCiAgIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLAogICBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZgogICBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlCiAgIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuCgogICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZQogICBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZQogICBGb3VuZGF0aW9uLCBJbmMuLCA1OSBUZW1wbGUgUGxhY2UgLSBTdWl0ZSAzMzAsIEJvc3RvbiwgTUEgIDAyMTExLTEzMDcsIFVTQS4KKi8KCiNpZiBkZWZpbmVkKFZFUlRFWCkKCiNpZiBfX1ZFUlNJT05fXyA+PSAxMzAKI2RlZmluZSBDT01QQVRfVkFSWUlORyBvdXQKI2RlZmluZSBDT01QQVRfQVRUUklCVVRFIGluCiNkZWZpbmUgQ09NUEFUX1RFWFRVUkUgdGV4dHVyZQojZWxzZQojZGVmaW5lIENPTVBBVF9WQVJZSU5HIHZhcnlpbmcgCiNkZWZpbmUgQ09NUEFUX0FUVFJJQlVURSBhdHRyaWJ1dGUgCiNkZWZpbmUgQ09NUEFUX1RFWFRVUkUgdGV4dHVyZTJECiNlbmRpZgoKI2lmZGVmIEdMX0VTCiNkZWZpbmUgQ09NUEFUX1BSRUNJU0lPTiBtZWRpdW1wCiNlbHNlCiNkZWZpbmUgQ09NUEFUX1BSRUNJU0lPTgojZW5kaWYKCkNPTVBBVF9BVFRSSUJVVEUgdmVjNCBWZXJ0ZXhDb29yZDsKQ09NUEFUX0FUVFJJQlVURSB2ZWM0IENPTE9SOwpDT01QQVRfQVRUUklCVVRFIHZlYzQgVGV4Q29vcmQ7CkNPTVBBVF9WQVJZSU5HIHZlYzQgQ09MMDsKQ09NUEFUX1ZBUllJTkcgdmVjNCBURVgwOwpDT01QQVRfVkFSWUlORyB2ZWM0IHQxOwpDT01QQVRfVkFSWUlORyB2ZWM0IHQyOwpDT01QQVRfVkFSWUlORyB2ZWM0IHQzOwpDT01QQVRfVkFSWUlORyB2ZWM0IHQ0OwpDT01QQVRfVkFSWUlORyB2ZWM0IHQ1OwpDT01QQVRfVkFSWUlORyB2ZWM0IHQ2OwoKdmVjNCBfb1Bvc2l0aW9uMTsgCnVuaWZvcm0gbWF0NCBNVlBNYXRyaXg7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBpbnQgRnJhbWVEaXJlY3Rpb247CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBpbnQgRnJhbWVDb3VudDsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIHZlYzIgT3V0cHV0U2l6ZTsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIHZlYzIgVGV4dHVyZVNpemU7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiB2ZWMyIElucHV0U2l6ZTsKCi8vIGNvbXBhdGliaWxpdHkgI2RlZmluZXMKI2RlZmluZSB2VGV4Q29vcmQgVEVYMC54eQojZGVmaW5lIFNvdXJjZVNpemUgdmVjNChUZXh0dXJlU2l6ZSwgMS4wIC8gVGV4dHVyZVNpemUpIC8vZWl0aGVyIFRleHR1cmVTaXplIG9yIElucHV0U2l6ZQojZGVmaW5lIE91dFNpemUgdmVjNChPdXRwdXRTaXplLCAxLjAgLyBPdXRwdXRTaXplKQoKdm9pZCBtYWluKCkKewogICAgZ2xfUG9zaXRpb24gPSBNVlBNYXRyaXggKiBWZXJ0ZXhDb29yZDsKICAgIFRFWDAueHkgPSBUZXhDb29yZC54eTsKICAgZmxvYXQgeCA9IDAuNSAqIFNvdXJjZVNpemUuejsKICAgZmxvYXQgeSA9IDAuNSAqIFNvdXJjZVNpemUudzsKICAgdmVjMiBkZzEgPSB2ZWMyKCB4LCB5KTsKICAgdmVjMiBkZzIgPSB2ZWMyKC14LCB5KTsKICAgdmVjMiBzZDEgPSBkZzEgKiAwLjU7CiAgIHZlYzIgc2QyID0gZGcyICogMC41OwogICB2ZWMyIGRkeCA9IHZlYzIoeCwgMC4wKTsKICAgdmVjMiBkZHkgPSB2ZWMyKDAuMCwgeSk7CiAgIHQxID0gdmVjNCh2VGV4Q29vcmQgLSBzZDEsIHZUZXhDb29yZCAtIGRkeSk7CiAgIHQyID0gdmVjNCh2VGV4Q29vcmQgLSBzZDIsIHZUZXhDb29yZCArIGRkeCk7CiAgIHQzID0gdmVjNCh2VGV4Q29vcmQgKyBzZDEsIHZUZXhDb29yZCArIGRkeSk7CiAgIHQ0ID0gdmVjNCh2VGV4Q29vcmQgKyBzZDIsIHZUZXhDb29yZCAtIGRkeCk7CiAgIHQ1ID0gdmVjNCh2VGV4Q29vcmQgLSBkZzEsIHZUZXhDb29yZCAtIGRnMik7CiAgIHQ2ID0gdmVjNCh2VGV4Q29vcmQgKyBkZzEsIHZUZXhDb29yZCArIGRnMik7Cn0KCiNlbGlmIGRlZmluZWQoRlJBR01FTlQpCgojaWYgX19WRVJTSU9OX18gPj0gMTMwCiNkZWZpbmUgQ09NUEFUX1ZBUllJTkcgaW4KI2RlZmluZSBDT01QQVRfVEVYVFVSRSB0ZXh0dXJlCm91dCB2ZWM0IEZyYWdDb2xvcjsKI2Vsc2UKI2RlZmluZSBDT01QQVRfVkFSWUlORyB2YXJ5aW5nCiNkZWZpbmUgRnJhZ0NvbG9yIGdsX0ZyYWdDb2xvcgojZGVmaW5lIENPTVBBVF9URVhUVVJFIHRleHR1cmUyRAojZW5kaWYKCiNpZmRlZiBHTF9FUwojaWZkZWYgR0xfRlJBR01FTlRfUFJFQ0lTSU9OX0hJR0gKcHJlY2lzaW9uIGhpZ2hwIGZsb2F0OwojZWxzZQpwcmVjaXNpb24gbWVkaXVtcCBmbG9hdDsKI2VuZGlmCiNkZWZpbmUgQ09NUEFUX1BSRUNJU0lPTiBtZWRpdW1wCiNlbHNlCiNkZWZpbmUgQ09NUEFUX1BSRUNJU0lPTgojZW5kaWYKCnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBpbnQgRnJhbWVEaXJlY3Rpb247CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBpbnQgRnJhbWVDb3VudDsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIHZlYzIgT3V0cHV0U2l6ZTsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIHZlYzIgVGV4dHVyZVNpemU7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiB2ZWMyIElucHV0U2l6ZTsKdW5pZm9ybSBzYW1wbGVyMkQgVGV4dHVyZTsKQ09NUEFUX1ZBUllJTkcgdmVjNCBURVgwOwpDT01QQVRfVkFSWUlORyB2ZWM0IHQxOwpDT01QQVRfVkFSWUlORyB2ZWM0IHQyOwpDT01QQVRfVkFSWUlORyB2ZWM0IHQzOwpDT01QQVRfVkFSWUlORyB2ZWM0IHQ0OwpDT01QQVRfVkFSWUlORyB2ZWM0IHQ1OwpDT01QQVRfVkFSWUlORyB2ZWM0IHQ2OwoKLy8gY29tcGF0aWJpbGl0eSAjZGVmaW5lcwojZGVmaW5lIFNvdXJjZSBUZXh0dXJlCiNkZWZpbmUgdlRleENvb3JkIFRFWDAueHkKCiNkZWZpbmUgU291cmNlU2l6ZSB2ZWM0KFRleHR1cmVTaXplLCAxLjAgLyBUZXh0dXJlU2l6ZSkgLy9laXRoZXIgVGV4dHVyZVNpemUgb3IgSW5wdXRTaXplCiNkZWZpbmUgT3V0U2l6ZSB2ZWM0KE91dHB1dFNpemUsIDEuMCAvIE91dHB1dFNpemUpCgpmbG9hdCBteCA9IDEuMDsgICAgICAvLyBzdGFydCBzbW9vdGhpbmcgd3QuCmZsb2F0IGsgPSAtMS4xMDsgICAgICAvLyB3dC4gZGVjcmVhc2UgZmFjdG9yCmZsb2F0IG1heF93ID0gMC43NTsgICAgLy8gbWF4IGZpbHRlciB3ZWlnaHQKZmxvYXQgbWluX3cgPSAwLjAzOyAgICAvLyBtaW4gZmlsdGVyIHdlaWdodApmbG9hdCBsdW1fYWRkID0gMC4zMzsgIC8vIGFmZmVjdHMgc21vb3RoaW5nCnZlYzMgZHQgPSB2ZWMzKDEuMCk7Cgp2b2lkIG1haW4oKQp7CiAgIHZlYzMgYyAgPSBDT01QQVRfVEVYVFVSRShTb3VyY2UsIHZUZXhDb29yZCkueHl6OwogICB2ZWMzIGkxID0gQ09NUEFUX1RFWFRVUkUoU291cmNlLCB0MS54eSkueHl6OyAKICAgdmVjMyBpMiA9IENPTVBBVF9URVhUVVJFKFNvdXJjZSwgdDIueHkpLnh5ejsgCiAgIHZlYzMgaTMgPSBDT01QQVRfVEVYVFVSRShTb3VyY2UsIHQzLnh5KS54eXo7IAogICB2ZWMzIGk0ID0gQ09NUEFUX1RFWFRVUkUoU291cmNlLCB0NC54eSkueHl6OyAKICAgdmVjMyBvMSA9IENPTVBBVF9URVhUVVJFKFNvdXJjZSwgdDUueHkpLnh5ejsgCiAgIHZlYzMgbzMgPSBDT01QQVRfVEVYVFVSRShTb3VyY2UsIHQ2Lnh5KS54eXo7IAogICB2ZWMzIG8yID0gQ09NUEFUX1RFWFRVUkUoU291cmNlLCB0NS56dykueHl6OwogICB2ZWMzIG80ID0gQ09NUEFUX1RFWFRVUkUoU291cmNlLCB0Ni56dykueHl6OwogICB2ZWMzIHMxID0gQ09NUEFUX1RFWFRVUkUoU291cmNlLCB0MS56dykueHl6OyAKICAgdmVjMyBzMiA9IENPTVBBVF9URVhUVVJFKFNvdXJjZSwgdDIuencpLnh5ejsgCiAgIHZlYzMgczMgPSBDT01QQVRfVEVYVFVSRShTb3VyY2UsIHQzLnp3KS54eXo7IAogICB2ZWMzIHM0ID0gQ09NUEFUX1RFWFRVUkUoU291cmNlLCB0NC56dykueHl6OyAKCiAgIGZsb2F0IGtvMT1kb3QoYWJzKG8xLWMpLGR0KTsKICAgZmxvYXQga28yPWRvdChhYnMobzItYyksZHQpOwogICBmbG9hdCBrbzM9ZG90KGFicyhvMy1jKSxkdCk7CiAgIGZsb2F0IGtvND1kb3QoYWJzKG80LWMpLGR0KTsKCiAgIGZsb2F0IGsxPW1pbihkb3QoYWJzKGkxLWkzKSxkdCksbWF4KGtvMSxrbzMpKTsKICAgZmxvYXQgazI9bWluKGRvdChhYnMoaTItaTQpLGR0KSxtYXgoa28yLGtvNCkpOwoKICAgZmxvYXQgdzEgPSBrMjsgaWYoa28zPGtvMSkgdzEqPWtvMy9rbzE7CiAgIGZsb2F0IHcyID0gazE7IGlmKGtvNDxrbzIpIHcyKj1rbzQva28yOwogICBmbG9hdCB3MyA9IGsyOyBpZihrbzE8a28zKSB3Myo9a28xL2tvMzsKICAgZmxvYXQgdzQgPSBrMTsgaWYoa28yPGtvNCkgdzQqPWtvMi9rbzQ7CgogICBjPSh3MSpvMSt3MipvMit3MypvMyt3NCpvNCswLjAwMSpjKS8odzErdzIrdzMrdzQrMC4wMDEpOwogICB3MSA9IGsqZG90KGFicyhpMS1jKSthYnMoaTMtYyksZHQpLygwLjEyNSpkb3QoaTEraTMsZHQpK2x1bV9hZGQpOwogICB3MiA9IGsqZG90KGFicyhpMi1jKSthYnMoaTQtYyksZHQpLygwLjEyNSpkb3QoaTIraTQsZHQpK2x1bV9hZGQpOwogICB3MyA9IGsqZG90KGFicyhzMS1jKSthYnMoczMtYyksZHQpLygwLjEyNSpkb3QoczErczMsZHQpK2x1bV9hZGQpOwogICB3NCA9IGsqZG90KGFicyhzMi1jKSthYnMoczQtYyksZHQpLygwLjEyNSpkb3QoczIrczQsZHQpK2x1bV9hZGQpOwoKICAgdzEgPSBjbGFtcCh3MStteCxtaW5fdyxtYXhfdyk7IAogICB3MiA9IGNsYW1wKHcyK214LG1pbl93LG1heF93KTsKICAgdzMgPSBjbGFtcCh3MytteCxtaW5fdyxtYXhfdyk7IAogICB3NCA9IGNsYW1wKHc0K214LG1pbl93LG1heF93KTsKCiAgIEZyYWdDb2xvciA9IHZlYzQoKHcxKihpMStpMykrdzIqKGkyK2k0KSt3MyooczErczMpK3c0KihzMitzNCkrYykvKDIuMCoodzErdzIrdzMrdzQpKzEuMCksIDEuMCk7Cn0gCiNlbmRpZgo=", + }, + ], + }, + + //https://github.com/libretro/glsl-shaders/blob/master/sabr/sabr.glslp + "sabr": { + "shader": { + "type": "text", + "value": "shaders = 1\n\nshader0 = sabr-v3.0.glsl\nfilter_linear0 = false\n", + }, + "resources": [ + { + "name": "sabr-v3.0.glsl", + "type": "base64", + "value": "LyoKCVNBQlIgdjMuMCBTaGFkZXIKCUpvc2h1YSBTdHJlZXQKCQoJUG9ydGlvbnMgb2YgdGhpcyBhbGdvcml0aG0gd2VyZSB0YWtlbiBmcm9tIEh5bGxpYW4ncyA1eEJSIHYzLjdjCglzaGFkZXIuCgkKCVRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IKCW1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlCglhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyIHZlcnNpb24gMgoJb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uCgoJVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsCglidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZgoJTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZQoJR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy4KCglZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZQoJYWxvbmcgd2l0aCB0aGlzIHByb2dyYW07IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmUKCUZvdW5kYXRpb24sIEluYy4sIDU5IFRlbXBsZSBQbGFjZSAtIFN1aXRlIDMzMCwgQm9zdG9uLCBNQSAgMDIxMTEtMTMwNywgVVNBLgoKKi8KCiNpZiBkZWZpbmVkKFZFUlRFWCkKCiNpZiBfX1ZFUlNJT05fXyA+PSAxMzAKI2RlZmluZSBDT01QQVRfVkFSWUlORyBvdXQKI2RlZmluZSBDT01QQVRfQVRUUklCVVRFIGluCiNkZWZpbmUgQ09NUEFUX1RFWFRVUkUgdGV4dHVyZQojZWxzZQojZGVmaW5lIENPTVBBVF9WQVJZSU5HIHZhcnlpbmcgCiNkZWZpbmUgQ09NUEFUX0FUVFJJQlVURSBhdHRyaWJ1dGUgCiNkZWZpbmUgQ09NUEFUX1RFWFRVUkUgdGV4dHVyZTJECiNlbmRpZgoKI2lmZGVmIEdMX0VTCiNkZWZpbmUgQ09NUEFUX1BSRUNJU0lPTiBtZWRpdW1wCiNlbHNlCiNkZWZpbmUgQ09NUEFUX1BSRUNJU0lPTgojZW5kaWYKCkNPTVBBVF9BVFRSSUJVVEUgdmVjNCBWZXJ0ZXhDb29yZDsKQ09NUEFUX0FUVFJJQlVURSB2ZWM0IENPTE9SOwpDT01QQVRfQVRUUklCVVRFIHZlYzQgVGV4Q29vcmQ7CkNPTVBBVF9WQVJZSU5HIHZlYzQgQ09MMDsKQ09NUEFUX1ZBUllJTkcgdmVjNCBURVgwOwoKdW5pZm9ybSBtYXQ0IE1WUE1hdHJpeDsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIGludCBGcmFtZURpcmVjdGlvbjsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIGludCBGcmFtZUNvdW50Owp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gdmVjMiBPdXRwdXRTaXplOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gdmVjMiBUZXh0dXJlU2l6ZTsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIHZlYzIgSW5wdXRTaXplOwpDT01QQVRfVkFSWUlORyB2ZWMyIHRjOwpDT01QQVRfVkFSWUlORyB2ZWM0IHh5cF8xXzJfMzsKQ09NUEFUX1ZBUllJTkcgdmVjNCB4eXBfNV8xMF8xNTsKQ09NUEFUX1ZBUllJTkcgdmVjNCB4eXBfNl83Xzg7CkNPTVBBVF9WQVJZSU5HIHZlYzQgeHlwXzlfMTRfOTsKQ09NUEFUX1ZBUllJTkcgdmVjNCB4eXBfMTFfMTJfMTM7CkNPTVBBVF9WQVJZSU5HIHZlYzQgeHlwXzE2XzE3XzE4OwpDT01QQVRfVkFSWUlORyB2ZWM0IHh5cF8yMV8yMl8yMzsKCi8vIHZlcnRleCBjb21wYXRpYmlsaXR5ICNkZWZpbmVzCiNkZWZpbmUgdlRleENvb3JkIFRFWDAueHkKI2RlZmluZSBTb3VyY2VTaXplIHZlYzQoVGV4dHVyZVNpemUsIDEuMCAvIFRleHR1cmVTaXplKSAvL2VpdGhlciBUZXh0dXJlU2l6ZSBvciBJbnB1dFNpemUKI2RlZmluZSBvdXRzaXplIHZlYzQoT3V0cHV0U2l6ZSwgMS4wIC8gT3V0cHV0U2l6ZSkKCnZvaWQgbWFpbigpCnsKICAgIGdsX1Bvc2l0aW9uID0gTVZQTWF0cml4ICogVmVydGV4Q29vcmQ7CiAgICBDT0wwID0gQ09MT1I7CiAgICBURVgwLnh5ID0gVGV4Q29vcmQueHk7CiAgIAlmbG9hdCB4ID0gU291cmNlU2l6ZS56Oy8vMS4wIC8gSU4udGV4dHVyZV9zaXplLng7CglmbG9hdCB5ID0gU291cmNlU2l6ZS53Oy8vMS4wIC8gSU4udGV4dHVyZV9zaXplLnk7CgkKCXRjID0gVEVYMC54eSAqIHZlYzIoMS4wMDA0LCAxLjApOwoJeHlwXzFfMl8zICAgID0gdGMueHh4eSArIHZlYzQoICAgICAgLXgsIDAuMCwgICB4LCAtMi4wICogeSk7Cgl4eXBfNl83XzggICAgPSB0Yy54eHh5ICsgdmVjNCggICAgICAteCwgMC4wLCAgIHgsICAgICAgIC15KTsKCXh5cF8xMV8xMl8xMyA9IHRjLnh4eHkgKyB2ZWM0KCAgICAgIC14LCAwLjAsICAgeCwgICAgICAwLjApOwoJeHlwXzE2XzE3XzE4ID0gdGMueHh4eSArIHZlYzQoICAgICAgLXgsIDAuMCwgICB4LCAgICAgICAgeSk7Cgl4eXBfMjFfMjJfMjMgPSB0Yy54eHh5ICsgdmVjNCggICAgICAteCwgMC4wLCAgIHgsICAyLjAgKiB5KTsKCXh5cF81XzEwXzE1ICA9IHRjLnh5eXkgKyB2ZWM0KC0yLjAgKiB4LCAgLXksIDAuMCwgICAgICAgIHkpOwoJeHlwXzlfMTRfOSAgID0gdGMueHl5eSArIHZlYzQoIDIuMCAqIHgsICAteSwgMC4wLCAgICAgICAgeSk7Cn0KCiNlbGlmIGRlZmluZWQoRlJBR01FTlQpCgojaWYgX19WRVJTSU9OX18gPj0gMTMwCiNkZWZpbmUgQ09NUEFUX1ZBUllJTkcgaW4KI2RlZmluZSBDT01QQVRfVEVYVFVSRSB0ZXh0dXJlCm91dCB2ZWM0IEZyYWdDb2xvcjsKI2Vsc2UKI2RlZmluZSBDT01QQVRfVkFSWUlORyB2YXJ5aW5nCiNkZWZpbmUgRnJhZ0NvbG9yIGdsX0ZyYWdDb2xvcgojZGVmaW5lIENPTVBBVF9URVhUVVJFIHRleHR1cmUyRAojZW5kaWYKCiNpZmRlZiBHTF9FUwojaWZkZWYgR0xfRlJBR01FTlRfUFJFQ0lTSU9OX0hJR0gKcHJlY2lzaW9uIGhpZ2hwIGZsb2F0OwojZWxzZQpwcmVjaXNpb24gbWVkaXVtcCBmbG9hdDsKI2VuZGlmCiNkZWZpbmUgQ09NUEFUX1BSRUNJU0lPTiBtZWRpdW1wCiNlbHNlCiNkZWZpbmUgQ09NUEFUX1BSRUNJU0lPTgojZW5kaWYKCnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBpbnQgRnJhbWVEaXJlY3Rpb247CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBpbnQgRnJhbWVDb3VudDsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIHZlYzIgT3V0cHV0U2l6ZTsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIHZlYzIgVGV4dHVyZVNpemU7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiB2ZWMyIElucHV0U2l6ZTsKdW5pZm9ybSBzYW1wbGVyMkQgVGV4dHVyZTsKQ09NUEFUX1ZBUllJTkcgdmVjNCBURVgwOwpDT01QQVRfVkFSWUlORyB2ZWMyIHRjOwpDT01QQVRfVkFSWUlORyB2ZWM0IHh5cF8xXzJfMzsKQ09NUEFUX1ZBUllJTkcgdmVjNCB4eXBfNV8xMF8xNTsKQ09NUEFUX1ZBUllJTkcgdmVjNCB4eXBfNl83Xzg7CkNPTVBBVF9WQVJZSU5HIHZlYzQgeHlwXzlfMTRfOTsKQ09NUEFUX1ZBUllJTkcgdmVjNCB4eXBfMTFfMTJfMTM7CkNPTVBBVF9WQVJZSU5HIHZlYzQgeHlwXzE2XzE3XzE4OwpDT01QQVRfVkFSWUlORyB2ZWM0IHh5cF8yMV8yMl8yMzsKCi8vIGZyYWdtZW50IGNvbXBhdGliaWxpdHkgI2RlZmluZXMKI2RlZmluZSBTb3VyY2UgVGV4dHVyZQojZGVmaW5lIHZUZXhDb29yZCBURVgwLnh5CgojZGVmaW5lIFNvdXJjZVNpemUgdmVjNChUZXh0dXJlU2l6ZSwgMS4wIC8gVGV4dHVyZVNpemUpIC8vZWl0aGVyIFRleHR1cmVTaXplIG9yIElucHV0U2l6ZQojZGVmaW5lIG91dHNpemUgdmVjNChPdXRwdXRTaXplLCAxLjAgLyBPdXRwdXRTaXplKQoKLyoKCUNvbnN0YW50cwoqLwovKgoJSW5lcXVhdGlvbiBjb2VmZmljaWVudHMgZm9yIGludGVycG9sYXRpb24KRXF1YXRpb25zIGFyZSBpbiB0aGUgZm9ybTogQXkgKyBCeCA9IEMKNDUsIDMwLCBhbmQgNjAgZGVub3RlIHRoZSBhbmdsZSBmcm9tIHggZWFjaCBsaW5lIHRoZSBjb29lZmljaWVudCB2YXJpYWJsZSBzZXQgYnVpbGRzCiovCmNvbnN0IHZlYzQgQWkgID0gdmVjNCggMS4wLCAtMS4wLCAtMS4wLCAgMS4wKTsKY29uc3QgdmVjNCBCNDUgPSB2ZWM0KCAxLjAsICAxLjAsIC0xLjAsIC0xLjApOwpjb25zdCB2ZWM0IEM0NSA9IHZlYzQoIDEuNSwgIDAuNSwgLTAuNSwgIDAuNSk7CmNvbnN0IHZlYzQgQjMwID0gdmVjNCggMC41LCAgMi4wLCAtMC41LCAtMi4wKTsKY29uc3QgdmVjNCBDMzAgPSB2ZWM0KCAxLjAsICAxLjAsIC0wLjUsICAwLjApOwpjb25zdCB2ZWM0IEI2MCA9IHZlYzQoIDIuMCwgIDAuNSwgLTIuMCwgLTAuNSk7CmNvbnN0IHZlYzQgQzYwID0gdmVjNCggMi4wLCAgMC4wLCAtMS4wLCAgMC41KTsKCmNvbnN0IHZlYzQgTTQ1ID0gdmVjNCgwLjQsIDAuNCwgMC40LCAwLjQpOwpjb25zdCB2ZWM0IE0zMCA9IHZlYzQoMC4yLCAwLjQsIDAuMiwgMC40KTsKY29uc3QgdmVjNCBNNjAgPSBNMzAueXh3ejsKY29uc3QgdmVjNCBNc2hpZnQgPSB2ZWM0KDAuMik7CgovLyBDb2VmZmljaWVudCBmb3Igd2VpZ2h0ZWQgZWRnZSBkZXRlY3Rpb24KY29uc3QgZmxvYXQgY29lZiA9IDIuMDsKLy8gVGhyZXNob2xkIGZvciBpZiBsdW1pbmFuY2UgdmFsdWVzIGFyZSAiZXF1YWwiCmNvbnN0IHZlYzQgdGhyZXNob2xkID0gdmVjNCgwLjMyKTsKCi8vIENvbnZlcnNpb24gZnJvbSBSR0IgdG8gTHVtaW5hbmNlIChmcm9tIEdJTVApCmNvbnN0IHZlYzMgbHVtID0gdmVjMygwLjIxLCAwLjcyLCAwLjA3KTsKCi8vIFBlcmZvcm1zIHNhbWUgbG9naWMgb3BlcmF0aW9uIGFzICYmIGZvciB2ZWN0b3JzCmJ2ZWM0IF9hbmRfKGJ2ZWM0IEEsIGJ2ZWM0IEIpIHsKCXJldHVybiBidmVjNChBLnggJiYgQi54LCBBLnkgJiYgQi55LCBBLnogJiYgQi56LCBBLncgJiYgQi53KTsKfQoKLy8gUGVyZm9ybXMgc2FtZSBsb2dpYyBvcGVyYXRpb24gYXMgfHwgZm9yIHZlY3RvcnMKYnZlYzQgX29yXyhidmVjNCBBLCBidmVjNCBCKSB7CglyZXR1cm4gYnZlYzQoQS54IHx8IEIueCwgQS55IHx8IEIueSwgQS56IHx8IEIueiwgQS53IHx8IEIudyk7Cn0KCi8vIENvbnZlcnRzIDQgMy1jb2xvciB2ZWN0b3JzIGludG8gMSA0LXZhbHVlIGx1bWluYW5jZSB2ZWN0b3IKdmVjNCBsdW1fdG8odmVjMyB2MCwgdmVjMyB2MSwgdmVjMyB2MiwgdmVjMyB2MykgewoJcmV0dXJuIHZlYzQoZG90KGx1bSwgdjApLCBkb3QobHVtLCB2MSksIGRvdChsdW0sIHYyKSwgZG90KGx1bSwgdjMpKTsKfQoKLy8gR2V0cyB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIDIgNC12YWx1ZSBsdW1pbmFuY2UgdmVjdG9ycwp2ZWM0IGx1bV9kZih2ZWM0IEEsIHZlYzQgQikgewoJcmV0dXJuIGFicyhBIC0gQik7Cn0KCi8vIERldGVybWluZXMgaWYgMiA0LXZhbHVlIGx1bWluYW5jZSB2ZWN0b3JzIGFyZSAiZXF1YWwiIGJhc2VkIG9uIHRocmVzaG9sZApidmVjNCBsdW1fZXEodmVjNCBBLCB2ZWM0IEIpIHsKCXJldHVybiBsZXNzVGhhbihsdW1fZGYoQSwgQiksIHRocmVzaG9sZCk7Cn0KCnZlYzQgbHVtX3dkKHZlYzQgYSwgdmVjNCBiLCB2ZWM0IGMsIHZlYzQgZCwgdmVjNCBlLCB2ZWM0IGYsIHZlYzQgZywgdmVjNCBoKSB7CglyZXR1cm4gbHVtX2RmKGEsIGIpICsgbHVtX2RmKGEsIGMpICsgbHVtX2RmKGQsIGUpICsgbHVtX2RmKGQsIGYpICsgNC4wICogbHVtX2RmKGcsIGgpOwp9CgovLyBHZXRzIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gMiAzLXZhbHVlIHJnYiBjb2xvcnMKZmxvYXQgY19kZih2ZWMzIGMxLCB2ZWMzIGMyKSB7Cgl2ZWMzIGRmID0gYWJzKGMxIC0gYzIpOwoJcmV0dXJuIGRmLnIgKyBkZi5nICsgZGYuYjsKfQoKdm9pZCBtYWluKCkKewovKgpNYXNrIGZvciBhbGdvcml0aG0KKy0tLS0tKy0tLS0tKy0tLS0tKy0tLS0tKy0tLS0tKwp8ICAgICB8ICAxICB8ICAyICB8ICAzICB8ICAgICB8CistLS0tLSstLS0tLSstLS0tLSstLS0tLSstLS0tLSsKfCAgNSAgfCAgNiAgfCAgNyAgfCAgOCAgfCAgOSAgfAorLS0tLS0rLS0tLS0rLS0tLS0rLS0tLS0rLS0tLS0rCnwgMTAgIHwgMTEgIHwgMTIgIHwgMTMgIHwgMTQgIHwKKy0tLS0tKy0tLS0tKy0tLS0tKy0tLS0tKy0tLS0tKwp8IDE1ICB8IDE2ICB8IDE3ICB8IDE4ICB8IDE5ICB8CistLS0tLSstLS0tLSstLS0tLSstLS0tLSstLS0tLSsKfCAgICAgfCAyMSAgfCAyMiAgfCAyMyAgfCAgICAgfAorLS0tLS0rLS0tLS0rLS0tLS0rLS0tLS0rLS0tLS0rCgkqLwoJLy8gR2V0IG1hc2sgdmFsdWVzIGJ5IHBlcmZvcm1pbmcgdGV4dHVyZSBsb29rdXAgd2l0aCB0aGUgdW5pZm9ybSBzYW1wbGVyCgl2ZWMzIFAxICA9IENPTVBBVF9URVhUVVJFKFNvdXJjZSwgeHlwXzFfMl8zLnh3ICAgKS5yZ2I7Cgl2ZWMzIFAyICA9IENPTVBBVF9URVhUVVJFKFNvdXJjZSwgeHlwXzFfMl8zLnl3ICAgKS5yZ2I7Cgl2ZWMzIFAzICA9IENPTVBBVF9URVhUVVJFKFNvdXJjZSwgeHlwXzFfMl8zLnp3ICAgKS5yZ2I7CgkKCXZlYzMgUDYgID0gQ09NUEFUX1RFWFRVUkUoU291cmNlLCB4eXBfNl83XzgueHcgICApLnJnYjsKCXZlYzMgUDcgID0gQ09NUEFUX1RFWFRVUkUoU291cmNlLCB4eXBfNl83XzgueXcgICApLnJnYjsKCXZlYzMgUDggID0gQ09NUEFUX1RFWFRVUkUoU291cmNlLCB4eXBfNl83XzguencgICApLnJnYjsKCQoJdmVjMyBQMTEgPSBDT01QQVRfVEVYVFVSRShTb3VyY2UsIHh5cF8xMV8xMl8xMy54dykucmdiOwoJdmVjMyBQMTIgPSBDT01QQVRfVEVYVFVSRShTb3VyY2UsIHh5cF8xMV8xMl8xMy55dykucmdiOwoJdmVjMyBQMTMgPSBDT01QQVRfVEVYVFVSRShTb3VyY2UsIHh5cF8xMV8xMl8xMy56dykucmdiOwoJCgl2ZWMzIFAxNiA9IENPTVBBVF9URVhUVVJFKFNvdXJjZSwgeHlwXzE2XzE3XzE4Lnh3KS5yZ2I7Cgl2ZWMzIFAxNyA9IENPTVBBVF9URVhUVVJFKFNvdXJjZSwgeHlwXzE2XzE3XzE4Lnl3KS5yZ2I7Cgl2ZWMzIFAxOCA9IENPTVBBVF9URVhUVVJFKFNvdXJjZSwgeHlwXzE2XzE3XzE4Lnp3KS5yZ2I7CgkKCXZlYzMgUDIxID0gQ09NUEFUX1RFWFRVUkUoU291cmNlLCB4eXBfMjFfMjJfMjMueHcpLnJnYjsKCXZlYzMgUDIyID0gQ09NUEFUX1RFWFRVUkUoU291cmNlLCB4eXBfMjFfMjJfMjMueXcpLnJnYjsKCXZlYzMgUDIzID0gQ09NUEFUX1RFWFRVUkUoU291cmNlLCB4eXBfMjFfMjJfMjMuencpLnJnYjsKCQoJdmVjMyBQNSAgPSBDT01QQVRfVEVYVFVSRShTb3VyY2UsIHh5cF81XzEwXzE1Lnh5ICkucmdiOwoJdmVjMyBQMTAgPSBDT01QQVRfVEVYVFVSRShTb3VyY2UsIHh5cF81XzEwXzE1Lnh6ICkucmdiOwoJdmVjMyBQMTUgPSBDT01QQVRfVEVYVFVSRShTb3VyY2UsIHh5cF81XzEwXzE1Lnh3ICkucmdiOwoJCgl2ZWMzIFA5ICA9IENPTVBBVF9URVhUVVJFKFNvdXJjZSwgeHlwXzlfMTRfOS54eSAgKS5yZ2I7Cgl2ZWMzIFAxNCA9IENPTVBBVF9URVhUVVJFKFNvdXJjZSwgeHlwXzlfMTRfOS54eiAgKS5yZ2I7Cgl2ZWMzIFAxOSA9IENPTVBBVF9URVhUVVJFKFNvdXJjZSwgeHlwXzlfMTRfOS54dyAgKS5yZ2I7CgkKCS8vIFN0b3JlIGx1bWluYW5jZSB2YWx1ZXMgb2YgZWFjaCBwb2ludCBpbiBncm91cHMgb2YgNAoJLy8gc28gdGhhdCB3ZSBtYXkgb3BlcmF0ZSBvbiBhbGwgZm91ciBjb3JuZXJzIGF0IG9uY2UKCXZlYzQgcDcgID0gbHVtX3RvKFA3LCAgUDExLCBQMTcsIFAxMyk7Cgl2ZWM0IHA4ICA9IGx1bV90byhQOCwgIFA2LCAgUDE2LCBQMTgpOwoJdmVjNCBwMTEgPSBwNy55end4OyAgICAgICAgICAgICAgICAgICAgICAvLyBQMTEsIFAxNywgUDEzLCBQNwoJdmVjNCBwMTIgPSBsdW1fdG8oUDEyLCBQMTIsIFAxMiwgUDEyKTsKCXZlYzQgcDEzID0gcDcud3h5ejsgICAgICAgICAgICAgICAgICAgICAgLy8gUDEzLCBQNywgIFAxMSwgUDE3Cgl2ZWM0IHAxNCA9IGx1bV90byhQMTQsIFAyLCAgUDEwLCBQMjIpOwoJdmVjNCBwMTYgPSBwOC56d3h5OyAgICAgICAgICAgICAgICAgICAgICAvLyBQMTYsIFAxOCwgUDgsICBQNgoJdmVjNCBwMTcgPSBwNy56d3h5OyAgICAgICAgICAgICAgICAgICAgICAvLyBQMTcsIFAxMywgUDcsICBQMTEKCXZlYzQgcDE4ID0gcDgud3h5ejsgICAgICAgICAgICAgICAgICAgICAgLy8gUDE4LCBQOCwgIFA2LCAgUDE2Cgl2ZWM0IHAxOSA9IGx1bV90byhQMTksIFAzLCAgUDUsICBQMjEpOwoJdmVjNCBwMjIgPSBwMTQud3h5ejsgICAgICAgICAgICAgICAgICAgICAvLyBQMjIsIFAxNCwgUDIsICBQMTAKCXZlYzQgcDIzID0gbHVtX3RvKFAyMywgUDksICBQMSwgIFAxNSk7CgkKCS8vIFNjYWxlIGN1cnJlbnQgdGV4ZWwgY29vcmRpbmF0ZSB0byBbMC4uMV0KCXZlYzIgZnAgPSBmcmFjdCh0YyAqIFNvdXJjZVNpemUueHkpOwoJCgkvLyBEZXRlcm1pbmUgYW1vdW50IG9mICJzbW9vdGhpbmciIG9yIG1peGluZyB0aGF0IGNvdWxkIGJlIGRvbmUgb24gdGV4ZWwgY29ybmVycwoJdmVjNCBtYTQ1ID0gc21vb3Roc3RlcChDNDUgLSBNNDUsIEM0NSArIE00NSwgQWkgKiBmcC55ICsgQjQ1ICogZnAueCk7Cgl2ZWM0IG1hMzAgPSBzbW9vdGhzdGVwKEMzMCAtIE0zMCwgQzMwICsgTTMwLCBBaSAqIGZwLnkgKyBCMzAgKiBmcC54KTsKCXZlYzQgbWE2MCA9IHNtb290aHN0ZXAoQzYwIC0gTTYwLCBDNjAgKyBNNjAsIEFpICogZnAueSArIEI2MCAqIGZwLngpOwoJdmVjNCBtYXJuID0gc21vb3Roc3RlcChDNDUgLSBNNDUgKyBNc2hpZnQsIEM0NSArIE00NSArIE1zaGlmdCwgQWkgKiBmcC55ICsgQjQ1ICogZnAueCk7CgkKCS8vIFBlcmZvcm0gZWRnZSB3ZWlnaHQgY2FsY3VsYXRpb25zCgl2ZWM0IGU0NSAgID0gbHVtX3dkKHAxMiwgcDgsIHAxNiwgcDE4LCBwMjIsIHAxNCwgcDE3LCBwMTMpOwoJdmVjNCBlY29udCA9IGx1bV93ZChwMTcsIHAxMSwgcDIzLCBwMTMsIHA3LCBwMTksIHAxMiwgcDE4KTsKCXZlYzQgZTMwICAgPSBsdW1fZGYocDEzLCBwMTYpOwoJdmVjNCBlNjAgICA9IGx1bV9kZihwOCwgcDE3KTsKCQoJLy8gQ2FsY3VsYXRlIHJ1bGUgcmVzdWx0cyBmb3IgaW50ZXJwb2xhdGlvbgoJYnZlYzQgcjQ1XzEgICA9IF9hbmRfKG5vdEVxdWFsKHAxMiwgcDEzKSwgbm90RXF1YWwocDEyLCBwMTcpKTsKCWJ2ZWM0IHI0NV8yICAgPSBfYW5kXyhub3QobHVtX2VxKHAxMywgcDcpKSwgbm90KGx1bV9lcShwMTMsIHA4KSkpOwoJYnZlYzQgcjQ1XzMgICA9IF9hbmRfKG5vdChsdW1fZXEocDE3LCBwMTEpKSwgbm90KGx1bV9lcShwMTcsIHAxNikpKTsKCWJ2ZWM0IHI0NV80XzEgPSBfYW5kXyhub3QobHVtX2VxKHAxMywgcDE0KSksIG5vdChsdW1fZXEocDEzLCBwMTkpKSk7CglidmVjNCByNDVfNF8yID0gX2FuZF8obm90KGx1bV9lcShwMTcsIHAyMikpLCBub3QobHVtX2VxKHAxNywgcDIzKSkpOwoJYnZlYzQgcjQ1XzQgICA9IF9hbmRfKGx1bV9lcShwMTIsIHAxOCksIF9vcl8ocjQ1XzRfMSwgcjQ1XzRfMikpOwoJYnZlYzQgcjQ1XzUgICA9IF9vcl8obHVtX2VxKHAxMiwgcDE2KSwgbHVtX2VxKHAxMiwgcDgpKTsKCWJ2ZWM0IHI0NSAgICAgPSBfYW5kXyhyNDVfMSwgX29yXyhfb3JfKF9vcl8ocjQ1XzIsIHI0NV8zKSwgcjQ1XzQpLCByNDVfNSkpOwoJYnZlYzQgcjMwID0gX2FuZF8obm90RXF1YWwocDEyLCBwMTYpLCBub3RFcXVhbChwMTEsIHAxNikpOwoJYnZlYzQgcjYwID0gX2FuZF8obm90RXF1YWwocDEyLCBwOCksIG5vdEVxdWFsKHA3LCBwOCkpOwoJCgkvLyBDb21iaW5lIHJ1bGVzIHdpdGggZWRnZSB3ZWlnaHRzCglidmVjNCBlZHI0NSA9IF9hbmRfKGxlc3NUaGFuKGU0NSwgZWNvbnQpLCByNDUpOwoJYnZlYzQgZWRycm4gPSBsZXNzVGhhbkVxdWFsKGU0NSwgZWNvbnQpOwoJYnZlYzQgZWRyMzAgPSBfYW5kXyhsZXNzVGhhbkVxdWFsKGNvZWYgKiBlMzAsIGU2MCksIHIzMCk7CglidmVjNCBlZHI2MCA9IF9hbmRfKGxlc3NUaGFuRXF1YWwoY29lZiAqIGU2MCwgZTMwKSwgcjYwKTsKCQoJLy8gRmluYWxpemUgaW50ZXJwb2xhdGlvbiBydWxlcyBhbmQgY2FzdCB0byBmbG9hdCAoMC4wIGZvciBmYWxzZSwgMS4wIGZvciB0cnVlKQoJdmVjNCBmaW5hbDQ1ID0gdmVjNChfYW5kXyhfYW5kXyhub3QoZWRyMzApLCBub3QoZWRyNjApKSwgZWRyNDUpKTsKCXZlYzQgZmluYWwzMCA9IHZlYzQoX2FuZF8oX2FuZF8oZWRyNDUsIG5vdChlZHI2MCkpLCBlZHIzMCkpOwoJdmVjNCBmaW5hbDYwID0gdmVjNChfYW5kXyhfYW5kXyhlZHI0NSwgbm90KGVkcjMwKSksIGVkcjYwKSk7Cgl2ZWM0IGZpbmFsMzYgPSB2ZWM0KF9hbmRfKF9hbmRfKGVkcjYwLCBlZHIzMCksIGVkcjQ1KSk7Cgl2ZWM0IGZpbmFscm4gPSB2ZWM0KF9hbmRfKG5vdChlZHI0NSksIGVkcnJuKSk7CgkKCS8vIERldGVybWluZSB0aGUgY29sb3IgdG8gbWl4IHdpdGggZm9yIGVhY2ggY29ybmVyCgl2ZWM0IHB4ID0gc3RlcChsdW1fZGYocDEyLCBwMTcpLCBsdW1fZGYocDEyLCBwMTMpKTsKCQoJLy8gRGV0ZXJtaW5lIHRoZSBtaXggYW1vdW50cyBieSBjb21iaW5pbmcgdGhlIGZpbmFsIHJ1bGUgcmVzdWx0IGFuZCBjb3JyZXNwb25kaW5nCgkvLyBtaXggYW1vdW50IGZvciB0aGUgcnVsZSBpbiBlYWNoIGNvcm5lcgoJdmVjNCBtYWMgPSBmaW5hbDM2ICogbWF4KG1hMzAsIG1hNjApICsgZmluYWwzMCAqIG1hMzAgKyBmaW5hbDYwICogbWE2MCArIGZpbmFsNDUgKiBtYTQ1ICsgZmluYWxybiAqIG1hcm47CgkKLyoKQ2FsY3VsYXRlIHRoZSByZXN1bHRpbmcgY29sb3IgYnkgdHJhdmVyc2luZyBjbG9ja3dpc2UgYW5kIGNvdW50ZXItY2xvY2t3aXNlIGFyb3VuZAp0aGUgY29ybmVycyBvZiB0aGUgdGV4ZWwKCkZpbmFsbHkgY2hvb3NlIHRoZSByZXN1bHQgdGhhdCBoYXMgdGhlIGxhcmdlc3QgZGlmZmVyZW5jZSBmcm9tIHRoZSB0ZXhlbCdzIG9yaWdpbmFsCmNvbG9yCiovCgl2ZWMzIHJlczEgPSBQMTI7CglyZXMxID0gbWl4KHJlczEsIG1peChQMTMsIFAxNywgcHgueCksIG1hYy54KTsKCXJlczEgPSBtaXgocmVzMSwgbWl4KFA3LCBQMTMsIHB4LnkpLCBtYWMueSk7CglyZXMxID0gbWl4KHJlczEsIG1peChQMTEsIFA3LCBweC56KSwgbWFjLnopOwoJcmVzMSA9IG1peChyZXMxLCBtaXgoUDE3LCBQMTEsIHB4LncpLCBtYWMudyk7CgkKCXZlYzMgcmVzMiA9IFAxMjsKCXJlczIgPSBtaXgocmVzMiwgbWl4KFAxNywgUDExLCBweC53KSwgbWFjLncpOwoJcmVzMiA9IG1peChyZXMyLCBtaXgoUDExLCBQNywgcHgueiksIG1hYy56KTsKCXJlczIgPSBtaXgocmVzMiwgbWl4KFA3LCBQMTMsIHB4LnkpLCBtYWMueSk7CglyZXMyID0gbWl4KHJlczIsIG1peChQMTMsIFAxNywgcHgueCksIG1hYy54KTsKCQoJRnJhZ0NvbG9yID0gdmVjNChtaXgocmVzMSwgcmVzMiwgc3RlcChjX2RmKFAxMiwgcmVzMSksIGNfZGYoUDEyLCByZXMyKSkpLCAxLjApOwp9IAojZW5kaWYK", + }, + ], + }, + + //https://github.com/libretro/glsl-shaders/blob/master/crt/crt-aperture.glslp + "crt-aperture.glslp": { + "shader": { + "type": "text", + "value": "shaders = 1\n\nshader0 = crt-aperture.glsl\nfilter_linear0 = false\n", + }, + "resources": [ + { + "name": "crt-aperture.glsl", + "type": "base64", + "value": "LyoKICAgIENSVCBTaGFkZXIgYnkgRWFzeU1vZGUKICAgIExpY2Vuc2U6IEdQTAoqLwoKI3ByYWdtYSBwYXJhbWV0ZXIgU0hBUlBORVNTX0lNQUdFICJTaGFycG5lc3MgSW1hZ2UiIDEuMCAxLjAgNS4wIDEuMAojcHJhZ21hIHBhcmFtZXRlciBTSEFSUE5FU1NfRURHRVMgIlNoYXJwbmVzcyBFZGdlcyIgMy4wIDEuMCA1LjAgMS4wCiNwcmFnbWEgcGFyYW1ldGVyIEdMT1dfV0lEVEggIkdsb3cgV2lkdGgiIDAuNSAwLjA1IDAuNjUgMC4wNQojcHJhZ21hIHBhcmFtZXRlciBHTE9XX0hFSUdIVCAiR2xvdyBIZWlnaHQiIDAuNSAwLjA1IDAuNjUgMC4wNQojcHJhZ21hIHBhcmFtZXRlciBHTE9XX0hBTEFUSU9OICJHbG93IEhhbGF0aW9uIiAwLjEgMC4wIDEuMCAwLjAxCiNwcmFnbWEgcGFyYW1ldGVyIEdMT1dfRElGRlVTSU9OICJHbG93IERpZmZ1c2lvbiIgMC4wNSAwLjAgMS4wIDAuMDEKI3ByYWdtYSBwYXJhbWV0ZXIgTUFTS19DT0xPUlMgIk1hc2sgQ29sb3JzIiAyLjAgMi4wIDMuMCAxLjAKI3ByYWdtYSBwYXJhbWV0ZXIgTUFTS19TVFJFTkdUSCAiTWFzayBTdHJlbmd0aCIgMC4zIDAuMCAxLjAgMC4wNQojcHJhZ21hIHBhcmFtZXRlciBNQVNLX1NJWkUgIk1hc2sgU2l6ZSIgMS4wIDEuMCA5LjAgMS4wCiNwcmFnbWEgcGFyYW1ldGVyIFNDQU5MSU5FX1NJWkVfTUlOICJTY2FubGluZSBTaXplIE1pbi4iIDAuNSAwLjUgMS41IDAuMDUKI3ByYWdtYSBwYXJhbWV0ZXIgU0NBTkxJTkVfU0laRV9NQVggIlNjYW5saW5lIFNpemUgTWF4LiIgMS41IDAuNSAxLjUgMC4wNQojcHJhZ21hIHBhcmFtZXRlciBTQ0FOTElORV9TSEFQRSAiU2NhbmxpbmUgU2hhcGUiIDIuNSAxLjAgMTAwLjAgMC4xCiNwcmFnbWEgcGFyYW1ldGVyIFNDQU5MSU5FX09GRlNFVCAiU2NhbmxpbmUgT2Zmc2V0IiAxLjAgMC4wIDEuMCAxLjAKI3ByYWdtYSBwYXJhbWV0ZXIgR0FNTUFfSU5QVVQgIkdhbW1hIElucHV0IiAyLjQgMS4wIDUuMCAwLjEKI3ByYWdtYSBwYXJhbWV0ZXIgR0FNTUFfT1VUUFVUICJHYW1tYSBPdXRwdXQiIDIuNCAxLjAgNS4wIDAuMQojcHJhZ21hIHBhcmFtZXRlciBCUklHSFRORVNTICJCcmlnaHRuZXNzIiAxLjUgMC4wIDIuMCAwLjA1CgojZGVmaW5lIENvb3JkIFRFWDAKCiNpZiBkZWZpbmVkKFZFUlRFWCkKCiNpZiBfX1ZFUlNJT05fXyA+PSAxMzAKI2RlZmluZSBPVVQgb3V0CiNkZWZpbmUgSU4gIGluCiNkZWZpbmUgdGV4MkQgdGV4dHVyZQojZWxzZQojZGVmaW5lIE9VVCB2YXJ5aW5nIAojZGVmaW5lIElOIGF0dHJpYnV0ZSAKI2RlZmluZSB0ZXgyRCB0ZXh0dXJlMkQKI2VuZGlmCgojaWZkZWYgR0xfRVMKI2RlZmluZSBQUkVDSVNJT04gbWVkaXVtcAojZWxzZQojZGVmaW5lIFBSRUNJU0lPTgojZW5kaWYKCklOICB2ZWM0IFZlcnRleENvb3JkOwpJTiAgdmVjNCBDb2xvcjsKSU4gIHZlYzIgVGV4Q29vcmQ7Ck9VVCB2ZWM0IGNvbG9yOwpPVVQgdmVjMiBDb29yZDsKCnVuaWZvcm0gbWF0NCBNVlBNYXRyaXg7CnVuaWZvcm0gUFJFQ0lTSU9OIGludCBGcmFtZURpcmVjdGlvbjsKdW5pZm9ybSBQUkVDSVNJT04gaW50IEZyYW1lQ291bnQ7CnVuaWZvcm0gUFJFQ0lTSU9OIHZlYzIgT3V0cHV0U2l6ZTsKdW5pZm9ybSBQUkVDSVNJT04gdmVjMiBUZXh0dXJlU2l6ZTsKdW5pZm9ybSBQUkVDSVNJT04gdmVjMiBJbnB1dFNpemU7Cgp2b2lkIG1haW4oKQp7CiAgICBnbF9Qb3NpdGlvbiA9IE1WUE1hdHJpeCAqIFZlcnRleENvb3JkOwogICAgY29sb3IgPSBDb2xvcjsKICAgIENvb3JkID0gVGV4Q29vcmQgKiAxLjAwMDE7Cn0KCiNlbGlmIGRlZmluZWQoRlJBR01FTlQpCgojaWYgX19WRVJTSU9OX18gPj0gMTMwCiNkZWZpbmUgSU4gaW4KI2RlZmluZSB0ZXgyRCB0ZXh0dXJlCm91dCB2ZWM0IEZyYWdDb2xvcjsKI2Vsc2UKI2RlZmluZSBJTiB2YXJ5aW5nCiNkZWZpbmUgRnJhZ0NvbG9yIGdsX0ZyYWdDb2xvcgojZGVmaW5lIHRleDJEIHRleHR1cmUyRAojZW5kaWYKCiNpZmRlZiBHTF9FUwojaWZkZWYgR0xfRlJBR01FTlRfUFJFQ0lTSU9OX0hJR0gKcHJlY2lzaW9uIGhpZ2hwIGZsb2F0OwojZWxzZQpwcmVjaXNpb24gbWVkaXVtcCBmbG9hdDsKI2VuZGlmCiNkZWZpbmUgUFJFQ0lTSU9OIG1lZGl1bXAKI2Vsc2UKI2RlZmluZSBQUkVDSVNJT04KI2VuZGlmCgp1bmlmb3JtIFBSRUNJU0lPTiBpbnQgRnJhbWVEaXJlY3Rpb247CnVuaWZvcm0gUFJFQ0lTSU9OIGludCBGcmFtZUNvdW50Owp1bmlmb3JtIFBSRUNJU0lPTiB2ZWMyIE91dHB1dFNpemU7CnVuaWZvcm0gUFJFQ0lTSU9OIHZlYzIgVGV4dHVyZVNpemU7CnVuaWZvcm0gUFJFQ0lTSU9OIHZlYzIgSW5wdXRTaXplOwp1bmlmb3JtIHNhbXBsZXIyRCBUZXh0dXJlOwpJTiB2ZWMyIENvb3JkOwoKI2lmZGVmIFBBUkFNRVRFUl9VTklGT1JNCnVuaWZvcm0gUFJFQ0lTSU9OIGZsb2F0IFNIQVJQTkVTU19JTUFHRTsKdW5pZm9ybSBQUkVDSVNJT04gZmxvYXQgU0hBUlBORVNTX0VER0VTOwp1bmlmb3JtIFBSRUNJU0lPTiBmbG9hdCBHTE9XX1dJRFRIOwp1bmlmb3JtIFBSRUNJU0lPTiBmbG9hdCBHTE9XX0hFSUdIVDsKdW5pZm9ybSBQUkVDSVNJT04gZmxvYXQgR0xPV19IQUxBVElPTjsKdW5pZm9ybSBQUkVDSVNJT04gZmxvYXQgR0xPV19ESUZGVVNJT047CnVuaWZvcm0gUFJFQ0lTSU9OIGZsb2F0IE1BU0tfQ09MT1JTOwp1bmlmb3JtIFBSRUNJU0lPTiBmbG9hdCBNQVNLX1NUUkVOR1RIOwp1bmlmb3JtIFBSRUNJU0lPTiBmbG9hdCBNQVNLX1NJWkU7CnVuaWZvcm0gUFJFQ0lTSU9OIGZsb2F0IFNDQU5MSU5FX1NJWkVfTUlOOwp1bmlmb3JtIFBSRUNJU0lPTiBmbG9hdCBTQ0FOTElORV9TSVpFX01BWDsKdW5pZm9ybSBQUkVDSVNJT04gZmxvYXQgU0NBTkxJTkVfU0hBUEU7CnVuaWZvcm0gUFJFQ0lTSU9OIGZsb2F0IFNDQU5MSU5FX09GRlNFVDsKdW5pZm9ybSBQUkVDSVNJT04gZmxvYXQgR0FNTUFfSU5QVVQ7CnVuaWZvcm0gUFJFQ0lTSU9OIGZsb2F0IEdBTU1BX09VVFBVVDsKdW5pZm9ybSBQUkVDSVNJT04gZmxvYXQgQlJJR0hUTkVTUzsKI2Vsc2UKI2RlZmluZSBTSEFSUE5FU1NfSU1BR0UgMS4wCiNkZWZpbmUgU0hBUlBORVNTX0VER0VTIDMuMAojZGVmaW5lIEdMT1dfV0lEVEggMC41CiNkZWZpbmUgR0xPV19IRUlHSFQgMC41CiNkZWZpbmUgR0xPV19IQUxBVElPTiAwLjEKI2RlZmluZSBHTE9XX0RJRkZVU0lPTiAwLjA1CiNkZWZpbmUgTUFTS19DT0xPUlMgMi4wCiNkZWZpbmUgTUFTS19TVFJFTkdUSCAwLjMKI2RlZmluZSBNQVNLX1NJWkUgMS4wCiNkZWZpbmUgU0NBTkxJTkVfU0laRV9NSU4gMC41CiNkZWZpbmUgU0NBTkxJTkVfU0laRV9NQVggMS41CiNkZWZpbmUgU0NBTkxJTkVfU0hBUEUgMS41CiNkZWZpbmUgU0NBTkxJTkVfT0ZGU0VUIDEuMAojZGVmaW5lIEdBTU1BX0lOUFVUIDIuNAojZGVmaW5lIEdBTU1BX09VVFBVVCAyLjQKI2RlZmluZSBCUklHSFRORVNTIDEuNQojZW5kaWYKCiNkZWZpbmUgRklYKGMpIG1heChhYnMoYyksIDFlLTUpCiNkZWZpbmUgUEkgMy4xNDE1OTI2NTM1ODkKI2RlZmluZSBzYXR1cmF0ZShjKSBjbGFtcChjLCAwLjAsIDEuMCkKI2RlZmluZSBURVgyRChjKSBwb3codGV4MkQodGV4LCBjKS5yZ2IsIHZlYzMoR0FNTUFfSU5QVVQpKQoKbWF0MyBnZXRfY29sb3JfbWF0cml4KHNhbXBsZXIyRCB0ZXgsIHZlYzIgY28sIHZlYzIgZHgpCnsKICAgIHJldHVybiBtYXQzKFRFWDJEKGNvIC0gZHgpLCBURVgyRChjbyksIFRFWDJEKGNvICsgZHgpKTsKfQoKdmVjMyBibHVyKG1hdDMgbSwgZmxvYXQgZGlzdCwgZmxvYXQgcmFkKQp7CiAgICB2ZWMzIHggPSB2ZWMzKGRpc3QgLSAxLjAsIGRpc3QsIGRpc3QgKyAxLjApIC8gcmFkOwogICAgdmVjMyB3ID0gZXhwMih4ICogeCAqIC0xLjApOwoKICAgIHJldHVybiAobVswXSAqIHcueCArIG1bMV0gKiB3LnkgKyBtWzJdICogdy56KSAvICh3LnggKyB3LnkgKyB3LnopOwp9Cgp2ZWMzIGZpbHRlcl9nYXVzc2lhbihzYW1wbGVyMkQgdGV4LCB2ZWMyIGNvLCB2ZWMyIHRleF9zaXplKQp7CiAgICB2ZWMyIGR4ID0gdmVjMigxLjAgLyB0ZXhfc2l6ZS54LCAwLjApOwogICAgdmVjMiBkeSA9IHZlYzIoMC4wLCAxLjAgLyB0ZXhfc2l6ZS55KTsKICAgIHZlYzIgcGl4X2NvID0gY28gKiB0ZXhfc2l6ZTsKICAgIHZlYzIgdGV4X2NvID0gKGZsb29yKHBpeF9jbykgKyAwLjUpIC8gdGV4X3NpemU7CiAgICB2ZWMyIGRpc3QgPSAoZnJhY3QocGl4X2NvKSAtIDAuNSkgKiAtMS4wOwoKICAgIG1hdDMgbGluZTAgPSBnZXRfY29sb3JfbWF0cml4KHRleCwgdGV4X2NvIC0gZHksIGR4KTsKICAgIG1hdDMgbGluZTEgPSBnZXRfY29sb3JfbWF0cml4KHRleCwgdGV4X2NvLCBkeCk7CiAgICBtYXQzIGxpbmUyID0gZ2V0X2NvbG9yX21hdHJpeCh0ZXgsIHRleF9jbyArIGR5LCBkeCk7CiAgICBtYXQzIGNvbHVtbiA9IG1hdDMoYmx1cihsaW5lMCwgZGlzdC54LCBHTE9XX1dJRFRIKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJsdXIobGluZTEsIGRpc3QueCwgR0xPV19XSURUSCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBibHVyKGxpbmUyLCBkaXN0LngsIEdMT1dfV0lEVEgpKTsKCiAgICByZXR1cm4gYmx1cihjb2x1bW4sIGRpc3QueSwgR0xPV19IRUlHSFQpOwp9Cgp2ZWMzIGZpbHRlcl9sYW5jem9zKHNhbXBsZXIyRCB0ZXgsIHZlYzIgY28sIHZlYzIgdGV4X3NpemUsIGZsb2F0IHNoYXJwKQp7CiAgICB0ZXhfc2l6ZS54ICo9IHNoYXJwOwoKICAgIHZlYzIgZHggPSB2ZWMyKDEuMCAvIHRleF9zaXplLngsIDAuMCk7CiAgICB2ZWMyIHBpeF9jbyA9IGNvICogdGV4X3NpemUgLSB2ZWMyKDAuNSwgMC4wKTsKICAgIHZlYzIgdGV4X2NvID0gKGZsb29yKHBpeF9jbykgKyB2ZWMyKDAuNSwgMC4wKSkgLyB0ZXhfc2l6ZTsKICAgIHZlYzIgZGlzdCA9IGZyYWN0KHBpeF9jbyk7CiAgICB2ZWM0IGNvZWYgPSBQSSAqIHZlYzQoZGlzdC54ICsgMS4wLCBkaXN0LngsIGRpc3QueCAtIDEuMCwgZGlzdC54IC0gMi4wKTsKCiAgICBjb2VmID0gRklYKGNvZWYpOwogICAgY29lZiA9IDIuMCAqIHNpbihjb2VmKSAqIHNpbihjb2VmIC8gMi4wKSAvIChjb2VmICogY29lZik7CiAgICBjb2VmIC89IGRvdChjb2VmLCB2ZWM0KDEuMCkpOwoKICAgIHZlYzQgY29sMSA9IHZlYzQoVEVYMkQodGV4X2NvKSwgMS4wKTsKICAgIHZlYzQgY29sMiA9IHZlYzQoVEVYMkQodGV4X2NvICsgZHgpLCAxLjApOwoKICAgIHJldHVybiAobWF0NChjb2wxLCBjb2wxLCBjb2wyLCBjb2wyKSAqIGNvZWYpLnJnYjsKfQoKdmVjMyBnZXRfc2NhbmxpbmVfd2VpZ2h0KGZsb2F0IHgsIHZlYzMgY29sKQp7CiAgICB2ZWMzIGJlYW0gPSBtaXgodmVjMyhTQ0FOTElORV9TSVpFX01JTiksIHZlYzMoU0NBTkxJTkVfU0laRV9NQVgpLCBwb3coY29sLCB2ZWMzKDEuMCAvIFNDQU5MSU5FX1NIQVBFKSkpOwogICAgdmVjMyB4X211bCA9IDIuMCAvIGJlYW07CiAgICB2ZWMzIHhfb2Zmc2V0ID0geF9tdWwgKiAwLjU7CgogICAgcmV0dXJuIHNtb290aHN0ZXAoMC4wLCAxLjAsIDEuMCAtIGFicyh4ICogeF9tdWwgLSB4X29mZnNldCkpICogeF9vZmZzZXQ7Cn0KCnZlYzMgZ2V0X21hc2tfd2VpZ2h0KGZsb2F0IHgpCnsKICAgIGZsb2F0IGkgPSBtb2QoZmxvb3IoeCAqIE91dHB1dFNpemUueCAqIFRleHR1cmVTaXplLnggLyAoSW5wdXRTaXplLnggKiBNQVNLX1NJWkUpKSwgTUFTS19DT0xPUlMpOwoKICAgIGlmIChpID09IDAuMCkgcmV0dXJuIG1peCh2ZWMzKDEuMCwgMC4wLCAxLjApLCB2ZWMzKDEuMCwgMC4wLCAwLjApLCBNQVNLX0NPTE9SUyAtIDIuMCk7CiAgICBlbHNlIGlmIChpID09IDEuMCkgcmV0dXJuIHZlYzMoMC4wLCAxLjAsIDAuMCk7CiAgICBlbHNlIHJldHVybiB2ZWMzKDAuMCwgMC4wLCAxLjApOwp9Cgp2b2lkIG1haW4oKQp7CiAgICBmbG9hdCBzY2FsZSA9IGZsb29yKChPdXRwdXRTaXplLnkgLyBJbnB1dFNpemUueSkgKyAwLjAwMSk7CiAgICBmbG9hdCBvZmZzZXQgPSAxLjAgLyBzY2FsZSAqIDAuNTsKICAgIAogICAgaWYgKGJvb2wobW9kKHNjYWxlLCAyLjApKSkgb2Zmc2V0ID0gMC4wOwogICAgCiAgICB2ZWMyIGNvID0gKENvb3JkICogVGV4dHVyZVNpemUgLSB2ZWMyKDAuMCwgb2Zmc2V0ICogU0NBTkxJTkVfT0ZGU0VUKSkgLyBUZXh0dXJlU2l6ZTsKCiAgICB2ZWMzIGNvbF9nbG93ID0gZmlsdGVyX2dhdXNzaWFuKFRleHR1cmUsIGNvLCBUZXh0dXJlU2l6ZSk7CiAgICB2ZWMzIGNvbF9zb2Z0ID0gZmlsdGVyX2xhbmN6b3MoVGV4dHVyZSwgY28sIFRleHR1cmVTaXplLCBTSEFSUE5FU1NfSU1BR0UpOwogICAgdmVjMyBjb2xfc2hhcnAgPSBmaWx0ZXJfbGFuY3pvcyhUZXh0dXJlLCBjbywgVGV4dHVyZVNpemUsIFNIQVJQTkVTU19FREdFUyk7CiAgICB2ZWMzIGNvbCA9IHNxcnQoY29sX3NoYXJwICogY29sX3NvZnQpOwoKICAgIGNvbCAqPSBnZXRfc2NhbmxpbmVfd2VpZ2h0KGZyYWN0KGNvLnkgKiBUZXh0dXJlU2l6ZS55KSwgY29sX3NvZnQpOwogICAgY29sX2dsb3cgPSBzYXR1cmF0ZShjb2xfZ2xvdyAtIGNvbCk7CiAgICBjb2wgKz0gY29sX2dsb3cgKiBjb2xfZ2xvdyAqIEdMT1dfSEFMQVRJT047CiAgICBjb2wgPSBtaXgoY29sLCBjb2wgKiBnZXRfbWFza193ZWlnaHQoY28ueCkgKiBNQVNLX0NPTE9SUywgTUFTS19TVFJFTkdUSCk7CiAgICBjb2wgKz0gY29sX2dsb3cgKiBHTE9XX0RJRkZVU0lPTjsKICAgIGNvbCA9IHBvdyhjb2wgKiBCUklHSFRORVNTLCB2ZWMzKDEuMCAvIEdBTU1BX09VVFBVVCkpOwoKICAgIEZyYWdDb2xvciA9IHZlYzQoY29sLCAxLjApOwp9CgojZW5kaWYK", + }, + ], + }, + + //https://github.com/libretro/glsl-shaders/blob/master/crt/crt-easymode.glslp + "crt-easymode.glslp": { + "shader": { + "type": "text", + "value": "shaders = 1\n\nshader0 = crt-easymode.glsl\nfilter_linear0 = false\n", + }, + "resources": [ + { + "name": "crt-easymode.glsl", + "type": "base64", + "value": "LyoKICAgIENSVCBTaGFkZXIgYnkgRWFzeU1vZGUKICAgIExpY2Vuc2U6IEdQTAoKICAgIEEgZmxhdCBDUlQgc2hhZGVyIGlkZWFsbHkgZm9yIDEwODBwIG9yIGhpZ2hlciBkaXNwbGF5cy4KCiAgICBSZWNvbW1lbmRlZCBTZXR0aW5nczoKCiAgICBWaWRlbwogICAgLSBBc3BlY3QgUmF0aW86ICA0OjMKICAgIC0gSW50ZWdlciBTY2FsZTogT2ZmCgogICAgU2hhZGVyCiAgICAtIEZpbHRlcjogTmVhcmVzdAogICAgLSBTY2FsZTogIERvbid0IENhcmUKCiAgICBFeGFtcGxlIFJHQiBNYXNrIFBhcmFtZXRlciBTZXR0aW5nczoKCiAgICBBcGVydHVyZSBHcmlsbGUgKERlZmF1bHQpCiAgICAtIERvdCBXaWR0aDogIDEKICAgIC0gRG90IEhlaWdodDogMQogICAgLSBTdGFnZ2VyOiAgICAwCgogICAgTG90dGVzJyBTaGFkb3cgTWFzawogICAgLSBEb3QgV2lkdGg6ICAyCiAgICAtIERvdCBIZWlnaHQ6IDEKICAgIC0gU3RhZ2dlcjogICAgMwoqLwoKLy8gUGFyYW1ldGVyIGxpbmVzIGdvIGhlcmU6CiNwcmFnbWEgcGFyYW1ldGVyIFNIQVJQTkVTU19IICJTaGFycG5lc3MgSG9yaXpvbnRhbCIgMC41IDAuMCAxLjAgMC4wNQojcHJhZ21hIHBhcmFtZXRlciBTSEFSUE5FU1NfViAiU2hhcnBuZXNzIFZlcnRpY2FsIiAxLjAgMC4wIDEuMCAwLjA1CiNwcmFnbWEgcGFyYW1ldGVyIE1BU0tfU1RSRU5HVEggIk1hc2sgU3RyZW5ndGgiIDAuMyAwLjAgMS4wIDAuMDEKI3ByYWdtYSBwYXJhbWV0ZXIgTUFTS19ET1RfV0lEVEggIk1hc2sgRG90IFdpZHRoIiAxLjAgMS4wIDEwMC4wIDEuMAojcHJhZ21hIHBhcmFtZXRlciBNQVNLX0RPVF9IRUlHSFQgIk1hc2sgRG90IEhlaWdodCIgMS4wIDEuMCAxMDAuMCAxLjAKI3ByYWdtYSBwYXJhbWV0ZXIgTUFTS19TVEFHR0VSICJNYXNrIFN0YWdnZXIiIDAuMCAwLjAgMTAwLjAgMS4wCiNwcmFnbWEgcGFyYW1ldGVyIE1BU0tfU0laRSAiTWFzayBTaXplIiAxLjAgMS4wIDEwMC4wIDEuMAojcHJhZ21hIHBhcmFtZXRlciBTQ0FOTElORV9TVFJFTkdUSCAiU2NhbmxpbmUgU3RyZW5ndGgiIDEuMCAwLjAgMS4wIDAuMDUKI3ByYWdtYSBwYXJhbWV0ZXIgU0NBTkxJTkVfQkVBTV9XSURUSF9NSU4gIlNjYW5saW5lIEJlYW0gV2lkdGggTWluLiIgMS41IDAuNSA1LjAgMC41CiNwcmFnbWEgcGFyYW1ldGVyIFNDQU5MSU5FX0JFQU1fV0lEVEhfTUFYICJTY2FubGluZSBCZWFtIFdpZHRoIE1heC4iIDEuNSAwLjUgNS4wIDAuNQojcHJhZ21hIHBhcmFtZXRlciBTQ0FOTElORV9CUklHSFRfTUlOICJTY2FubGluZSBCcmlnaHRuZXNzIE1pbi4iIDAuMzUgMC4wIDEuMCAwLjA1CiNwcmFnbWEgcGFyYW1ldGVyIFNDQU5MSU5FX0JSSUdIVF9NQVggIlNjYW5saW5lIEJyaWdodG5lc3MgTWF4LiIgMC42NSAwLjAgMS4wIDAuMDUKI3ByYWdtYSBwYXJhbWV0ZXIgU0NBTkxJTkVfQ1VUT0ZGICJTY2FubGluZSBDdXRvZmYiIDQwMC4wIDEuMCAxMDAwLjAgMS4wCiNwcmFnbWEgcGFyYW1ldGVyIEdBTU1BX0lOUFVUICJHYW1tYSBJbnB1dCIgMi4wIDAuMSA1LjAgMC4xCiNwcmFnbWEgcGFyYW1ldGVyIEdBTU1BX09VVFBVVCAiR2FtbWEgT3V0cHV0IiAxLjggMC4xIDUuMCAwLjEKI3ByYWdtYSBwYXJhbWV0ZXIgQlJJR0hUX0JPT1NUICJCcmlnaHRuZXNzIEJvb3N0IiAxLjIgMS4wIDIuMCAwLjAxCiNwcmFnbWEgcGFyYW1ldGVyIERJTEFUSU9OICJEaWxhdGlvbiIgMS4wIDAuMCAxLjAgMS4wCgojaWYgZGVmaW5lZChWRVJURVgpCgojaWYgX19WRVJTSU9OX18gPj0gMTMwCiNkZWZpbmUgQ09NUEFUX1ZBUllJTkcgb3V0CiNkZWZpbmUgQ09NUEFUX0FUVFJJQlVURSBpbgojZGVmaW5lIENPTVBBVF9URVhUVVJFIHRleHR1cmUKI2Vsc2UKI2RlZmluZSBDT01QQVRfVkFSWUlORyB2YXJ5aW5nIAojZGVmaW5lIENPTVBBVF9BVFRSSUJVVEUgYXR0cmlidXRlIAojZGVmaW5lIENPTVBBVF9URVhUVVJFIHRleHR1cmUyRAojZW5kaWYKCiNpZmRlZiBHTF9FUwojZGVmaW5lIENPTVBBVF9QUkVDSVNJT04gbWVkaXVtcAojZWxzZQojZGVmaW5lIENPTVBBVF9QUkVDSVNJT04KI2VuZGlmCgpDT01QQVRfQVRUUklCVVRFIHZlYzQgVmVydGV4Q29vcmQ7CkNPTVBBVF9BVFRSSUJVVEUgdmVjNCBDT0xPUjsKQ09NUEFUX0FUVFJJQlVURSB2ZWM0IFRleENvb3JkOwpDT01QQVRfVkFSWUlORyB2ZWM0IENPTDA7CkNPTVBBVF9WQVJZSU5HIHZlYzQgVEVYMDsKCnZlYzQgX29Qb3NpdGlvbjE7IAp1bmlmb3JtIG1hdDQgTVZQTWF0cml4Owp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gaW50IEZyYW1lRGlyZWN0aW9uOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gaW50IEZyYW1lQ291bnQ7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiB2ZWMyIE91dHB1dFNpemU7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiB2ZWMyIFRleHR1cmVTaXplOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gdmVjMiBJbnB1dFNpemU7Cgp2b2lkIG1haW4oKQp7CiAgICBnbF9Qb3NpdGlvbiA9IE1WUE1hdHJpeCAqIFZlcnRleENvb3JkOwogICAgQ09MMCA9IENPTE9SOwogICAgVEVYMC54eSA9IFRleENvb3JkLnh5Owp9CgojZWxpZiBkZWZpbmVkKEZSQUdNRU5UKQoKI2lmIF9fVkVSU0lPTl9fID49IDEzMAojZGVmaW5lIENPTVBBVF9WQVJZSU5HIGluCiNkZWZpbmUgQ09NUEFUX1RFWFRVUkUgdGV4dHVyZQpvdXQgdmVjNCBGcmFnQ29sb3I7CiNlbHNlCiNkZWZpbmUgQ09NUEFUX1ZBUllJTkcgdmFyeWluZwojZGVmaW5lIEZyYWdDb2xvciBnbF9GcmFnQ29sb3IKI2RlZmluZSBDT01QQVRfVEVYVFVSRSB0ZXh0dXJlMkQKI2VuZGlmCgojaWZkZWYgR0xfRVMKI2lmZGVmIEdMX0ZSQUdNRU5UX1BSRUNJU0lPTl9ISUdICnByZWNpc2lvbiBoaWdocCBmbG9hdDsKI2Vsc2UKcHJlY2lzaW9uIG1lZGl1bXAgZmxvYXQ7CnByZWNpc2lvbiBtZWRpdW1wIGludDsKI2VuZGlmCiNkZWZpbmUgQ09NUEFUX1BSRUNJU0lPTiBtZWRpdW1wCiNlbHNlCiNkZWZpbmUgQ09NUEFUX1BSRUNJU0lPTgojZW5kaWYKCnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBpbnQgRnJhbWVEaXJlY3Rpb247CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBpbnQgRnJhbWVDb3VudDsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIHZlYzIgT3V0cHV0U2l6ZTsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIHZlYzIgVGV4dHVyZVNpemU7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiB2ZWMyIElucHV0U2l6ZTsKdW5pZm9ybSBzYW1wbGVyMkQgVGV4dHVyZTsKQ09NUEFUX1ZBUllJTkcgdmVjNCBURVgwOwoKI2RlZmluZSBGSVgoYykgbWF4KGFicyhjKSwgMWUtNSkKI2RlZmluZSBQSSAzLjE0MTU5MjY1MzU4OQoKI2RlZmluZSBURVgyRChjKSBkaWxhdGUoQ09NUEFUX1RFWFRVUkUoVGV4dHVyZSwgYykpCgovLyBjb21wYXRpYmlsaXR5ICNkZWZpbmVzCiNkZWZpbmUgU291cmNlIFRleHR1cmUKI2RlZmluZSB2VGV4Q29vcmQgVEVYMC54eQoKI2RlZmluZSBTb3VyY2VTaXplIHZlYzQoVGV4dHVyZVNpemUsIDEuMCAvIFRleHR1cmVTaXplKSAvL2VpdGhlciBUZXh0dXJlU2l6ZSBvciBJbnB1dFNpemUKI2RlZmluZSBvdXRzaXplIHZlYzQoT3V0cHV0U2l6ZSwgMS4wIC8gT3V0cHV0U2l6ZSkKCiNpZmRlZiBQQVJBTUVURVJfVU5JRk9STQovLyBBbGwgcGFyYW1ldGVyIGZsb2F0cyBuZWVkIHRvIGhhdmUgQ09NUEFUX1BSRUNJU0lPTiBpbiBmcm9udCBvZiB0aGVtCnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCBTSEFSUE5FU1NfSDsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIGZsb2F0IFNIQVJQTkVTU19WOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gZmxvYXQgTUFTS19TVFJFTkdUSDsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIGZsb2F0IE1BU0tfRE9UX1dJRFRIOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gZmxvYXQgTUFTS19ET1RfSEVJR0hUOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gZmxvYXQgTUFTS19TVEFHR0VSOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gZmxvYXQgTUFTS19TSVpFOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gZmxvYXQgU0NBTkxJTkVfU1RSRU5HVEg7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCBTQ0FOTElORV9CRUFNX1dJRFRIX01JTjsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIGZsb2F0IFNDQU5MSU5FX0JFQU1fV0lEVEhfTUFYOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gZmxvYXQgU0NBTkxJTkVfQlJJR0hUX01JTjsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIGZsb2F0IFNDQU5MSU5FX0JSSUdIVF9NQVg7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCBTQ0FOTElORV9DVVRPRkY7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCBHQU1NQV9JTlBVVDsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIGZsb2F0IEdBTU1BX09VVFBVVDsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIGZsb2F0IEJSSUdIVF9CT09TVDsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIGZsb2F0IERJTEFUSU9OOwojZWxzZQojZGVmaW5lIFNIQVJQTkVTU19IIDAuNQojZGVmaW5lIFNIQVJQTkVTU19WIDEuMAojZGVmaW5lIE1BU0tfU1RSRU5HVEggMC4zCiNkZWZpbmUgTUFTS19ET1RfV0lEVEggMS4wCiNkZWZpbmUgTUFTS19ET1RfSEVJR0hUIDEuMAojZGVmaW5lIE1BU0tfU1RBR0dFUiAwLjAKI2RlZmluZSBNQVNLX1NJWkUgMS4wCiNkZWZpbmUgU0NBTkxJTkVfU1RSRU5HVEggMS4wCiNkZWZpbmUgU0NBTkxJTkVfQkVBTV9XSURUSF9NSU4gMS41CiNkZWZpbmUgU0NBTkxJTkVfQkVBTV9XSURUSF9NQVggMS41CiNkZWZpbmUgU0NBTkxJTkVfQlJJR0hUX01JTiAwLjM1CiNkZWZpbmUgU0NBTkxJTkVfQlJJR0hUX01BWCAwLjY1CiNkZWZpbmUgU0NBTkxJTkVfQ1VUT0ZGIDQwMC4wCiNkZWZpbmUgR0FNTUFfSU5QVVQgMi4wCiNkZWZpbmUgR0FNTUFfT1VUUFVUIDEuOAojZGVmaW5lIEJSSUdIVF9CT09TVCAxLjIKI2RlZmluZSBESUxBVElPTiAxLjAKI2VuZGlmCgovLyBTZXQgdG8gMCB0byB1c2UgbGluZWFyIGZpbHRlciBhbmQgZ2FpbiBzcGVlZAojZGVmaW5lIEVOQUJMRV9MQU5DWk9TIDEKCnZlYzQgZGlsYXRlKHZlYzQgY29sKQp7CiAgICB2ZWM0IHggPSBtaXgodmVjNCgxLjApLCBjb2wsIERJTEFUSU9OKTsKCiAgICByZXR1cm4gY29sICogeDsKfQoKZmxvYXQgY3VydmVfZGlzdGFuY2UoZmxvYXQgeCwgZmxvYXQgc2hhcnApCnsKCi8qCiAgICBhcHBseSBoYWxmLWNpcmNsZSBzLWN1cnZlIHRvIGRpc3RhbmNlIGZvciBzaGFycGVyIChtb3JlIHBpeGVsYXRlZCkgaW50ZXJwb2xhdGlvbgogICAgc2luZ2xlIGxpbmUgZm9ybXVsYSBmb3IgR3JhcGggVG95OgogICAgMC41IC0gc3FydCgwLjI1IC0gKHggLSBzdGVwKDAuNSwgeCkpICogKHggLSBzdGVwKDAuNSwgeCkpKSAqIHNpZ24oMC41IC0geCkKKi8KCiAgICBmbG9hdCB4X3N0ZXAgPSBzdGVwKDAuNSwgeCk7CiAgICBmbG9hdCBjdXJ2ZSA9IDAuNSAtIHNxcnQoMC4yNSAtICh4IC0geF9zdGVwKSAqICh4IC0geF9zdGVwKSkgKiBzaWduKDAuNSAtIHgpOwoKICAgIHJldHVybiBtaXgoeCwgY3VydmUsIHNoYXJwKTsKfQoKbWF0NCBnZXRfY29sb3JfbWF0cml4KHZlYzIgY28sIHZlYzIgZHgpCnsKICAgIHJldHVybiBtYXQ0KFRFWDJEKGNvIC0gZHgpLCBURVgyRChjbyksIFRFWDJEKGNvICsgZHgpLCBURVgyRChjbyArIDIuMCAqIGR4KSk7Cn0KCnZlYzMgZmlsdGVyX2xhbmN6b3ModmVjNCBjb2VmZnMsIG1hdDQgY29sb3JfbWF0cml4KQp7CiAgICB2ZWM0IGNvbCAgICAgICAgPSBjb2xvcl9tYXRyaXggKiBjb2VmZnM7CiAgICB2ZWM0IHNhbXBsZV9taW4gPSBtaW4oY29sb3JfbWF0cml4WzFdLCBjb2xvcl9tYXRyaXhbMl0pOwogICAgdmVjNCBzYW1wbGVfbWF4ID0gbWF4KGNvbG9yX21hdHJpeFsxXSwgY29sb3JfbWF0cml4WzJdKTsKCiAgICBjb2wgPSBjbGFtcChjb2wsIHNhbXBsZV9taW4sIHNhbXBsZV9tYXgpOwoKICAgIHJldHVybiBjb2wucmdiOwp9Cgp2b2lkIG1haW4oKQp7CiAgICB2ZWMyIGR4ICAgICA9IHZlYzIoU291cmNlU2l6ZS56LCAwLjApOwogICAgdmVjMiBkeSAgICAgPSB2ZWMyKDAuMCwgU291cmNlU2l6ZS53KTsKICAgIHZlYzIgcGl4X2NvID0gdlRleENvb3JkICogU291cmNlU2l6ZS54eSAtIHZlYzIoMC41LCAwLjUpOwogICAgdmVjMiB0ZXhfY28gPSAoZmxvb3IocGl4X2NvKSArIHZlYzIoMC41LCAwLjUpKSAqIFNvdXJjZVNpemUuenc7CiAgICB2ZWMyIGRpc3QgICA9IGZyYWN0KHBpeF9jbyk7CiAgICBmbG9hdCBjdXJ2ZV94OwogICAgdmVjMyBjb2wsIGNvbDI7CgojaWYgRU5BQkxFX0xBTkNaT1MKICAgIGN1cnZlX3ggPSBjdXJ2ZV9kaXN0YW5jZShkaXN0LngsIFNIQVJQTkVTU19IICogU0hBUlBORVNTX0gpOwoKICAgIHZlYzQgY29lZmZzID0gUEkgKiB2ZWM0KDEuMCArIGN1cnZlX3gsIGN1cnZlX3gsIDEuMCAtIGN1cnZlX3gsIDIuMCAtIGN1cnZlX3gpOwoKICAgIGNvZWZmcyA9IEZJWChjb2VmZnMpOwogICAgY29lZmZzID0gMi4wICogc2luKGNvZWZmcykgKiBzaW4oY29lZmZzICogMC41KSAvIChjb2VmZnMgKiBjb2VmZnMpOwogICAgY29lZmZzIC89IGRvdChjb2VmZnMsIHZlYzQoMS4wKSk7CgogICAgY29sICA9IGZpbHRlcl9sYW5jem9zKGNvZWZmcywgZ2V0X2NvbG9yX21hdHJpeCh0ZXhfY28sIGR4KSk7CiAgICBjb2wyID0gZmlsdGVyX2xhbmN6b3MoY29lZmZzLCBnZXRfY29sb3JfbWF0cml4KHRleF9jbyArIGR5LCBkeCkpOwojZWxzZQogICAgY3VydmVfeCA9IGN1cnZlX2Rpc3RhbmNlKGRpc3QueCwgU0hBUlBORVNTX0gpOwoKICAgIGNvbCAgPSBtaXgoVEVYMkQodGV4X2NvKS5yZ2IsICAgICAgVEVYMkQodGV4X2NvICsgZHgpLnJnYiwgICAgICBjdXJ2ZV94KTsKICAgIGNvbDIgPSBtaXgoVEVYMkQodGV4X2NvICsgZHkpLnJnYiwgVEVYMkQodGV4X2NvICsgZHggKyBkeSkucmdiLCBjdXJ2ZV94KTsKI2VuZGlmCgogICAgY29sID0gbWl4KGNvbCwgY29sMiwgY3VydmVfZGlzdGFuY2UoZGlzdC55LCBTSEFSUE5FU1NfVikpOwogICAgY29sID0gcG93KGNvbCwgdmVjMyhHQU1NQV9JTlBVVCAvIChESUxBVElPTiArIDEuMCkpKTsKCiAgICBmbG9hdCBsdW1hICAgICAgICA9IGRvdCh2ZWMzKDAuMjEyNiwgMC43MTUyLCAwLjA3MjIpLCBjb2wpOwogICAgZmxvYXQgYnJpZ2h0ICAgICAgPSAobWF4KGNvbC5yLCBtYXgoY29sLmcsIGNvbC5iKSkgKyBsdW1hKSAqIDAuNTsKICAgIGZsb2F0IHNjYW5fYnJpZ2h0ID0gY2xhbXAoYnJpZ2h0LCBTQ0FOTElORV9CUklHSFRfTUlOLCBTQ0FOTElORV9CUklHSFRfTUFYKTsKICAgIGZsb2F0IHNjYW5fYmVhbSAgID0gY2xhbXAoYnJpZ2h0ICogU0NBTkxJTkVfQkVBTV9XSURUSF9NQVgsIFNDQU5MSU5FX0JFQU1fV0lEVEhfTUlOLCBTQ0FOTElORV9CRUFNX1dJRFRIX01BWCk7CiAgICBmbG9hdCBzY2FuX3dlaWdodCA9IDEuMCAtIHBvdyhjb3ModlRleENvb3JkLnkgKiAyLjAgKiBQSSAqIFNvdXJjZVNpemUueSkgKiAwLjUgKyAwLjUsIHNjYW5fYmVhbSkgKiBTQ0FOTElORV9TVFJFTkdUSDsKCiAgICBmbG9hdCBtYXNrICAgPSAxLjAgLSBNQVNLX1NUUkVOR1RIOyAgICAKICAgIHZlYzIgbW9kX2ZhYyA9IGZsb29yKHZUZXhDb29yZCAqIG91dHNpemUueHkgKiBTb3VyY2VTaXplLnh5IC8gKElucHV0U2l6ZS54eSAqIHZlYzIoTUFTS19TSVpFLCBNQVNLX0RPVF9IRUlHSFQgKiBNQVNLX1NJWkUpKSk7CiAgICBpbnQgZG90X25vICAgPSBpbnQobW9kKChtb2RfZmFjLnggKyBtb2QobW9kX2ZhYy55LCAyLjApICogTUFTS19TVEFHR0VSKSAvIE1BU0tfRE9UX1dJRFRILCAzLjApKTsKICAgIHZlYzMgbWFza193ZWlnaHQ7CgogICAgaWYgICAgICAoZG90X25vID09IDApIG1hc2tfd2VpZ2h0ID0gdmVjMygxLjAsICBtYXNrLCBtYXNrKTsKICAgIGVsc2UgaWYgKGRvdF9ubyA9PSAxKSBtYXNrX3dlaWdodCA9IHZlYzMobWFzaywgMS4wLCAgbWFzayk7CiAgICBlbHNlICAgICAgICAgICAgICAgICAgbWFza193ZWlnaHQgPSB2ZWMzKG1hc2ssIG1hc2ssIDEuMCk7CgogICAgaWYgKElucHV0U2l6ZS55ID49IFNDQU5MSU5FX0NVVE9GRikgCiAgICAgICAgc2Nhbl93ZWlnaHQgPSAxLjA7CgogICAgY29sMiA9IGNvbC5yZ2I7CiAgICBjb2wgKj0gdmVjMyhzY2FuX3dlaWdodCk7CiAgICBjb2wgID0gbWl4KGNvbCwgY29sMiwgc2Nhbl9icmlnaHQpOwogICAgY29sICo9IG1hc2tfd2VpZ2h0OwogICAgY29sICA9IHBvdyhjb2wsIHZlYzMoMS4wIC8gR0FNTUFfT1VUUFVUKSk7CgogICAgRnJhZ0NvbG9yID0gdmVjNChjb2wgKiBCUklHSFRfQk9PU1QsIDEuMCk7Cn0gCiNlbmRpZgo=", + }, + ], + }, + + //https://github.com/libretro/glsl-shaders/blob/master/crt/crt-geom.glslp + "crt-geom.glslp": { + "shader": { + "type": "text", + "value": "shaders = 1\n\nshader0 = crt-geom.glsl\nfilter_linear0 = false\n", + }, + "resources": [ + { + "name": "crt-geom.glsl", + "type": "base64", + "value": "LyoKICAgIENSVC1pbnRlcmxhY2VkCgogICAgQ29weXJpZ2h0IChDKSAyMDEwLTIwMTIgY2d3ZywgVGhlbWFpc3RlciBhbmQgRE9MTFMKCiAgICBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeSBpdAogICAgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUKICAgIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlciB2ZXJzaW9uIDIgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikKICAgIGFueSBsYXRlciB2ZXJzaW9uLgoKICAgIChjZ3dnIGdhdmUgdGhlaXIgY29uc2VudCB0byBoYXZlIHRoZSBvcmlnaW5hbCB2ZXJzaW9uIG9mIHRoaXMgc2hhZGVyCiAgICBkaXN0cmlidXRlZCB1bmRlciB0aGUgR1BMIGluIHRoaXMgbWVzc2FnZToKCiAgICAgICAgaHR0cDovL2JvYXJkLmJ5dXUub3JnL3ZpZXd0b3BpYy5waHA/cD0yNjA3NSNwMjYwNzUKCiAgICAgICAgIkZlZWwgZnJlZSB0byBkaXN0cmlidXRlIG15IHNoYWRlcnMgdW5kZXIgdGhlIEdQTC4gQWZ0ZXIgYWxsLCB0aGUKICAgICAgICBiYXJyZWwgZGlzdG9ydGlvbiBjb2RlIHdhcyB0YWtlbiBmcm9tIHRoZSBDdXJ2YXR1cmUgc2hhZGVyLCB3aGljaCBpcwogICAgICAgIHVuZGVyIHRoZSBHUEwuIgogICAgKQoJVGhpcyBzaGFkZXIgdmFyaWFudCBpcyBwcmUtY29uZmlndXJlZCB3aXRoIHNjcmVlbiBjdXJ2YXR1cmUKKi8KCiNwcmFnbWEgcGFyYW1ldGVyIENSVGdhbW1hICJDUlRHZW9tIFRhcmdldCBHYW1tYSIgMi40IDAuMSA1LjAgMC4xCiNwcmFnbWEgcGFyYW1ldGVyIElOViAiSW52ZXJzZSBHYW1tYS9DUlQtR2VvbSBHYW1tYSBvdXQiIDEuMCAwLjAgMS4wIDEuMAojcHJhZ21hIHBhcmFtZXRlciBtb25pdG9yZ2FtbWEgIkNSVEdlb20gTW9uaXRvciBHYW1tYSIgMi4yIDAuMSA1LjAgMC4xCiNwcmFnbWEgcGFyYW1ldGVyIGQgIkNSVEdlb20gRGlzdGFuY2UiIDEuNiAwLjEgMy4wIDAuMQojcHJhZ21hIHBhcmFtZXRlciBDVVJWQVRVUkUgIkNSVEdlb20gQ3VydmF0dXJlIFRvZ2dsZSIgMS4wIDAuMCAxLjAgMS4wCiNwcmFnbWEgcGFyYW1ldGVyIFIgIkNSVEdlb20gQ3VydmF0dXJlIFJhZGl1cyIgMi4wIDAuMSAxMC4wIDAuMQojcHJhZ21hIHBhcmFtZXRlciBjb3JuZXJzaXplICJDUlRHZW9tIENvcm5lciBTaXplIiAwLjAzIDAuMDAxIDEuMCAwLjAwNQojcHJhZ21hIHBhcmFtZXRlciBjb3JuZXJzbW9vdGggIkNSVEdlb20gQ29ybmVyIFNtb290aG5lc3MiIDEwMDAuMCA4MC4wIDIwMDAuMCAxMDAuMAojcHJhZ21hIHBhcmFtZXRlciB4X3RpbHQgIkNSVEdlb20gSG9yaXpvbnRhbCBUaWx0IiAwLjAgLTAuNSAwLjUgMC4wNQojcHJhZ21hIHBhcmFtZXRlciB5X3RpbHQgIkNSVEdlb20gVmVydGljYWwgVGlsdCIgMC4wIC0wLjUgMC41IDAuMDUKI3ByYWdtYSBwYXJhbWV0ZXIgb3ZlcnNjYW5feCAiQ1JUR2VvbSBIb3Jpei4gT3ZlcnNjYW4gJSIgMTAwLjAgLTEyNS4wIDEyNS4wIDEuMAojcHJhZ21hIHBhcmFtZXRlciBvdmVyc2Nhbl95ICJDUlRHZW9tIFZlcnQuIE92ZXJzY2FuICUiIDEwMC4wIC0xMjUuMCAxMjUuMCAxLjAKI3ByYWdtYSBwYXJhbWV0ZXIgRE9UTUFTSyAiQ1JUR2VvbSBEb3QgTWFzayBTdHJlbmd0aCIgMC4zIDAuMCAxLjAgMC4xCiNwcmFnbWEgcGFyYW1ldGVyIFNIQVJQRVIgIkNSVEdlb20gU2hhcnBuZXNzIiAxLjAgMS4wIDMuMCAxLjAKI3ByYWdtYSBwYXJhbWV0ZXIgc2NhbmxpbmVfd2VpZ2h0ICJDUlRHZW9tIFNjYW5saW5lIFdlaWdodCIgMC4zIDAuMSAwLjUgMC4wNQojcHJhZ21hIHBhcmFtZXRlciBsdW0gIkNSVEdlb20gTHVtaW5hbmNlIiAwLjAgMC4wIDEuMCAwLjAxCiNwcmFnbWEgcGFyYW1ldGVyIGludGVybGFjZV9kZXRlY3QgIkNSVEdlb20gSW50ZXJsYWNpbmcgU2ltdWxhdGlvbiIgMS4wIDAuMCAxLjAgMS4wCiNwcmFnbWEgcGFyYW1ldGVyIFNBVFVSQVRJT04gIkNSVEdlb20gU2F0dXJhdGlvbiIgMS4wIDAuMCAyLjAgMC4wNQoKI2lmbmRlZiBQQVJBTUVURVJfVU5JRk9STQojZGVmaW5lIENSVGdhbW1hIDIuNAojZGVmaW5lIG1vbml0b3JnYW1tYSAyLjIKI2RlZmluZSBkIDEuNgojZGVmaW5lIENVUlZBVFVSRSAxLjAKI2RlZmluZSBSIDIuMAojZGVmaW5lIGNvcm5lcnNpemUgMC4wMwojZGVmaW5lIGNvcm5lcnNtb290aCAxMDAwLjAKI2RlZmluZSB4X3RpbHQgMC4wCiNkZWZpbmUgeV90aWx0IDAuMAojZGVmaW5lIG92ZXJzY2FuX3ggMTAwLjAKI2RlZmluZSBvdmVyc2Nhbl95IDEwMC4wCiNkZWZpbmUgRE9UTUFTSyAwLjMKI2RlZmluZSBTSEFSUEVSIDEuMAojZGVmaW5lIHNjYW5saW5lX3dlaWdodCAwLjMKI2RlZmluZSBsdW0gMC4wCiNkZWZpbmUgaW50ZXJsYWNlX2RldGVjdCAxLjAKI2RlZmluZSBTQVRVUkFUSU9OIDEuMAojZGVmaW5lIElOViAxLjAKI2VuZGlmCgojaWYgZGVmaW5lZChWRVJURVgpCgojaWYgX19WRVJTSU9OX18gPj0gMTMwCiNkZWZpbmUgQ09NUEFUX1ZBUllJTkcgb3V0CiNkZWZpbmUgQ09NUEFUX0FUVFJJQlVURSBpbgojZGVmaW5lIENPTVBBVF9URVhUVVJFIHRleHR1cmUKI2Vsc2UKI2RlZmluZSBDT01QQVRfVkFSWUlORyB2YXJ5aW5nIAojZGVmaW5lIENPTVBBVF9BVFRSSUJVVEUgYXR0cmlidXRlIAojZGVmaW5lIENPTVBBVF9URVhUVVJFIHRleHR1cmUyRAojZW5kaWYKCiNpZmRlZiBHTF9FUwojZGVmaW5lIENPTVBBVF9QUkVDSVNJT04gbWVkaXVtcAojZWxzZQojZGVmaW5lIENPTVBBVF9QUkVDSVNJT04KI2VuZGlmCgpDT01QQVRfQVRUUklCVVRFIHZlYzQgVmVydGV4Q29vcmQ7CkNPTVBBVF9BVFRSSUJVVEUgdmVjNCBDT0xPUjsKQ09NUEFUX0FUVFJJQlVURSB2ZWM0IFRleENvb3JkOwpDT01QQVRfVkFSWUlORyB2ZWM0IENPTDA7CkNPTVBBVF9WQVJZSU5HIHZlYzQgVEVYMDsKCnZlYzQgX29Qb3NpdGlvbjE7IAp1bmlmb3JtIG1hdDQgTVZQTWF0cml4Owp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gaW50IEZyYW1lRGlyZWN0aW9uOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gaW50IEZyYW1lQ291bnQ7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiB2ZWMyIE91dHB1dFNpemU7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiB2ZWMyIFRleHR1cmVTaXplOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gdmVjMiBJbnB1dFNpemU7CgpDT01QQVRfVkFSWUlORyB2ZWMyIG92ZXJzY2FuOwpDT01QQVRfVkFSWUlORyB2ZWMyIGFzcGVjdDsKQ09NUEFUX1ZBUllJTkcgdmVjMyBzdHJldGNoOwpDT01QQVRfVkFSWUlORyB2ZWMyIHNpbmFuZ2xlOwpDT01QQVRfVkFSWUlORyB2ZWMyIGNvc2FuZ2xlOwpDT01QQVRfVkFSWUlORyB2ZWMyIG9uZTsKQ09NUEFUX1ZBUllJTkcgZmxvYXQgbW9kX2ZhY3RvcjsKQ09NUEFUX1ZBUllJTkcgdmVjMiBpbGZhYzsKCiNpZmRlZiBQQVJBTUVURVJfVU5JRk9STQp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gZmxvYXQgQ1JUZ2FtbWE7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCBtb25pdG9yZ2FtbWE7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCBkOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gZmxvYXQgQ1VSVkFUVVJFOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gZmxvYXQgUjsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIGZsb2F0IGNvcm5lcnNpemU7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCBjb3JuZXJzbW9vdGg7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCB4X3RpbHQ7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCB5X3RpbHQ7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCBvdmVyc2Nhbl94Owp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gZmxvYXQgb3ZlcnNjYW5feTsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIGZsb2F0IERPVE1BU0s7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCBTSEFSUEVSOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gZmxvYXQgc2NhbmxpbmVfd2VpZ2h0Owp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gZmxvYXQgbHVtOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gZmxvYXQgaW50ZXJsYWNlX2RldGVjdDsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIGZsb2F0IFNBVFVSQVRJT047CiNlbmRpZgoKI2RlZmluZSBGSVgoYykgbWF4KGFicyhjKSwgMWUtNSk7CgpmbG9hdCBpbnRlcnNlY3QodmVjMiB4eSkKICAgICAgICB7CglmbG9hdCBBID0gZG90KHh5LHh5KStkKmQ7CglmbG9hdCBCID0gMi4wKihSKihkb3QoeHksc2luYW5nbGUpLWQqY29zYW5nbGUueCpjb3NhbmdsZS55KS1kKmQpOwoJZmxvYXQgQyA9IGQqZCArIDIuMCpSKmQqY29zYW5nbGUueCpjb3NhbmdsZS55OwoJcmV0dXJuICgtQi1zcXJ0KEIqQi00LjAqQSpDKSkvKDIuMCpBKTsKICAgICAgICB9Cgp2ZWMyIGJrd3RyYW5zKHZlYzIgeHkpCiAgICAgICAgewoJZmxvYXQgYyA9IGludGVyc2VjdCh4eSk7Cgl2ZWMyIHBvaW50ID0gdmVjMihjKSp4eTsKCXBvaW50IC09IHZlYzIoLVIpKnNpbmFuZ2xlOwoJcG9pbnQgLz0gdmVjMihSKTsKCXZlYzIgdGFuZyA9IHNpbmFuZ2xlL2Nvc2FuZ2xlOwoJdmVjMiBwb2MgPSBwb2ludC9jb3NhbmdsZTsKCWZsb2F0IEEgPSBkb3QodGFuZyx0YW5nKSsxLjA7CglmbG9hdCBCID0gLTIuMCpkb3QocG9jLHRhbmcpOwoJZmxvYXQgQyA9IGRvdChwb2MscG9jKS0xLjA7CglmbG9hdCBhID0gKC1CK3NxcnQoQipCLTQuMCpBKkMpKS8oMi4wKkEpOwoJdmVjMiB1diA9IChwb2ludC1hKnNpbmFuZ2xlKS9jb3NhbmdsZTsKCWZsb2F0IHIgPSBSKmFjb3MoYSk7CglyZXR1cm4gdXYqci9zaW4oci9SKTsKICAgICAgICB9Cgp2ZWMyIGZ3dHJhbnModmVjMiB1dikKICAgICAgICB7CglmbG9hdCByID0gRklYKHNxcnQoZG90KHV2LHV2KSkpOwoJdXYgKj0gc2luKHIvUikvcjsKCWZsb2F0IHggPSAxLjAtY29zKHIvUik7CglmbG9hdCBEID0gZC9SICsgeCpjb3NhbmdsZS54KmNvc2FuZ2xlLnkrZG90KHV2LHNpbmFuZ2xlKTsKCXJldHVybiBkKih1dipjb3NhbmdsZS14KnNpbmFuZ2xlKS9EOwogICAgICAgIH0KCnZlYzMgbWF4c2NhbGUoKQogICAgICAgIHsKCXZlYzIgYyA9IGJrd3RyYW5zKC1SICogc2luYW5nbGUgLyAoMS4wICsgUi9kKmNvc2FuZ2xlLngqY29zYW5nbGUueSkpOwoJdmVjMiBhID0gdmVjMigwLjUsMC41KSphc3BlY3Q7Cgl2ZWMyIGxvID0gdmVjMihmd3RyYW5zKHZlYzIoLWEueCxjLnkpKS54LCBmd3RyYW5zKHZlYzIoYy54LC1hLnkpKS55KS9hc3BlY3Q7Cgl2ZWMyIGhpID0gdmVjMihmd3RyYW5zKHZlYzIoK2EueCxjLnkpKS54LCBmd3RyYW5zKHZlYzIoYy54LCthLnkpKS55KS9hc3BlY3Q7CglyZXR1cm4gdmVjMygoaGkrbG8pKmFzcGVjdCowLjUsbWF4KGhpLngtbG8ueCxoaS55LWxvLnkpKTsKICAgICAgICB9Cgp2b2lkIG1haW4oKQp7Ci8vIFNUQVJUIG9mIHBhcmFtZXRlcnMKCi8vIGdhbW1hIG9mIHNpbXVsYXRlZCBDUlQKLy8JQ1JUZ2FtbWEgPSAxLjg7Ci8vIGdhbW1hIG9mIGRpc3BsYXkgbW9uaXRvciAodHlwaWNhbGx5IDIuMiBpcyBjb3JyZWN0KQovLwltb25pdG9yZ2FtbWEgPSAyLjI7Ci8vIG92ZXJzY2FuIChlLmcuIDEuMDIgZm9yIDIlIG92ZXJzY2FuKQoJb3ZlcnNjYW4gPSB2ZWMyKDEuMDAsMS4wMCk7Ci8vIGFzcGVjdCByYXRpbwoJYXNwZWN0ID0gdmVjMigxLjAsIDAuNzUpOwovLyBsZW5ndGhzIGFyZSBtZWFzdXJlZCBpbiB1bml0cyBvZiAoYXBwcm94aW1hdGVseSkgdGhlIHdpZHRoCi8vIG9mIHRoZSBtb25pdG9yIHNpbXVsYXRlZCBkaXN0YW5jZSBmcm9tIHZpZXdlciB0byBtb25pdG9yCi8vCWQgPSAyLjA7Ci8vIHJhZGl1cyBvZiBjdXJ2YXR1cmUKLy8JUiA9IDEuNTsKLy8gdGlsdCBhbmdsZSBpbiByYWRpYW5zCi8vIChiZWhhdmlvciBtaWdodCBiZSBhIGJpdCB3cm9uZyBpZiBib3RoIGNvbXBvbmVudHMgYXJlCi8vIG5vbnplcm8pCgljb25zdCB2ZWMyIGFuZ2xlID0gdmVjMigwLjAsMC4wKTsKLy8gc2l6ZSBvZiBjdXJ2ZWQgY29ybmVycwovLwljb3JuZXJzaXplID0gMC4wMzsKLy8gYm9yZGVyIHNtb290aG5lc3MgcGFyYW1ldGVyCi8vIGRlY3JlYXNlIGlmIGJvcmRlcnMgYXJlIHRvbyBhbGlhc2VkCi8vCWNvcm5lcnNtb290aCA9IDEwMDAuMDsKCi8vIEVORCBvZiBwYXJhbWV0ZXJzCgogICAgdmVjNCBfb0NvbG9yOwogICAgdmVjMiBfb3RleENvb3JkOwogICAgZ2xfUG9zaXRpb24gPSBWZXJ0ZXhDb29yZC54ICogTVZQTWF0cml4WzBdICsgVmVydGV4Q29vcmQueSAqIE1WUE1hdHJpeFsxXSArIFZlcnRleENvb3JkLnogKiBNVlBNYXRyaXhbMl0gKyBWZXJ0ZXhDb29yZC53ICogTVZQTWF0cml4WzNdOwogICAgX29Qb3NpdGlvbjEgPSBnbF9Qb3NpdGlvbjsKICAgIF9vQ29sb3IgPSBDT0xPUjsKICAgIF9vdGV4Q29vcmQgPSBUZXhDb29yZC54eSoxLjAwMDE7CiAgICBDT0wwID0gQ09MT1I7CiAgICBURVgwLnh5ID0gVGV4Q29vcmQueHkqMS4wMDAxOwoKLy8gUHJlY2FsY3VsYXRlIGEgYnVuY2ggb2YgdXNlZnVsIHZhbHVlcyB3ZSdsbCBuZWVkIGluIHRoZSBmcmFnbWVudAovLyBzaGFkZXIuCglzaW5hbmdsZSA9IHNpbih2ZWMyKHhfdGlsdCwgeV90aWx0KSkgKyB2ZWMyKDAuMDAxKTsvL3Npbih2ZWMyKG1heChhYnMoeF90aWx0KSwgMWUtMyksIG1heChhYnMoeV90aWx0KSwgMWUtMykpKTsKCWNvc2FuZ2xlID0gY29zKHZlYzIoeF90aWx0LCB5X3RpbHQpKSArIHZlYzIoMC4wMDEpOy8vY29zKHZlYzIobWF4KGFicyh4X3RpbHQpLCAxZS0zKSwgbWF4KGFicyh5X3RpbHQpLCAxZS0zKSkpOwoJc3RyZXRjaCA9IG1heHNjYWxlKCk7CgoJaWxmYWMgPSB2ZWMyKDEuMCxjbGFtcChmbG9vcihJbnB1dFNpemUueS8yMDAuMCksIDEuMCwgMi4wKSk7CgovLyBUaGUgc2l6ZSBvZiBvbmUgdGV4ZWwsIGluIHRleHR1cmUtY29vcmRpbmF0ZXMuCgl2ZWMyIHNoYXJwVGV4dHVyZVNpemUgPSB2ZWMyKFNIQVJQRVIgKiBUZXh0dXJlU2l6ZS54LCBUZXh0dXJlU2l6ZS55KTsKCW9uZSA9IGlsZmFjIC8gc2hhcnBUZXh0dXJlU2l6ZTsKCi8vIFJlc3VsdGluZyBYIHBpeGVsLWNvb3JkaW5hdGUgb2YgdGhlIHBpeGVsIHdlJ3JlIGRyYXdpbmcuCgltb2RfZmFjdG9yID0gVGV4Q29vcmQueCAqIFRleHR1cmVTaXplLnggKiBPdXRwdXRTaXplLnggLyBJbnB1dFNpemUueDsKCn0KCiNlbGlmIGRlZmluZWQoRlJBR01FTlQpCgojaWYgX19WRVJTSU9OX18gPj0gMTMwCiNkZWZpbmUgQ09NUEFUX1ZBUllJTkcgaW4KI2RlZmluZSBDT01QQVRfVEVYVFVSRSB0ZXh0dXJlCm91dCB2ZWM0IEZyYWdDb2xvcjsKI2Vsc2UKI2RlZmluZSBDT01QQVRfVkFSWUlORyB2YXJ5aW5nCiNkZWZpbmUgRnJhZ0NvbG9yIGdsX0ZyYWdDb2xvcgojZGVmaW5lIENPTVBBVF9URVhUVVJFIHRleHR1cmUyRAojZW5kaWYKCiNpZmRlZiBHTF9FUwojaWZkZWYgR0xfRlJBR01FTlRfUFJFQ0lTSU9OX0hJR0gKcHJlY2lzaW9uIGhpZ2hwIGZsb2F0OwojZWxzZQpwcmVjaXNpb24gbWVkaXVtcCBmbG9hdDsKI2VuZGlmCiNkZWZpbmUgQ09NUEFUX1BSRUNJU0lPTiBtZWRpdW1wCiNlbHNlCiNkZWZpbmUgQ09NUEFUX1BSRUNJU0lPTgojZW5kaWYKCnN0cnVjdCBvdXRwdXRfZHVtbXkgewogICAgdmVjNCBfY29sb3I7Cn07Cgp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gaW50IEZyYW1lRGlyZWN0aW9uOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gaW50IEZyYW1lQ291bnQ7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiB2ZWMyIE91dHB1dFNpemU7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiB2ZWMyIFRleHR1cmVTaXplOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gdmVjMiBJbnB1dFNpemU7CnVuaWZvcm0gc2FtcGxlcjJEIFRleHR1cmU7CkNPTVBBVF9WQVJZSU5HIHZlYzQgVEVYMDsKCi8vIENvbW1lbnQgdGhlIG5leHQgbGluZSB0byBkaXNhYmxlIGludGVycG9sYXRpb24gaW4gbGluZWFyIGdhbW1hIChhbmQKLy8gZ2FpbiBzcGVlZCkuCgkjZGVmaW5lIExJTkVBUl9QUk9DRVNTSU5HCgovLyBFbmFibGUgc2NyZWVuIGN1cnZhdHVyZS4KLy8gICAgICAgICNkZWZpbmUgQ1VSVkFUVVJFCgovLyBFbmFibGUgM3ggb3ZlcnNhbXBsaW5nIG9mIHRoZSBiZWFtIHByb2ZpbGUKICAgICAgICAjZGVmaW5lIE9WRVJTQU1QTEUKCi8vIFVzZSB0aGUgb2xkZXIsIHB1cmVseSBnYXVzc2lhbiBiZWFtIHByb2ZpbGUKICAgICAgICAvLyNkZWZpbmUgVVNFR0FVU1NJQU4KCi8vIE1hY3Jvcy4KI2RlZmluZSBGSVgoYykgbWF4KGFicyhjKSwgMWUtNSk7CiNkZWZpbmUgUEkgMy4xNDE1OTI2NTM1ODkKCiNpZmRlZiBMSU5FQVJfUFJPQ0VTU0lORwojICAgICAgIGRlZmluZSBURVgyRChjKSBwb3coQ09NUEFUX1RFWFRVUkUoVGV4dHVyZSwgKGMpKSwgdmVjNChDUlRnYW1tYSkpCiNlbHNlCiMgICAgICAgZGVmaW5lIFRFWDJEKGMpIENPTVBBVF9URVhUVVJFKFRleHR1cmUsIChjKSkKI2VuZGlmCgpDT01QQVRfVkFSWUlORyB2ZWMyIG9uZTsKQ09NUEFUX1ZBUllJTkcgZmxvYXQgbW9kX2ZhY3RvcjsKQ09NUEFUX1ZBUllJTkcgdmVjMiBpbGZhYzsKQ09NUEFUX1ZBUllJTkcgdmVjMiBvdmVyc2NhbjsKQ09NUEFUX1ZBUllJTkcgdmVjMiBhc3BlY3Q7CkNPTVBBVF9WQVJZSU5HIHZlYzMgc3RyZXRjaDsKQ09NUEFUX1ZBUllJTkcgdmVjMiBzaW5hbmdsZTsKQ09NUEFUX1ZBUllJTkcgdmVjMiBjb3NhbmdsZTsKCiNpZmRlZiBQQVJBTUVURVJfVU5JRk9STQp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gZmxvYXQgQ1JUZ2FtbWE7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCBtb25pdG9yZ2FtbWE7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCBkOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gZmxvYXQgQ1VSVkFUVVJFOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gZmxvYXQgUjsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIGZsb2F0IGNvcm5lcnNpemU7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCBjb3JuZXJzbW9vdGg7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCB4X3RpbHQ7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCB5X3RpbHQ7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCBvdmVyc2Nhbl94Owp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gZmxvYXQgb3ZlcnNjYW5feTsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIGZsb2F0IERPVE1BU0s7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCBTSEFSUEVSOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gZmxvYXQgc2NhbmxpbmVfd2VpZ2h0Owp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gZmxvYXQgbHVtOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gZmxvYXQgaW50ZXJsYWNlX2RldGVjdDsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIGZsb2F0IFNBVFVSQVRJT047CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCBJTlY7CiNlbmRpZgoKZmxvYXQgaW50ZXJzZWN0KHZlYzIgeHkpCiAgICAgICAgewoJZmxvYXQgQSA9IGRvdCh4eSx4eSkrZCpkOwoJZmxvYXQgQiA9IDIuMCooUiooZG90KHh5LHNpbmFuZ2xlKS1kKmNvc2FuZ2xlLngqY29zYW5nbGUueSktZCpkKTsKCWZsb2F0IEMgPSBkKmQgKyAyLjAqUipkKmNvc2FuZ2xlLngqY29zYW5nbGUueTsKCXJldHVybiAoLUItc3FydChCKkItNC4wKkEqQykpLygyLjAqQSk7CiAgICAgICAgfQoKdmVjMiBia3d0cmFucyh2ZWMyIHh5KQogICAgICAgIHsKCWZsb2F0IGMgPSBpbnRlcnNlY3QoeHkpOwoJdmVjMiBwb2ludCA9IHZlYzIoYykqeHk7Cglwb2ludCAtPSB2ZWMyKC1SKSpzaW5hbmdsZTsKCXBvaW50IC89IHZlYzIoUik7Cgl2ZWMyIHRhbmcgPSBzaW5hbmdsZS9jb3NhbmdsZTsKCXZlYzIgcG9jID0gcG9pbnQvY29zYW5nbGU7CglmbG9hdCBBID0gZG90KHRhbmcsdGFuZykrMS4wOwoJZmxvYXQgQiA9IC0yLjAqZG90KHBvYyx0YW5nKTsKCWZsb2F0IEMgPSBkb3QocG9jLHBvYyktMS4wOwoJZmxvYXQgYSA9ICgtQitzcXJ0KEIqQi00LjAqQSpDKSkvKDIuMCpBKTsKCXZlYzIgdXYgPSAocG9pbnQtYSpzaW5hbmdsZSkvY29zYW5nbGU7CglmbG9hdCByID0gRklYKFIqYWNvcyhhKSk7CglyZXR1cm4gdXYqci9zaW4oci9SKTsKICAgICAgICB9Cgp2ZWMyIHRyYW5zZm9ybSh2ZWMyIGNvb3JkKQogICAgICAgIHsKCWNvb3JkICo9IFRleHR1cmVTaXplIC8gSW5wdXRTaXplOwoJY29vcmQgPSAoY29vcmQtdmVjMigwLjUpKSphc3BlY3Qqc3RyZXRjaC56K3N0cmV0Y2gueHk7CglyZXR1cm4gKGJrd3RyYW5zKGNvb3JkKS92ZWMyKG92ZXJzY2FuX3ggLyAxMDAuMCwgb3ZlcnNjYW5feSAvIDEwMC4wKS9hc3BlY3QrdmVjMigwLjUpKSAqIElucHV0U2l6ZSAvIFRleHR1cmVTaXplOwogICAgICAgIH0KCmZsb2F0IGNvcm5lcih2ZWMyIGNvb3JkKQogICAgICAgIHsKCWNvb3JkICo9IFRleHR1cmVTaXplIC8gSW5wdXRTaXplOwoJY29vcmQgPSAoY29vcmQgLSB2ZWMyKDAuNSkpICogdmVjMihvdmVyc2Nhbl94IC8gMTAwLjAsIG92ZXJzY2FuX3kgLyAxMDAuMCkgKyB2ZWMyKDAuNSk7Cgljb29yZCA9IG1pbihjb29yZCwgdmVjMigxLjApLWNvb3JkKSAqIGFzcGVjdDsKCXZlYzIgY2Rpc3QgPSB2ZWMyKGNvcm5lcnNpemUpOwoJY29vcmQgPSAoY2Rpc3QgLSBtaW4oY29vcmQsY2Rpc3QpKTsKCWZsb2F0IGRpc3QgPSBzcXJ0KGRvdChjb29yZCxjb29yZCkpOwoJcmV0dXJuIGNsYW1wKChjZGlzdC54LWRpc3QpKmNvcm5lcnNtb290aCwwLjAsIDEuMCkqMS4wMDAxOwogICAgICAgIH0KCi8vIENhbGN1bGF0ZSB0aGUgaW5mbHVlbmNlIG9mIGEgc2NhbmxpbmUgb24gdGhlIGN1cnJlbnQgcGl4ZWwuCi8vCi8vICdkaXN0YW5jZScgaXMgdGhlIGRpc3RhbmNlIGluIHRleHR1cmUgY29vcmRpbmF0ZXMgZnJvbSB0aGUgY3VycmVudAovLyBwaXhlbCB0byB0aGUgc2NhbmxpbmUgaW4gcXVlc3Rpb24uCi8vICdjb2xvcicgaXMgdGhlIGNvbG91ciBvZiB0aGUgc2NhbmxpbmUgYXQgdGhlIGhvcml6b250YWwgbG9jYXRpb24gb2YKLy8gdGhlIGN1cnJlbnQgcGl4ZWwuCnZlYzQgc2NhbmxpbmVXZWlnaHRzKGZsb2F0IGRpc3RhbmNlLCB2ZWM0IGNvbG9yKQogICAgICAgIHsKCS8vICJ3aWQiIGNvbnRyb2xzIHRoZSB3aWR0aCBvZiB0aGUgc2NhbmxpbmUgYmVhbSwgZm9yIGVhY2ggUkdCCgkvLyBjaGFubmVsIFRoZSAid2VpZ2h0cyIgbGluZXMgYmFzaWNhbGx5IHNwZWNpZnkgdGhlIGZvcm11bGEKCS8vIHRoYXQgZ2l2ZXMgeW91IHRoZSBwcm9maWxlIG9mIHRoZSBiZWFtLCBpLmUuIHRoZSBpbnRlbnNpdHkgYXMKCS8vIGEgZnVuY3Rpb24gb2YgZGlzdGFuY2UgZnJvbSB0aGUgdmVydGljYWwgY2VudGVyIG9mIHRoZQoJLy8gc2NhbmxpbmUuIEluIHRoaXMgY2FzZSwgaXQgaXMgZ2F1c3NpYW4gaWYgd2lkdGg9MiwgYW5kCgkvLyBiZWNvbWVzIG5vbmdhdXNzaWFuIGZvciBsYXJnZXIgd2lkdGhzLiBJZGVhbGx5IHRoaXMgc2hvdWxkCgkvLyBiZSBub3JtYWxpemVkIHNvIHRoYXQgdGhlIGludGVncmFsIGFjcm9zcyB0aGUgYmVhbSBpcwoJLy8gaW5kZXBlbmRlbnQgb2YgaXRzIHdpZHRoLiBUaGF0IGlzLCBmb3IgYSBuYXJyb3dlciBiZWFtCgkvLyAid2VpZ2h0cyIgc2hvdWxkIGhhdmUgYSBoaWdoZXIgcGVhayBhdCB0aGUgY2VudGVyIG9mIHRoZQoJLy8gc2NhbmxpbmUgdGhhbiBmb3IgYSB3aWRlciBiZWFtLgojaWZkZWYgVVNFR0FVU1NJQU4KCXZlYzQgd2lkID0gMC4zICsgMC4xICogcG93KGNvbG9yLCB2ZWM0KDMuMCkpOwoJdmVjNCB3ZWlnaHRzID0gdmVjNChkaXN0YW5jZSAvIHdpZCk7CglyZXR1cm4gKGx1bSArIDAuNCkgKiBleHAoLXdlaWdodHMgKiB3ZWlnaHRzKSAvIHdpZDsKI2Vsc2UKCXZlYzQgd2lkID0gMi4wICsgMi4wICogcG93KGNvbG9yLCB2ZWM0KDQuMCkpOwoJdmVjNCB3ZWlnaHRzID0gdmVjNChkaXN0YW5jZSAvIHNjYW5saW5lX3dlaWdodCk7CglyZXR1cm4gKGx1bSArIDEuNCkgKiBleHAoLXBvdyh3ZWlnaHRzICogaW52ZXJzZXNxcnQoMC41ICogd2lkKSwgd2lkKSkgLyAoMC42ICsgMC4yICogd2lkKTsKI2VuZGlmCiAgICAgICAgfQoKdmVjMyBzYXR1cmF0aW9uICh2ZWMzIHRleHR1cmVDb2xvcikKewogICAgZmxvYXQgbHVtPWxlbmd0aCh0ZXh0dXJlQ29sb3IpKjAuNTc3NTsKCiAgICB2ZWMzIGx1bWluYW5jZVdlaWdodGluZyA9IHZlYzMoMC4zLDAuNiwwLjEpOwogICAgaWYgKGx1bTwwLjUpIGx1bWluYW5jZVdlaWdodGluZy5yZ2I9KGx1bWluYW5jZVdlaWdodGluZy5yZ2IqbHVtaW5hbmNlV2VpZ2h0aW5nLnJnYikrKGx1bWluYW5jZVdlaWdodGluZy5yZ2IqbHVtaW5hbmNlV2VpZ2h0aW5nLnJnYik7CgogICAgZmxvYXQgbHVtaW5hbmNlID0gZG90KHRleHR1cmVDb2xvciwgbHVtaW5hbmNlV2VpZ2h0aW5nKTsKICAgIHZlYzMgZ3JleVNjYWxlQ29sb3IgPSB2ZWMzKGx1bWluYW5jZSk7CgogICAgdmVjMyByZXMgPSB2ZWMzKG1peChncmV5U2NhbGVDb2xvciwgdGV4dHVyZUNvbG9yLCBTQVRVUkFUSU9OKSk7CiAgICByZXR1cm4gcmVzOwp9CgojZGVmaW5lIHB3ciB2ZWMzKDEuMC8oKC0wLjcqKDEuMC1zY2FubGluZV93ZWlnaHQpKzEuMCkqKC0wLjUqRE9UTUFTSysxLjApKS0xLjI1KQoKCi8vIFJldHVybnMgZ2FtbWEgY29ycmVjdGVkIG91dHB1dCwgY29tcGVuc2F0ZWQgZm9yIHNjYW5saW5lK21hc2sgZW1iZWRkZWQgZ2FtbWEKdmVjMyBpbnZfZ2FtbWEodmVjMyBjb2wsIHZlYzMgcG93ZXIpCnsKICAgIHZlYzMgY2lyICA9IGNvbC0xLjA7CiAgICAgICAgIGNpciAqPSBjaXI7CiAgICAgICAgIGNvbCAgPSBtaXgoc3FydChjb2wpLHNxcnQoMS4wLWNpcikscG93ZXIpOwogICAgcmV0dXJuIGNvbDsKfQoKdm9pZCBtYWluKCkKewovLyBIZXJlJ3MgYSBoZWxwZnVsIGRpYWdyYW0gdG8ga2VlcCBpbiBtaW5kIHdoaWxlIHRyeWluZyB0bwovLyB1bmRlcnN0YW5kIHRoZSBjb2RlOgovLwovLyAgfCAgICAgIHwgICAgICB8ICAgICAgfCAgICAgIHwKLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQovLyAgfCAgICAgIHwgICAgICB8ICAgICAgfCAgICAgIHwKLy8gIHwgIDAxICB8ICAxMSAgfCAgMjEgIHwgIDMxICB8IDwtLSBjdXJyZW50IHNjYW5saW5lCi8vICB8ICAgICAgfCBAICAgIHwgICAgICB8ICAgICAgfAovLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCi8vICB8ICAgICAgfCAgICAgIHwgICAgICB8ICAgICAgfAovLyAgfCAgMDIgIHwgIDEyICB8ICAyMiAgfCAgMzIgIHwgPC0tIG5leHQgc2NhbmxpbmUKLy8gIHwgICAgICB8ICAgICAgfCAgICAgIHwgICAgICB8Ci8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KLy8gIHwgICAgICB8ICAgICAgfCAgICAgIHwgICAgICB8Ci8vCi8vIEVhY2ggY2hhcmFjdGVyLWNlbGwgcmVwcmVzZW50cyBhIHBpeGVsIG9uIHRoZSBvdXRwdXQKLy8gc3VyZmFjZSwgIkAiIHJlcHJlc2VudHMgdGhlIGN1cnJlbnQgcGl4ZWwgKGFsd2F5cyBzb21ld2hlcmUKLy8gaW4gdGhlIGJvdHRvbSBoYWxmIG9mIHRoZSBjdXJyZW50IHNjYW4tbGluZSwgb3IgdGhlIHRvcC1oYWxmCi8vIG9mIHRoZSBuZXh0IHNjYW5saW5lKS4gVGhlIGdyaWQgb2YgbGluZXMgcmVwcmVzZW50cyB0aGUKLy8gZWRnZXMgb2YgdGhlIHRleGVscyBvZiB0aGUgdW5kZXJseWluZyB0ZXh0dXJlLgoKLy8gVGV4dHVyZSBjb29yZGluYXRlcyBvZiB0aGUgdGV4ZWwgY29udGFpbmluZyB0aGUgYWN0aXZlIHBpeGVsLgoJdmVjMiB4eSA9IChDVVJWQVRVUkUgPiAwLjUpID8gdHJhbnNmb3JtKFRFWDAueHkpIDogVEVYMC54eTsKCglmbG9hdCBjdmFsID0gY29ybmVyKHh5KTsKCi8vIE9mIGFsbCB0aGUgcGl4ZWxzIHRoYXQgYXJlIG1hcHBlZCBvbnRvIHRoZSB0ZXhlbCB3ZSBhcmUKLy8gY3VycmVudGx5IHJlbmRlcmluZywgd2hpY2ggcGl4ZWwgYXJlIHdlIGN1cnJlbnRseSByZW5kZXJpbmc/Cgl2ZWMyIGlsdmVjID0gdmVjMigwLjAsaWxmYWMueSAqIGludGVybGFjZV9kZXRlY3QgPiAxLjUgPyBtb2QoZmxvYXQoRnJhbWVDb3VudCksMi4wKSA6IDAuMCk7Cgl2ZWMyIHJhdGlvX3NjYWxlID0gKHh5ICogVGV4dHVyZVNpemUgLSB2ZWMyKDAuNSkgKyBpbHZlYykvaWxmYWM7CiNpZmRlZiBPVkVSU0FNUExFCglmbG9hdCBmaWx0ZXJfID0gSW5wdXRTaXplLnkvT3V0cHV0U2l6ZS55Oy8vZndpZHRoKHJhdGlvX3NjYWxlLnkpOwojZW5kaWYKCXZlYzIgdXZfcmF0aW8gPSBmcmFjdChyYXRpb19zY2FsZSk7CgovLyBTbmFwIHRvIHRoZSBjZW50ZXIgb2YgdGhlIHVuZGVybHlpbmcgdGV4ZWwuCgl4eSA9IChmbG9vcihyYXRpb19zY2FsZSkqaWxmYWMgKyB2ZWMyKDAuNSkgLSBpbHZlYykgLyBUZXh0dXJlU2l6ZTsKCi8vIENhbGN1bGF0ZSBMYW5jem9zIHNjYWxpbmcgY29lZmZpY2llbnRzIGRlc2NyaWJpbmcgdGhlIGVmZmVjdAovLyBvZiB2YXJpb3VzIG5laWdoYm91ciB0ZXhlbHMgaW4gYSBzY2FubGluZSBvbiB0aGUgY3VycmVudAovLyBwaXhlbC4KCXZlYzQgY29lZmZzID0gUEkgKiB2ZWM0KDEuMCArIHV2X3JhdGlvLngsIHV2X3JhdGlvLngsIDEuMCAtIHV2X3JhdGlvLngsIDIuMCAtIHV2X3JhdGlvLngpOwoKLy8gUHJldmVudCBkaXZpc2lvbiBieSB6ZXJvLgoJY29lZmZzID0gRklYKGNvZWZmcyk7CgovLyBMYW5jem9zMiBrZXJuZWwuCgljb2VmZnMgPSAyLjAgKiBzaW4oY29lZmZzKSAqIHNpbihjb2VmZnMgLyAyLjApIC8gKGNvZWZmcyAqIGNvZWZmcyk7CgovLyBOb3JtYWxpemUuCgljb2VmZnMgLz0gZG90KGNvZWZmcywgdmVjNCgxLjApKTsKCi8vIENhbGN1bGF0ZSB0aGUgZWZmZWN0aXZlIGNvbG91ciBvZiB0aGUgY3VycmVudCBhbmQgbmV4dAovLyBzY2FubGluZXMgYXQgdGhlIGhvcml6b250YWwgbG9jYXRpb24gb2YgdGhlIGN1cnJlbnQgcGl4ZWwsCi8vIHVzaW5nIHRoZSBMYW5jem9zIGNvZWZmaWNpZW50cyBhYm92ZS4KCXZlYzQgY29sICA9IGNsYW1wKG1hdDQoCiAgICAgICAgICAgICAgICAgICAgICAgIFRFWDJEKHh5ICsgdmVjMigtb25lLngsIDAuMCkpLAogICAgICAgICAgICAgICAgICAgICAgICBURVgyRCh4eSksCiAgICAgICAgICAgICAgICAgICAgICAgIFRFWDJEKHh5ICsgdmVjMihvbmUueCwgMC4wKSksCiAgICAgICAgICAgICAgICAgICAgICAgIFRFWDJEKHh5ICsgdmVjMigyLjAgKiBvbmUueCwgMC4wKSkpICogY29lZmZzLAogICAgICAgICAgICAgICAgICAgICAgICAwLjAsIDEuMCk7CiAgICAgICAgdmVjNCBjb2wyID0gY2xhbXAobWF0NCgKICAgICAgICAgICAgICAgICAgICAgICAgVEVYMkQoeHkgKyB2ZWMyKC1vbmUueCwgb25lLnkpKSwKICAgICAgICAgICAgICAgICAgICAgICAgVEVYMkQoeHkgKyB2ZWMyKDAuMCwgb25lLnkpKSwKICAgICAgICAgICAgICAgICAgICAgICAgVEVYMkQoeHkgKyBvbmUpLAogICAgICAgICAgICAgICAgICAgICAgICBURVgyRCh4eSArIHZlYzIoMi4wICogb25lLngsIG9uZS55KSkpICogY29lZmZzLAogICAgICAgICAgICAgICAgICAgICAgICAwLjAsIDEuMCk7CgojaWZuZGVmIExJTkVBUl9QUk9DRVNTSU5HCgljb2wgID0gcG93KGNvbCAsIHZlYzQoQ1JUZ2FtbWEpKTsKCWNvbDIgPSBwb3coY29sMiwgdmVjNChDUlRnYW1tYSkpOwojZW5kaWYKCi8vIENhbGN1bGF0ZSB0aGUgaW5mbHVlbmNlIG9mIHRoZSBjdXJyZW50IGFuZCBuZXh0IHNjYW5saW5lcyBvbgovLyB0aGUgY3VycmVudCBwaXhlbC4KCXZlYzQgd2VpZ2h0cyAgPSBzY2FubGluZVdlaWdodHModXZfcmF0aW8ueSwgY29sKTsKCXZlYzQgd2VpZ2h0czIgPSBzY2FubGluZVdlaWdodHMoMS4wIC0gdXZfcmF0aW8ueSwgY29sMik7CiNpZmRlZiBPVkVSU0FNUExFCgl1dl9yYXRpby55ID11dl9yYXRpby55KzEuMC8zLjAqZmlsdGVyXzsKCXdlaWdodHMgPSAod2VpZ2h0cytzY2FubGluZVdlaWdodHModXZfcmF0aW8ueSwgY29sKSkvMy4wOwoJd2VpZ2h0czI9KHdlaWdodHMyK3NjYW5saW5lV2VpZ2h0cyhhYnMoMS4wLXV2X3JhdGlvLnkpLCBjb2wyKSkvMy4wOwoJdXZfcmF0aW8ueSA9dXZfcmF0aW8ueS0yLjAvMy4wKmZpbHRlcl87Cgl3ZWlnaHRzPXdlaWdodHMrc2NhbmxpbmVXZWlnaHRzKGFicyh1dl9yYXRpby55KSwgY29sKS8zLjA7Cgl3ZWlnaHRzMj13ZWlnaHRzMitzY2FubGluZVdlaWdodHMoYWJzKDEuMC11dl9yYXRpby55KSwgY29sMikvMy4wOwojZW5kaWYKCgl2ZWMzIG11bF9yZXMgID0gKGNvbCAqIHdlaWdodHMgKyBjb2wyICogd2VpZ2h0czIpLnJnYiAqIHZlYzMoY3ZhbCk7CgovLyBkb3QtbWFzayBlbXVsYXRpb246Ci8vIE91dHB1dCBwaXhlbHMgYXJlIGFsdGVybmF0ZWx5IHRpbnRlZCBncmVlbiBhbmQgbWFnZW50YS4KdmVjMyBkb3RNYXNrV2VpZ2h0cyA9IG1peCgKCXZlYzMoMS4wLCAxLjAgLSBET1RNQVNLLCAxLjApLAoJdmVjMygxLjAgLSBET1RNQVNLLCAxLjAsIDEuMCAtIERPVE1BU0spLAoJZmxvb3IobW9kKG1vZF9mYWN0b3IsIDIuMCkpCiAgICAgICAgKTsKCgltdWxfcmVzICo9IGRvdE1hc2tXZWlnaHRzOwoKLy8gQ29udmVydCB0aGUgaW1hZ2UgZ2FtbWEgZm9yIGRpc3BsYXkgb24gb3VyIG91dHB1dCBkZXZpY2UuCmlmIChJTlYgPT0gMS4wKXsgbXVsX3JlcyA9IGludl9nYW1tYShtdWxfcmVzLHB3cik7fSAKCWVsc2UgbXVsX3JlcyA9IHBvdyhtdWxfcmVzLCB2ZWMzKDEuMC9tb25pdG9yZ2FtbWEpKTsKICAgICAgICAKICAgICAgICBtdWxfcmVzID0gc2F0dXJhdGlvbihtdWxfcmVzKTsKCgoKLy8gQ29sb3IgdGhlIHRleGVsLgogICAgb3V0cHV0X2R1bW15IF9PVVQ7CiAgICBfT1VULl9jb2xvciA9IHZlYzQobXVsX3JlcywgMS4wKTsKICAgIEZyYWdDb2xvciA9IF9PVVQuX2NvbG9yOwogICAgcmV0dXJuOwp9IAojZW5kaWYK", + }, + ], + }, + + //https://github.com/libretro/glsl-shaders/blob/master/crt/crt-mattias.glslp + "crt-mattias.glslp": { + "shader": { + "type": "text", + "value": "shaders = 1\n\nshader0 = crt-mattias.glsl\nfilter_linear0 = false", + }, + "resources": [ + { + "name": "crt-mattias.glsl", + "type": "base64", + "value": "Ly8gQ1JUIEVtdWxhdGlvbgovLyBieSBNYXR0aWFzCi8vIGh0dHBzOi8vd3d3LnNoYWRlcnRveS5jb20vdmlldy9sc0IzRFYKCiNwcmFnbWEgcGFyYW1ldGVyIENVUlZBVFVSRSAiQ3VydmF0dXJlIiAwLjUgMC4wIDEuMCAwLjA1CiNwcmFnbWEgcGFyYW1ldGVyIFNDQU5TUEVFRCAiU2NhbmxpbmUgQ3Jhd2wgU3BlZWQiIDEuMCAwLjAgMTAuMCAwLjUKCiNpZiBkZWZpbmVkKFZFUlRFWCkKCiNpZiBfX1ZFUlNJT05fXyA+PSAxMzAKI2RlZmluZSBDT01QQVRfVkFSWUlORyBvdXQKI2RlZmluZSBDT01QQVRfQVRUUklCVVRFIGluCiNkZWZpbmUgQ09NUEFUX1RFWFRVUkUgdGV4dHVyZQojZWxzZQojZGVmaW5lIENPTVBBVF9WQVJZSU5HIHZhcnlpbmcgCiNkZWZpbmUgQ09NUEFUX0FUVFJJQlVURSBhdHRyaWJ1dGUgCiNkZWZpbmUgQ09NUEFUX1RFWFRVUkUgdGV4dHVyZTJECiNlbmRpZgoKI2lmZGVmIEdMX0VTCiNkZWZpbmUgQ09NUEFUX1BSRUNJU0lPTiBtZWRpdW1wCiNlbHNlCiNkZWZpbmUgQ09NUEFUX1BSRUNJU0lPTgojZW5kaWYKCkNPTVBBVF9BVFRSSUJVVEUgdmVjNCBWZXJ0ZXhDb29yZDsKQ09NUEFUX0FUVFJJQlVURSB2ZWM0IENPTE9SOwpDT01QQVRfQVRUUklCVVRFIHZlYzQgVGV4Q29vcmQ7CkNPTVBBVF9WQVJZSU5HIHZlYzQgQ09MMDsKQ09NUEFUX1ZBUllJTkcgdmVjNCBURVgwOwovLyBvdXQgdmFyaWFibGVzIGdvIGhlcmUgYXMgQ09NUEFUX1ZBUllJTkcgd2hhdGV2ZXIKCnZlYzQgX29Qb3NpdGlvbjE7IAp1bmlmb3JtIG1hdDQgTVZQTWF0cml4Owp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gaW50IEZyYW1lRGlyZWN0aW9uOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gaW50IEZyYW1lQ291bnQ7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiB2ZWMyIE91dHB1dFNpemU7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiB2ZWMyIFRleHR1cmVTaXplOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gdmVjMiBJbnB1dFNpemU7CgovLyBjb21wYXRpYmlsaXR5ICNkZWZpbmVzCiNkZWZpbmUgdlRleENvb3JkIFRFWDAueHkKI2RlZmluZSBTb3VyY2VTaXplIHZlYzQoVGV4dHVyZVNpemUsIDEuMCAvIFRleHR1cmVTaXplKSAvL2VpdGhlciBUZXh0dXJlU2l6ZSBvciBJbnB1dFNpemUKI2RlZmluZSBPdXRTaXplIHZlYzQoT3V0cHV0U2l6ZSwgMS4wIC8gT3V0cHV0U2l6ZSkKCnZvaWQgbWFpbigpCnsKICAgIGdsX1Bvc2l0aW9uID0gTVZQTWF0cml4ICogVmVydGV4Q29vcmQ7CiAgICBURVgwLnh5ID0gVGV4Q29vcmQueHk7Cn0KCiNlbGlmIGRlZmluZWQoRlJBR01FTlQpCgojaWZkZWYgR0xfRVMKI2lmZGVmIEdMX0ZSQUdNRU5UX1BSRUNJU0lPTl9ISUdICnByZWNpc2lvbiBoaWdocCBmbG9hdDsKI2Vsc2UKcHJlY2lzaW9uIG1lZGl1bXAgZmxvYXQ7CiNlbmRpZgojZGVmaW5lIENPTVBBVF9QUkVDSVNJT04gbWVkaXVtcAojZWxzZQojZGVmaW5lIENPTVBBVF9QUkVDSVNJT04KI2VuZGlmCgojaWYgX19WRVJTSU9OX18gPj0gMTMwCiNkZWZpbmUgQ09NUEFUX1ZBUllJTkcgaW4KI2RlZmluZSBDT01QQVRfVEVYVFVSRSB0ZXh0dXJlCm91dCBDT01QQVRfUFJFQ0lTSU9OIHZlYzQgRnJhZ0NvbG9yOwojZWxzZQojZGVmaW5lIENPTVBBVF9WQVJZSU5HIHZhcnlpbmcKI2RlZmluZSBGcmFnQ29sb3IgZ2xfRnJhZ0NvbG9yCiNkZWZpbmUgQ09NUEFUX1RFWFRVUkUgdGV4dHVyZTJECiNlbmRpZgoKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIGludCBGcmFtZURpcmVjdGlvbjsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIGludCBGcmFtZUNvdW50Owp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gdmVjMiBPdXRwdXRTaXplOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gdmVjMiBUZXh0dXJlU2l6ZTsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIHZlYzIgSW5wdXRTaXplOwp1bmlmb3JtIHNhbXBsZXIyRCBUZXh0dXJlOwpDT01QQVRfVkFSWUlORyB2ZWM0IFRFWDA7CgovLyBjb21wYXRpYmlsaXR5ICNkZWZpbmVzCiNkZWZpbmUgU291cmNlIFRleHR1cmUKI2RlZmluZSB2VGV4Q29vcmQgVEVYMC54eQoKI2RlZmluZSBTb3VyY2VTaXplIHZlYzQoVGV4dHVyZVNpemUsIDEuMCAvIFRleHR1cmVTaXplKSAvL2VpdGhlciBUZXh0dXJlU2l6ZSBvciBJbnB1dFNpemUKI2RlZmluZSBPdXRTaXplIHZlYzQoT3V0cHV0U2l6ZSwgMS4wIC8gT3V0cHV0U2l6ZSkKCiNpZmRlZiBQQVJBTUVURVJfVU5JRk9STQp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gZmxvYXQgQ1VSVkFUVVJFLCBTQ0FOU1BFRUQ7CiNlbHNlCiNkZWZpbmUgQ1VSVkFUVVJFIDAuNQojZGVmaW5lIFNDQU5TUEVFRCAxLjAKI2VuZGlmCgojZGVmaW5lIGlDaGFubmVsMCBUZXh0dXJlCiNkZWZpbmUgaVRpbWUgKGZsb2F0KEZyYW1lQ291bnQpIC8gNjAuMCkKI2RlZmluZSBpUmVzb2x1dGlvbiBPdXRwdXRTaXplLnh5CiNkZWZpbmUgZnJhZ0Nvb3JkIGdsX0ZyYWdDb29yZC54eQoKdmVjMyBzYW1wbGVfKCBzYW1wbGVyMkQgdGV4LCB2ZWMyIHRjICkKewoJdmVjMyBzID0gcG93KENPTVBBVF9URVhUVVJFKHRleCx0YykucmdiLCB2ZWMzKDIuMikpOwoJcmV0dXJuIHM7Cn0KCnZlYzMgYmx1cihzYW1wbGVyMkQgdGV4LCB2ZWMyIHRjLCBmbG9hdCBvZmZzKQp7Cgl2ZWM0IHhvZmZzID0gb2ZmcyAqIHZlYzQoLTIuMCwgLTEuMCwgMS4wLCAyLjApIC8gKGlSZXNvbHV0aW9uLnggKiBUZXh0dXJlU2l6ZS54IC8gSW5wdXRTaXplLngpOwoJdmVjNCB5b2ZmcyA9IG9mZnMgKiB2ZWM0KC0yLjAsIC0xLjAsIDEuMCwgMi4wKSAvIChpUmVzb2x1dGlvbi55ICogVGV4dHVyZVNpemUueSAvIElucHV0U2l6ZS55KTsKICAgdGMgPSB0YyAqIElucHV0U2l6ZSAvIFRleHR1cmVTaXplOwoJCgl2ZWMzIGNvbG9yID0gdmVjMygwLjAsIDAuMCwgMC4wKTsKCWNvbG9yICs9IHNhbXBsZV8odGV4LHRjICsgdmVjMih4b2Zmcy54LCB5b2Zmcy54KSkgKiAwLjAwMzY2OwoJY29sb3IgKz0gc2FtcGxlXyh0ZXgsdGMgKyB2ZWMyKHhvZmZzLnksIHlvZmZzLngpKSAqIDAuMDE0NjU7Cgljb2xvciArPSBzYW1wbGVfKHRleCx0YyArIHZlYzIoICAgIDAuMCwgeW9mZnMueCkpICogMC4wMjU2NDsKCWNvbG9yICs9IHNhbXBsZV8odGV4LHRjICsgdmVjMih4b2Zmcy56LCB5b2Zmcy54KSkgKiAwLjAxNDY1OwoJY29sb3IgKz0gc2FtcGxlXyh0ZXgsdGMgKyB2ZWMyKHhvZmZzLncsIHlvZmZzLngpKSAqIDAuMDAzNjY7CgkKCWNvbG9yICs9IHNhbXBsZV8odGV4LHRjICsgdmVjMih4b2Zmcy54LCB5b2Zmcy55KSkgKiAwLjAxNDY1OwoJY29sb3IgKz0gc2FtcGxlXyh0ZXgsdGMgKyB2ZWMyKHhvZmZzLnksIHlvZmZzLnkpKSAqIDAuMDU4NjE7Cgljb2xvciArPSBzYW1wbGVfKHRleCx0YyArIHZlYzIoICAgIDAuMCwgeW9mZnMueSkpICogMC4wOTUyNDsKCWNvbG9yICs9IHNhbXBsZV8odGV4LHRjICsgdmVjMih4b2Zmcy56LCB5b2Zmcy55KSkgKiAwLjA1ODYxOwoJY29sb3IgKz0gc2FtcGxlXyh0ZXgsdGMgKyB2ZWMyKHhvZmZzLncsIHlvZmZzLnkpKSAqIDAuMDE0NjU7CgkKCWNvbG9yICs9IHNhbXBsZV8odGV4LHRjICsgdmVjMih4b2Zmcy54LCAwLjApKSAqIDAuMDI1NjQ7Cgljb2xvciArPSBzYW1wbGVfKHRleCx0YyArIHZlYzIoeG9mZnMueSwgMC4wKSkgKiAwLjA5NTI0OwoJY29sb3IgKz0gc2FtcGxlXyh0ZXgsdGMgKyB2ZWMyKCAgICAwLjAsIDAuMCkpICogMC4xNTAxODsKCWNvbG9yICs9IHNhbXBsZV8odGV4LHRjICsgdmVjMih4b2Zmcy56LCAwLjApKSAqIDAuMDk1MjQ7Cgljb2xvciArPSBzYW1wbGVfKHRleCx0YyArIHZlYzIoeG9mZnMudywgMC4wKSkgKiAwLjAyNTY0OwoJCgljb2xvciArPSBzYW1wbGVfKHRleCx0YyArIHZlYzIoeG9mZnMueCwgeW9mZnMueikpICogMC4wMTQ2NTsKCWNvbG9yICs9IHNhbXBsZV8odGV4LHRjICsgdmVjMih4b2Zmcy55LCB5b2Zmcy56KSkgKiAwLjA1ODYxOwoJY29sb3IgKz0gc2FtcGxlXyh0ZXgsdGMgKyB2ZWMyKCAgICAwLjAsIHlvZmZzLnopKSAqIDAuMDk1MjQ7Cgljb2xvciArPSBzYW1wbGVfKHRleCx0YyArIHZlYzIoeG9mZnMueiwgeW9mZnMueikpICogMC4wNTg2MTsKCWNvbG9yICs9IHNhbXBsZV8odGV4LHRjICsgdmVjMih4b2Zmcy53LCB5b2Zmcy56KSkgKiAwLjAxNDY1OwoJCgljb2xvciArPSBzYW1wbGVfKHRleCx0YyArIHZlYzIoeG9mZnMueCwgeW9mZnMudykpICogMC4wMDM2NjsKCWNvbG9yICs9IHNhbXBsZV8odGV4LHRjICsgdmVjMih4b2Zmcy55LCB5b2Zmcy53KSkgKiAwLjAxNDY1OwoJY29sb3IgKz0gc2FtcGxlXyh0ZXgsdGMgKyB2ZWMyKCAgICAwLjAsIHlvZmZzLncpKSAqIDAuMDI1NjQ7Cgljb2xvciArPSBzYW1wbGVfKHRleCx0YyArIHZlYzIoeG9mZnMueiwgeW9mZnMudykpICogMC4wMTQ2NTsKCWNvbG9yICs9IHNhbXBsZV8odGV4LHRjICsgdmVjMih4b2Zmcy53LCB5b2Zmcy53KSkgKiAwLjAwMzY2OwoKCXJldHVybiBjb2xvcjsKfQoKLy9DYW5vbmljYWwgbm9pc2UgZnVuY3Rpb247IHJlcGxhY2VkIHRvIHByZXZlbnQgcHJlY2lzaW9uIGVycm9ycwovL2Zsb2F0IHJhbmQodmVjMiBjbyl7Ci8vICAgIHJldHVybiBmcmFjdChzaW4oZG90KGNvLnh5ICx2ZWMyKDEyLjk4OTgsNzguMjMzKSkpICogNDM3NTguNTQ1Myk7Ci8vfQoKZmxvYXQgcmFuZCh2ZWMyIGNvKQp7CiAgICBmbG9hdCBhID0gMTIuOTg5ODsKICAgIGZsb2F0IGIgPSA3OC4yMzM7CiAgICBmbG9hdCBjID0gNDM3NTguNTQ1MzsKICAgIGZsb2F0IGR0PSBkb3QoY28ueHkgLHZlYzIoYSxiKSk7CiAgICBmbG9hdCBzbj0gbW9kKGR0LDMuMTQpOwogICAgcmV0dXJuIGZyYWN0KHNpbihzbikgKiBjKTsKfQoKdmVjMiBjdXJ2ZSh2ZWMyIHV2KQp7Cgl1diA9ICh1diAtIDAuNSkgKiAyLjA7Cgl1diAqPSAxLjE7CQoJdXYueCAqPSAxLjAgKyBwb3coKGFicyh1di55KSAvIDUuMCksIDIuMCk7Cgl1di55ICo9IDEuMCArIHBvdygoYWJzKHV2LngpIC8gNC4wKSwgMi4wKTsKCXV2ICA9ICh1diAvIDIuMCkgKyAwLjU7Cgl1diA9ICB1diAqMC45MiArIDAuMDQ7CglyZXR1cm4gdXY7Cn0KCnZvaWQgbWFpbigpCnsKICAgIHZlYzIgcSA9ICh2VGV4Q29vcmQueHkgKiBUZXh0dXJlU2l6ZS54eSAvIElucHV0U2l6ZS54eSk7Ly9mcmFnQ29vcmQueHkgLyBpUmVzb2x1dGlvbi54eTsKICAgIHZlYzIgdXYgPSBxOwogICAgdXYgPSBtaXgoIHV2LCBjdXJ2ZSggdXYgKSwgQ1VSVkFUVVJFICkgKiBJbnB1dFNpemUueHkgLyBUZXh0dXJlU2l6ZS54eTsKICAgIHZlYzMgY29sOwoJZmxvYXQgeCA9ICBzaW4oMC4xKmlUaW1lK3V2LnkqMjEuMCkqc2luKDAuMjMqaVRpbWUrdXYueSoyOS4wKSpzaW4oMC4zKzAuMTEqaVRpbWUrdXYueSozMS4wKSowLjAwMTc7CglmbG9hdCBvID0yLjAqbW9kKGZyYWdDb29yZC55LDIuMCkvaVJlc29sdXRpb24ueDsKCXgrPW87CiAgIHV2ID0gdXYgKiBUZXh0dXJlU2l6ZSAvIElucHV0U2l6ZTsKICAgIGNvbC5yID0gMS4wKmJsdXIoaUNoYW5uZWwwLHZlYzIodXYueCswLjAwMDksdXYueSswLjAwMDkpLDEuMikueCswLjAwNTsKICAgIGNvbC5nID0gMS4wKmJsdXIoaUNoYW5uZWwwLHZlYzIodXYueCswLjAwMCx1di55LTAuMDAxNSksMS4yKS55KzAuMDA1OwogICAgY29sLmIgPSAxLjAqYmx1cihpQ2hhbm5lbDAsdmVjMih1di54LTAuMDAxNSx1di55KzAuMDAwKSwxLjIpLnorMC4wMDU7CiAgICBjb2wuciArPSAwLjIqYmx1cihpQ2hhbm5lbDAsdmVjMih1di54KzAuMDAwOSx1di55KzAuMDAwOSksMi4yNSkueC0wLjAwNTsKICAgIGNvbC5nICs9IDAuMipibHVyKGlDaGFubmVsMCx2ZWMyKHV2LngrMC4wMDAsdXYueS0wLjAwMTUpLDEuNzUpLnktMC4wMDU7CiAgICBjb2wuYiArPSAwLjIqYmx1cihpQ2hhbm5lbDAsdmVjMih1di54LTAuMDAxNSx1di55KzAuMDAwKSwxLjI1KS56LTAuMDA1OwogICAgZmxvYXQgZ2hzID0gMC4wNTsKCWNvbC5yICs9IGdocyooMS4wLTAuMjk5KSpibHVyKGlDaGFubmVsMCwwLjc1KnZlYzIoMC4wMSwgLTAuMDI3KSt2ZWMyKHV2LngrMC4wMDEsdXYueSswLjAwMSksNy4wKS54OwogICAgY29sLmcgKz0gZ2hzKigxLjAtMC41ODcpKmJsdXIoaUNoYW5uZWwwLDAuNzUqdmVjMigtMC4wMjIsIC0wLjAyKSt2ZWMyKHV2LngrMC4wMDAsdXYueS0wLjAwMiksNS4wKS55OwogICAgY29sLmIgKz0gZ2hzKigxLjAtMC4xMTQpKmJsdXIoaUNoYW5uZWwwLDAuNzUqdmVjMigtMC4wMiwgLTAuMCkrdmVjMih1di54LTAuMDAyLHV2LnkrMC4wMDApLDMuMCkuejsKICAgIAogICAgCgogICAgY29sID0gY2xhbXAoY29sKjAuNCswLjYqY29sKmNvbCoxLjAsMC4wLDEuMCk7CiAgICBmbG9hdCB2aWcgPSAoMC4wICsgMS4wKjE2LjAqdXYueCp1di55KigxLjAtdXYueCkqKDEuMC11di55KSk7Cgl2aWcgPSBwb3codmlnLDAuMyk7Cgljb2wgKj0gdmVjMyh2aWcpOwoKICAgIGNvbCAqPSB2ZWMzKDAuOTUsMS4wNSwwLjk1KTsKCWNvbCA9IG1peCggY29sLCBjb2wgKiBjb2wsIDAuMykgKiAzLjg7CgoJZmxvYXQgc2NhbnMgPSBjbGFtcCggMC4zNSswLjE1KnNpbigzLjUqKGlUaW1lICogU0NBTlNQRUVEKSt1di55KmlSZXNvbHV0aW9uLnkqMS41KSwgMC4wLCAxLjApOwoJCglmbG9hdCBzID0gcG93KHNjYW5zLDAuOSk7Cgljb2wgPSBjb2wqdmVjMyggcykgOwoKICAgIGNvbCAqPSAxLjArMC4wMDE1KnNpbigzMDAuMCppVGltZSk7CgkKCWNvbCo9MS4wLTAuMTUqdmVjMyhjbGFtcCgobW9kKGZyYWdDb29yZC54K28sIDIuMCktMS4wKSoyLjAsMC4wLDEuMCkpOwoJY29sICo9IHZlYzMoIDEuMCApIC0gMC4yNSp2ZWMzKCByYW5kKCB1diswLjAwMDEqaVRpbWUpLCAgcmFuZCggdXYrMC4wMDAxKmlUaW1lICsgMC4zICksICByYW5kKCB1diswLjAwMDEqaVRpbWUrIDAuNSApICApOwoJY29sID0gcG93KGNvbCwgdmVjMygwLjQ1KSk7CgoJaWYgKHV2LnggPCAwLjAgfHwgdXYueCA+IDEuMCkKCQljb2wgKj0gMC4wOwoJaWYgKHV2LnkgPCAwLjAgfHwgdXYueSA+IDEuMCkKCQljb2wgKj0gMC4wOwoJCgogICAgZmxvYXQgY29tcCA9IHNtb290aHN0ZXAoIDAuMSwgMC45LCBzaW4oaVRpbWUpICk7CgogICAgRnJhZ0NvbG9yID0gdmVjNChjb2wsMS4wKTsKfSAKI2VuZGlmCg==", + }, + ], + }, + + //https://github.com/libretro/glsl-shaders/blob/master/crt/CRT-beam.glslp + "crt-beam": { + "shader": { + "type": "text", + "value": "shaders = \"1\"\nfeedback_pass = \"0\"\nshader0 = \"CRT-Beam.glsl\"\nfilter_linear0 = \"true\"\nwrap_mode0 = \"clamp_to_border\"\nmipmap_input0 = \"false\"\nalias0 = \"\"\nfloat_framebuffer0 = \"false\"\nsrgb_framebuffer0 = \"false\"\n\n", + }, + "resources": [ + { + "name": "CRT-Beam.glsl", + "type": "base64", + "value": "LyoKCWNydC1iZWFtCglmb3IgYmVzdCByZXN1bHRzIHVzZSBpbnRlZ2VyIHNjYWxlIDV4IG9yIG1vcmUKKi8KCiNwcmFnbWEgcGFyYW1ldGVyIGJsdXIgIkhvcml6b250YWwgQmx1ci9CZWFtIHNoYXBlIiAwLjYgMC4wIDEuMCAwLjEKI3ByYWdtYSBwYXJhbWV0ZXIgU2NhbmxpbmUgIlNjYW5saW5lIHRoaWNrbmVzcyIgMC4yIDAuMCAxLjAgMC4wNQojcHJhZ21hIHBhcmFtZXRlciB3ZWlnaHRyICJTY2FubGluZSBSZWQgYnJpZ2h0bmVzcyIgMC44IDAuMCAxLjAgMC4wNQojcHJhZ21hIHBhcmFtZXRlciB3ZWlnaHRnICJTY2FubGluZSBHcmVlbiBicmlnaHRuZXNzIiAwLjggMC4wIDEuMCAwLjA1CiNwcmFnbWEgcGFyYW1ldGVyIHdlaWdodGIgIlNjYW5saW5lIEJsdWUgYnJpZ2h0bmVzcyIgMC44IDAuMCAxLjAgMC4wNQojcHJhZ21hIHBhcmFtZXRlciBib2d1c19tc2sgIiBbIE1BU0tTIF0gIiAwLjAgMC4wIDAuMCAwLjAKI3ByYWdtYSBwYXJhbWV0ZXIgbWFzayAiTWFzayAwOkNHV0csMS0yOkxvdHRlcywzLTQgR3JheSw1LTY6Q0dXRyBzbG90LDcgVkdBIiAzLjAgLTEuMCA3LjAgMS4wCiNwcmFnbWEgcGFyYW1ldGVyIG1za19zaXplICJNYXNrIHNpemUiIDEuMCAxLjAgMi4wIDEuMAojcHJhZ21hIHBhcmFtZXRlciBzY2FsZSAiVkdBIE1hc2sgVmVydGljYWwgU2NhbGUiIDIuMCAyLjAwIDEwLjAwIDEuMAojcHJhZ21hIHBhcmFtZXRlciBNYXNrRGFyayAiTG90dGVzIE1hc2sgRGFyayIgMC43IDAuMDAgMi4wMCAwLjEwCiNwcmFnbWEgcGFyYW1ldGVyIE1hc2tMaWdodCAiTG90dGVzIE1hc2sgTGlnaHQiIDEuMCAwLjAwIDIuMDAgMC4xMAojcHJhZ21hIHBhcmFtZXRlciBib2d1c19jb2wgIiBbIENPTE9SIF0gIiAwLjAgMC4wIDAuMCAwLjAKI3ByYWdtYSBwYXJhbWV0ZXIgc2F0ICJTYXR1cmF0aW9uIiAxLjAgMC4wMCAyLjAwIDAuMDUKI3ByYWdtYSBwYXJhbWV0ZXIgYnJpZ2h0ICJCb29zdCBicmlnaHQiIDEuMCAxLjAwIDIuMDAgMC4wNQojcHJhZ21hIHBhcmFtZXRlciBkYXJrICJCb29zdCBkYXJrIiAxLjQ1IDEuMDAgMi4wMCAwLjA1CiNwcmFnbWEgcGFyYW1ldGVyIGdsb3cgIkdsb3cgU3RyZW5ndGgiIDAuMDggMC4wIDAuNSAwLjAxCgoKI2RlZmluZSBwaSAzLjE0MTU5CgojaWZkZWYgR0xfRVMKI2RlZmluZSBDT01QQVRfUFJFQ0lTSU9OIG1lZGl1bXAKcHJlY2lzaW9uIG1lZGl1bXAgZmxvYXQ7CiNlbHNlCiNkZWZpbmUgQ09NUEFUX1BSRUNJU0lPTgojZW5kaWYKCgp1bmlmb3JtIHZlYzIgVGV4dHVyZVNpemU7CnZhcnlpbmcgdmVjMiBURVgwOwp2YXJ5aW5nIHZlYzIgZnJhZ3BvczsKCiNpZiBkZWZpbmVkKFZFUlRFWCkKdW5pZm9ybSBtYXQ0IE1WUE1hdHJpeDsKYXR0cmlidXRlIHZlYzQgVmVydGV4Q29vcmQ7CmF0dHJpYnV0ZSB2ZWMyIFRleENvb3JkOwp1bmlmb3JtIHZlYzIgSW5wdXRTaXplOwp1bmlmb3JtIHZlYzIgT3V0cHV0U2l6ZTsKCnZvaWQgbWFpbigpCnsKCVRFWDAgPSBUZXhDb29yZCoxLjAwMDE7ICAgICAgICAgICAgICAgICAgICAKCWdsX1Bvc2l0aW9uID0gTVZQTWF0cml4ICogVmVydGV4Q29vcmQ7ICAKCWZyYWdwb3MgPSBURVgwLnh5Kk91dHB1dFNpemUueHkqVGV4dHVyZVNpemUueHkvSW5wdXRTaXplLnh5OyAgIAp9CgojZWxpZiBkZWZpbmVkKEZSQUdNRU5UKQoKdW5pZm9ybSBzYW1wbGVyMkQgVGV4dHVyZTsKdW5pZm9ybSB2ZWMyIE91dHB1dFNpemU7CnVuaWZvcm0gdmVjMiBJbnB1dFNpemU7CgojZGVmaW5lIHZUZXhDb29yZCBURVgwLnh5CiNkZWZpbmUgU291cmNlU2l6ZSB2ZWM0KFRleHR1cmVTaXplLCAxLjAgLyBUZXh0dXJlU2l6ZSkgLy9laXRoZXIgVGV4dHVyZVNpemUgb3IgSW5wdXRTaXplCiNkZWZpbmUgb3V0U2l6ZSB2ZWM0KE91dHB1dFNpemUueHksIDEuMC9PdXRwdXRTaXplLnh5LzQuMCkKI2RlZmluZSBGcmFnQ29sb3IgZ2xfRnJhZ0NvbG9yCiNkZWZpbmUgU291cmNlIFRleHR1cmUKCgojaWZkZWYgUEFSQU1FVEVSX1VOSUZPUk0KCnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCBibHVyOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gZmxvYXQgU2NhbmxpbmU7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCB3ZWlnaHRyOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gZmxvYXQgd2VpZ2h0ZzsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIGZsb2F0IHdlaWdodGI7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCBtYXNrOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gZmxvYXQgc2NhbGU7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCBtc2tfc2l6ZTsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIGZsb2F0IE1hc2tEYXJrOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gZmxvYXQgTWFza0xpZ2h0Owp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gZmxvYXQgYnJpZ2h0Owp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gZmxvYXQgZGFyazsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIGZsb2F0IHNhdDsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIGZsb2F0IGdsb3c7CgojZWxzZQoKI2RlZmluZSBibHVyIDAuNgojZGVmaW5lIFNjYW5saW5lIDAuMgojZGVmaW5lIHdlaWdodHIgIDAuMgojZGVmaW5lIHdlaWdodGcgIDAuNgojZGVmaW5lIHdlaWdodGIgIDAuMQojZGVmaW5lIG1hc2sgICAgICA3LjAgICAKI2RlZmluZSBtc2tfc2l6ZSAgMS4wCiNkZWZpbmUgc2NhbGUgICAyLjAKI2RlZmluZSBNYXNrRGFyayAgMC41CiNkZWZpbmUgTWFza0xpZ2h0ICAxLjUKI2RlZmluZSBicmlnaHQgIDEuNQojZGVmaW5lIGRhcmsgIDEuMjUKI2RlZmluZSBnbG93ICAgICAgMC4wNSAgIAojZGVmaW5lIHNhdCAgICAgICAxLjAKCiNlbmRpZgoKdmVjNCBNYXNrICh2ZWMyIHApCnsJCQoJCXAgPSBmbG9vcihwL21za19zaXplKTsKCQlmbG9hdCBtZj1mcmFjdChwLngqMC41KTsKCQlmbG9hdCBtPU1hc2tEYXJrOwoJCXZlYzMgTWFzayA9IHZlYzMgKE1hc2tEYXJrKTsKCi8vIFBob3NwaG9yLgoJaWYgKG1hc2s9PTAuMCkKCXsKCQlpZiAobWYgPCAwLjUpIHJldHVybiB2ZWM0IChNYXNrTGlnaHQsbSxNYXNrTGlnaHQsMS4wKTsgCgkJZWxzZSByZXR1cm4gdmVjNCAobSxNYXNrTGlnaHQsbSwxLjApOwoJfQoKLy8gVmVyeSBjb21wcmVzc2VkIFRWIHN0eWxlIHNoYWRvdyBtYXNrLgoJZWxzZSBpZiAobWFzayA9PSAxLjApCgl7CgkJZmxvYXQgbGluZSA9IE1hc2tMaWdodDsKCQlmbG9hdCBvZGQgID0gMC4wOwoKCQlpZiAoZnJhY3QocC54LzYuMCkgPCAwLjUpCgkJCW9kZCA9IDEuMDsKCQlpZiAoZnJhY3QoKHAueSArIG9kZCkvMi4wKSA8IDAuNSkKCQkJbGluZSA9IE1hc2tEYXJrOwoKCQlwLnggPSBmcmFjdChwLngvMy4wKTsKICAgIAoJCWlmICAgICAgKHAueCA8IDAuMzMzKSBNYXNrLnIgPSBNYXNrTGlnaHQ7CgkJZWxzZSBpZiAocC54IDwgMC42NjYpIE1hc2suZyA9IE1hc2tMaWdodDsKCQllbHNlICAgICAgICAgICAgICAgICAgTWFzay5iID0gTWFza0xpZ2h0OwoJCQoJCU1hc2sqPWxpbmU7CgkJcmV0dXJuIHZlYzQgKE1hc2suciwgTWFzay5nLCBNYXNrLmIsMS4wKTsgIAoJfSAKCi8vIEFwZXJ0dXJlLWdyaWxsZS4KCWVsc2UgaWYgKG1hc2sgPT0gMi4wKQoJewoJCXAueCA9IGZyYWN0KHAueC8zLjApOwoKCQlpZiAgICAgIChwLnggPCAwLjMzMykgTWFzay5yID0gTWFza0xpZ2h0OwoJCWVsc2UgaWYgKHAueCA8IDAuNjY2KSBNYXNrLmcgPSBNYXNrTGlnaHQ7CgkJZWxzZSAgICAgICAgICAgICAgICAgIE1hc2suYiA9IE1hc2tMaWdodDsKCQlyZXR1cm4gdmVjNCAoTWFzay5yLCBNYXNrLmcsIE1hc2suYiwxLjApOyAgCgoJfSAKLy8gZ3JheQoJZWxzZSBpZiAobWFzaz09My4wKQoJewoJCQoJCWlmIChtZiA8IDAuNSkgcmV0dXJuIHZlYzQgKE1hc2tMaWdodCxNYXNrTGlnaHQsTWFza0xpZ2h0LDEuMCk7IAoJCWVsc2UgcmV0dXJuIHZlYzQgKG0sbSxtLDEuMCk7Cgl9Ci8vZ3JheSAzcHgKCWVsc2UgaWYgKG1hc2s9PTQuMCkKCXsKCQlmbG9hdCBtZj1mcmFjdChwLngqMC4zMzMzKTsKCQlpZiAobWYgPCAwLjY2NjYpIHJldHVybiB2ZWM0IChNYXNrTGlnaHQsTWFza0xpZ2h0LE1hc2tMaWdodCwxLjApOyAKCQllbHNlIHJldHVybiB2ZWM0IChtLG0sbSwxLjApOwoJfQovL2Nnd2cgc2xvdAoJZWxzZSBpZiAobWFzayA9PSA1LjApCgl7CgkJZmxvYXQgbGluZSA9IE1hc2tMaWdodDsKCQlmbG9hdCBvZGQgID0gMC4wOwoKCQlpZiAoZnJhY3QocC54LzQuMCkgPCAwLjUpCgkJCW9kZCA9IDEuMDsKCQlpZiAoZnJhY3QoKHAueSArIG9kZCkvMi4wKSA8IDAuNSkKCQkJbGluZSA9IE1hc2tEYXJrOwoKCQlwLnggPSBmcmFjdChwLngvMi4wKTsKICAgIAoJCWlmICAocC54IDwgMC41KSB7TWFzay5yID0gMS4wOyBNYXNrLmIgPSAxLjA7fQoJCWVsc2UgIE1hc2suZyA9IDEuMDsJCgkJTWFzayo9bGluZTsgIAoJCXJldHVybiB2ZWM0IChNYXNrLnIsIE1hc2suZywgTWFzay5iLDEuMCk7ICAKCgl9IAoKLy9jZ3dnIHNsb3QgMTQ0MHAKCWVsc2UgaWYgKG1hc2sgPT0gNi4wKQoJewoJCWZsb2F0IGxpbmUgPSBNYXNrTGlnaHQ7CgkJZmxvYXQgb2RkICA9IDAuMDsKCgkJaWYgKGZyYWN0KHAueC82LjApIDwgMC41KQoJCQlvZGQgPSAxLjA7CgkJaWYgKGZyYWN0KChwLnkgKyBvZGQpLzMuMCkgPCAwLjUpCgkJCWxpbmUgPSBNYXNrRGFyazsKCgkJcC54ID0gZnJhY3QocC54LzIuMCk7CiAgICAKCQlpZiAgKHAueCA8IDAuNSkge01hc2suciA9IE1hc2tMaWdodDsgTWFzay5iID0gTWFza0xpZ2h0O30KCQkJZWxzZSAge01hc2suZyA9IE1hc2tMaWdodDt9CQoJCQoJCU1hc2sqPWxpbmU7IAoJCXJldHVybiB2ZWM0IChNYXNrLnIsIE1hc2suZywgTWFzay5iLDEuMCk7ICAgCgl9IAoKLy9QQyBDUlQgVkdBIHN0eWxlIG1hc2sKCWVsc2UgaWYgKG1hc2sgPT0gNy4wKQoJewoJCWZsb2F0IGxpbmUgPSAxLjA7CgkJcC54ID0gZnJhY3QocC54LzIuMCk7CgoJCWlmIChmcmFjdChwLnkvc2NhbGUpIDwgMC41KQoJCQl7CgkJCQlpZiAgKHAueCA8IDAuNSkge01hc2suciA9IDEuMDsgTWFzay5iID0gMS4wO30KCQkJCWVsc2UgIHtNYXNrLmcgPSAxLjA7fQkKCQkJfQoJCWVsc2UKCQkJewoJCQkJaWYgIChwLnggPCAwLjUpIHtNYXNrLmcgPSAxLjA7fQkKCQkJCWVsc2UgICB7TWFzay5yID0gMS4wOyBNYXNrLmIgPSAxLjA7fQoJfQoJCU1hc2sqPWxpbmU7CgkJcmV0dXJuIHZlYzQgKE1hc2suciwgTWFzay5nLCBNYXNrLmIsMS4wKTsgICAKCgl9IAplbHNlIHJldHVybiB2ZWM0KDEuMCk7Cn0KdmVjMyBib29zdGVyICh2ZWMyIHBvcykKewoJdmVjMiBkeCA9IHZlYzIoU291cmNlU2l6ZS56LDAuMCk7Cgl2ZWMyIGR5ID0gdmVjMigwLjAsU291cmNlU2l6ZS53KTsKCgl2ZWM0IGMwMCA9IHRleHR1cmUyRChTb3VyY2UscG9zKTsKCXZlYzQgYzAxID0gdGV4dHVyZTJEKFNvdXJjZSxwb3MrZHgpOwoJdmVjNCBjMDIgPSB0ZXh0dXJlMkQoU291cmNlLHBvcytkeSk7Cgl2ZWM0IGMwMyA9IHRleHR1cmUyRChTb3VyY2UscG9zK2R4K2R5KTsKCgl2ZWM0IGdsID0gKGMwMCtjMDErYzAyK2MwMykvNC4wOyBnbCAqPWdsOwoJdmVjMyBnbDAgPSBnbC5yZ2I7CglyZXR1cm4gZ2wwKmdsb3c7Cn0KCnZvaWQgbWFpbigpCnsJCgl2ZWMyIHBvcyA9dlRleENvb3JkOwoJdmVjMiBPR0wyUG9zID0gcG9zKlRleHR1cmVTaXplOwoJdmVjMiBjZW50ID0gKGZsb29yKE9HTDJQb3MpKzAuNSkvVGV4dHVyZVNpemU7CglmbG9hdCB4Y29vcmQgPSBtaXgoY2VudC54LHZUZXhDb29yZC54LGJsdXIpOwoJdmVjMiBjb29yZHMgPSB2ZWMyKHhjb29yZCwgY2VudC55KTsKCgl2ZWMzIHJlcz0gdGV4dHVyZTJEKFNvdXJjZSwgY29vcmRzKS5yZ2I7CgoJZmxvYXQgbHVtID0gbWF4KG1heChyZXMucip3ZWlnaHRyLHJlcy5nKndlaWdodGcpLHJlcy5iKndlaWdodGIpOwoJZmxvYXQgZiA9IGZyYWN0KE9HTDJQb3MueSk7CgkKCXJlcyAqPSAxLjAtKGYtMC41KSooZi0wLjUpKjQ1LjAqKFNjYW5saW5lKigxLjAtbHVtKSk7CglyZXMgPSBjbGFtcChyZXMsMC4wLDEuMCk7CgkKCWZsb2F0IGwgPSBkb3QocmVzLHZlYzMoMC4zLDAuNiwwLjEpKTsKCXJlcyA9IG1peCh2ZWMzKGwpLCByZXMsIHNhdCk7CglyZXMgKz0gYm9vc3Rlcihjb29yZHMpOwoJdmVjNCByZXMwID0gdmVjNChyZXMsMS4wKTsgCglyZXMwICo9IE1hc2soZnJhZ3BvcyoxLjAwMDEpOwoJcmVzMCAqPSBtaXgoZGFyayxicmlnaHQsbCk7CgkKCUZyYWdDb2xvciA9IHJlczA7Cn0KI2VuZGlmCg==", + }, + ], + }, + + //https://github.com/libretro/glsl-shaders/blob/master/crt/crt-caligari.glslp + "crt-caligari": { + "shader": { + "type": "text", + "value": "shaders = 1\n\nshader0 = crt-caligari.glsl\nfilter_linear0 = false\n", + }, + "resources": [ + { + "name": "crt-caligari.glsl", + "type": "base64", + "value": "Ly8gUGFyYW1ldGVyIGxpbmVzIGdvIGhlcmU6Ci8vIDAuNSA9IHRoZSBzcG90IHN0YXlzIGluc2lkZSB0aGUgb3JpZ2luYWwgcGl4ZWwKLy8gMS4wID0gdGhlIHNwb3QgYmxlZWRzIHVwIHRvIHRoZSBjZW50ZXIgb2YgbmV4dCBwaXhlbAojcHJhZ21hIHBhcmFtZXRlciBTUE9UX1dJRFRIICJDUlRDYWxpZ2FyaSBTcG90IFdpZHRoIiAwLjkgMC41IDEuNSAwLjA1CiNwcmFnbWEgcGFyYW1ldGVyIFNQT1RfSEVJR0hUICJDUlRDYWxpZ2FyaSBTcG90IEhlaWdodCIgMC42NSAwLjUgMS41IDAuMDUKLy8gVXNlZCB0byBjb3VudGVyYWN0IHRoZSBkZXNhdHVyYXRpb24gZWZmZWN0IG9mIHdlaWdodGluZy4KI3ByYWdtYSBwYXJhbWV0ZXIgQ09MT1JfQk9PU1QgIkNSVENhbGlnYXJpIENvbG9yIEJvb3N0IiAxLjQ1IDEuMCAyLjAgMC4wNQovLyBDb25zdGFudHMgdXNlZCB3aXRoIGdhbW1hIGNvcnJlY3Rpb24uCiNwcmFnbWEgcGFyYW1ldGVyIElucHV0R2FtbWEgIkNSVENhbGlnYXJpIElucHV0IEdhbW1hIiAyLjQgMC4wIDUuMCAwLjEKI3ByYWdtYSBwYXJhbWV0ZXIgT3V0cHV0R2FtbWEgIkNSVENhbGlnYXJpIE91dHB1dCBHYW1tYSIgMi4yIDAuMCA1LjAgMC4xCgojaWYgZGVmaW5lZChWRVJURVgpCgojaWYgX19WRVJTSU9OX18gPj0gMTMwCiNkZWZpbmUgQ09NUEFUX1ZBUllJTkcgb3V0CiNkZWZpbmUgQ09NUEFUX0FUVFJJQlVURSBpbgojZGVmaW5lIENPTVBBVF9URVhUVVJFIHRleHR1cmUKI2Vsc2UKI2RlZmluZSBDT01QQVRfVkFSWUlORyB2YXJ5aW5nIAojZGVmaW5lIENPTVBBVF9BVFRSSUJVVEUgYXR0cmlidXRlIAojZGVmaW5lIENPTVBBVF9URVhUVVJFIHRleHR1cmUyRAojZW5kaWYKCiNpZmRlZiBHTF9FUwojZGVmaW5lIENPTVBBVF9QUkVDSVNJT04gbWVkaXVtcAojZWxzZQojZGVmaW5lIENPTVBBVF9QUkVDSVNJT04KI2VuZGlmCgpDT01QQVRfQVRUUklCVVRFIHZlYzQgVmVydGV4Q29vcmQ7CkNPTVBBVF9BVFRSSUJVVEUgdmVjNCBDT0xPUjsKQ09NUEFUX0FUVFJJQlVURSB2ZWM0IFRleENvb3JkOwpDT01QQVRfVkFSWUlORyB2ZWM0IENPTDA7CkNPTVBBVF9WQVJZSU5HIHZlYzQgVEVYMDsKQ09NUEFUX1ZBUllJTkcgdmVjMiBvbmV4OwpDT01QQVRfVkFSWUlORyB2ZWMyIG9uZXk7Cgp2ZWM0IF9vUG9zaXRpb24xOyAKdW5pZm9ybSBtYXQ0IE1WUE1hdHJpeDsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIGludCBGcmFtZURpcmVjdGlvbjsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIGludCBGcmFtZUNvdW50Owp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gdmVjMiBPdXRwdXRTaXplOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gdmVjMiBUZXh0dXJlU2l6ZTsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIHZlYzIgSW5wdXRTaXplOwoKI2RlZmluZSBTb3VyY2VTaXplIHZlYzQoVGV4dHVyZVNpemUsIDEuMCAvIFRleHR1cmVTaXplKSAvL2VpdGhlciBUZXh0dXJlU2l6ZSBvciBJbnB1dFNpemUKCnZvaWQgbWFpbigpCnsKICAgIGdsX1Bvc2l0aW9uID0gTVZQTWF0cml4ICogVmVydGV4Q29vcmQ7CiAgICBDT0wwID0gQ09MT1I7CiAgICBURVgwLnh5ID0gVGV4Q29vcmQueHk7CiAgIG9uZXggPSB2ZWMyKFNvdXJjZVNpemUueiwgMC4wKTsKICAgb25leSA9IHZlYzIoMC4wLCBTb3VyY2VTaXplLncpOwp9CgojZWxpZiBkZWZpbmVkKEZSQUdNRU5UKQoKI2lmIF9fVkVSU0lPTl9fID49IDEzMAojZGVmaW5lIENPTVBBVF9WQVJZSU5HIGluCiNkZWZpbmUgQ09NUEFUX1RFWFRVUkUgdGV4dHVyZQpvdXQgdmVjNCBGcmFnQ29sb3I7CiNlbHNlCiNkZWZpbmUgQ09NUEFUX1ZBUllJTkcgdmFyeWluZwojZGVmaW5lIEZyYWdDb2xvciBnbF9GcmFnQ29sb3IKI2RlZmluZSBDT01QQVRfVEVYVFVSRSB0ZXh0dXJlMkQKI2VuZGlmCgojaWZkZWYgR0xfRVMKI2lmZGVmIEdMX0ZSQUdNRU5UX1BSRUNJU0lPTl9ISUdICnByZWNpc2lvbiBoaWdocCBmbG9hdDsKI2Vsc2UKcHJlY2lzaW9uIG1lZGl1bXAgZmxvYXQ7CiNlbmRpZgojZGVmaW5lIENPTVBBVF9QUkVDSVNJT04gbWVkaXVtcAojZWxzZQojZGVmaW5lIENPTVBBVF9QUkVDSVNJT04KI2VuZGlmCgp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gaW50IEZyYW1lRGlyZWN0aW9uOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gaW50IEZyYW1lQ291bnQ7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiB2ZWMyIE91dHB1dFNpemU7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiB2ZWMyIFRleHR1cmVTaXplOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gdmVjMiBJbnB1dFNpemU7CnVuaWZvcm0gc2FtcGxlcjJEIFRleHR1cmU7CkNPTVBBVF9WQVJZSU5HIHZlYzQgVEVYMDsKQ09NUEFUX1ZBUllJTkcgdmVjMiBvbmV4OwpDT01QQVRfVkFSWUlORyB2ZWMyIG9uZXk7CgovLyBjb21wYXRpYmlsaXR5ICNkZWZpbmVzCiNkZWZpbmUgU291cmNlIFRleHR1cmUKI2RlZmluZSB2VGV4Q29vcmQgVEVYMC54eQoKI2RlZmluZSBTb3VyY2VTaXplIHZlYzQoVGV4dHVyZVNpemUsIDEuMCAvIFRleHR1cmVTaXplKSAvL2VpdGhlciBUZXh0dXJlU2l6ZSBvciBJbnB1dFNpemUKI2RlZmluZSBPdXRwdXRTaXplIHZlYzQoT3V0cHV0U2l6ZSwgMS4wIC8gT3V0cHV0U2l6ZSkKCiNpZmRlZiBQQVJBTUVURVJfVU5JRk9STQovLyBBbGwgcGFyYW1ldGVyIGZsb2F0cyBuZWVkIHRvIGhhdmUgQ09NUEFUX1BSRUNJU0lPTiBpbiBmcm9udCBvZiB0aGVtCnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCBTUE9UX1dJRFRIOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gZmxvYXQgU1BPVF9IRUlHSFQ7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCBDT0xPUl9CT09TVDsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIGZsb2F0IElucHV0R2FtbWE7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCBPdXRwdXRHYW1tYTsKI2Vsc2UKI2RlZmluZSBTUE9UX1dJRFRIIDAuOQojZGVmaW5lIFNQT1RfSEVJR0hUIDAuNjUKI2RlZmluZSBDT0xPUl9CT09TVCAxLjQ1CiNkZWZpbmUgSW5wdXRHYW1tYSAyLjQKI2RlZmluZSBPdXRwdXRHYW1tYSAyLjIKI2VuZGlmCgojZGVmaW5lIEdBTU1BX0lOKGNvbG9yKSAgICAgcG93KGNvbG9yLHZlYzQoSW5wdXRHYW1tYSkpCiNkZWZpbmUgR0FNTUFfT1VUKGNvbG9yKSAgICBwb3coY29sb3IsIHZlYzQoMS4wIC8gT3V0cHV0R2FtbWEpKQoKI2RlZmluZSBURVgyRChjb29yZHMpCUdBTU1BX0lOKCBDT01QQVRfVEVYVFVSRShTb3VyY2UsIGNvb3JkcykgKQoKLy8gTWFjcm8gZm9yIHdlaWdodHMgY29tcHV0aW5nCiNkZWZpbmUgV0VJR0hUKHcpIFwKICAgaWYodz4xLjApIHc9MS4wOyBcCncgPSAxLjAgLSB3ICogdzsgXAp3ID0gdyAqIHc7Cgp2b2lkIG1haW4oKQp7CiAgIHZlYzIgY29vcmRzID0gKCB2VGV4Q29vcmQgKiBTb3VyY2VTaXplLnh5ICk7CiAgIHZlYzIgcGl4ZWxfY2VudGVyID0gZmxvb3IoIGNvb3JkcyApICsgdmVjMigwLjUsIDAuNSk7CiAgIHZlYzIgdGV4dHVyZV9jb29yZHMgPSBwaXhlbF9jZW50ZXIgKiBTb3VyY2VTaXplLnp3OwoKICAgdmVjNCBjb2xvciA9IFRFWDJEKCB0ZXh0dXJlX2Nvb3JkcyApOwoKICAgZmxvYXQgZHggPSBjb29yZHMueCAtIHBpeGVsX2NlbnRlci54OwoKICAgZmxvYXQgaF93ZWlnaHRfMDAgPSBkeCAvIFNQT1RfV0lEVEg7CiAgIFdFSUdIVCggaF93ZWlnaHRfMDAgKTsKCiAgIGNvbG9yICo9IHZlYzQoIGhfd2VpZ2h0XzAwLCBoX3dlaWdodF8wMCwgaF93ZWlnaHRfMDAsIGhfd2VpZ2h0XzAwICApOwoKICAgLy8gZ2V0IGNsb3Nlc3QgaG9yaXpvbnRhbCBuZWlnaGJvdXIgdG8gYmxlbmQKICAgdmVjMiBjb29yZHMwMTsKICAgaWYgKGR4PjAuMCkgewogICAgICBjb29yZHMwMSA9IG9uZXg7CiAgICAgIGR4ID0gMS4wIC0gZHg7CiAgIH0gZWxzZSB7CiAgICAgIGNvb3JkczAxID0gLW9uZXg7CiAgICAgIGR4ID0gMS4wICsgZHg7CiAgIH0KICAgdmVjNCBjb2xvck5CID0gVEVYMkQoIHRleHR1cmVfY29vcmRzICsgY29vcmRzMDEgKTsKCiAgIGZsb2F0IGhfd2VpZ2h0XzAxID0gZHggLyBTUE9UX1dJRFRIOwogICBXRUlHSFQoIGhfd2VpZ2h0XzAxICk7CgogICBjb2xvciA9IGNvbG9yICsgY29sb3JOQiAqIHZlYzQoIGhfd2VpZ2h0XzAxICk7CgogICAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KICAgLy8gVmVydGljYWwgQmxlbmRpbmcKICAgZmxvYXQgZHkgPSBjb29yZHMueSAtIHBpeGVsX2NlbnRlci55OwogICBmbG9hdCB2X3dlaWdodF8wMCA9IGR5IC8gU1BPVF9IRUlHSFQ7CiAgIFdFSUdIVCggdl93ZWlnaHRfMDAgKTsKICAgY29sb3IgKj0gdmVjNCggdl93ZWlnaHRfMDAgKTsKCiAgIC8vIGdldCBjbG9zZXN0IHZlcnRpY2FsIG5laWdoYm91ciB0byBibGVuZAogICB2ZWMyIGNvb3JkczEwOwogICBpZiAoZHk+MC4wKSB7CiAgICAgIGNvb3JkczEwID0gb25leTsKICAgICAgZHkgPSAxLjAgLSBkeTsKICAgfSBlbHNlIHsKICAgICAgY29vcmRzMTAgPSAtb25leTsKICAgICAgZHkgPSAxLjAgKyBkeTsKICAgfQogICBjb2xvck5CID0gVEVYMkQoIHRleHR1cmVfY29vcmRzICsgY29vcmRzMTAgKTsKCiAgIGZsb2F0IHZfd2VpZ2h0XzEwID0gZHkgLyBTUE9UX0hFSUdIVDsKICAgV0VJR0hUKCB2X3dlaWdodF8xMCApOwoKICAgY29sb3IgPSBjb2xvciArIGNvbG9yTkIgKiB2ZWM0KCB2X3dlaWdodF8xMCAqIGhfd2VpZ2h0XzAwLCB2X3dlaWdodF8xMCAqIGhfd2VpZ2h0XzAwLCB2X3dlaWdodF8xMCAqIGhfd2VpZ2h0XzAwLCB2X3dlaWdodF8xMCAqIGhfd2VpZ2h0XzAwICk7CgogICBjb2xvck5CID0gVEVYMkQoICB0ZXh0dXJlX2Nvb3JkcyArIGNvb3JkczAxICsgY29vcmRzMTAgKTsKCiAgIGNvbG9yID0gY29sb3IgKyBjb2xvck5CICogdmVjNCggdl93ZWlnaHRfMTAgKiBoX3dlaWdodF8wMSwgdl93ZWlnaHRfMTAgKiBoX3dlaWdodF8wMSwgdl93ZWlnaHRfMTAgKiBoX3dlaWdodF8wMSwgdl93ZWlnaHRfMTAgKiBoX3dlaWdodF8wMSApOwoKICAgY29sb3IgKj0gdmVjNCggQ09MT1JfQk9PU1QgKTsKCiAgIEZyYWdDb2xvciA9IGNsYW1wKCBHQU1NQV9PVVQoY29sb3IpLCAwLjAsIDEuMCApOwp9IAojZW5kaWYK", + }, + ], + }, + + //https://github.com/libretro/glsl-shaders/blob/master/crt/crt-lottes.glslp + "crt-lottes": { + "shader": { + "type": "text", + "value": "shaders = 1\n\nshader0 = crt-lottes.glsl\nfilter_linear0 = false\n", + }, + "resources": [ + { + "name": "crt-lottes.glsl", + "type": "base64", + "value": "Ly8gUGFyYW1ldGVyIGxpbmVzIGdvIGhlcmU6CiNwcmFnbWEgcGFyYW1ldGVyIGhhcmRTY2FuICJoYXJkU2NhbiIgLTguMCAtMjAuMCAwLjAgMS4wCiNwcmFnbWEgcGFyYW1ldGVyIGhhcmRQaXggImhhcmRQaXgiIC0zLjAgLTIwLjAgMC4wIDEuMAojcHJhZ21hIHBhcmFtZXRlciB3YXJwWCAid2FycFgiIDAuMDMxIDAuMCAwLjEyNSAwLjAxCiNwcmFnbWEgcGFyYW1ldGVyIHdhcnBZICJ3YXJwWSIgMC4wNDEgMC4wIDAuMTI1IDAuMDEKI3ByYWdtYSBwYXJhbWV0ZXIgbWFza0RhcmsgIm1hc2tEYXJrIiAwLjUgMC4wIDIuMCAwLjEKI3ByYWdtYSBwYXJhbWV0ZXIgbWFza0xpZ2h0ICJtYXNrTGlnaHQiIDEuNSAwLjAgMi4wIDAuMQojcHJhZ21hIHBhcmFtZXRlciBzY2FsZUluTGluZWFyR2FtbWEgInNjYWxlSW5MaW5lYXJHYW1tYSIgMS4wIDAuMCAxLjAgMS4wCiNwcmFnbWEgcGFyYW1ldGVyIHNoYWRvd01hc2sgInNoYWRvd01hc2siIDMuMCAwLjAgNC4wIDEuMAojcHJhZ21hIHBhcmFtZXRlciBicmlnaHRCb29zdCAiYnJpZ2h0bmVzcyBib29zdCIgMS4wIDAuMCAyLjAgMC4wNQojcHJhZ21hIHBhcmFtZXRlciBoYXJkQmxvb21QaXggImJsb29tLXggc29mdCIgLTEuNSAtMi4wIC0wLjUgMC4xCiNwcmFnbWEgcGFyYW1ldGVyIGhhcmRCbG9vbVNjYW4gImJsb29tLXkgc29mdCIgLTIuMCAtNC4wIC0xLjAgMC4xCiNwcmFnbWEgcGFyYW1ldGVyIGJsb29tQW1vdW50ICJibG9vbSBhbW1vdW50IiAwLjE1IDAuMCAxLjAgMC4wNQojcHJhZ21hIHBhcmFtZXRlciBzaGFwZSAiZmlsdGVyIGtlcm5lbCBzaGFwZSIgMi4wIDAuMCAxMC4wIDAuMDUKCiNpZiBkZWZpbmVkKFZFUlRFWCkKCiNpZiBfX1ZFUlNJT05fXyA+PSAxMzAKI2RlZmluZSBDT01QQVRfVkFSWUlORyBvdXQKI2RlZmluZSBDT01QQVRfQVRUUklCVVRFIGluCiNkZWZpbmUgQ09NUEFUX1RFWFRVUkUgdGV4dHVyZQojZWxzZQojZGVmaW5lIENPTVBBVF9WQVJZSU5HIHZhcnlpbmcgCiNkZWZpbmUgQ09NUEFUX0FUVFJJQlVURSBhdHRyaWJ1dGUgCiNkZWZpbmUgQ09NUEFUX1RFWFRVUkUgdGV4dHVyZTJECiNlbmRpZgoKI2lmZGVmIEdMX0VTCiNkZWZpbmUgQ09NUEFUX1BSRUNJU0lPTiBtZWRpdW1wCiNlbHNlCiNkZWZpbmUgQ09NUEFUX1BSRUNJU0lPTgojZW5kaWYKCkNPTVBBVF9BVFRSSUJVVEUgdmVjNCBWZXJ0ZXhDb29yZDsKQ09NUEFUX0FUVFJJQlVURSB2ZWM0IENPTE9SOwpDT01QQVRfQVRUUklCVVRFIHZlYzQgVGV4Q29vcmQ7CkNPTVBBVF9WQVJZSU5HIHZlYzQgQ09MMDsKQ09NUEFUX1ZBUllJTkcgdmVjNCBURVgwOwoKdW5pZm9ybSBtYXQ0IE1WUE1hdHJpeDsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIGludCBGcmFtZURpcmVjdGlvbjsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIGludCBGcmFtZUNvdW50Owp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gdmVjMiBPdXRwdXRTaXplOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gdmVjMiBUZXh0dXJlU2l6ZTsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIHZlYzIgSW5wdXRTaXplOwoKLy8gdmVydGV4IGNvbXBhdGliaWxpdHkgI2RlZmluZXMKI2RlZmluZSB2VGV4Q29vcmQgVEVYMC54eQojZGVmaW5lIFNvdXJjZVNpemUgdmVjNChUZXh0dXJlU2l6ZSwgMS4wIC8gVGV4dHVyZVNpemUpIC8vZWl0aGVyIFRleHR1cmVTaXplIG9yIElucHV0U2l6ZQojZGVmaW5lIG91dHNpemUgdmVjNChPdXRwdXRTaXplLCAxLjAgLyBPdXRwdXRTaXplKQoKdm9pZCBtYWluKCkKewogICAgZ2xfUG9zaXRpb24gPSBNVlBNYXRyaXggKiBWZXJ0ZXhDb29yZDsKICAgIFRFWDAueHkgPSBUZXhDb29yZC54eTsKfQoKI2VsaWYgZGVmaW5lZChGUkFHTUVOVCkKCiNpZiBfX1ZFUlNJT05fXyA+PSAxMzAKI2RlZmluZSBDT01QQVRfVkFSWUlORyBpbgojZGVmaW5lIENPTVBBVF9URVhUVVJFIHRleHR1cmUKb3V0IHZlYzQgRnJhZ0NvbG9yOwojZWxzZQojZGVmaW5lIENPTVBBVF9WQVJZSU5HIHZhcnlpbmcKI2RlZmluZSBGcmFnQ29sb3IgZ2xfRnJhZ0NvbG9yCiNkZWZpbmUgQ09NUEFUX1RFWFRVUkUgdGV4dHVyZTJECiNlbmRpZgoKI2lmZGVmIEdMX0VTCiNpZmRlZiBHTF9GUkFHTUVOVF9QUkVDSVNJT05fSElHSApwcmVjaXNpb24gaGlnaHAgZmxvYXQ7CiNlbHNlCnByZWNpc2lvbiBtZWRpdW1wIGZsb2F0OwojZW5kaWYKI2RlZmluZSBDT01QQVRfUFJFQ0lTSU9OIG1lZGl1bXAKI2Vsc2UKI2RlZmluZSBDT01QQVRfUFJFQ0lTSU9OCiNlbmRpZgoKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIGludCBGcmFtZURpcmVjdGlvbjsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIGludCBGcmFtZUNvdW50Owp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gdmVjMiBPdXRwdXRTaXplOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gdmVjMiBUZXh0dXJlU2l6ZTsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIHZlYzIgSW5wdXRTaXplOwp1bmlmb3JtIHNhbXBsZXIyRCBUZXh0dXJlOwpDT01QQVRfVkFSWUlORyB2ZWM0IFRFWDA7CgovLyBmcmFnbWVudCBjb21wYXRpYmlsaXR5ICNkZWZpbmVzCiNkZWZpbmUgU291cmNlIFRleHR1cmUKI2RlZmluZSB2VGV4Q29vcmQgVEVYMC54eQoKI2RlZmluZSBTb3VyY2VTaXplIHZlYzQoVGV4dHVyZVNpemUsIDEuMCAvIFRleHR1cmVTaXplKSAvL2VpdGhlciBUZXh0dXJlU2l6ZSBvciBJbnB1dFNpemUKI2RlZmluZSBvdXRzaXplIHZlYzQoT3V0cHV0U2l6ZSwgMS4wIC8gT3V0cHV0U2l6ZSkKCiNpZmRlZiBQQVJBTUVURVJfVU5JRk9STQovLyBBbGwgcGFyYW1ldGVyIGZsb2F0cyBuZWVkIHRvIGhhdmUgQ09NUEFUX1BSRUNJU0lPTiBpbiBmcm9udCBvZiB0aGVtCnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCBoYXJkU2NhbjsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIGZsb2F0IGhhcmRQaXg7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCB3YXJwWDsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIGZsb2F0IHdhcnBZOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gZmxvYXQgbWFza0Rhcms7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCBtYXNrTGlnaHQ7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCBzY2FsZUluTGluZWFyR2FtbWE7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCBzaGFkb3dNYXNrOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gZmxvYXQgYnJpZ2h0Qm9vc3Q7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCBoYXJkQmxvb21QaXg7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCBoYXJkQmxvb21TY2FuOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gZmxvYXQgYmxvb21BbW91bnQ7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCBzaGFwZTsKI2Vsc2UKI2RlZmluZSBoYXJkU2NhbiAtOC4wCiNkZWZpbmUgaGFyZFBpeCAtMy4wCiNkZWZpbmUgd2FycFggMC4wMzEKI2RlZmluZSB3YXJwWSAwLjA0MQojZGVmaW5lIG1hc2tEYXJrIDAuNQojZGVmaW5lIG1hc2tMaWdodCAxLjUKI2RlZmluZSBzY2FsZUluTGluZWFyR2FtbWEgMS4wCiNkZWZpbmUgc2hhZG93TWFzayAzLjAKI2RlZmluZSBicmlnaHRCb29zdCAxLjAKI2RlZmluZSBoYXJkQmxvb21QaXggLTEuNQojZGVmaW5lIGhhcmRCbG9vbVNjYW4gLTIuMAojZGVmaW5lIGJsb29tQW1vdW50IDAuMTUKI2RlZmluZSBzaGFwZSAyLjAKI2VuZGlmCgovL1VuY29tbWVudCB0byByZWR1Y2UgaW5zdHJ1Y3Rpb25zIHdpdGggc2ltcGxlciBsaW5lYXJpemF0aW9uCi8vKGZpeGVzIEhEMzAwMCBTYW5keSBCcmlkZ2UgSUdQKQovLyNkZWZpbmUgU0lNUExFX0xJTkVBUl9HQU1NQQojZGVmaW5lIERPX0JMT09NCgovLyAtLS0tLS0tLS0tLS0tIC8vCgovLyBzUkdCIHRvIExpbmVhci4KLy8gQXNzdW1pbmcgdXNpbmcgc1JHQiB0eXBlZCB0ZXh0dXJlcyB0aGlzIHNob3VsZCBub3QgYmUgbmVlZGVkLgojaWZkZWYgU0lNUExFX0xJTkVBUl9HQU1NQQpmbG9hdCBUb0xpbmVhcjEoZmxvYXQgYykKewogICAgcmV0dXJuIGM7Cn0KdmVjMyBUb0xpbmVhcih2ZWMzIGMpCnsKICAgIHJldHVybiBjOwp9CnZlYzMgVG9TcmdiKHZlYzMgYykKewogICAgcmV0dXJuIHBvdyhjLCB2ZWMzKDEuMCAvIDIuMikpOwp9CiNlbHNlCmZsb2F0IFRvTGluZWFyMShmbG9hdCBjKQp7CiAgICBpZiAoc2NhbGVJbkxpbmVhckdhbW1hID09IDAuKSAKICAgICAgICByZXR1cm4gYzsKICAgIAogICAgcmV0dXJuKGM8PTAuMDQwNDUpID8gYy8xMi45MiA6IHBvdygoYyArIDAuMDU1KS8xLjA1NSwgMi40KTsKfQoKdmVjMyBUb0xpbmVhcih2ZWMzIGMpCnsKICAgIGlmIChzY2FsZUluTGluZWFyR2FtbWE9PTAuKSAKICAgICAgICByZXR1cm4gYzsKICAgIAogICAgcmV0dXJuIHZlYzMoVG9MaW5lYXIxKGMuciksIFRvTGluZWFyMShjLmcpLCBUb0xpbmVhcjEoYy5iKSk7Cn0KCi8vIExpbmVhciB0byBzUkdCLgovLyBBc3N1bWluZyB1c2luZyBzUkdCIHR5cGVkIHRleHR1cmVzIHRoaXMgc2hvdWxkIG5vdCBiZSBuZWVkZWQuCmZsb2F0IFRvU3JnYjEoZmxvYXQgYykKewogICAgaWYgKHNjYWxlSW5MaW5lYXJHYW1tYSA9PSAwLikgCiAgICAgICAgcmV0dXJuIGM7CiAgICAKICAgIHJldHVybihjPDAuMDAzMTMwOCA/IGMqMTIuOTIgOiAxLjA1NSpwb3coYywgMC40MTY2NikgLSAwLjA1NSk7Cn0KCnZlYzMgVG9TcmdiKHZlYzMgYykKewogICAgaWYgKHNjYWxlSW5MaW5lYXJHYW1tYSA9PSAwLikgCiAgICAgICAgcmV0dXJuIGM7CiAgICAKICAgIHJldHVybiB2ZWMzKFRvU3JnYjEoYy5yKSwgVG9TcmdiMShjLmcpLCBUb1NyZ2IxKGMuYikpOwp9CiNlbmRpZgoKLy8gTmVhcmVzdCBlbXVsYXRlZCBzYW1wbGUgZ2l2ZW4gZmxvYXRpbmcgcG9pbnQgcG9zaXRpb24gYW5kIHRleGVsIG9mZnNldC4KLy8gQWxzbyB6ZXJvJ3Mgb2ZmIHNjcmVlbi4KdmVjMyBGZXRjaCh2ZWMyIHBvcyx2ZWMyIG9mZil7CiAgcG9zPShmbG9vcihwb3MqU291cmNlU2l6ZS54eStvZmYpK3ZlYzIoMC41LDAuNSkpL1NvdXJjZVNpemUueHk7CiNpZmRlZiBTSU1QTEVfTElORUFSX0dBTU1BCiAgcmV0dXJuIFRvTGluZWFyKGJyaWdodEJvb3N0ICogcG93KENPTVBBVF9URVhUVVJFKFNvdXJjZSxwb3MueHkpLnJnYiwgdmVjMygyLjIpKSk7CiNlbHNlCiAgcmV0dXJuIFRvTGluZWFyKGJyaWdodEJvb3N0ICogQ09NUEFUX1RFWFRVUkUoU291cmNlLHBvcy54eSkucmdiKTsKI2VuZGlmCn0KCi8vIERpc3RhbmNlIGluIGVtdWxhdGVkIHBpeGVscyB0byBuZWFyZXN0IHRleGVsLgp2ZWMyIERpc3QodmVjMiBwb3MpCnsKICAgIHBvcyA9IHBvcypTb3VyY2VTaXplLnh5OwogICAgCiAgICByZXR1cm4gLSgocG9zIC0gZmxvb3IocG9zKSkgLSB2ZWMyKDAuNSkpOwp9CiAgICAKLy8gMUQgR2F1c3NpYW4uCmZsb2F0IEdhdXMoZmxvYXQgcG9zLCBmbG9hdCBzY2FsZSkKewogICAgcmV0dXJuIGV4cDIoc2NhbGUqcG93KGFicyhwb3MpLCBzaGFwZSkpOwp9CgovLyAzLXRhcCBHYXVzc2lhbiBmaWx0ZXIgYWxvbmcgaG9yeiBsaW5lLgp2ZWMzIEhvcnozKHZlYzIgcG9zLCBmbG9hdCBvZmYpCnsKICAgIHZlYzMgYiAgICA9IEZldGNoKHBvcywgdmVjMigtMS4wLCBvZmYpKTsKICAgIHZlYzMgYyAgICA9IEZldGNoKHBvcywgdmVjMiggMC4wLCBvZmYpKTsKICAgIHZlYzMgZCAgICA9IEZldGNoKHBvcywgdmVjMiggMS4wLCBvZmYpKTsKICAgIGZsb2F0IGRzdCA9IERpc3QocG9zKS54OwoKICAgIC8vIENvbnZlcnQgZGlzdGFuY2UgdG8gd2VpZ2h0LgogICAgZmxvYXQgc2NhbGUgPSBoYXJkUGl4OwogICAgZmxvYXQgd2IgPSBHYXVzKGRzdC0xLjAsc2NhbGUpOwogICAgZmxvYXQgd2MgPSBHYXVzKGRzdCswLjAsc2NhbGUpOwogICAgZmxvYXQgd2QgPSBHYXVzKGRzdCsxLjAsc2NhbGUpOwoKICAgIC8vIFJldHVybiBmaWx0ZXJlZCBzYW1wbGUuCiAgICByZXR1cm4gKGIqd2IrYyp3YytkKndkKS8od2Ird2Mrd2QpOwp9CgovLyA1LXRhcCBHYXVzc2lhbiBmaWx0ZXIgYWxvbmcgaG9yeiBsaW5lLgp2ZWMzIEhvcno1KHZlYzIgcG9zLGZsb2F0IG9mZil7CiAgICB2ZWMzIGEgPSBGZXRjaChwb3MsdmVjMigtMi4wLCBvZmYpKTsKICAgIHZlYzMgYiA9IEZldGNoKHBvcyx2ZWMyKC0xLjAsIG9mZikpOwogICAgdmVjMyBjID0gRmV0Y2gocG9zLHZlYzIoIDAuMCwgb2ZmKSk7CiAgICB2ZWMzIGQgPSBGZXRjaChwb3MsdmVjMiggMS4wLCBvZmYpKTsKICAgIHZlYzMgZSA9IEZldGNoKHBvcyx2ZWMyKCAyLjAsIG9mZikpOwogICAgCiAgICBmbG9hdCBkc3QgPSBEaXN0KHBvcykueDsKICAgIC8vIENvbnZlcnQgZGlzdGFuY2UgdG8gd2VpZ2h0LgogICAgZmxvYXQgc2NhbGUgPSBoYXJkUGl4OwogICAgZmxvYXQgd2EgPSBHYXVzKGRzdCAtIDIuMCwgc2NhbGUpOwogICAgZmxvYXQgd2IgPSBHYXVzKGRzdCAtIDEuMCwgc2NhbGUpOwogICAgZmxvYXQgd2MgPSBHYXVzKGRzdCArIDAuMCwgc2NhbGUpOwogICAgZmxvYXQgd2QgPSBHYXVzKGRzdCArIDEuMCwgc2NhbGUpOwogICAgZmxvYXQgd2UgPSBHYXVzKGRzdCArIDIuMCwgc2NhbGUpOwogICAgCiAgICAvLyBSZXR1cm4gZmlsdGVyZWQgc2FtcGxlLgogICAgcmV0dXJuIChhKndhK2Iqd2IrYyp3YytkKndkK2Uqd2UpLyh3YSt3Yit3Yyt3ZCt3ZSk7Cn0KICAKLy8gNy10YXAgR2F1c3NpYW4gZmlsdGVyIGFsb25nIGhvcnogbGluZS4KdmVjMyBIb3J6Nyh2ZWMyIHBvcyxmbG9hdCBvZmYpCnsKICAgIHZlYzMgYSA9IEZldGNoKHBvcywgdmVjMigtMy4wLCBvZmYpKTsKICAgIHZlYzMgYiA9IEZldGNoKHBvcywgdmVjMigtMi4wLCBvZmYpKTsKICAgIHZlYzMgYyA9IEZldGNoKHBvcywgdmVjMigtMS4wLCBvZmYpKTsKICAgIHZlYzMgZCA9IEZldGNoKHBvcywgdmVjMiggMC4wLCBvZmYpKTsKICAgIHZlYzMgZSA9IEZldGNoKHBvcywgdmVjMiggMS4wLCBvZmYpKTsKICAgIHZlYzMgZiA9IEZldGNoKHBvcywgdmVjMiggMi4wLCBvZmYpKTsKICAgIHZlYzMgZyA9IEZldGNoKHBvcywgdmVjMiggMy4wLCBvZmYpKTsKCiAgICBmbG9hdCBkc3QgPSBEaXN0KHBvcykueDsKICAgIC8vIENvbnZlcnQgZGlzdGFuY2UgdG8gd2VpZ2h0LgogICAgZmxvYXQgc2NhbGUgPSBoYXJkQmxvb21QaXg7CiAgICBmbG9hdCB3YSA9IEdhdXMoZHN0IC0gMy4wLCBzY2FsZSk7CiAgICBmbG9hdCB3YiA9IEdhdXMoZHN0IC0gMi4wLCBzY2FsZSk7CiAgICBmbG9hdCB3YyA9IEdhdXMoZHN0IC0gMS4wLCBzY2FsZSk7CiAgICBmbG9hdCB3ZCA9IEdhdXMoZHN0ICsgMC4wLCBzY2FsZSk7CiAgICBmbG9hdCB3ZSA9IEdhdXMoZHN0ICsgMS4wLCBzY2FsZSk7CiAgICBmbG9hdCB3ZiA9IEdhdXMoZHN0ICsgMi4wLCBzY2FsZSk7CiAgICBmbG9hdCB3ZyA9IEdhdXMoZHN0ICsgMy4wLCBzY2FsZSk7CgogICAgLy8gUmV0dXJuIGZpbHRlcmVkIHNhbXBsZS4KICAgIHJldHVybiAoYSp3YStiKndiK2Mqd2MrZCp3ZCtlKndlK2Yqd2YrZyp3ZykvKHdhK3diK3djK3dkK3dlK3dmK3dnKTsKfQogIAovLyBSZXR1cm4gc2NhbmxpbmUgd2VpZ2h0LgpmbG9hdCBTY2FuKHZlYzIgcG9zLCBmbG9hdCBvZmYpCnsKICAgIGZsb2F0IGRzdCA9IERpc3QocG9zKS55OwoKICAgIHJldHVybiBHYXVzKGRzdCArIG9mZiwgaGFyZFNjYW4pOwp9CiAgCi8vIFJldHVybiBzY2FubGluZSB3ZWlnaHQgZm9yIGJsb29tLgpmbG9hdCBCbG9vbVNjYW4odmVjMiBwb3MsIGZsb2F0IG9mZikKewogICAgZmxvYXQgZHN0ID0gRGlzdChwb3MpLnk7CiAgICAKICAgIHJldHVybiBHYXVzKGRzdCArIG9mZiwgaGFyZEJsb29tU2Nhbik7Cn0KCi8vIEFsbG93IG5lYXJlc3QgdGhyZWUgbGluZXMgdG8gZWZmZWN0IHBpeGVsLgp2ZWMzIFRyaSh2ZWMyIHBvcykKewogICAgdmVjMyBhID0gSG9yejMocG9zLC0xLjApOwogICAgdmVjMyBiID0gSG9yejUocG9zLCAwLjApOwogICAgdmVjMyBjID0gSG9yejMocG9zLCAxLjApOwogICAgCiAgICBmbG9hdCB3YSA9IFNjYW4ocG9zLC0xLjApOyAKICAgIGZsb2F0IHdiID0gU2Nhbihwb3MsIDAuMCk7CiAgICBmbG9hdCB3YyA9IFNjYW4ocG9zLCAxLjApOwogICAgCiAgICByZXR1cm4gYSp3YSArIGIqd2IgKyBjKndjOwp9CiAgCi8vIFNtYWxsIGJsb29tLgp2ZWMzIEJsb29tKHZlYzIgcG9zKQp7CiAgICB2ZWMzIGEgPSBIb3J6NShwb3MsLTIuMCk7CiAgICB2ZWMzIGIgPSBIb3J6Nyhwb3MsLTEuMCk7CiAgICB2ZWMzIGMgPSBIb3J6Nyhwb3MsIDAuMCk7CiAgICB2ZWMzIGQgPSBIb3J6Nyhwb3MsIDEuMCk7CiAgICB2ZWMzIGUgPSBIb3J6NShwb3MsIDIuMCk7CgogICAgZmxvYXQgd2EgPSBCbG9vbVNjYW4ocG9zLC0yLjApOwogICAgZmxvYXQgd2IgPSBCbG9vbVNjYW4ocG9zLC0xLjApOyAKICAgIGZsb2F0IHdjID0gQmxvb21TY2FuKHBvcywgMC4wKTsKICAgIGZsb2F0IHdkID0gQmxvb21TY2FuKHBvcywgMS4wKTsKICAgIGZsb2F0IHdlID0gQmxvb21TY2FuKHBvcywgMi4wKTsKCiAgICByZXR1cm4gYSp3YStiKndiK2Mqd2MrZCp3ZCtlKndlOwp9CiAgCi8vIERpc3RvcnRpb24gb2Ygc2NhbmxpbmVzLCBhbmQgZW5kIG9mIHNjcmVlbiBhbHBoYS4KdmVjMiBXYXJwKHZlYzIgcG9zKQp7CiAgICBwb3MgID0gcG9zKjIuMC0xLjA7ICAgIAogICAgcG9zICo9IHZlYzIoMS4wICsgKHBvcy55KnBvcy55KSp3YXJwWCwgMS4wICsgKHBvcy54KnBvcy54KSp3YXJwWSk7CiAgICAKICAgIHJldHVybiBwb3MqMC41ICsgMC41Owp9CiAgCi8vIFNoYWRvdyBtYXNrLgp2ZWMzIE1hc2sodmVjMiBwb3MpCnsKICAgIHZlYzMgbWFzayA9IHZlYzMobWFza0RhcmssIG1hc2tEYXJrLCBtYXNrRGFyayk7CiAgCiAgICAvLyBWZXJ5IGNvbXByZXNzZWQgVFYgc3R5bGUgc2hhZG93IG1hc2suCiAgICBpZiAoc2hhZG93TWFzayA9PSAxLjApIAogICAgewogICAgICAgIGZsb2F0IGxpbmUgPSBtYXNrTGlnaHQ7CiAgICAgICAgZmxvYXQgb2RkID0gMC4wOwogICAgICAgIAogICAgICAgIGlmIChmcmFjdChwb3MueCowLjE2NjY2NjY2NikgPCAwLjUpIG9kZCA9IDEuMDsKICAgICAgICBpZiAoZnJhY3QoKHBvcy55ICsgb2RkKSAqIDAuNSkgPCAwLjUpIGxpbmUgPSBtYXNrRGFyazsgIAogICAgICAgIAogICAgICAgIHBvcy54ID0gZnJhY3QocG9zLngqMC4zMzMzMzMzMzMpOwoKICAgICAgICBpZiAgICAgIChwb3MueCA8IDAuMzMzKSBtYXNrLnIgPSBtYXNrTGlnaHQ7CiAgICAgICAgZWxzZSBpZiAocG9zLnggPCAwLjY2NikgbWFzay5nID0gbWFza0xpZ2h0OwogICAgICAgIGVsc2UgICAgICAgICAgICAgICAgICAgIG1hc2suYiA9IG1hc2tMaWdodDsKICAgICAgICBtYXNrKj1saW5lOyAgCiAgICB9IAoKICAgIC8vIEFwZXJ0dXJlLWdyaWxsZS4KICAgIGVsc2UgaWYgKHNoYWRvd01hc2sgPT0gMi4wKSAKICAgIHsKICAgICAgICBwb3MueCA9IGZyYWN0KHBvcy54KjAuMzMzMzMzMzMzKTsKCiAgICAgICAgaWYgICAgICAocG9zLnggPCAwLjMzMykgbWFzay5yID0gbWFza0xpZ2h0OwogICAgICAgIGVsc2UgaWYgKHBvcy54IDwgMC42NjYpIG1hc2suZyA9IG1hc2tMaWdodDsKICAgICAgICBlbHNlICAgICAgICAgICAgICAgICAgICBtYXNrLmIgPSBtYXNrTGlnaHQ7CiAgICB9IAoKICAgIC8vIFN0cmV0Y2hlZCBWR0Egc3R5bGUgc2hhZG93IG1hc2sgKHNhbWUgYXMgcHJpb3Igc2hhZGVycykuCiAgICBlbHNlIGlmIChzaGFkb3dNYXNrID09IDMuMCkgCiAgICB7CiAgICAgICAgcG9zLnggKz0gcG9zLnkqMy4wOwogICAgICAgIHBvcy54ICA9IGZyYWN0KHBvcy54KjAuMTY2NjY2NjY2KTsKCiAgICAgICAgaWYgICAgICAocG9zLnggPCAwLjMzMykgbWFzay5yID0gbWFza0xpZ2h0OwogICAgICAgIGVsc2UgaWYgKHBvcy54IDwgMC42NjYpIG1hc2suZyA9IG1hc2tMaWdodDsKICAgICAgICBlbHNlICAgICAgICAgICAgICAgICAgICBtYXNrLmIgPSBtYXNrTGlnaHQ7CiAgICB9CgogICAgLy8gVkdBIHN0eWxlIHNoYWRvdyBtYXNrLgogICAgZWxzZSBpZiAoc2hhZG93TWFzayA9PSA0LjApIAogICAgewogICAgICAgIHBvcy54eSAgPSBmbG9vcihwb3MueHkqdmVjMigxLjAsIDAuNSkpOwogICAgICAgIHBvcy54ICArPSBwb3MueSozLjA7CiAgICAgICAgcG9zLnggICA9IGZyYWN0KHBvcy54KjAuMTY2NjY2NjY2KTsKCiAgICAgICAgaWYgICAgICAocG9zLnggPCAwLjMzMykgbWFzay5yID0gbWFza0xpZ2h0OwogICAgICAgIGVsc2UgaWYgKHBvcy54IDwgMC42NjYpIG1hc2suZyA9IG1hc2tMaWdodDsKICAgICAgICBlbHNlICAgICAgICAgICAgICAgICAgICBtYXNrLmIgPSBtYXNrTGlnaHQ7CiAgICB9CgogICAgcmV0dXJuIG1hc2s7Cn0KCnZvaWQgbWFpbigpCnsKICAgIHZlYzIgcG9zID0gV2FycChURVgwLnh5KihUZXh0dXJlU2l6ZS54eS9JbnB1dFNpemUueHkpKSooSW5wdXRTaXplLnh5L1RleHR1cmVTaXplLnh5KTsKICAgIHZlYzMgb3V0Q29sb3IgPSBUcmkocG9zKTsKCiNpZmRlZiBET19CTE9PTQogICAgLy9BZGQgQmxvb20KICAgIG91dENvbG9yLnJnYiArPSBCbG9vbShwb3MpKmJsb29tQW1vdW50OwojZW5kaWYKCiAgICBpZiAoc2hhZG93TWFzayA+IDAuMCkKICAgICAgICBvdXRDb2xvci5yZ2IgKj0gTWFzayhnbF9GcmFnQ29vcmQueHkgKiAxLjAwMDAwMSk7CiAgICAKI2lmZGVmIEdMX0VTICAgIC8qIFRPRE8vRklYTUUgLSBoYWNreSBjbGFtcCBmaXggKi8KICAgIHZlYzIgYm9yZGVydGVzdCA9IChwb3MpOwogICAgaWYgKCBib3JkZXJ0ZXN0LnggPiAwLjAwMDEgJiYgYm9yZGVydGVzdC54IDwgMC45OTk5ICYmIGJvcmRlcnRlc3QueSA+IDAuMDAwMSAmJiBib3JkZXJ0ZXN0LnkgPCAwLjk5OTkpCiAgICAgICAgb3V0Q29sb3IucmdiID0gb3V0Q29sb3IucmdiOwogICAgZWxzZQogICAgICAgIG91dENvbG9yLnJnYiA9IHZlYzMoMC4wKTsKI2VuZGlmCiAgICBGcmFnQ29sb3IgPSB2ZWM0KFRvU3JnYihvdXRDb2xvci5yZ2IpLCAxLjApOwp9IAojZW5kaWYK", + }, + ], + }, + + //https://github.com/libretro/glsl-shaders/blob/master/crt/zfast-crt.glslp + "crt-zfast": { + "shader": { + "type": "text", + "value": "shaders = 1\n\nshader0 = zfast_crt.glsl\nfilter_linear0 = true", + }, + "resources": [ + { + "name": "zfast_crt.glsl", + "type": "base64", + "value": "Ly9Gb3IgdGVzdGluZyBjb21waWxhdGlvbg0KLy8jZGVmaW5lIEZSQUdNRU5UDQovLyNkZWZpbmUgVkVSVEVYDQoNCi8vVGhpcyBjYW4ndCBiZSBhbiBvcHRpb24gd2l0aG91dCBzbG93aW5nIHRoZSBzaGFkZXIgZG93bg0KLy9Db21tZW50IHRoaXMgb3V0IGZvciBhIGNvYXJzZXIgMyBwaXhlbCBtYXNrLi4ud2hpY2ggaXMgY3VycmVudGx5IGJyb2tlbg0KLy9vbiBTTkVTIENsYXNzaWMgRWRpdGlvbiBkdWUgdG8gTWFsaSA0MDAgZ3B1IHByZWNpc2lvbg0KI2RlZmluZSBGSU5FTUFTSw0KLy9Tb21lIGRyaXZlcnMgZG9uJ3QgcmV0dXJuIGJsYWNrIHdpdGggdGV4dHVyZSBjb29yZGluYXRlcyBvdXQgb2YgYm91bmRzDQovL1NORVMgQ2xhc3NpYyBpcyB0b28gc2xvdyB0byBibGFjayB0aGVzZSBhcmVhcyBvdXQgd2hlbiB1c2luZyBmdWxsc2NyZWVuDQovL292ZXJsYXlzLiAgQnV0IHlvdSBjYW4gdW5jb21tZW50IHRoZSBiZWxvdyB0byBibGFjayB0aGVtIG91dCBpZiBuZWNlc3NhcnkNCi8vI2RlZmluZSBCTEFDS19PVVRfQk9SREVSDQoNCi8vIFBhcmFtZXRlciBsaW5lcyBnbyBoZXJlOg0KI3ByYWdtYSBwYXJhbWV0ZXIgQkxVUlNDQUxFWCAiQmx1ciBBbW91bnQgWC1BeGlzIiAwLjMwIDAuMCAxLjAgMC4wNQ0KI3ByYWdtYSBwYXJhbWV0ZXIgTE9XTFVNU0NBTiAiU2NhbmxpbmUgRGFya25lc3MgLSBMb3ciIDYuMCAwLjAgMTAuMCAwLjUNCiNwcmFnbWEgcGFyYW1ldGVyIEhJTFVNU0NBTiAiU2NhbmxpbmUgRGFya25lc3MgLSBIaWdoIiA4LjAgMC4wIDUwLjAgMS4wDQojcHJhZ21hIHBhcmFtZXRlciBCUklHSFRCT09TVCAiRGFyayBQaXhlbCBCcmlnaHRuZXNzIEJvb3N0IiAxLjI1IDAuNSAxLjUgMC4wNQ0KI3ByYWdtYSBwYXJhbWV0ZXIgTUFTS19EQVJLICJNYXNrIEVmZmVjdCBBbW91bnQiIDAuMjUgMC4wIDEuMCAwLjA1DQojcHJhZ21hIHBhcmFtZXRlciBNQVNLX0ZBREUgIk1hc2svU2NhbmxpbmUgRmFkZSIgMC44IDAuMCAxLjAgMC4wNQ0KDQojaWYgZGVmaW5lZChWRVJURVgpDQoNCiNpZiBfX1ZFUlNJT05fXyA+PSAxMzANCiNkZWZpbmUgQ09NUEFUX1ZBUllJTkcgb3V0DQojZGVmaW5lIENPTVBBVF9BVFRSSUJVVEUgaW4NCiNkZWZpbmUgQ09NUEFUX1RFWFRVUkUgdGV4dHVyZQ0KI2Vsc2UNCiNkZWZpbmUgQ09NUEFUX1ZBUllJTkcgdmFyeWluZyANCiNkZWZpbmUgQ09NUEFUX0FUVFJJQlVURSBhdHRyaWJ1dGUgDQojZGVmaW5lIENPTVBBVF9URVhUVVJFIHRleHR1cmUyRA0KI2VuZGlmDQoNCiNpZmRlZiBHTF9FUw0KI2RlZmluZSBDT01QQVRfUFJFQ0lTSU9OIG1lZGl1bXANCiNlbHNlDQojZGVmaW5lIENPTVBBVF9QUkVDSVNJT04NCiNlbmRpZg0KDQpDT01QQVRfQVRUUklCVVRFIHZlYzQgVmVydGV4Q29vcmQ7DQpDT01QQVRfQVRUUklCVVRFIHZlYzQgQ09MT1I7DQpDT01QQVRfQVRUUklCVVRFIHZlYzQgVGV4Q29vcmQ7DQpDT01QQVRfVkFSWUlORyB2ZWM0IENPTDA7DQpDT01QQVRfVkFSWUlORyB2ZWM0IFRFWDA7DQpDT01QQVRfVkFSWUlORyBmbG9hdCBtYXNrRmFkZTsNCkNPTVBBVF9WQVJZSU5HIHZlYzIgaW52RGltczsNCg0KdmVjNCBfb1Bvc2l0aW9uMTsgDQp1bmlmb3JtIG1hdDQgTVZQTWF0cml4Ow0KdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIGludCBGcmFtZURpcmVjdGlvbjsNCnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBpbnQgRnJhbWVDb3VudDsNCnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiB2ZWMyIE91dHB1dFNpemU7DQp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gdmVjMiBUZXh0dXJlU2l6ZTsNCnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiB2ZWMyIElucHV0U2l6ZTsNCg0KLy8gY29tcGF0aWJpbGl0eSAjZGVmaW5lcw0KI2RlZmluZSB2VGV4Q29vcmQgVEVYMC54eQ0KI2RlZmluZSBTb3VyY2VTaXplIHZlYzQoVGV4dHVyZVNpemUsIDEuMCAvIFRleHR1cmVTaXplKSAvL2VpdGhlciBUZXh0dXJlU2l6ZSBvciBJbnB1dFNpemUNCiNkZWZpbmUgT3V0U2l6ZSB2ZWM0KE91dHB1dFNpemUsIDEuMCAvIE91dHB1dFNpemUpDQoNCiNpZmRlZiBQQVJBTUVURVJfVU5JRk9STQ0KLy8gQWxsIHBhcmFtZXRlciBmbG9hdHMgbmVlZCB0byBoYXZlIENPTVBBVF9QUkVDSVNJT04gaW4gZnJvbnQgb2YgdGhlbQ0KdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIGZsb2F0IEJMVVJTQ0FMRVg7DQovL3VuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCBCTFVSU0NBTEVZOw0KdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIGZsb2F0IExPV0xVTVNDQU47DQp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gZmxvYXQgSElMVU1TQ0FOOw0KdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIGZsb2F0IEJSSUdIVEJPT1NUOw0KdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIGZsb2F0IE1BU0tfREFSSzsNCnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCBNQVNLX0ZBREU7DQojZWxzZQ0KI2RlZmluZSBCTFVSU0NBTEVYIDAuNDUNCi8vI2RlZmluZSBCTFVSU0NBTEVZIDAuMjANCiNkZWZpbmUgTE9XTFVNU0NBTiA1LjANCiNkZWZpbmUgSElMVU1TQ0FOIDEwLjANCiNkZWZpbmUgQlJJR0hUQk9PU1QgMS4yNQ0KI2RlZmluZSBNQVNLX0RBUksgMC4yNQ0KI2RlZmluZSBNQVNLX0ZBREUgMC44DQojZW5kaWYNCg0Kdm9pZCBtYWluKCkNCnsNCiAgICBnbF9Qb3NpdGlvbiA9IE1WUE1hdHJpeCAqIFZlcnRleENvb3JkOw0KCQ0KCVRFWDAueHkgPSBUZXhDb29yZC54eSoxLjAwMDE7DQoJbWFza0ZhZGUgPSAwLjMzMzMqTUFTS19GQURFOw0KCWludkRpbXMgPSAxLjAvVGV4dHVyZVNpemUueHk7DQp9DQoNCiNlbGlmIGRlZmluZWQoRlJBR01FTlQpDQoNCiNpZmRlZiBHTF9FUw0KI2lmZGVmIEdMX0ZSQUdNRU5UX1BSRUNJU0lPTl9ISUdIDQpwcmVjaXNpb24gaGlnaHAgZmxvYXQ7DQojZWxzZQ0KcHJlY2lzaW9uIG1lZGl1bXAgZmxvYXQ7DQojZW5kaWYNCiNkZWZpbmUgQ09NUEFUX1BSRUNJU0lPTiBtZWRpdW1wDQojZWxzZQ0KI2RlZmluZSBDT01QQVRfUFJFQ0lTSU9ODQojZW5kaWYNCg0KI2lmIF9fVkVSU0lPTl9fID49IDEzMA0KI2RlZmluZSBDT01QQVRfVkFSWUlORyBpbg0KI2RlZmluZSBDT01QQVRfVEVYVFVSRSB0ZXh0dXJlDQpvdXQgQ09NUEFUX1BSRUNJU0lPTiB2ZWM0IEZyYWdDb2xvcjsNCiNlbHNlDQojZGVmaW5lIENPTVBBVF9WQVJZSU5HIHZhcnlpbmcNCiNkZWZpbmUgRnJhZ0NvbG9yIGdsX0ZyYWdDb2xvcg0KI2RlZmluZSBDT01QQVRfVEVYVFVSRSB0ZXh0dXJlMkQNCiNlbmRpZg0KDQp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gaW50IEZyYW1lRGlyZWN0aW9uOw0KdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIGludCBGcmFtZUNvdW50Ow0KdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIHZlYzIgT3V0cHV0U2l6ZTsNCnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiB2ZWMyIFRleHR1cmVTaXplOw0KdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIHZlYzIgSW5wdXRTaXplOw0KdW5pZm9ybSBzYW1wbGVyMkQgVGV4dHVyZTsNCkNPTVBBVF9WQVJZSU5HIHZlYzQgVEVYMDsNCkNPTVBBVF9WQVJZSU5HIGZsb2F0IG1hc2tGYWRlOw0KQ09NUEFUX1ZBUllJTkcgdmVjMiBpbnZEaW1zOw0KDQovLyBjb21wYXRpYmlsaXR5ICNkZWZpbmVzDQojZGVmaW5lIFNvdXJjZSBUZXh0dXJlDQojZGVmaW5lIHZUZXhDb29yZCBURVgwLnh5DQojZGVmaW5lIHRleHR1cmUoYywgZCkgQ09NUEFUX1RFWFRVUkUoYywgZCkNCiNkZWZpbmUgU291cmNlU2l6ZSB2ZWM0KFRleHR1cmVTaXplLCAxLjAgLyBUZXh0dXJlU2l6ZSkgLy9laXRoZXIgVGV4dHVyZVNpemUgb3IgSW5wdXRTaXplDQojZGVmaW5lIE91dFNpemUgdmVjNChPdXRwdXRTaXplLCAxLjAgLyBPdXRwdXRTaXplKQ0KDQojaWZkZWYgUEFSQU1FVEVSX1VOSUZPUk0NCi8vIEFsbCBwYXJhbWV0ZXIgZmxvYXRzIG5lZWQgdG8gaGF2ZSBDT01QQVRfUFJFQ0lTSU9OIGluIGZyb250IG9mIHRoZW0NCnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCBCTFVSU0NBTEVYOw0KLy91bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gZmxvYXQgQkxVUlNDQUxFWTsNCnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCBMT1dMVU1TQ0FOOw0KdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIGZsb2F0IEhJTFVNU0NBTjsNCnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCBCUklHSFRCT09TVDsNCnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCBNQVNLX0RBUks7DQp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gZmxvYXQgTUFTS19GQURFOw0KI2Vsc2UNCiNkZWZpbmUgQkxVUlNDQUxFWCAwLjQ1DQovLyNkZWZpbmUgQkxVUlNDQUxFWSAwLjIwDQojZGVmaW5lIExPV0xVTVNDQU4gNS4wDQojZGVmaW5lIEhJTFVNU0NBTiAxMC4wDQojZGVmaW5lIEJSSUdIVEJPT1NUIDEuMjUNCiNkZWZpbmUgTUFTS19EQVJLIDAuMjUNCiNkZWZpbmUgTUFTS19GQURFIDAuOA0KI2VuZGlmDQoNCnZvaWQgbWFpbigpDQp7DQoNCgkvL1RoaXMgaXMganVzdCBsaWtlICJRdWlsZXogU2NhbGluZyIgYnV0IHNoYXJwZXINCglDT01QQVRfUFJFQ0lTSU9OIHZlYzIgcCA9IHZUZXhDb29yZCAqIFRleHR1cmVTaXplOw0KCUNPTVBBVF9QUkVDSVNJT04gdmVjMiBpID0gZmxvb3IocCkgKyAwLjUwOw0KCUNPTVBBVF9QUkVDSVNJT04gdmVjMiBmID0gcCAtIGk7DQoJcCA9IChpICsgNC4wKmYqZipmKSppbnZEaW1zOw0KCXAueCA9IG1peCggcC54ICwgdlRleENvb3JkLngsIEJMVVJTQ0FMRVgpOw0KCUNPTVBBVF9QUkVDSVNJT04gZmxvYXQgWSA9IGYueSpmLnk7DQoJQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCBZWSA9IFkqWTsNCiNkZWZpbmUgcmF0aW8gU291cmNlU2l6ZS54L0lucHV0U2l6ZS54CQ0KI2lmIGRlZmluZWQoRklORU1BU0spIA0KCUNPTVBBVF9QUkVDSVNJT04gZmxvYXQgd2hpY2htYXNrID0gZmxvb3IodlRleENvb3JkLngqT3V0cHV0U2l6ZS54KnJhdGlvKSotMC41Ow0KCUNPTVBBVF9QUkVDSVNJT04gZmxvYXQgbWFzayA9IDEuMCArIGZsb2F0KGZyYWN0KHdoaWNobWFzaykgPCAwLjUpICogLU1BU0tfREFSSzsNCiNlbHNlDQoJQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCB3aGljaG1hc2sgPSBmbG9vcih2VGV4Q29vcmQueCpPdXRwdXRTaXplLngqcmF0aW8pKi0wLjMzMzM7DQoJQ09NUEFUX1BSRUNJU0lPTiBmbG9hdCBtYXNrID0gMS4wICsgZmxvYXQoZnJhY3Qod2hpY2htYXNrKSA8IDAuMzMzMykgKiAtTUFTS19EQVJLOw0KI2VuZGlmDQoJQ09NUEFUX1BSRUNJU0lPTiB2ZWMzIGNvbG91ciA9IENPTVBBVF9URVhUVVJFKFNvdXJjZSwgcCkucmdiOw0KCQ0KCUNPTVBBVF9QUkVDSVNJT04gZmxvYXQgc2NhbkxpbmVXZWlnaHQgPSAoQlJJR0hUQk9PU1QgLSBMT1dMVU1TQ0FOKihZIC0gMi4wNSpZWSkpOw0KCUNPTVBBVF9QUkVDSVNJT04gZmxvYXQgc2NhbkxpbmVXZWlnaHRCID0gMS4wIC0gSElMVU1TQ0FOKihZWS0yLjgqWVkqWSk7CQ0KCQ0KI2lmIGRlZmluZWQoQkxBQ0tfT1VUX0JPUkRFUikNCgljb2xvdXIucmdiKj1mbG9hdCh0Yy54ID4gMC4wKSpmbG9hdCh0Yy55ID4gMC4wKTsgLy93aHkgZG9lc24ndCB0aGUgZHJpdmVyIGRvIHRoZSByaWdodCB0aGluZz8NCiNlbmRpZg0KDQoJRnJhZ0NvbG9yLnJnYmEgPSB2ZWM0KGNvbG91ci5yZ2IqbWl4KHNjYW5MaW5lV2VpZ2h0Km1hc2ssIHNjYW5MaW5lV2VpZ2h0QiwgZG90KGNvbG91ci5yZ2IsdmVjMyhtYXNrRmFkZSkpKSwxLjApOw0KCQ0KfSANCiNlbmRpZg0K", + }, + ], + }, + + //https://github.com/libretro/glsl-shaders/blob/master/crt/yeetron.glslp + "crt-yeetron": { + "shader": { + "type": "text", + "value": "shaders = 1\n\nshader0 = yeetron.glsl\nfilter_linear0 = false\n", + }, + "resources": [ + { + "name": "yeetron.glsl", + "type": "base64", + "value": "Ly8gcG9ydGVkIGZyb20gUmVTaGFkZQoKI2lmIGRlZmluZWQoVkVSVEVYKQoKI2lmIF9fVkVSU0lPTl9fID49IDEzMAojZGVmaW5lIENPTVBBVF9WQVJZSU5HIG91dAojZGVmaW5lIENPTVBBVF9BVFRSSUJVVEUgaW4KI2RlZmluZSBDT01QQVRfVEVYVFVSRSB0ZXh0dXJlCiNlbHNlCiNkZWZpbmUgQ09NUEFUX1ZBUllJTkcgdmFyeWluZyAKI2RlZmluZSBDT01QQVRfQVRUUklCVVRFIGF0dHJpYnV0ZSAKI2RlZmluZSBDT01QQVRfVEVYVFVSRSB0ZXh0dXJlMkQKI2VuZGlmCgojaWZkZWYgR0xfRVMKI2RlZmluZSBDT01QQVRfUFJFQ0lTSU9OIG1lZGl1bXAKI2Vsc2UKI2RlZmluZSBDT01QQVRfUFJFQ0lTSU9OCiNlbmRpZgoKQ09NUEFUX0FUVFJJQlVURSB2ZWM0IFZlcnRleENvb3JkOwpDT01QQVRfQVRUUklCVVRFIHZlYzQgQ09MT1I7CkNPTVBBVF9BVFRSSUJVVEUgdmVjNCBUZXhDb29yZDsKQ09NUEFUX1ZBUllJTkcgdmVjNCBDT0wwOwpDT01QQVRfVkFSWUlORyB2ZWM0IFRFWDA7Cgp2ZWM0IF9vUG9zaXRpb24xOyAKdW5pZm9ybSBtYXQ0IE1WUE1hdHJpeDsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIGludCBGcmFtZURpcmVjdGlvbjsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIGludCBGcmFtZUNvdW50Owp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gdmVjMiBPdXRwdXRTaXplOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gdmVjMiBUZXh0dXJlU2l6ZTsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIHZlYzIgSW5wdXRTaXplOwoKLy8gY29tcGF0aWJpbGl0eSAjZGVmaW5lcwojZGVmaW5lIHZUZXhDb29yZCBURVgwLnh5CiNkZWZpbmUgU291cmNlU2l6ZSB2ZWM0KFRleHR1cmVTaXplLCAxLjAgLyBUZXh0dXJlU2l6ZSkgLy9laXRoZXIgVGV4dHVyZVNpemUgb3IgSW5wdXRTaXplCiNkZWZpbmUgT3V0U2l6ZSB2ZWM0KE91dHB1dFNpemUsIDEuMCAvIE91dHB1dFNpemUpCgp2b2lkIG1haW4oKQp7CiAgICBnbF9Qb3NpdGlvbiA9IE1WUE1hdHJpeCAqIFZlcnRleENvb3JkOwogICAgVEVYMC54eSA9IFRleENvb3JkLnh5Owp9CgojZWxpZiBkZWZpbmVkKEZSQUdNRU5UKQoKI2lmZGVmIEdMX0VTCiNpZmRlZiBHTF9GUkFHTUVOVF9QUkVDSVNJT05fSElHSApwcmVjaXNpb24gaGlnaHAgZmxvYXQ7CiNlbHNlCnByZWNpc2lvbiBtZWRpdW1wIGZsb2F0OwojZW5kaWYKI2RlZmluZSBDT01QQVRfUFJFQ0lTSU9OIG1lZGl1bXAKI2Vsc2UKI2RlZmluZSBDT01QQVRfUFJFQ0lTSU9OCiNlbmRpZgoKI2lmIF9fVkVSU0lPTl9fID49IDEzMAojZGVmaW5lIENPTVBBVF9WQVJZSU5HIGluCiNkZWZpbmUgQ09NUEFUX1RFWFRVUkUgdGV4dHVyZQpvdXQgQ09NUEFUX1BSRUNJU0lPTiB2ZWM0IEZyYWdDb2xvcjsKI2Vsc2UKI2RlZmluZSBDT01QQVRfVkFSWUlORyB2YXJ5aW5nCiNkZWZpbmUgRnJhZ0NvbG9yIGdsX0ZyYWdDb2xvcgojZGVmaW5lIENPTVBBVF9URVhUVVJFIHRleHR1cmUyRAojZW5kaWYKCnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBpbnQgRnJhbWVEaXJlY3Rpb247CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBpbnQgRnJhbWVDb3VudDsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIHZlYzIgT3V0cHV0U2l6ZTsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIHZlYzIgVGV4dHVyZVNpemU7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiB2ZWMyIElucHV0U2l6ZTsKdW5pZm9ybSBzYW1wbGVyMkQgVGV4dHVyZTsKQ09NUEFUX1ZBUllJTkcgdmVjNCBURVgwOwoKLy8gY29tcGF0aWJpbGl0eSAjZGVmaW5lcwojZGVmaW5lIFNvdXJjZSBUZXh0dXJlCiNkZWZpbmUgdlRleENvb3JkIFRFWDAueHkKCiNkZWZpbmUgU291cmNlU2l6ZSB2ZWM0KFRleHR1cmVTaXplLCAxLjAgLyBUZXh0dXJlU2l6ZSkgLy9laXRoZXIgVGV4dHVyZVNpemUgb3IgSW5wdXRTaXplCiNkZWZpbmUgT3V0U2l6ZSB2ZWM0KE91dHB1dFNpemUsIDEuMCAvIE91dHB1dFNpemUpCgp2ZWM0IGNtcCh2ZWM0IHNyYzAsIHZlYzQgc3JjMSwgdmVjNCBzcmMyKSB7CglyZXR1cm4gdmVjNCgKCQlzcmMwLnggPj0gMC4wID8gc3JjMS54IDogc3JjMi54LAoJCXNyYzAueSA+PSAwLjAgPyBzcmMxLnkgOiBzcmMyLnksCgkJc3JjMC56ID49IDAuMCA/IHNyYzEueiA6IHNyYzIueiwKCQlzcmMwLncgPj0gMC4wID8gc3JjMS53IDogc3JjMi53CgkpOwp9CgojZGVmaW5lIHNhdHVyYXRlKGMpIGNsYW1wKGMsIDAuMCwgMS4wKQoKdm9pZCBtYWluKCkKewoJLy9EZWNsYXJlIHBhcmFtZXRlcnMKCS8vcGl4ZWxTaXplCgl2ZWM0IGMwID0gSW5wdXRTaXplLnh5eXk7CgkvL3RleHR1cmVTaXplCgl2ZWM0IGMxID0gU291cmNlU2l6ZTsKCS8vdmlld1NpemUKCXZlYzQgYzIgPSBPdXRTaXplOwogICAKCS8vRGVjbGFyZSBjb25zdGFudHMKCWNvbnN0IHZlYzQgYzMgPSB2ZWM0KDEuNSwgMC44MDAwMDAwMTIsIDEuMjUsIDAuNzUpOwoJY29uc3QgdmVjNCBjNCA9IHZlYzQoNi4yODMxODU0OCwgLTMuMTQxNTkyNzQsIDAuMjUsIC0wLjI1KTsKCWNvbnN0IHZlYzQgYzUgPSB2ZWM0KDEuLCAwLjUsIDcyMC4sIDMuKTsKCWNvbnN0IHZlYzQgYzYgPSB2ZWM0KDAuMTY2NjY2NjcyLCAtMC4zMzMwMDAwMDQsIC0wLjY2NjAwMDAwOSwgMC44OTk5OTk5NzYpOwoJY29uc3QgdmVjNCBjNyA9IHZlYzQoMC44OTk5OTk5NzYsIDEuMTAwMDAwMDIsIDAuLCAwLik7Cgljb25zdCB2ZWM0IGM4ID0gdmVjNCgtMC41LCAtMC4yNSwgMi4sIDAuNSk7CgoJLy9EZWNsYXJlIHJlZ2lzdGVycwoJdmVjNCByMCwgcjEsIHIyLCByMywgcjQsIHI1LCByNiwgcjcsIHI4LCByOTsKCgkvL0NvZGUgc3RhcnRzIGhlcmUKCXZlYzQgdjAgPSB2VGV4Q29vcmQueHl5eTsKCS8vZGNsXzJkIHMwCglyMC54ID0gMS4wIC8gYzAueDsKCXIwLnkgPSAxLjAgLyBjMC55OwoJcjAueHkgPSAocjAgKiBjMSkueHk7CglyMC54eSA9IChyMCAqIHYwKS54eTsKCXIwLnh5ID0gKHIwICogYzIpLnh5OwoJcjAuencgPSBmcmFjdChyMC54eXh5KS56dzsKCXIwLnh5ID0gKC1yMC56d3p3ICsgcjApLnh5OwoJcjAueHkgPSAocjAgKyBjOC53d3d3KS54eTsKCXIwLnggPSByMC55ICogYzUudyArIHIwLng7CglyMC54ID0gcjAueCAqIGM2Lng7CglyMC54ID0gZnJhY3QocjAueCk7CglyMC54eSA9IChyMC54eHh4ICsgYzYueXp6dykueHk7CglyMS55eiA9IChyMC55ID49IDAuMCA/IGM3Lnh4eXcgOiBjNy54eXh3KS55ejsKCXIxLnggPSBjNi53OwoJcjAueHl6ID0gKHIwLnggPj0gMC4wID8gcjEgOiBjNy55eHh3KS54eXo7CglyMS54eSA9IChjMSAqIHYwKS54eTsKCXIwLncgPSByMS55ICogYzgudyArIGM4Lnc7CglyMC53ID0gZnJhY3QocjAudyk7CglyMC53ID0gcjAudyAqIGM0LnggKyBjNC55OwoJcjIueSA9IHNpbihyMC53KTsKCXIxLnp3ID0gKGFicyhyMikueXl5eSArIGM0KS56dzsKCXIxLnogPSBjbGFtcChyMS56LCAwLjAsIDEuMCk7CglyMC53ID0gcjEudyA+PSAwLjAgPyByMS56IDogYzgudzsKCXIyID0gZnJhY3QocjEueHl4eSk7CglyMS54eSA9IChyMSArIC1yMi56d3p3KS54eTsKCXIyID0gcjIgKyBjOC54eHl5OwoJcjEuencgPSAocjEueHl4eSArIGM4Lnd3d3cpLnp3OwoJcjEuencgPSAodjAueHl4eSAqIC1jMS54eXh5ICsgcjEpLnp3OwoJcjEudyA9IHIxLncgKyByMS53OwoJcjEueiA9IHIxLnogKiBjOC53OwoJcjEueiA9IC1hYnMocjEpLnogKyBjMy54OwoJcjMueCA9IG1heChjMy55LCByMS56KTsKCXI0LnggPSBtaW4ocjMueCwgYzMueik7CglyMS56dyA9ICgtYWJzKHIxKS53d3d3ICsgYzMpLnp3OwoJcjEueiA9IGNsYW1wKHIxLnosIDAuMCwgMS4wKTsKCXIxLnogPSByMS53ID49IDAuMCA/IHIxLnogOiBjOC53OwoJcjQueSA9IHIwLncgKyByMS56OwoJcjAudyA9IHIwLncgKiByNC54OwoJcjEueiA9IHIxLnogKiByNC54OwoJcjMueHkgPSAocjQgKiBjNSkueHk7CglyMS53ID0gcjMueSAqIHIzLng7CglyMi56ID0gY21wKHIyLCByMi54eXh5LCBjOC55eXl5KS56OwoJcjMueHkgPSBtYXgoYzgueXl5eSwgLXIyLnp3encpLnh5OwoJcjIueHkgPSAocjIgKyByMykueHk7CglyMS54eSA9IChyMiAqIGM4Lnp6enogKyByMSkueHk7CglyMS54eSA9IChyMSArIGM4Lnd3d3cpLnh5OwoJcjIueCA9IDEuMCAvIGMxLng7CglyMi55ID0gMS4wIC8gYzEueTsKCXIxLnh5ID0gKHIxICogcjIpLnh5OwoJcjIgPSBDT01QQVRfVEVYVFVSRShTb3VyY2UsIHIxLnh5KTsKCXIzLnggPSByMC53ICogcjIueDsKCXIzLnl6ID0gKHIxLnh6d3cgKiByMikueXo7CglGcmFnQ29sb3IudyA9IHIyLnc7CglyMC54eXogPSAocjAgKiByMykueHl6OwoJcjEueiA9IGM1Lno7CglyMC53ID0gcjEueiArIC1jMi55OwoJRnJhZ0NvbG9yLnh5eiA9IChyMC53ID49IDAuMCA/IHIzIDogcjApLnh5ejsKfSAKI2VuZGlmCg==", + }, + ], + }, + + //https://github.com/libretro/glsl-shaders/blob/master/cubic/bicubic.glslp + "bicubic": { + "shader": { + "type": "text", + "value": "shaders = 1\n\nshader0 = bicubic.glsl\nfilter_linear0 = false", + }, + "resources": [ + { + "name": "bicubic.glsl", + "type": "base64", + "value": "Ly8gRGVmYXVsdCB0byBNaXRjaGVsLU5ldHJhdmFsaSBjb2VmZmljaWVudHMgZm9yIGJlc3QgcHN5Y2hvdmlzdWFsIHJlc3VsdAovLyBiaWN1YmljLXNoYXJwIGlzIEIgPSAwLjEgYW5kIEMgPSAwLjUKLy8gYmljdWJpYy1zaGFycGVyIGlzIEIgPSAwLjAgYW5kIEMgPSAwLjc1CiNwcmFnbWEgcGFyYW1ldGVyIEIgIkJpY3ViaWMgQ29lZmYgQiIgMC4zMyAwLjAgMS4wIDAuMDEKI3ByYWdtYSBwYXJhbWV0ZXIgQyAiQmljdWJpYyBDb2VmZiBDIiAwLjMzIDAuMCAxLjAgMC4wMQoKI2lmIGRlZmluZWQoVkVSVEVYKQoKI2lmIF9fVkVSU0lPTl9fID49IDEzMAojZGVmaW5lIENPTVBBVF9WQVJZSU5HIG91dAojZGVmaW5lIENPTVBBVF9BVFRSSUJVVEUgaW4KI2RlZmluZSBDT01QQVRfVEVYVFVSRSB0ZXh0dXJlCiNlbHNlCiNkZWZpbmUgQ09NUEFUX1ZBUllJTkcgdmFyeWluZyAKI2RlZmluZSBDT01QQVRfQVRUUklCVVRFIGF0dHJpYnV0ZSAKI2RlZmluZSBDT01QQVRfVEVYVFVSRSB0ZXh0dXJlMkQKI2VuZGlmCgojaWZkZWYgR0xfRVMKI2RlZmluZSBDT01QQVRfUFJFQ0lTSU9OIG1lZGl1bXAKI2Vsc2UKI2RlZmluZSBDT01QQVRfUFJFQ0lTSU9OCiNlbmRpZgoKQ09NUEFUX0FUVFJJQlVURSB2ZWM0IFZlcnRleENvb3JkOwpDT01QQVRfQVRUUklCVVRFIHZlYzQgVGV4Q29vcmQ7CkNPTVBBVF9WQVJZSU5HIHZlYzQgVEVYMDsKCnVuaWZvcm0gbWF0NCBNVlBNYXRyaXg7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBpbnQgRnJhbWVEaXJlY3Rpb247CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBpbnQgRnJhbWVDb3VudDsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIHZlYzIgT3V0cHV0U2l6ZTsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIHZlYzIgVGV4dHVyZVNpemU7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiB2ZWMyIElucHV0U2l6ZTsKCi8vIGNvbXBhdGliaWxpdHkgI2RlZmluZXMKI2RlZmluZSB2VGV4Q29vcmQgVEVYMC54eQojZGVmaW5lIFNvdXJjZVNpemUgdmVjNChUZXh0dXJlU2l6ZSwgMS4wIC8gVGV4dHVyZVNpemUpIC8vZWl0aGVyIFRleHR1cmVTaXplIG9yIElucHV0U2l6ZQojZGVmaW5lIE91dFNpemUgdmVjNChPdXRwdXRTaXplLCAxLjAgLyBPdXRwdXRTaXplKQoKdm9pZCBtYWluKCkKewogICBnbF9Qb3NpdGlvbiA9IE1WUE1hdHJpeCAqIFZlcnRleENvb3JkOwogICBURVgwLnh5ID0gVGV4Q29vcmQueHk7Cn0KCiNlbGlmIGRlZmluZWQoRlJBR01FTlQpCgojaWZkZWYgR0xfRVMKI2lmZGVmIEdMX0ZSQUdNRU5UX1BSRUNJU0lPTl9ISUdICnByZWNpc2lvbiBoaWdocCBmbG9hdDsKI2Vsc2UKcHJlY2lzaW9uIG1lZGl1bXAgZmxvYXQ7CiNlbmRpZgojZGVmaW5lIENPTVBBVF9QUkVDSVNJT04gbWVkaXVtcAojZWxzZQojZGVmaW5lIENPTVBBVF9QUkVDSVNJT04KI2VuZGlmCgojaWYgX19WRVJTSU9OX18gPj0gMTMwCiNkZWZpbmUgQ09NUEFUX1ZBUllJTkcgaW4KI2RlZmluZSBDT01QQVRfVEVYVFVSRSB0ZXh0dXJlCm91dCBDT01QQVRfUFJFQ0lTSU9OIHZlYzQgRnJhZ0NvbG9yOwojZWxzZQojZGVmaW5lIENPTVBBVF9WQVJZSU5HIHZhcnlpbmcKI2RlZmluZSBGcmFnQ29sb3IgZ2xfRnJhZ0NvbG9yCiNkZWZpbmUgQ09NUEFUX1RFWFRVUkUgdGV4dHVyZTJECiNlbmRpZgoKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIGludCBGcmFtZURpcmVjdGlvbjsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIGludCBGcmFtZUNvdW50Owp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gdmVjMiBPdXRwdXRTaXplOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gdmVjMiBUZXh0dXJlU2l6ZTsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIHZlYzIgSW5wdXRTaXplOwp1bmlmb3JtIHNhbXBsZXIyRCBUZXh0dXJlOwpDT01QQVRfVkFSWUlORyB2ZWM0IFRFWDA7CgovLyBjb21wYXRpYmlsaXR5ICNkZWZpbmVzCiNkZWZpbmUgU291cmNlIFRleHR1cmUKI2RlZmluZSB2VGV4Q29vcmQgVEVYMC54eQoKI2RlZmluZSBTb3VyY2VTaXplIHZlYzQoVGV4dHVyZVNpemUsIDEuMCAvIFRleHR1cmVTaXplKSAvL2VpdGhlciBUZXh0dXJlU2l6ZSBvciBJbnB1dFNpemUKI2RlZmluZSBPdXRTaXplIHZlYzQoT3V0cHV0U2l6ZSwgMS4wIC8gT3V0cHV0U2l6ZSkKCiNpZmRlZiBQQVJBTUVURVJfVU5JRk9STQp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gZmxvYXQgQiwgQzsKI2Vsc2UKI2RlZmluZSBCIDAuMzMzMwojZGVmaW5lIEMgMC4zMzMzCiNlbmRpZgoKZmxvYXQgd2VpZ2h0KGZsb2F0IHgpCnsKCWZsb2F0IGF4ID0gYWJzKHgpOwoKCWlmIChheCA8IDEuMCkKCXsKCQlyZXR1cm4KCQkJKAoJCQkgcG93KHgsIDIuMCkgKiAoKDEyLjAgLSA5LjAgKiBCIC0gNi4wICogQykgKiBheCArICgtMTguMCArIDEyLjAgKiBCICsgNi4wICogQykpICsKCQkJICg2LjAgLSAyLjAgKiBCKQoJCQkpIC8gNi4wOwoJfQoJZWxzZSBpZiAoKGF4ID49IDEuMCkgJiYgKGF4IDwgMi4wKSkKCXsKCQlyZXR1cm4KCQkJKAoJCQkgcG93KHgsIDIuMCkgKiAoKC1CIC0gNi4wICogQykgKiBheCArICg2LjAgKiBCICsgMzAuMCAqIEMpKSArCgkJCSAoLTEyLjAgKiBCIC0gNDguMCAqIEMpICogYXggKyAoOC4wICogQiArIDI0LjAgKiBDKQoJCQkpIC8gNi4wOwoJfQoJZWxzZQoJewoJCXJldHVybiAwLjA7Cgl9Cn0KCQp2ZWM0IHdlaWdodDQoZmxvYXQgeCkKewoJcmV0dXJuIHZlYzQoCgkJCXdlaWdodCh4IC0gMi4wKSwKCQkJd2VpZ2h0KHggLSAxLjApLAoJCQl3ZWlnaHQoeCksCgkJCXdlaWdodCh4ICsgMS4wKSk7Cn0KCnZlYzMgcGl4ZWwoZmxvYXQgeHBvcywgZmxvYXQgeXBvcywgc2FtcGxlcjJEIHRleCkKewoJcmV0dXJuIENPTVBBVF9URVhUVVJFKHRleCwgdmVjMih4cG9zLCB5cG9zKSkucmdiOwp9Cgp2ZWMzIGxpbmVfcnVuKGZsb2F0IHlwb3MsIHZlYzQgeHBvcywgdmVjNCBsaW5ldGFwcywgc2FtcGxlcjJEIHRleCkKewoJcmV0dXJuCgkJcGl4ZWwoeHBvcy5yLCB5cG9zLCB0ZXgpICogbGluZXRhcHMuciArCgkJcGl4ZWwoeHBvcy5nLCB5cG9zLCB0ZXgpICogbGluZXRhcHMuZyArCgkJcGl4ZWwoeHBvcy5iLCB5cG9zLCB0ZXgpICogbGluZXRhcHMuYiArCgkJcGl4ZWwoeHBvcy5hLCB5cG9zLCB0ZXgpICogbGluZXRhcHMuYTsKfQoKdm9pZCBtYWluKCkKewogICAgICAgIHZlYzIgc3RlcHh5ID0gdmVjMigxLjAvU291cmNlU2l6ZS54LCAxLjAvU291cmNlU2l6ZS55KTsKICAgICAgICB2ZWMyIHBvcyA9IHZUZXhDb29yZC54eSArIHN0ZXB4eSAqIDAuNTsKICAgICAgICB2ZWMyIGYgPSBmcmFjdChwb3MgLyBzdGVweHkpOwoJCQoJdmVjNCBsaW5ldGFwcyAgID0gd2VpZ2h0NCgxLjAgLSBmLngpOwoJdmVjNCBjb2x1bW50YXBzID0gd2VpZ2h0NCgxLjAgLSBmLnkpOwoKCS8vbWFrZSBzdXJlIGFsbCB0YXBzIGFkZGVkIHRvZ2V0aGVyIGlzIGV4YWN0bHkgMS4wLCBvdGhlcndpc2Ugc29tZSAodmVyeSBzbWFsbCkgZGlzdG9ydGlvbiBjYW4gb2NjdXIKCWxpbmV0YXBzIC89IGxpbmV0YXBzLnIgKyBsaW5ldGFwcy5nICsgbGluZXRhcHMuYiArIGxpbmV0YXBzLmE7Cgljb2x1bW50YXBzIC89IGNvbHVtbnRhcHMuciArIGNvbHVtbnRhcHMuZyArIGNvbHVtbnRhcHMuYiArIGNvbHVtbnRhcHMuYTsKCgl2ZWMyIHh5c3RhcnQgPSAoLTEuNSAtIGYpICogc3RlcHh5ICsgcG9zOwoJdmVjNCB4cG9zID0gdmVjNCh4eXN0YXJ0LngsIHh5c3RhcnQueCArIHN0ZXB4eS54LCB4eXN0YXJ0LnggKyBzdGVweHkueCAqIDIuMCwgeHlzdGFydC54ICsgc3RlcHh5LnggKiAzLjApOwoKCi8vIGZpbmFsIHN1bSBhbmQgd2VpZ2h0IG5vcm1hbGl6YXRpb24KICAgdmVjNCBmaW5hbCA9IHZlYzQobGluZV9ydW4oeHlzdGFydC55ICAgICAgICAgICAgICAgICAsIHhwb3MsIGxpbmV0YXBzLCBTb3VyY2UpICogY29sdW1udGFwcy5yICsKICAgICAgICAgICAgICAgICAgICAgIGxpbmVfcnVuKHh5c3RhcnQueSArIHN0ZXB4eS55ICAgICAgLCB4cG9zLCBsaW5ldGFwcywgU291cmNlKSAqIGNvbHVtbnRhcHMuZyArCiAgICAgICAgICAgICAgICAgICAgICBsaW5lX3J1bih4eXN0YXJ0LnkgKyBzdGVweHkueSAqIDIuMCwgeHBvcywgbGluZXRhcHMsIFNvdXJjZSkgKiBjb2x1bW50YXBzLmIgKwogICAgICAgICAgICAgICAgICAgICAgbGluZV9ydW4oeHlzdGFydC55ICsgc3RlcHh5LnkgKiAzLjAsIHhwb3MsIGxpbmV0YXBzLCBTb3VyY2UpICogY29sdW1udGFwcy5hLDEpOwoKICAgRnJhZ0NvbG9yID0gZmluYWw7Cn0gCiNlbmRpZgo=\n", + }, + ], + }, + + //https://github.com/libretro/glsl-shaders/blob/master/motionblur/mix_frames.glslp + "mix-frames": { + "shader": { + "type": "text", + "value": "shaders = \"1\"\n\nshader0 = \"mix_frames.glsl\"\nfilter_linear0 = \"false\"\n", + }, + "resources": [ + { + "name": "mix_frames.glsl", + "type": "base64", + "value": "LyoKCW1peF9mcmFtZXMgLSBwZXJmb3JtcyA1MDo1MCBibGVuZGluZyBiZXR3ZWVuIHRoZSBjdXJyZW50IGFuZCBwcmV2aW91cwoJZnJhbWVzLgoJCglBdXRob3I6IGpkZ2xlYXZlcgoJCglUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeSBpdAoJdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUKCVNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlciB2ZXJzaW9uIDIgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikKCWFueSBsYXRlciB2ZXJzaW9uLgoqLwoKI2lmIGRlZmluZWQoVkVSVEVYKQoKI2lmIF9fVkVSU0lPTl9fID49IDEzMAojZGVmaW5lIENPTVBBVF9WQVJZSU5HIG91dAojZGVmaW5lIENPTVBBVF9BVFRSSUJVVEUgaW4KI2RlZmluZSBDT01QQVRfVEVYVFVSRSB0ZXh0dXJlCiNlbHNlCiNkZWZpbmUgQ09NUEFUX1ZBUllJTkcgdmFyeWluZyAKI2RlZmluZSBDT01QQVRfQVRUUklCVVRFIGF0dHJpYnV0ZSAKI2RlZmluZSBDT01QQVRfVEVYVFVSRSB0ZXh0dXJlMkQKI2VuZGlmCgojaWZkZWYgR0xfRVMKI2lmZGVmIEdMX0ZSQUdNRU5UX1BSRUNJU0lPTl9ISUdICiNkZWZpbmUgQ09NUEFUX1BSRUNJU0lPTiBoaWdocAojZWxzZQojZGVmaW5lIENPTVBBVF9QUkVDSVNJT04gbWVkaXVtcAojZW5kaWYKI2Vsc2UKI2RlZmluZSBDT01QQVRfUFJFQ0lTSU9OCiNlbmRpZgoKLyogQ09NUEFUSUJJTElUWQogICAtIEdMU0wgY29tcGlsZXJzCiovCgpDT01QQVRfQVRUUklCVVRFIENPTVBBVF9QUkVDSVNJT04gdmVjNCBWZXJ0ZXhDb29yZDsKQ09NUEFUX0FUVFJJQlVURSBDT01QQVRfUFJFQ0lTSU9OIHZlYzQgQ09MT1I7CkNPTVBBVF9BVFRSSUJVVEUgQ09NUEFUX1BSRUNJU0lPTiB2ZWM0IFRleENvb3JkOwpDT01QQVRfVkFSWUlORyBDT01QQVRfUFJFQ0lTSU9OIHZlYzQgQ09MMDsKQ09NUEFUX1ZBUllJTkcgQ09NUEFUX1BSRUNJU0lPTiB2ZWM0IFRFWDA7CgpDT01QQVRfUFJFQ0lTSU9OIHZlYzQgX29Qb3NpdGlvbjE7IAp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gbWF0NCBNVlBNYXRyaXg7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBpbnQgRnJhbWVEaXJlY3Rpb247CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiBpbnQgRnJhbWVDb3VudDsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIHZlYzIgT3V0cHV0U2l6ZTsKdW5pZm9ybSBDT01QQVRfUFJFQ0lTSU9OIHZlYzIgVGV4dHVyZVNpemU7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiB2ZWMyIElucHV0U2l6ZTsKCnZvaWQgbWFpbigpCnsKCVRFWDAgPSBUZXhDb29yZCAqIDEuMDAwMTsKCWdsX1Bvc2l0aW9uID0gTVZQTWF0cml4ICogVmVydGV4Q29vcmQ7Cn0KCiNlbGlmIGRlZmluZWQoRlJBR01FTlQpCgojaWYgX19WRVJTSU9OX18gPj0gMTMwCiNkZWZpbmUgQ09NUEFUX1ZBUllJTkcgaW4KI2RlZmluZSBDT01QQVRfVEVYVFVSRSB0ZXh0dXJlCm91dCB2ZWM0IEZyYWdDb2xvcjsKI2Vsc2UKI2RlZmluZSBDT01QQVRfVkFSWUlORyB2YXJ5aW5nCiNkZWZpbmUgRnJhZ0NvbG9yIGdsX0ZyYWdDb2xvcgojZGVmaW5lIENPTVBBVF9URVhUVVJFIHRleHR1cmUyRAojZW5kaWYKCiNpZmRlZiBHTF9FUwojaWZkZWYgR0xfRlJBR01FTlRfUFJFQ0lTSU9OX0hJR0gKcHJlY2lzaW9uIGhpZ2hwIGZsb2F0OwojZGVmaW5lIENPTVBBVF9QUkVDSVNJT04gaGlnaHAKI2Vsc2UKcHJlY2lzaW9uIG1lZGl1bXAgZmxvYXQ7CiNkZWZpbmUgQ09NUEFUX1BSRUNJU0lPTiBtZWRpdW1wCiNlbmRpZgojZWxzZQojZGVmaW5lIENPTVBBVF9QUkVDSVNJT04KI2VuZGlmCgp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gaW50IEZyYW1lRGlyZWN0aW9uOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gaW50IEZyYW1lQ291bnQ7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiB2ZWMyIE91dHB1dFNpemU7CnVuaWZvcm0gQ09NUEFUX1BSRUNJU0lPTiB2ZWMyIFRleHR1cmVTaXplOwp1bmlmb3JtIENPTVBBVF9QUkVDSVNJT04gdmVjMiBJbnB1dFNpemU7CnVuaWZvcm0gc2FtcGxlcjJEIFRleHR1cmU7CnVuaWZvcm0gc2FtcGxlcjJEIFByZXZUZXh0dXJlOwpDT01QQVRfVkFSWUlORyBDT01QQVRfUFJFQ0lTSU9OIHZlYzQgVEVYMDsKCnZvaWQgbWFpbigpCnsKCS8vIEdldCBjb2xvdXIgb2YgY3VycmVudCBwaXhlbAoJQ09NUEFUX1BSRUNJU0lPTiB2ZWMzIGNvbG91ciA9IENPTVBBVF9URVhUVVJFKFRleHR1cmUsIFRFWDAueHkpLnJnYjsKCQoJLy8gR2V0IGNvbG91ciBvZiBwcmV2aW91cyBwaXhlbAoJQ09NUEFUX1BSRUNJU0lPTiB2ZWMzIGNvbG91clByZXYgPSBDT01QQVRfVEVYVFVSRShQcmV2VGV4dHVyZSwgVEVYMC54eSkucmdiOwoJCgkvLyBNaXggY29sb3VycwoJY29sb3VyLnJnYiA9IG1peChjb2xvdXIucmdiLCBjb2xvdXJQcmV2LnJnYiwgMC41KTsKCQoJZ2xfRnJhZ0NvbG9yID0gdmVjNChjb2xvdXIucmdiLCAxLjApOwp9CiNlbmRpZgo=", + } + ], + }, + +}; diff --git a/data/version.json b/data/version.json index 893f310..6a42649 100644 --- a/data/version.json +++ b/data/version.json @@ -1 +1 @@ -{ "current_version": 401.1 } +{ "current_version": 401.2 } diff --git a/docs/Contributors.md b/docs/Contributors.md index c65ad9b..f806b9c 100644 --- a/docs/Contributors.md +++ b/docs/Contributors.md @@ -1,6 +1,4 @@ -
-
# Contributors @@ -14,7 +12,9 @@ ***Main Contributor*** -**![Badge Ethan GitHub]**  +**![Badge Ethan GitHub]** + +**![Badge Ethan Website]**

@@ -23,9 +23,11 @@ ### Co-Owner -***Various Fixes & Additions*** +***Maintainer, Along with Various Fixes and Additions*** -**![Badge Allan GitHub]**  +**![Badge Allan GitHub]** + +**![Badge Allan Website]**

@@ -43,6 +45,16 @@

+![Michael Avatar] + +***External Project Maintainer*** + +**![Badge Michael GitHub]**  + +**![Badge Michael Website]** + +
+
![Archiver Avatar] @@ -56,20 +68,18 @@

- ![Avatar Alexey]  ![Avatar Grey]  ![Avatar Nekro]  ![Avatar seedgou]  ![Avatar incredibleIdea]  -  +  ![Avatar Kyle]  ![Avatar andrigamerita]  ![Avatar Protektor]  ![Avatar Priyansh]  ![Avatar debuggerx01]  ![Avatar ericKuang]  -![Avatar Michael]  ![Avatar gantoine] 
@@ -100,35 +110,30 @@ [Avatar debuggerx01]: https://github.com/debuggerx01.png?size=95 -[Avatar Michael]: https://github.com/michael-j-green.png?size=95 - [Avatar gantoine]: https://github.com/gantoine.png?size=95 - [Badge Ethan GitHub]: https://img.shields.io/badge/Ethan_O'_Brien-181717.svg?style=for-the-badge&logo=GitHub&logoColor=white - +[Badge Ethan Website]: https://img.shields.io/badge/ethanthesleepy.one-lightgray.svg?style=for-the-badge&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAKTSURBVEhLtdVbaM5hHMDxlzmvHNoyzbHEZlphyanckRslh0SK2sUutms3btyhKBdiEgoX5GK5IOdQIo0UEW2hOZ/mkOOcvt/1PH9v75937zK/+vTufd49p9//9zz/zP+OovBZSAzACAzFD3xFl9ErfP4tirEQyzAVfWF8Qwv24TA+o1vhaqfjPL4HP+GqHdy/3YXtrXARg1BQjMRGvMcHnMQLOGATjsCBn+IYXsL/24bRyBsDsQVu+TVWwvS8ggPNx1g8xhssxgxcgrs7irw7mQcH78AiWARbw/dm9IOxAabJT9M5GabKne1Cb6RiCK7Df9qOSajBRTiYO5sQLICTXsM0VGATPuEd3GkqGuDgskJu4A4+wgnuhzbdghPodmizj2my/w70RxKWa1xpT7iAUUhyZeWMgZVTj5nBWhhWUmzTLGyGcRCxfTZMkwfSlCcxBU9g6VXZQLir1XBF5j/3UK6Cvx3o/PY7fI7P4DlKdpDd2XqPEX93oNww10budWO7/TrHjAO0wx/6oAyWnuJ9U4rYJmu9BIZVE9s9Rx42D94XJCv3jvEhm6orMFWGuZwDD9ZlxJ3Yz3KthpV2E4YL9Nrw4K1AG5JYD9PjIP9qN+KhTMIqsgLcWi1cvSt0R3ayuoYHlbDi7mFiaKvDW5ger5g/xjo4wXN4x7jlPfD5HEe8rp3MSXfCvDvJ1dB2GqnVx7B298MT6urWYDm82Jx0LtzZXbjaJTDnZ+Dgp+BlmDdM1Qm4agdx5Q/D90bsDX/7AD2xTuyzOwt3UlAMhgfIEnSw+PBNX/YLR95V5zAeqcg9ndnhGfFWXIpxKIdXin1c9SM8gCs/BAskFfkmiOEB8kU/LLCPO/OF5Iuo2+/jHoxM5hef3tZ5zF6TlgAAAABJRU5ErkJggg== [Ethan Avatar]: https://avatars.githubusercontent.com/u/77750390?s=90 'Ethan O\'Brien' - - [Badge Archiver GitHub]: https://img.shields.io/badge/ElectronicsArchiver-181717.svg?style=for-the-badge&logo=GitHub&logoColor=white [Badge Archiver Marked]: https://img.shields.io/badge/MarkedDown-49a2d5.svg?style=for-the-badge&logo=GitHub&logoColor=white - [Archiver Avatar]: https://avatars.githubusercontent.com/u/85485984?s=90 'ElectronicsArchiver - トトも' - [Badge Allan GitHub]: https://img.shields.io/badge/allancoding-181717.svg?style=for-the-badge&logo=GitHub&logoColor=white - +[Badge Allan Website]: https://img.shields.io/badge/allancoding.is–a.dev-lightgray.svg?style=for-the-badge&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAATCAYAAACKsM07AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAALJSURBVEhLtZVNSFRRGIbfc2emctLUimmV4KIWBbNpUf4lZAYRBBH0syioTZA/1cKKcVGkbqQkCKJNGRlRVLpwMSiWlakhakaaWv7kIFqZVKhDznjv13vGASWTGdCel4d75zuHc+6ZOeeODdGjaAF101ZdiIZoJ9CDn6M+6qDbaDuNiBG+RiKPjg4C1Z1ABe/1g53QDZGIZoIc+pODV1lKVTmVul8P3GZtNT2mOyyFU/QkB181oFT1gGGItl+pB5zEzrZ8ekR3XAz93XqU0pcFbKBptHI7kJmh1J5QNUydSHUH8Ia3egIv/aXr8xERqKKiIsnP1w+y/HBsoLS0lBP9Hzwej9iys7MvB1MDaJJGeMWLFJWKErMYKUYqcs3TSFCJeCQP0SFv4UQMcq0cDDPXrTIEGI95EVvUVtyVO6ixatAoDaiQexhkpur9s7uo1qpFuVWOdmlDkOlHH3ziwxPrMSqtpygzr2JIhjAogzikDiOByVK78VyewWTOmnnolm7csm7iPaPHWMFoQiv4kTIOUQKdFmlBl3TiA7qwSW3Gd4whQ2XCpVxYyejV+Jg+fIKL6WWu2IoxKl/gVm5uLTt6pAfjzLr69VD6Nygo0G+AOV6+8CMYFPj9FpKSHPD5gtwRbKDpO5143eAPtcXFGpgOCPsCu7KccLn0zp2jsLAQ9kAggImJiXBplslJP9rbfmNkJIi0dCeGPgcxPDyD+HgDlsTgXcc0vn2dgV2/NIhp8gXlTkRMTLgQRo+tHA7HNRouzcFN4LIsy22z2eoyLSs1WWRHuClEr2G8alaq1TTNvYZhNPEsLTgHQb20CJynB/j+ie0zjIZ5J9nLmv4Vj1N92hfln0f4Lzy06yNQbzcML5c2pUT2JwMHWV9Lb+hOS6WQ7hsD4vhH4OT9UXpGN0QimhVodL9LtJmuoRtpGV1W9CQl9ELoU1QAfwCDI3HISCyhigAAAABJRU5ErkJggg== [Allan Avatar]: https://avatars.githubusercontent.com/u/74841470?s=90 'Allancoding - Allan Niles' - - [Badge BinBashBanana GitHub]: https://img.shields.io/badge/BinBashBanana-181717.svg?style=for-the-badge&logo=GitHub&logoColor=white [Badge BinBashBanana Website]: https://img.shields.io/badge/binbashbanana.github.io-lightgray.svg?style=for-the-badge&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAA3lBMVEVHcEwiIgAYGAqfngcdHhIVFRHHyZkAAAAbGxMfGQVub1TR0Ak+Py05PBnb2QohIBeblnJ2d1tiYkthYQCOkG60swiamQciHBQoKBySk3BLSwIpLhEtMBlPSBJgXgOpqAe4LiBLDAqoqoJ3d1tlYgXBw5SzsgiDgwWio3wsLB+kowiSkQdrblVMTDheWUOkpn6dmwZ/fQWYmwc6CQkeJQKfoHmNjAZBTgMjJwRESQI6RQRmVEBiDw1sRSB0GhaQOzCBexOEhF13YyfU1qPkaCnOPiHEwgm1tAiRkAiurQs+wUq/AAAAQ3RSTlMABCP9GhL8ASoKcvtKIf5D/o5YLqTK6FY5ukIyedNR/P19zlpt+cOMzVLg4FFXcsKmu/JYbtTt48ySw9Ka/vv+9DT+PQB0UwAAAKhJREFUGBlNwQUSgkAABdAP7LK7tIXd3d0tYNz/Qs4wKr6HEDEY5YhQOVPIcBk/xtDmPJ9m+JBs06a8y/HBhDGvHqppwhAS2tI5+X5lP07GBQAzq6rOOQgqjuepMQYkm9nB9XI7FkdaR60JIKZRiPLrOWUg9ThDSOpZj76MCGtbd6WBPyRlKW4OfxIpXXFLEiKJll5ebfOE4Muc6LN1cbfBj1TKCboovAFtNA6G3DFC7wAAAABJRU5ErkJggg== - [BinBashBanana Avatar]: https://avatars.githubusercontent.com/u/51469593?s=90 'BinBashBanana' + + +[Badge Michael GitHub]: https://img.shields.io/badge/michael–j–green-181717.svg?style=for-the-badge&logo=GitHub&logoColor=white +[Badge Michael Website]: https://img.shields.io/badge/www.mrgtech.net-lightgray.svg?style=for-the-badge&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAMAAADXqc3KAAAAe1BMVEVHcEwUFhkUFhkUFhkUFhkUFhkUFhkqKioTFRkTFhkVFxocHBwVFxkRESIYGBgVFxr///8YGh35+fkhIyY6PD7y8vL8/Pzc3d1maGpKTE5dXmC/v8DNzs6HiInU1dWrrK3j5OSam5wnKSwsLjBxcnR9foCAgYLq6urp6upDOJtqAAAAD3RSTlMA+e3V54a0Bm9NpRHaDxUPtKeMAAABIElEQVQYGVXBB3KkQBAAwQYGtyupehye9Ub/f+FBcFKgTFkd67zI0gSSNCvy+iibsjL8YapSFuWBjQ/BszmUIlKxuj8np+qm151VJXI0gO2+1bXn88npu7OAOUoN2NnFOViw/ajNbIFacqBrLoGNvarrgFwKuL914D9rR33foZAMXnqy/Lq1+oRMUpj0ys7QTJBKgnf6YG9ynkQgaNOz99QAAkHjjb1OA0iCd/HG3uw8iaQwusCOb0cw8gEPndm56gMyKcC3MfDDX5vWQyE52D62gc1w0tgDudQsuhhfwdrbMKrGjkUtX4ZFf2rcpY2NNqeehfkUqVj54Xxx7nIePKtKRMoDG7tgcyhlUVaGP0xVyuazzovMJJCkH0Vef8niH/cwItH/Rh67AAAAAElFTkSuQmCC +[Michael Avatar]: https://avatars.githubusercontent.com/u/84688932?s=90 'michael-j-green - Michael Green' diff --git a/package.json b/package.json index f3c77ff..8a46ee6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@emulatorjs/emulatorjs", - "version": "4.0.11", + "version": "4.0.12", "repository": { "type": "git", "url": "https://github.com/EmulatorJS/EmulatorJS.git"