157 lines
3 KiB
JavaScript
157 lines
3 KiB
JavaScript
// IMPORTS
|
|
|
|
import {None, Some} from "./option.js";
|
|
import {canvas, fill_rect, clear} from "./canvas.js";
|
|
import * as cursor from "./cursor.js";
|
|
|
|
// CONSTANTS
|
|
|
|
const MIN_SCALE = 32;
|
|
const MIN_DRAW_RES = 1;
|
|
|
|
// QUADTREE
|
|
|
|
function Tree() {
|
|
let parent = None();
|
|
let children = None();
|
|
let color = "#000000";
|
|
|
|
const node = {
|
|
set_parent: p => { parent = Some(p); },
|
|
get_parent: () => parent,
|
|
|
|
create_children: () => {
|
|
children.none(() => {
|
|
let _children = Array(4);
|
|
for (let i = 0; i < 4; i++) {
|
|
_children[i] = Tree();
|
|
_children[i].set_color(color);
|
|
_children[i].set_parent(node);
|
|
}
|
|
children = Some(_children);
|
|
});
|
|
},
|
|
get_children: () => children,
|
|
|
|
set_color: c => { color = c; },
|
|
get_color: () => color,
|
|
|
|
to_string: () => {
|
|
return children
|
|
.some(cs => {
|
|
return Some(`{color: "${color}", children: [${
|
|
cs.map(c => c.to_string()).join(", ")
|
|
}]}`);
|
|
})
|
|
.unwrap(`{color: "${color}"}`);
|
|
},
|
|
};
|
|
|
|
return node;
|
|
}
|
|
|
|
function draw_tree(tree, x, y, size) {
|
|
fill_rect(x, y, size, size, tree.get_color());
|
|
|
|
if (size < MIN_DRAW_RES) { return; }
|
|
|
|
tree.get_children()
|
|
.none(None)
|
|
.some(c => {
|
|
const new_size = size / 2;
|
|
draw_tree(c[0], x, y, new_size);
|
|
draw_tree(c[1], x + new_size, y, new_size);
|
|
draw_tree(c[2], x, y + new_size, new_size);
|
|
draw_tree(c[3], x + new_size, y + new_size, new_size);
|
|
});
|
|
}
|
|
|
|
function find_containing_node(node, root_x, root_y, x, y, scale) {
|
|
if (scale <= MIN_SCALE) {
|
|
return node;
|
|
}
|
|
|
|
node.create_children();
|
|
return node.get_children().none(None).some(c => {
|
|
let index = 0;
|
|
scale /= 2;
|
|
if (x >= scale) {
|
|
index += 1;
|
|
root_x += scale;
|
|
x -= scale;
|
|
}
|
|
if (y >= scale) {
|
|
index += 2;
|
|
root_y += scale;
|
|
y -= scale;
|
|
}
|
|
|
|
return find_containing_node(c[index], root_x, root_y, x, y, scale);
|
|
});
|
|
}
|
|
|
|
function color_pixel(tree, root_x, root_y, x, y, scale, color) {
|
|
const node = find_containing_node(tree, 0, 0, x, y, 512);
|
|
node.set_color(color);
|
|
}
|
|
|
|
// MAIN
|
|
|
|
const root = Tree();
|
|
let pos = root;
|
|
|
|
function zoom(node, x, y, scale) {
|
|
// TODO replace with call to find_containing_node;
|
|
// edit that function to allow for max depth param.
|
|
let index = 0;
|
|
if (x >= scale/2) {
|
|
index += 1;
|
|
}
|
|
if (y >= scale/2) {
|
|
index += 2;
|
|
}
|
|
node.create_children();
|
|
return node.get_children().some(c => {
|
|
return c[index];
|
|
});
|
|
}
|
|
|
|
function render(tree) {
|
|
clear("#000000");
|
|
draw_tree(tree, 0, 0, 512);
|
|
}
|
|
|
|
function init() {
|
|
root.set_color("#0f0");
|
|
root.create_children();
|
|
root.get_children().none(None).some(c => {
|
|
c[0].set_color("#f80");
|
|
});
|
|
|
|
canvas.addEventListener("mousedown", e => {
|
|
if (e.button === 2) {
|
|
pos = zoom(pos, cursor.get_x(), cursor.get_y(), 512);
|
|
}
|
|
});
|
|
document.body.addEventListener("keydown", e => {
|
|
if (e.key === " ") {
|
|
pos.get_parent().some(p => pos = p);
|
|
}
|
|
});
|
|
|
|
console.log(root.to_string());
|
|
}
|
|
|
|
function main() {
|
|
if (cursor.button_pressed(0)) {
|
|
|
|
color_pixel(pos, 0, 0, cursor.get_x(), cursor.get_y(), 512, "#000");
|
|
}
|
|
|
|
render(pos);
|
|
|
|
requestAnimationFrame(main);
|
|
}
|
|
|
|
init();
|
|
main();
|