Skip to content

Commit 940b332

Browse files
Restructure the CLI and polygon color formatting
Extract parse_args() from main(), unfold the color-cache conditional into a plain if/else inside the render loop, wire --cache-colors through the windowed viewer, and order helpers below their callers in assets.py and make_assets.py. No behavior change. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 4cd77b6 commit 940b332

5 files changed

Lines changed: 111 additions & 104 deletions

File tree

python315-sampling-profiler/make_assets.py

Lines changed: 64 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -28,33 +28,49 @@
2828
}
2929

3030

31-
def trace_trefoil(t: float) -> Vector:
32-
return (
33-
math.sin(t) + 2.0 * math.sin(2.0 * t),
34-
math.cos(t) - 2.0 * math.cos(2.0 * t),
35-
-math.sin(3.0 * t) * 1.2,
36-
)
37-
38-
39-
def subtract(a: Vector, b: Vector) -> Vector:
40-
return (a[0] - b[0], a[1] - b[1], a[2] - b[2])
41-
42-
43-
def cross(a: Vector, b: Vector) -> Vector:
44-
return (
45-
a[1] * b[2] - a[2] * b[1],
46-
a[2] * b[0] - a[0] * b[2],
47-
a[0] * b[1] - a[1] * b[0],
48-
)
31+
def main() -> None:
32+
ASSETS_DIR.mkdir(parents=True, exist_ok=True)
33+
write_mesh(ASSETS_DIR / "pretzel.mdl")
34+
for name, (top, bottom, glow) in WALLPAPERS.items():
35+
write_wallpaper(ASSETS_DIR / name, top, bottom, glow)
4936

5037

51-
def dot(a: Vector, b: Vector) -> float:
52-
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]
38+
def write_mesh(path: pathlib.Path) -> None:
39+
vertices, faces = sweep_tube()
40+
with path.open("w", encoding="utf-8") as file:
41+
file.write(f"# Trefoil-knot pretzel: {len(vertices)} vertices,")
42+
file.write(f" {len(faces)} faces\n")
43+
for x, y, z in vertices:
44+
file.write(f"v {x:.6f} {y:.6f} {z:.6f}\n")
45+
for a, b, c in faces:
46+
file.write(f"f {a + 1} {b + 1} {c + 1}\n")
47+
print(f"Wrote {path} ({len(vertices)} vertices, {len(faces)} faces)")
5348

5449

55-
def normalize(vector: Vector) -> Vector:
56-
length = math.sqrt(dot(vector, vector)) or 1.0
57-
return (vector[0] / length, vector[1] / length, vector[2] / length)
50+
def write_wallpaper(
51+
path: pathlib.Path, top: Color, bottom: Color, glow: Color
52+
) -> None:
53+
size = WALLPAPER_SIZE
54+
lights = [
55+
(size * 0.25, size * 0.3, size * 0.22),
56+
(size * 0.7, size * 0.55, size * 0.3),
57+
(size * 0.45, size * 0.8, size * 0.18),
58+
]
59+
rows = bytearray()
60+
for y in range(size):
61+
vertical = y / (size - 1)
62+
base = blend(top, bottom, vertical)
63+
for x in range(size):
64+
halo = 0.0
65+
for cx, cy, radius in lights:
66+
distance = math.hypot(x - cx, y - cy)
67+
halo += max(0.0, 1.0 - distance / radius) ** 2
68+
color = blend(base, glow, min(1.0, halo))
69+
rows.extend(color)
70+
with path.open("wb") as file:
71+
file.write(b"P6\n%d %d\n255\n" % (size, size))
72+
file.write(rows)
73+
print(f"Wrote {path} ({size}x{size})")
5874

5975

6076
def sweep_tube() -> tuple[list[Vector], list[Face]]:
@@ -101,56 +117,40 @@ def sweep_tube() -> tuple[list[Vector], list[Face]]:
101117
return vertices, faces
102118

103119

104-
def write_mesh(path: pathlib.Path) -> None:
105-
vertices, faces = sweep_tube()
106-
with path.open("w", encoding="utf-8") as file:
107-
file.write(f"# Trefoil-knot pretzel: {len(vertices)} vertices,")
108-
file.write(f" {len(faces)} faces\n")
109-
for x, y, z in vertices:
110-
file.write(f"v {x:.6f} {y:.6f} {z:.6f}\n")
111-
for a, b, c in faces:
112-
file.write(f"f {a + 1} {b + 1} {c + 1}\n")
113-
print(f"Wrote {path} ({len(vertices)} vertices, {len(faces)} faces)")
114-
115-
116120
def blend(low: Color, high: Color, amount: float) -> Color:
117121
return tuple(
118122
round(low[channel] + (high[channel] - low[channel]) * amount)
119123
for channel in range(3)
120124
)
121125

122126

123-
def write_wallpaper(
124-
path: pathlib.Path, top: Color, bottom: Color, glow: Color
125-
) -> None:
126-
size = WALLPAPER_SIZE
127-
lights = [
128-
(size * 0.25, size * 0.3, size * 0.22),
129-
(size * 0.7, size * 0.55, size * 0.3),
130-
(size * 0.45, size * 0.8, size * 0.18),
131-
]
132-
rows = bytearray()
133-
for y in range(size):
134-
vertical = y / (size - 1)
135-
base = blend(top, bottom, vertical)
136-
for x in range(size):
137-
halo = 0.0
138-
for cx, cy, radius in lights:
139-
distance = math.hypot(x - cx, y - cy)
140-
halo += max(0.0, 1.0 - distance / radius) ** 2
141-
color = blend(base, glow, min(1.0, halo))
142-
rows.extend(color)
143-
with path.open("wb") as file:
144-
file.write(b"P6\n%d %d\n255\n" % (size, size))
145-
file.write(rows)
146-
print(f"Wrote {path} ({size}x{size})")
127+
def trace_trefoil(t: float) -> Vector:
128+
return (
129+
math.sin(t) + 2.0 * math.sin(2.0 * t),
130+
math.cos(t) - 2.0 * math.cos(2.0 * t),
131+
-math.sin(3.0 * t) * 1.2,
132+
)
147133

148134

149-
def main() -> None:
150-
ASSETS_DIR.mkdir(parents=True, exist_ok=True)
151-
write_mesh(ASSETS_DIR / "pretzel.mdl")
152-
for name, (top, bottom, glow) in WALLPAPERS.items():
153-
write_wallpaper(ASSETS_DIR / name, top, bottom, glow)
135+
def subtract(a: Vector, b: Vector) -> Vector:
136+
return (a[0] - b[0], a[1] - b[1], a[2] - b[2])
137+
138+
139+
def cross(a: Vector, b: Vector) -> Vector:
140+
return (
141+
a[1] * b[2] - a[2] * b[1],
142+
a[2] * b[0] - a[0] * b[2],
143+
a[0] * b[1] - a[1] * b[0],
144+
)
145+
146+
147+
def dot(a: Vector, b: Vector) -> float:
148+
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]
149+
150+
151+
def normalize(vector: Vector) -> Vector:
152+
length = math.sqrt(dot(vector, vector)) or 1.0
153+
return (vector[0] / length, vector[1] / length, vector[2] / length)
154154

155155

156156
if __name__ == "__main__":

python315-sampling-profiler/src/pretzel/assets.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,6 @@ class Background:
1919
pixels: npt.NDArray[np.float32]
2020

2121

22-
def asset_path(name: str) -> str:
23-
return str(ASSETS_DIR / name)
24-
25-
2622
def load_mesh(name: str) -> Mesh:
2723
vertices: list[Vertex] = []
2824
faces: list[Face] = []
@@ -60,10 +56,6 @@ def decode_ppm_pixel_by_pixel(path: str) -> npt.NDArray[np.float32]:
6056
return np.array(rows, dtype=np.float32)
6157

6258

63-
def to_linear(value: int) -> float:
64-
return 255.0 * (value / 255.0) ** 2.2
65-
66-
6759
def decode_ppm(path: str) -> npt.NDArray[np.float32]:
6860
with open(path, "rb") as file:
6961
width, height = read_ppm_header(file)
@@ -80,3 +72,11 @@ def read_ppm_header(file: BinaryIO) -> tuple[int, int]:
8072
width, height = map(int, file.readline().split())
8173
file.readline()
8274
return width, height
75+
76+
77+
def to_linear(value: int) -> float:
78+
return 255.0 * (value / 255.0) ** 2.2
79+
80+
81+
def asset_path(name: str) -> str:
82+
return str(ASSETS_DIR / name)

python315-sampling-profiler/src/pretzel/cli.py

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,33 +14,14 @@
1414

1515

1616
def main() -> None:
17-
parser = argparse.ArgumentParser(prog="pretzel", description=__doc__)
18-
parser.add_argument(
19-
"--frames",
20-
metavar="N",
21-
type=int,
22-
default=None,
23-
help="render N frames headlessly instead of opening a window",
24-
)
25-
parser.add_argument(
26-
"--fast",
27-
action="store_true",
28-
help="use the optimized asset loader and buffered telemetry",
29-
)
30-
parser.add_argument(
31-
"--cache-colors",
32-
action="store_true",
33-
help="memoize polygon color formatting in headless mode",
34-
)
35-
args = parser.parse_args()
36-
17+
args = parse_args()
3718
mesh = assets.load_mesh(MODEL)
3819
streamer = BackgroundStreamer(fast=args.fast)
3920
streamer.start()
4021
frame_log = FrameLog("telemetry.csv", durable=not args.fast)
4122
try:
4223
if args.frames is None:
43-
show_window(mesh, streamer, frame_log)
24+
show_window(mesh, streamer, frame_log, args.cache_colors)
4425
else:
4526
render_headlessly(
4627
mesh, streamer, frame_log, args.frames, args.cache_colors
@@ -50,11 +31,14 @@ def main() -> None:
5031

5132

5233
def show_window(
53-
mesh: Mesh, streamer: BackgroundStreamer, frame_log: FrameLog
34+
mesh: Mesh,
35+
streamer: BackgroundStreamer,
36+
frame_log: FrameLog,
37+
cache_colors: bool = False,
5438
) -> None:
5539
from pretzel.viewer import Viewer
5640

57-
Viewer(mesh, streamer, frame_log).run()
41+
Viewer(mesh, streamer, frame_log, cache_colors).run()
5842

5943

6044
def render_headlessly(
@@ -78,3 +62,25 @@ def render_headlessly(
7862
print(
7963
f"Rendered {frames} frames in {total:.2f}s ({frames / total:.1f} fps)"
8064
)
65+
66+
67+
def parse_args() -> argparse.Namespace:
68+
parser = argparse.ArgumentParser(prog="pretzel", description=__doc__)
69+
parser.add_argument(
70+
"--frames",
71+
metavar="N",
72+
type=int,
73+
default=None,
74+
help="render N frames headlessly instead of opening a window",
75+
)
76+
parser.add_argument(
77+
"--fast",
78+
action="store_true",
79+
help="use the optimized asset loader and buffered telemetry",
80+
)
81+
parser.add_argument(
82+
"--cache-colors",
83+
action="store_true",
84+
help="memoize polygon color formatting",
85+
)
86+
return parser.parse_args()

python315-sampling-profiler/src/pretzel/render.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,11 @@ def compute_frame(
4040
coordinates: list[float] = []
4141
for index in face:
4242
coordinates.extend(projected[index])
43-
polygons.append(
44-
(
45-
coordinates,
46-
hex_color(red, green, blue)
47-
if cache_colors
48-
else f"#{red:02x}{green:02x}{blue:02x}",
49-
)
50-
)
43+
if cache_colors:
44+
color = hex_color(red, green, blue)
45+
else:
46+
color = f"#{red:02x}{green:02x}{blue:02x}"
47+
polygons.append((coordinates, color))
5148
return polygons
5249

5350

python315-sampling-profiler/src/pretzel/viewer.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@ def __init__(
1919
mesh: Mesh,
2020
streamer: BackgroundStreamer,
2121
frame_log: FrameLog,
22+
cache_colors: bool = False,
2223
) -> None:
2324
self.mesh = mesh
2425
self.streamer = streamer
2526
self.frame_log = frame_log
27+
self.cache_colors = cache_colors
2628
self.frame = 0
2729
self.started = time.perf_counter()
2830
self.window = tk.Tk()
@@ -47,7 +49,9 @@ def render_next_frame(self) -> None:
4749
if background.path != str(self.wallpaper.cget("file")):
4850
self.wallpaper.configure(file=background.path)
4951
tick = frame_started - self.started
50-
polygons = compute_frame(self.mesh, background, tick, WIDTH, HEIGHT)
52+
polygons = compute_frame(
53+
self.mesh, background, tick, WIDTH, HEIGHT, self.cache_colors
54+
)
5155
self.canvas.delete("model")
5256
for coordinates, color in polygons:
5357
self.canvas.create_polygon(

0 commit comments

Comments
 (0)