Created
August 17, 2023 09:09
-
-
Save Alikberov/99c02e12fa83b8d6ad15736c60b0632a to your computer and use it in GitHub Desktop.
Televison Receiver Simulator
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
<html> | |
<head> | |
<meta http-equiv='refresh' content='1600'> | |
<title>Television Receiver Simulator</title> | |
<script> | |
class TELEVISION extends HTMLCanvasElement { | |
constructor() { | |
super(); | |
this.time = 0; | |
this.speed = 1; | |
this.teleVision = "v0.23.07.20"; | |
this.playing = false; | |
this.firstTime = new Date(); | |
this.ctx = this.getContext("2d"); | |
this.imageData = this.ctx.getImageData(0, 0, this.width, this.height); | |
this.raster = []; | |
this.lines = 768; | |
this.grains = 1024; | |
this.sync = 0; | |
this.new_lines = 0; | |
this.clock = 0; | |
this.noising = 502; | |
this.render(); | |
} | |
flush() { | |
this.ctx.putImageData(this.imageData, 0, 0); | |
} | |
rasterize_asm() { | |
"use asm"; | |
var width = this.width|0; | |
var height = this.height|0; | |
var lines = this.lines|0; | |
var grains = this.grains|0; | |
var pixels = this.imageData.data; | |
var i = 0|0; | |
var d = 0|0; | |
var c = 0|0; | |
var dots = 0|0; | |
var rows = 0|0; | |
var sync = 0|0; | |
var top = (((height|0) - (lines|0)) >> 1)|0; | |
var left = 0|0; | |
var r = 0|0; | |
var g = 0|0; | |
var b = 0|0; | |
var a = 0|0; | |
var x = 0|0; | |
var y = 0|0; | |
var flag = 0|0; | |
var raster = this.raster; | |
var clock = this.clock|0; | |
var raslen = this.raster.length|0; | |
for(y = 0|0; (y|0) < (height|0); y = (y|0) + 2 | 0) { | |
i = ((y|0) * (width|0) << 2)|0; | |
left = (((width|0) - (grains|0)) >> 1)|0; | |
for(x = 0|0; (x|0) < (width|0); x = (x|0) + 1 | 0) { | |
flag = (x|0) >= (left|0) && (y|0) >= (top|0) ? 1|0 : 0|0; | |
if((flag|0) > 0) { | |
d = raster[clock]|0; | |
clock = (clock|0) + 1 | 0; | |
if((clock|0) >= (raslen|0)) | |
clock = 0|0; | |
if((d|0) < 0) { | |
sync = (sync|0) + 1 | 0; | |
if((sync|0) > 800|0) { | |
if((lines|0) > 0) | |
rows = lines|0; | |
lines = 0|0; | |
} else | |
if((sync|0) > 8) { | |
if((dots|0) > 0) | |
lines = (lines|0) + 1 | 0, | |
grains = dots|0; | |
dots = 0|0; | |
} | |
} else { | |
dots = (dots + 1)|0; | |
if((dots|0) > 0) | |
sync = 0|0; | |
} | |
r = c|0; | |
g = c|0; | |
b = c|0; | |
a = 255|0; | |
} else | |
r = 0|0, | |
g = 96|0, | |
b = 255|0, | |
a = 255|0; | |
pixels[(i|0) + 3336] = r|0; | |
pixels[i|0] = r|0; i = (i|0) + 1 | 0; | |
pixels[(i|0) + 3336] = g|0; | |
pixels[i|0] = g|0; i = (i|0) + 1 | 0; | |
pixels[(i|0) + 3336] = b|0; | |
pixels[i|0] = b|0; i = (i|0) + 1 | 0; | |
pixels[(i|0) + 3336] = a|0; | |
pixels[i|0] = a|0; i = (i|0) + 1 | 0; | |
} | |
} | |
this.clock = clock; | |
this.lines = rows; | |
this.grains = grains; | |
} | |
rasterize() { | |
var width = this.width; | |
var height = this.height; | |
var lines = this.lines; | |
var grains = this.grains; | |
var pair = width * 4; | |
var clock = this.clock; | |
var pixels = this.imageData.data; | |
var raslen = this.raster.length; | |
var blanking = Math.floor(width * 3 / 2); | |
var sync = this.sync; | |
var top = sync > 0 ? 0 : (height - lines) >> 1; | |
var new_lines = this.new_lines; | |
var new_grains = 0; | |
var start = sync > width >> 6 ? 0 : 1; | |
var i, d = 0, c = 0, flag; | |
var left; | |
var yd = 1; | |
var r, g, b, a; | |
var x, y; | |
for(y = 0; y < height; y += 2) { | |
i = y * width * 4; | |
left = (width - grains) >> 1; | |
for(x = 0; x < width; ++ x) { | |
flag = y >= top * start && x >= left; | |
if(flag) { | |
d = this.raster[clock ++] + Math.random() * this.noising; | |
c = d < 0 ? 0 : Math.floor(d / 4); | |
if(clock >= raslen) | |
clock = 0; | |
if(d < 0) { | |
sync ++; | |
if(sync >= blanking) { | |
if(sync == blanking) { | |
lines = new_lines << 1, | |
new_lines = 0; | |
if(y < height / 2) | |
y -= y >= 4 ? 2 : 2; | |
else | |
y += 2; | |
i = y * width * 4; | |
x -= 0; | |
} | |
r = Math.random() * 25 + 160, | |
g = Math.random() * 25 + 64, | |
b = Math.random() * 25 + 60; | |
} else | |
if(sync >= width >> 6) { | |
if(sync == width >> 6) | |
new_lines ++, | |
grains = new_grains, | |
left = width, | |
new_grains = 78; | |
r = Math.random() * 25, | |
g = Math.random() * 25 + 64, | |
b = Math.random() * 25 + 192; | |
} | |
} else { | |
start = 1; | |
yd = 0; | |
new_grains ++; | |
//if(new_grains > 8) | |
sync = 0; | |
r = g = b = c; | |
} | |
a = 255; | |
} else | |
a = 255, | |
r = Math.random() * 25, | |
g = Math.random() * 25 + 48, | |
b = Math.random() * 25 + 160; | |
pixels[i + pair] = r; | |
pixels[i ++] = r; | |
pixels[i + pair] = g; | |
pixels[i ++] = g; | |
pixels[i + pair] = b; | |
pixels[i ++] = b; | |
pixels[i + pair] = a; | |
pixels[i ++] = a; | |
} | |
} | |
this.sync = sync; | |
this.clock = clock; | |
this.lines = lines; | |
this.new_lines = new_lines; | |
this.grains = grains; | |
} | |
render() { | |
if(this.playing) { | |
this.rasterize(); | |
this.flush(); | |
} | |
window.requestAnimationFrame(this.render.bind(this)); | |
} | |
play(img) { | |
this.playing = true; | |
if(img) | |
this.ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, this.width, this.height); | |
this.imageData = this.ctx.getImageData(0, 0, this.width, this.height); | |
var m = this.width * this.height >> 1; | |
var j = m >> 1; | |
for(var y = 0; y < this.height - 2; y += 2) { | |
for(var x = 0; x < this.width; ++ x) { | |
var i = (y * this.width + x) * 4; | |
var r = this.imageData.data[i + 2]; | |
var g = this.imageData.data[i + 1]; | |
var b = this.imageData.data[i]; | |
var d = y < 5 || x < (this.width >> 6) + Math.random() * 9 - 5 ? -500 - Math.floor(500 * Math.random()) : Math.max(r, g, b) * 4; | |
this.raster[j ++] = d; | |
if(j >= m) | |
j = 0; | |
} | |
} | |
} | |
stop() { | |
this.playing = false; | |
} | |
receive(signal) { | |
var line = { | |
shading :0, | |
noise :[] | |
}; | |
var shading = 0; | |
for(var data of signal) { | |
if(data < 0) { | |
if(shading > 10 && line.noise.length > 0) { | |
this.raster.push(line); | |
line = { | |
shading :0, | |
noise :[] | |
}; | |
} | |
shading ++; | |
} else { | |
if(shading > 10) | |
line.shading = shading; | |
line.noise.push(data); | |
if(shading > 0) | |
shading --; | |
} | |
} | |
} | |
} | |
customElements.define("tele-vision", TELEVISION, { extends: "canvas" }); | |
function main(img) { | |
canvas = document.querySelector("canvas"); | |
if("teleVision" in canvas) { | |
var speed = window.location.href.match(/speed=(?<speed>\d+)/i); | |
/*var arr = []; | |
for(var i = 0; i < 327684; ++ i) | |
arr[i] = Math.floor(Math.random() * 2000 - 900); | |
canvas.receive(arr);*/ | |
canvas.play(img); | |
} | |
} | |
</script> | |
<style> | |
body { | |
background-color:silver; | |
margin :0px 0px 0px 0px; | |
padding :0px 0px 0px 0px; | |
} | |
</style> | |
</head> | |
<body> | |
Noise level:<input type=number min=100 max=509 value=501 onchange='canvas.noising = this.value' /><br /> | |
<canvas is='tele-vision' width=512 height=384></canvas> | |
<img crossOrigin='' src='https://i.imgur.com/iWjkVft.jpg' onload='main(this)' /> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment