Perspective

HTML

<img id="img"...

CSS

canvas, img {
    border: 1px solid black;
}

#dbg { display: none; }

JavaScript

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext("2d");

var img = document.getElementById('img');

const Width = canvas.width;
const Height = canvas.height;
const HalfWidth = Width / 2;
const HalfHeight = Height / 2;


let mipstart = [];
ctx.imageSmoothingQuality = "high";
ctx.fillStyle = "#f00";
ctx.fillRect(0, 0, Width, Height);
ctx.fillStyle = "#00f";

let prev = document.createElement("canvas"), next = document.createElement("canvas");
let dbgc = document.getElementById("dbg");
let dbg = dbgc.getContext("2d");
dbg.imageSmoothingEnabled = false;

for (let w = 64, m = 0; w >= 1; w >>= 1, m++)
{
	if (m == 0)
	{
		ctx.drawImage(img, 0, 0, w, w);
		//ctx.fillRect(0, 0, 64, 64);
		prev.width = 64;
		prev.height = 64;
		prev.getContext("2d").drawImage(img, 0, 0, 64, 64);
	}
	else
	{
		next.width = w;
		next.height = w;
		let nc = next.getContext("2d");
		nc.imageSmoothingQuality = "high";
		nc.drawImage(prev, 0, 0, w, w);
	
		dbg.drawImage(next, 0, 0, 256, 256);
		ctx.drawImage(next, 0, m * 64, 64, 64);
		
		let tmp = next;
		next = prev;
		prev = tmp;
	}
	mipstart[m] = m * 64 * 64;
}
let idata = new Uint32Array(ctx.getImageData(0, 0, 64, 6*64).data.buffer);

var pixels = ctx.createImageData(Width, Height);
var pdata = new Uint32Array(pixels.data.buffer);

var dists = [];
for (let i = 1; i < HalfHeight; i++)
	dists[i] = 2 * HalfHeight / i;
dists[0] = dists[1];
dists[HalfHeight] = dists[HalfHeight - 1];

var h = 20;
var ypos = 0;
var xpos = 0;
var dir = 0;
var frame = 0;

let keyLeft = false, keyRight = false, keyUp = false, keyDown = false;
function keyEvent(e)
{
	let down = e.type == "keydown";
	if (e.key == "ArrowLeft")
		keyLeft = down;
	else if (e.key == "ArrowRight")
		keyRight = down;
	else if (e.key == "ArrowUp")
		keyUp = down;
	else if (e.key == "ArrowDown")
		keyDown = down;
}
document.addEventListener("keydown", keyEvent);
document.addEventListener("keyup", keyEvent);


function fetchFromMip(x, y, m)
{
	x = (x & 63);
	y = (y &...