Last active
July 5, 2024 04:51
-
-
Save Krazete/e2c0f77702ae95884e0556696e9789e3 to your computer and use it in GitHub Desktop.
Injects cognition.kizunaai.com with a playable DOOM. See comments for keyboard controls.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* copied from https://github.com/healeycodes/doom-checkboxes/blob/main/doom.js */ | |
var memory = new WebAssembly.Memory({ initial: 108 }); | |
function readWasmString(offset, length) { | |
const bytes = new Uint8Array(memory.buffer, offset, length); | |
return new TextDecoder("utf8").decode(bytes); | |
} | |
function consoleLogString(offset, length) { | |
const string = readWasmString(offset, length); | |
console.log('"' + string + '"'); | |
} | |
function appendOutput(style) { | |
return function (offset, length) { | |
const lines = readWasmString(offset, length).split("\n"); | |
for (var i = 0; i < lines.length; ++i) { | |
if (lines[i].length == 0) { | |
continue; | |
} | |
} | |
}; | |
} | |
/*stats about how often doom polls the time*/ | |
var getms_calls_total = 0; | |
var getms_calls = 0; /* in current second */ | |
window.setInterval(function () { | |
getms_calls_total += getms_calls; | |
getms_calls = 0; | |
}, 1000); | |
function getMilliseconds() { | |
++getms_calls; | |
return performance.now(); | |
} | |
/*doom is rendered here*/ | |
const DoomCanvas = document.createElement("canvas"); | |
DoomCanvas.width = 640; | |
DoomCanvas.height = 400; | |
var vw = 640; | |
var vh = 400; | |
const doom_screen_width = 320 * 2; | |
const doom_screen_height = 200 * 2; | |
/*printing stats*/ | |
var number_of_draws_total = 0; | |
var number_of_draws = 0; /* in current second */ | |
window.setInterval(function () { | |
number_of_draws_total += number_of_draws; | |
number_of_draws = 0; | |
}, 1000); | |
function drawDoomCanvas(ptr) { | |
var doom_screen = new Uint8ClampedArray( | |
memory.buffer, | |
ptr, | |
doom_screen_width * doom_screen_height * 4 | |
); | |
var render_screen = new ImageData( | |
doom_screen, | |
doom_screen_width, | |
doom_screen_height | |
); | |
var ctx = DoomCanvas.getContext("2d"); | |
ctx.putImageData(render_screen, 0, 0); | |
++number_of_draws; | |
} | |
/*These functions will be available in WebAssembly. We also share the memory to share larger amounts of data with javascript, e.g. strings of the video output.*/ | |
var importObject = { | |
js: { | |
js_console_log: appendOutput("log"), | |
js_stdout: appendOutput("stdout"), | |
js_stderr: appendOutput("stderr"), | |
js_milliseconds_since_start: getMilliseconds, | |
js_draw_screen: drawDoomCanvas, | |
}, | |
env: { | |
memory: memory, | |
}, | |
}; | |
const response = await fetch("https://raw.githubusercontent.com/healeycodes/doom-checkboxes/main/doom.wasm"); | |
const buffer = await response.arrayBuffer(); | |
const obj = await WebAssembly.instantiate(buffer, importObject).then( | |
(obj) => { | |
/*Initialize Doom*/ | |
obj.instance.exports.main(); | |
/*input handling*/ | |
let doomKeyCode = function (keyCode) { | |
/* Doom seems to use mostly the same keycodes, except for the following (maybe I'm missing a few.) */ | |
switch (keyCode) { | |
case 8: | |
return 127; /* KEY_BACKSPACE */ | |
case 17: | |
return 0x80 + 0x1d; /* KEY_RCTRL */ | |
case 18: | |
return 0x80 + 0x38; /* KEY_RALT */ | |
case 37: | |
return 0xac; /* KEY_LEFTARROW */ | |
case 38: | |
return 0xad; /* KEY_UPARROW */ | |
case 39: | |
return 0xae; /* KEY_RIGHTARROW */ | |
case 40: | |
return 0xaf; /* KEY_DOWNARROW */ | |
default: | |
if (keyCode >= 65 /*A*/ && keyCode <= 90 /*Z*/) { | |
return keyCode + 32; /* ASCII to lower case */ | |
} | |
if (keyCode >= 112 /*F1*/ && keyCode <= 123 /*F12*/) { | |
return keyCode + 75; /* KEY_F1 */ | |
} | |
return keyCode; | |
} | |
}; | |
let keyDown = function (keyCode) { | |
obj.instance.exports.add_browser_event(0 /*KeyDown*/, keyCode); | |
}; | |
let keyUp = function (keyCode) { | |
obj.instance.exports.add_browser_event(1 /*KeyUp*/, keyCode); | |
}; | |
/*keyboard input*/ | |
window.addEventListener( | |
"keydown", | |
function (event) { | |
keyDown(doomKeyCode(event.keyCode)); | |
event.preventDefault(); | |
}, | |
false | |
); | |
window.addEventListener( | |
"keyup", | |
function (event) { | |
keyUp(doomKeyCode(event.keyCode)); | |
event.preventDefault(); | |
}, | |
false | |
); | |
/*printing stats*/ | |
var number_of_animation_frames = 0; /* in current second */ | |
window.setInterval(function () { | |
number_of_animation_frames = 0; | |
}, 1000); | |
/*Main game loop*/ | |
function step(timestamp) { | |
++number_of_animation_frames; | |
obj.instance.exports.doom_loop_step(); | |
window.requestAnimationFrame(step); | |
} | |
window.requestAnimationFrame(step); | |
window.doomLoaded = true; | |
} | |
); | |
document.body.appendChild(DoomCanvas); | |
DoomCanvas.style.position = "absolute"; | |
DoomCanvas.style.bottom = "44px"; | |
DoomCanvas.style.zIndex = "2"; | |
DoomCanvas.style.width = "250px"; | |
/* copied from https://gist.github.com/Krazete/0fcfe6eeea57961df821f30c512cf2b2 */ | |
var video = DoomCanvas; | |
var dpr = Math.ceil(window.devicePixelRatio || 1); /* for high dpi screens */ | |
var canvas = document.getElementsByTagName("canvas")[0]; | |
var context = canvas.getContext("2d", {willReadFrequently: true}); | |
var cw, ch, ix, iy, r; | |
var vcanvas = document.createElement("canvas"); | |
var vcontext = vcanvas.getContext("2d"); | |
var vcw, vch; | |
function getRectInfo() { | |
var cd = context.getImageData(0, 0, cw, ch); | |
var x1count = 0; | |
var x0count = 0; | |
for (var x = 0; x < cd.width; x++) { | |
var i = 4 * x; | |
if (cd.data[i] || cd.data[i + 1] || cd.data[i + 2]) { | |
if (x0count) { | |
break; | |
} | |
x1count++; | |
} | |
else { | |
x0count++; | |
} | |
} | |
var y1count = 0; | |
var y0count = 0; | |
for (var y = 0; y < cd.height; y++) { | |
var i = 4 * cd.width * y; | |
if (cd.data[i] || cd.data[i + 1] || cd.data[i + 2]) { | |
if (y0count) { | |
break; | |
} | |
y1count++; | |
} | |
else { | |
y0count++; | |
} | |
} | |
return { | |
w: x1count / dpr, | |
h: y1count / dpr, | |
dx: (x1count + x0count) / dpr, | |
dy: (y1count + y0count) / dpr | |
}; | |
} | |
function recalculate() { | |
cw = canvas.width / dpr; | |
ch = canvas.height / dpr; | |
/* scale video resolution to fit canvas */ | |
var iw, ih; | |
if (vw / vh < cw / ch) { | |
iw = vw * ch / vh; | |
ih = ch; | |
} | |
else { | |
iw = cw; | |
ih = vh * cw / vw; | |
} | |
ix = (cw - iw) / 2; | |
iy = (ch - ih) / 2; | |
/* get rect info */ | |
r = getRectInfo(); | |
/* prepare video pixelation and adjust iw, ih, ix, iy with rect info */ | |
vcw = Math.ceil(iw / r.dx); | |
vch = Math.ceil(ih / r.dy); | |
vcanvas.width = vcw; | |
vcanvas.height = vch; | |
ix = Math.floor(ix / r.dx) * r.dx; | |
iy = Math.floor(iy / r.dy) * r.dy; | |
} | |
/* colors | |
black #000000 | |
white #ffffff | |
gray #0a0a0a | |
pink #eb50ae | |
blue #0000ff | |
*/ | |
function play() { | |
vcontext.drawImage(video, 0, 0, vcw, vch); | |
var vcd = vcontext.getImageData(0, 0, vcw, vch); | |
context.beginPath(); | |
for (var y = 0; y < vcd.height; y++) { | |
for (var x = 0; x < vcd.width; x++) { | |
var i = 4 * (vcd.width * y + x); | |
var j = (vcd.data[i] + vcd.data[i + 1] + vcd.data[i + 2]) / 3; | |
if (j >= 96) {context.fillStyle = "#ffffff";} | |
else if (vcd.data[i] >= 80) {context.fillStyle = "#eb50ae";} | |
else if (vcd.data[i + 2] >= 64) {context.fillStyle = "#0000ff";} | |
else {context.fillStyle = "#0a0a0a";} context.fillRect(ix + x * r.dx, iy + y * r.dy, r.w, r.h); | |
} | |
} | |
if (!video.paused) { | |
requestAnimationFrame(play); | |
} | |
}; | |
recalculate(); | |
play(); | |
window.addEventListener("resize", recalculate); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Preview: https://youtu.be/C15ZY6k9Vys
Code Credits
(they were very sloppily edited together in order to work on https://cognition.kizunaai.com)
Controls
(it's the same as https://healeycodes.github.io/doom-checkboxes)