# tk_subtractive_blend_polygons.py

import tkinter as tk
from PIL import Image, ImageDraw, ImageTk, ImageChops
import math

sz = 600

def center_coords(coords_list, sz):
    xs = [x for coords in coords_list for x, y in coords]
    ys = [y for coords in coords_list for x, y in coords]
    min_x, max_x = min(xs), max(xs)
    min_y, max_y = min(ys), max(ys)
    width = max_x - min_x
    height = max_y - min_y
    offset_x = (sz - width) / 2 - min_x
    offset_y = (sz - height) / 2 - min_y
    return [[(x + offset_x, y + offset_y) for x, y in coords] for coords in coords_list]

def srgb_from_linear(x):
    if x <= 0.0031308:
        return 12.92 * x
    return 1.055 * (x ** (1/2.4)) - 0.055

def linear_from_srgb(x):
    if x <= 0.04045:
        return x / 12.92
    return ((x + 0.055) / 1.055) ** 2.4

def channel_transmission(v_srgb, leak, gamma):
    v_lin = linear_from_srgb(v_srgb)
    t = leak + (1.0 - leak) * (v_lin ** gamma)
    return max(0.0, min(1.0, t))

def subtractive_blend(c1, c2,
                              leak1=(0.02, 0.20, 0.85),
                              gamma1=(1.6, 1.4, 1.0),
                              leak2=(0.85, 0.90, 0.02),
                              gamma2=(1.0, 1.0, 1.6)):
    r1, g1, b1 = [v/255.0 for v in c1[:3]]
    r2, g2, b2 = [v/255.0 for v in c2[:3]]

    t1_r = channel_transmission(r1, leak1[0], gamma1[0])
    t1_g = channel_transmission(g1, leak1[1], gamma1[1])
    t1_b = channel_transmission(b1, leak1[2], gamma1[2])

    t2_r = channel_transmission(r2, leak2[0], gamma2[0])
    t2_g = channel_transmission(g2, leak2[1], gamma2[1])
    t2_b = channel_transmission(b2, leak2[2], gamma2[2])

    t_r = t1_r * t2_r
    t_g = t1_g * t2_g
    t_b = t1_b * t2_b

    R = int(round(255 * srgb_from_linear(t_r)))
    G = int(round(255 * srgb_from_linear(t_g)))
    B = int(round(255 * srgb_from_linear(t_b)))

    A = max(c1[3], c2[3])
    return (R, G, B, A)

def composite_shapes(shapes, sz):
    result = Image.new("RGBA", (sz, sz), (255, 255, 255, 255))
    accumulated_mask = Image.new("L", (sz, sz), 0)
    accumulated_color = None

    for coords, color in shapes:
        layer = Image.new("RGBA", (sz, sz), (0, 0, 0, 0))
        ImageDraw.Draw(layer).polygon(coords, fill=color)
        mask = layer.split()[3]

        overlap = ImageChops.multiply(accumulated_mask, mask)
        only_new = ImageChops.subtract(mask, overlap)

        if accumulated_color:
            blended = subtractive_blend(accumulated_color, color)
            result.paste(blended, mask=overlap)

        result.paste(color, mask=only_new)

        accumulated_mask = ImageChops.add(accumulated_mask, mask)
        accumulated_color = color

    return result

# Example: two triangles
blue_coords = [(0, 0), (500, 0), (250, 450)]
cx = sum(x for x, y in blue_coords) / 3
cy = sum(y for x, y in blue_coords) / 3
theta = math.radians(30)
yellow_coords = []
for (x, y) in blue_coords:
    x_new = cx + (x - cx) * math.cos(theta) - (y - cy) * math.sin(theta)
    y_new = cy + (x - cx) * math.sin(theta) + (y - cy) * math.cos(theta)
    yellow_coords.append((x_new, y_new))

blue_coords, yellow_coords = center_coords([blue_coords, yellow_coords], sz)

shapes = [
    (blue_coords, (0, 0, 255, 255)),
    (yellow_coords, (255, 255, 0, 255)),
]

result = composite_shapes(shapes, sz)

root = tk.Tk()
root.geometry(f"{sz}x{sz}+0+0")
canvas = tk.Canvas(root, width=sz, height=sz, bg="white", highlightthickness=0)
canvas.pack()
tk_img = ImageTk.PhotoImage(result)
canvas.create_image(0, 0, anchor="nw", image=tk_img)
root.mainloop()