# tk_Basic_Optimizations_Demo.py
import tkinter as tk
canvas_width = 600
canvas_height = 600
pan_offset_x = 0
scene_objects = [
[50, 50, 50, 0, 0],
[150, 70, 40, 1, 0],
[250, 60, 60, 0, 1],
[350, 80, 30, 1, 1],
[450, 90, 55, 0, 2],
[550, 100, 45, 1, 2],
[100, 250, 70, 0, 0],
[200, 270, 50, 1, 0],
[300, 260, 80, 0, 1],
[400, 280, 35, 1, 1],
[500, 290, 65, 0, 2],
[50, 450, 60, 0, 0],
[150, 470, 45, 1, 0],
[250, 460, 75, 0, 1],
[350, 480, 38, 1, 1],
[450, 490, 60, 0, 2],
[550, 500, 50, 1, 2]
]
zsort_triangles = [
[60, 50, 50, 2, 0],
[80, 150, 50, 2, 0],
[220, 120, 60, 2, 1],
[400, 70, 70, 2, 2],
[520, 150, 80, 2, 3],
[100, 350, 90, 2, 4],
[300, 450, 100, 2, 5],
[580, 300, 70, 2, 6],
[180, 270, 60, 2, 7],
[480, 370, 80, 2, 8],
[360, 240, 90, 2, 9],
[60, 50, 15, 2, 0],
[100, 70, 10, 2, 1],
[140, 90, 12, 2, 2],
[180, 110, 8, 2, 3],
[220, 130, 14, 2, 4],
[260, 150, 9, 2, 5],
[300, 170, 13, 2, 6],
[340, 190, 11, 2, 7],
[380, 210, 10, 2, 8],
[420, 230, 12, 2, 9],
[460, 250, 14, 2, 10],
[500, 270, 9, 2, 11],
[540, 290, 13, 2, 12],
[580, 310, 11, 2, 13],
[100, 350, 10, 2, 14],
[140, 370, 12, 2, 15],
[180, 390, 8, 2, 16],
[220, 410, 14, 2, 17],
[260, 430, 9, 2, 18],
[300, 450, 13, 2, 19]
]
occluder = [200, 200, 200, "gray"]
frustum = [120, 120, 480, 480]
def get_wrapped_x(x):
return (x + pan_offset_x) % canvas_width
def get_bounding_box(x, y, size):
return (x, y, x + size, y + size)
def is_inside_frustum(x, y, size):
left, top, right, bottom = get_bounding_box(get_wrapped_x(x), y, size)
return not (right < frustum[0] or left > frustum[2] or bottom < frustum[1] or top > frustum[3])
def is_occluded(x, y, size):
left, top, right, bottom = get_bounding_box(get_wrapped_x(x), y, size)
return (left >= occluder[0] and top >= occluder[1] and right <= occluder[0] + occluder[2] and bottom <= occluder[1] + occluder[2])
def draw_object(x, y, size, shape_type, dashed=False, stationary=False):
x = x if stationary else get_wrapped_x(x)
dash = (2, 2) if dashed else None
outline = "black"
if shape_type == 0: # Rectangle
fill = "blue"
canvas.create_rectangle(x, y, x + size, y + size, fill=fill if not dashed else "", outline=outline, dash=dash)
elif shape_type == 1: # Oval
fill = "red"
canvas.create_oval(x, y, x + size, y + size, fill=fill if not dashed else "", outline=outline, dash=dash)
elif shape_type == 2: # Triangle
fill = "green"
points = [
x + size / 2, y,
x, y + size,
x + size, y + size
]
canvas.create_polygon(points, fill=fill, outline=outline,)
def draw_square(x, y, size, fill_color="blue"):
canvas.create_rectangle(x, y, x + size, y + size, fill=fill_color, outline="black")
def render_scene():
canvas.delete("all")
canvas.create_text(300, 20, text="Basic Optimizations Demo", fill="black", font=("Arial", 12))
draw_square(occluder[0], occluder[1], occluder[2], occluder[3])
canvas.create_text(occluder[0], occluder[1], text="Occluder", fill="black", anchor="s")
canvas.create_rectangle(frustum[0], frustum[1], frustum[2], frustum[3], outline="cyan", width=2)
canvas.create_text(frustum[0], frustum[1], text="Frustum", fill="cyan", anchor="s")
all_objects = scene_objects + zsort_triangles
if enable_zsort.get():
all_objects = sorted(all_objects, key=lambda o: o[2]) # ascending
else:
all_objects = sorted(all_objects, key=lambda o: -o[2]) # descending
for obj in all_objects:
x, y, size, shape_type, _ = obj
stationary = (shape_type == 2)
frustum_culled = enable_frustum.get() and not is_inside_frustum(x, y, size)
occlusion_culled = enable_occlusion.get() and is_occluded(x, y, size)
dashed = frustum_culled or occlusion_culled
draw_object(x, y, size, shape_type, dashed=dashed, stationary=stationary)
def auto_pan():
global pan_offset_x
pan_offset_x -= 2
render_scene()
root.after(20, auto_pan)
root = tk.Tk()
root.title("Basic Optimizations Demo")
root.geometry("800x600+0+0")
canvas = tk.Canvas(root, width=canvas_width, height=canvas_height, bg="white")
canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
control_frame = tk.Frame(root)
control_frame.pack(side=tk.RIGHT, fill=tk.Y)
enable_frustum = tk.BooleanVar()
enable_occlusion = tk.BooleanVar()
enable_zsort = tk.BooleanVar()
tk.Checkbutton(control_frame, text="Frustum Culling", variable=enable_frustum, command=render_scene).pack(anchor="w", padx=10, pady=5)
tk.Checkbutton(control_frame, text="Occlusion Culling", variable=enable_occlusion, command=render_scene).pack(anchor="w", padx=10, pady=5)
tk.Checkbutton(control_frame, text="Z-Index Sorting", variable=enable_zsort, command=render_scene).pack(anchor="w", padx=10, pady=5)
render_scene()
auto_pan()
root.mainloop()