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();
|