Skip to content

Commit 9d77d5b

Browse files
authored
Merge pull request #42 from ruifonseca/example/aurora
Adds aurora.psh example
2 parents 23e07f6 + 3dbed42 commit 9d77d5b

1 file changed

Lines changed: 139 additions & 0 deletions

File tree

examples/aurora.psh

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
// Mandelbrot Set Explorer
2+
3+
// This example builds on mandelbrot.psh.
4+
// Differences:
5+
// - Uses a different palette with green aurora borealis colors
6+
// - Renders the set concurrently using actors
7+
//
8+
// Each actor is given a (logical) portion of the image.
9+
// For each pixel it calculates the color to render and
10+
// sends a message to the main actor with the index and
11+
// the color to paint, both packed in a single Integer.
12+
13+
let WIDTH = 640;
14+
let HEIGHT = 480;
15+
16+
// The region of the complex plane to render
17+
let RE_START = -2.0;
18+
let RE_END = 1.0;
19+
let IM_START = -1.125;
20+
let IM_END = 1.125;
21+
22+
let MAX_ITER = 60;
23+
let NTHREADS = 16;
24+
25+
// Distribute rows to hand to actors
26+
fun calc_boundaries() {
27+
let chunk_size = HEIGHT _/ NTHREADS;
28+
let rem = HEIGHT % NTHREADS;
29+
let var limit = 0;
30+
31+
let boundaries = [];
32+
for (let var i=0; i<NTHREADS; ++i) {
33+
limit += (chunk_size + ((i < rem) ? 1 : 0));
34+
boundaries.push(limit);
35+
}
36+
37+
return boundaries;
38+
}
39+
40+
// Helper function to convert RGB values to a 32-bit color
41+
fun rgb32(r, g, b) {
42+
return 0xFF_00_00_00 | (r << 16) | (g << 8) | b;
43+
}
44+
45+
// Create a simple green aurora borealis color palette.
46+
// Go from rgb(21, 53, 72) to rgb(153, 233, 180) in 7 steps.
47+
let palette = [];
48+
for (let var i = 0; i < 7; ++i) {
49+
palette.push(rgb32(21+i*22, 53+i*30, 72+i*18));
50+
}
51+
52+
// Check if a point is in the Mandelbrot set in max_iter steps
53+
fun fugue(c_re, c_im, max_iter) {
54+
let var z_re = 0.0;
55+
let var z_im = 0.0;
56+
let var iter = 0;
57+
58+
while (z_re * z_re + z_im * z_im <= 4.0 && iter < max_iter) {
59+
let z_re_new = z_re * z_re - z_im * z_im + c_re;
60+
z_im = 2.0 * z_re * z_im + c_im;
61+
z_re = z_re_new;
62+
iter = iter + 1;
63+
}
64+
65+
return iter;
66+
}
67+
68+
// Colorize buffer points from..to
69+
fun colorizer(from, to) {
70+
for (let var y = from; y < to; ++y) {
71+
for (let var x = 0; x < WIDTH; ++x) {
72+
let c_re = RE_START + (x / WIDTH) * (RE_END - RE_START);
73+
let c_im = IM_START + (y / HEIGHT) * (IM_END - IM_START);
74+
75+
let iter = fugue(c_re, c_im, MAX_ITER);
76+
77+
// Set the pixel color based on the number of iterations
78+
let color = (iter == MAX_ITER) ? rgb32(0, 0, 0) : palette[iter % 7];
79+
80+
// send a single integer message to the main actor,
81+
// packing the color and the index of the frame buffer.
82+
let idx = (y * WIDTH + x) << 32;
83+
$actor_send(0, idx + color);
84+
}
85+
}
86+
// actor is done
87+
$actor_send(0, 0);
88+
}
89+
90+
// Color pixels in parallel
91+
let start_time = $time_current_ms();
92+
93+
let boundaries = calc_boundaries();
94+
let var start = 0;
95+
for (let var i = 0; i < boundaries.len; ++i) {
96+
// ignore the id of the actor...
97+
$actor_spawn(|| colorizer(start, boundaries[i]));
98+
start = boundaries[i];
99+
}
100+
101+
let frame_buffer = ByteArray.with_size(WIDTH * HEIGHT * 4);
102+
103+
// Main actor - loop until all actors are done
104+
let var completed = 0;
105+
loop {
106+
let msg = $actor_recv();
107+
108+
if (msg == 0) {
109+
if (++completed == NTHREADS) {
110+
break;
111+
}
112+
}
113+
let color = msg & 0x00000000_FFFFFFFF;
114+
let idx = msg >> 32;
115+
frame_buffer.set_u32(idx, color);
116+
}
117+
118+
// print render time
119+
let render_time = $time_current_ms() - start_time;
120+
$println("Mandelbrot render time: " + render_time.to_s() + "ms");
121+
122+
// --- Window and Event Loop ---
123+
let window = $window_create(WIDTH, HEIGHT, "Mandelbrot Set", 0);
124+
$window_draw_frame(window, frame_buffer);
125+
126+
loop {
127+
let msg = $actor_recv();
128+
129+
if (!(msg instanceof UIEvent)) {
130+
continue;
131+
}
132+
if (msg.kind == 'CLOSE_WINDOW' || (msg.kind == 'KEY_DOWN' && msg.key == 'ESCAPE')) {
133+
break;
134+
}
135+
$window_draw_frame(window, frame_buffer);
136+
}
137+
138+
// well, this helps a bit in Vim...
139+
// vim: set syn=cpp:

0 commit comments

Comments
 (0)