mandel-6502/sim.js

203 lines
4.1 KiB
JavaScript
Raw Permalink Normal View History

2023-01-08 06:57:18 +00:00
import {toFixed, mul} from './fixed.js';
2023-01-08 05:19:40 +00:00
2023-01-08 06:57:18 +00:00
let toFixedLog = toFixed;
function toFixed16(val) {
// 4.12
return Math.round(val * (2 ** 12))
}
let four16 = toFixed16(4);
2023-01-08 06:02:26 +00:00
function imul(a, b) {
return Math.imul(a, b) >> 12;
}
function logmul(a, b) {
if ((a | b) == 0) {
return 0;
}
let neg = 0;
if (a < 0) {
a = -a;
neg++;
}
if (b < 0) {
b = -b;
neg++;
}
let product = mul(a, b);
if (neg == 1) {
product = -product;
}
return product;
}
2023-01-08 06:57:18 +00:00
let fourLog = toFixedLog(4);
2023-01-08 06:02:26 +00:00
2023-01-08 05:19:40 +00:00
let max = 256;
let width = 256;
let height = 256;
2023-01-08 06:02:26 +00:00
let zoom = 0;
let offsetX = 0;
let offsetY = 0;
function scale() {
return 1 / (2 ** zoom);
}
let cancelled = false;
async function cancel() {
cancelled = true;
return await nap(100);
}
2023-01-08 05:19:40 +00:00
let black = 0xff000000;
let tricolor = [
0xffff0000,
0xff00ff00,
0xff0000ff,
];
let palette = new Uint32Array(256);
palette[0] = black;
for (let i = 0; i < 255; i++) {
palette[i + 1] = tricolor[i % 3];
}
2023-01-08 06:02:26 +00:00
function nap(ms=0) {
return new Promise((resolve) => setTimeout(() => resolve(), ms));
}
function attach(id, func) {
document.getElementById(id).addEventListener('click', (_event) => {
cancel().then(() => {
func();
run();
});
});
2023-01-08 05:19:40 +00:00
}
2023-01-08 06:02:26 +00:00
attach('zoom-in', () => {
zoom++;
});
attach('zoom-out', () => {
if (zoom >= 1) {
zoom--;
}
});
attach('left', () => {
offsetX -= scale();
});
attach('right', () => {
offsetX += scale();
});
attach('up', () => {
offsetY -= scale();
});
attach('down', () => {
offsetY += scale();
});
2023-01-08 05:19:40 +00:00
async function setup(id, iterfunc) {
let canvas = document.getElementById(id);
let ctx = canvas.getContext('2d');
let imageData = ctx.createImageData(width, height);
let rgba = new Uint32Array(imageData.data.buffer);
2023-01-08 06:02:26 +00:00
cancelled = false;
2023-01-08 05:19:40 +00:00
for (let y = 0; y < height; y++) {
2023-01-08 06:02:26 +00:00
let cy = scale() * (y * 2 - height) / (height / 2) + offsetY;
2023-01-08 05:19:40 +00:00
for (let x = 0; x < width; x++) {
2023-01-08 06:02:26 +00:00
let cx = scale() * (x * 2 - width) / (width / 2) + offsetX;
2023-01-08 05:19:40 +00:00
let i = iterfunc(cx, cy);
let color = palette[i];
rgba[y * width + x] = color;
2023-01-08 06:02:26 +00:00
if (x % 256 == 255) {
2023-01-08 05:19:40 +00:00
ctx.putImageData(imageData, 0, 0);
await nap();
2023-01-08 06:02:26 +00:00
if (cancelled) {
return;
}
2023-01-08 05:19:40 +00:00
}
}
}
}
2023-01-08 06:02:26 +00:00
function run() {
setup('float', (cx, cy) => {
let zx = 0;
let zy = 0;
let zx_2 = 0;
let zy_2 = 0;
let zx_zy = 0;
for (let i = 1; i < max; i++) {
zx = zx_2 - zy_2 + cx;
zy = zx_zy + zx_zy + cy;
zx_2 = zx * zx;
zy_2 = zy * zy;
zx_zy = zx * zy;
if (zx_2 + zy_2 >= 4) {
return i;
}
2023-01-08 05:19:40 +00:00
}
2023-01-08 06:02:26 +00:00
return 0;
}).then(() => {
console.log('float done');
});
setup('imul', (cx, cy) => {
2023-01-08 06:57:18 +00:00
cx = toFixed16(cx);
cy = toFixed16(cy);
2023-01-08 06:02:26 +00:00
let zx = 0;
let zy = 0;
let zx_2 = 0;
let zy_2 = 0;
let zx_zy = 0;
for (let i = 1; i < max; i++) {
zx = zx_2 - zy_2 + cx;
zy = zx_zy + zx_zy + cy;
zx_2 = imul(zx, zx);
zy_2 = imul(zy, zy);
zx_zy = imul(zx, zy);
2023-01-08 06:57:18 +00:00
if (zx_2 + zy_2 >= four16) {
2023-01-08 06:02:26 +00:00
return i;
}
}
return 0;
}).then(() => {
console.log('imul done');
});
setup('log', (cx, cy) => {
2023-01-08 06:57:18 +00:00
cx = toFixedLog(cx);
cy = toFixedLog(cy);
2023-01-08 06:02:26 +00:00
let zx = 0;
let zy = 0;
let zx_2 = 0;
let zy_2 = 0;
let zx_zy = 0;
for (let i = 1; i < max; i++) {
zx = zx_2 - zy_2 + cx;
zy = zx_zy + zx_zy + cy;
zx_2 = logmul(zx, zx);
zy_2 = logmul(zy, zy);
zx_zy = logmul(zx, zy);
2023-01-08 06:57:18 +00:00
if (zx_2 + zy_2 >= fourLog) {
2023-01-08 06:02:26 +00:00
return i;
}
}
return 0;
}).then(() => {
console.log('log done');
});
}
run();