Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # tk_PostMessage_DOM_renderer.py
- # the only bottleneck is waiting on Python to LOAD the image onto its canvas. seems far better than numpy... etc.
- import tkinter as tk
- from PIL import Image, ImageTk
- import subprocess
- import struct
- JS_ENGINE = """
- const width = @w, height = @h;
- let zoom = 1.0, centerX = -0.5, centerY = 0, max_iter = 100;
- let mouseX = width / 2, mouseY = height / 2;
- let density = 7;
- let dragging = false;
- let prevMouseX = 0;
- let prevMouseY = 0;
- function hslToRgb(h, s, l) {
- const hue2rgb = (p, q, t) => {
- if (t < 0) t += 1;
- if (t > 1) t -= 1;
- if (t < 1/6) return p + (q - p) * 6 * t;
- if (t < 1/2) return q;
- if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
- return p;
- };
- const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
- const p = 2 * l - q;
- return [
- Math.round(hue2rgb(p, q, h + 1/3) * 255),
- Math.round(hue2rgb(p, q, h) * 255),
- Math.round(hue2rgb(p, q, h - 1/3) * 255)
- ];
- }
- const colorCache = (() => {
- const arr = new Uint8Array(max_iter * 3);
- for (let i = 0; i < max_iter; i++) {
- const [r, g, b] = hslToRgb(i / max_iter, 1, 0.5);
- arr[i*3] = r;
- arr[i*3+1] = g;
- arr[i*3+2] = b;
- }
- return arr;
- })();
- function panByPixels(dx, dy) {
- centerX -= (dx / width) * 3.5 / zoom;
- centerY -= (dy / height) * 2.0 / zoom;
- }
- process.stdin.on('data', (data) => {
- while (data.length >= 20) {
- mouseX = data.readInt32LE(0);
- mouseY = data.readInt32LE(4);
- density = data.readInt32LE(8);
- const mode = data.readInt32LE(12);
- const reset = data.readInt32LE(16);
- if (reset === 1) {
- zoom = 1.0;
- centerX = -0.5;
- centerY = 0;
- dragging = false;
- prevMouseX = mouseX;
- prevMouseY = mouseY;
- data = data.subarray(20);
- continue;
- }
- if (mode === 1) {
- dragging = true;
- prevMouseX = mouseX;
- prevMouseY = mouseY;
- } else if (mode === 2 && dragging) {
- panByPixels(mouseX - prevMouseX, mouseY - prevMouseY);
- prevMouseX = mouseX;
- prevMouseY = mouseY;
- } else if (mode === 3) {
- dragging = false;
- } else if (mode === 0 && !dragging) {
- const mX = (mouseX / width * 3.5 - 2.5) / zoom + centerX;
- const mY = (mouseY / height * 2.0 - 1.0) / zoom + centerY;
- zoom *= 1.06;
- if (zoom > 1e13) {
- zoom = 1.0;
- centerX = -0.5;
- centerY = 0;
- }
- const newMX = (mouseX / width * 3.5 - 2.5) / zoom + centerX;
- const newMY = (mouseY / height * 2.0 - 1.0) / zoom + centerY;
- centerX += (mX - newMX);
- centerY += (mY - newMY);
- }
- data = data.subarray(20);
- }
- });
- function render() {
- const buffer = new Uint8ClampedArray(width * height * 3);
- for (let i = 0; i < width * height; i++) {
- let px = i % width;
- let py = (i / width) | 0;
- let x0 = (px / width * 3.5 - 2.5) / zoom + centerX;
- let y0 = (py / height * 2.0 - 1.0) / zoom + centerY;
- let x = 0, y = 0, iter = 0;
- while (x*x + y*y <= 4 && iter < max_iter) {
- let xt = x*x - y*y + x0;
- y = 2*x*y + y0;
- x = xt;
- iter++;
- }
- let idx = i * 3;
- if (iter === max_iter) {
- buffer[idx] = buffer[idx+1] = buffer[idx+2] = 0;
- } else {
- let hueIndex = (iter * density) % max_iter;
- buffer[idx] = colorCache[hueIndex*3];
- buffer[idx+1] = colorCache[hueIndex*3+1];
- buffer[idx+2] = colorCache[hueIndex*3+2];
- }
- }
- process.stdout.write(Buffer.from(buffer));
- setImmediate(render);
- }
- render();
- """
- w = 1200
- h = 600
- JS_ENGINE = JS_ENGINE.replace("@w", str(w)).replace("@h", str(h))
- root = tk.Tk()
- root.title("# tk_PostMessage_DOM_renderer.py")
- root.geometry(f"{w}x{h+60}+-5+0")
- root.resizable(False, False)
- canvas = tk.Canvas(root, width=w, height=h, bg="black", highlightthickness=0)
- canvas.pack()
- slider = tk.Scale(root, from_=7, to=140, resolution=0.5, orient="horizontal", label="Freq~")
- slider.set(98)
- slider.pack(fill="x")
- mx, my = w // 2, h // 2
- photo = None
- dragging = False
- proc = subprocess.Popen(
- ["node", "-e", JS_ENGINE],
- stdin=subprocess.PIPE,
- stdout=subprocess.PIPE,
- bufsize=w * h * 3
- )
- def send_packet(x, y, density, mode, reset=0):
- try:
- proc.stdin.write(struct.pack("<iiiii", int(x), int(y), int(density), int(mode), int(reset)))
- proc.stdin.flush()
- except:
- pass
- def on_press(event):
- global mx, my, dragging
- mx, my = event.x, event.y
- dragging = True
- send_packet(mx, my, slider.get(), 1, 0)
- def on_release(event):
- global mx, my, dragging
- mx, my = event.x, event.y
- dragging = False
- send_packet(mx, my, slider.get(), 3, 0)
- def on_drag(event):
- global mx, my
- mx, my = event.x, event.y
- send_packet(mx, my, slider.get(), 2, 0)
- def on_motion(event):
- global mx, my
- if not dragging:
- mx, my = event.x, event.y
- send_packet(mx, my, slider.get(), 0, 0)
- def on_space(event):
- send_packet(mx, my, slider.get(), 0, 1)
- canvas.bind("<ButtonPress-1>", on_press)
- canvas.bind("<ButtonRelease-1>", on_release)
- canvas.bind("<B1-Motion>", on_drag)
- canvas.bind("<Motion>", on_motion)
- root.bind("<space>", on_space)
- def update_loop():
- global photo
- send_packet(mx, my, slider.get(), 0, 0)
- raw_bytes = proc.stdout.read(w * h * 3)
- if raw_bytes:
- img = Image.frombytes("RGB", (w, h), raw_bytes)
- photo = ImageTk.PhotoImage(img)
- canvas.delete("all")
- canvas.create_image(0, 0, anchor="nw", image=photo)
- root.after(1, update_loop)
- update_loop()
- root.mainloop()
Advertisement
Add Comment
Please, Sign In to add comment