1+ #include < thread>
2+ #include < vector>
3+ #include < algorithm>
4+ #include < glsl_generated/generated_big_math.h>
5+ #include < glsl_generated/generated_math_mapper.h>
6+ #include < array>
7+ #include < interactions/interactions.h>
8+ #include < graphics/ui.h>
9+ #include < types/types.h>
10+ #include < types/type_mapper.h>
11+ #include < glm/common.hpp>
12+
13+ thread_local std::vector<big_vec2> reg_eval_stack (512 );
14+ thread_local size_t reg_sp;
15+ thread_local big_vec2 reg_operand_a;
16+ thread_local big_vec2 reg_operand_b;
17+ thread_local big_vec2 reg_math_res;
18+
19+ void evaluate_ast_stack (
20+ const std::vector<TokenOperator>& tokens,
21+ const big_vec2& z_in,
22+ const CPU_Interpreter& interpreter,
23+ big_vec2& out_result
24+ ) {
25+ reg_sp = 0 ;
26+
27+ for (const TokenOperator& token : tokens) {
28+
29+ const Operator curr_op = token.op ;
30+ if (curr_op == Operator::VARIABLEZ) {
31+ reg_eval_stack[reg_sp] = z_in;
32+ reg_sp++;
33+ }
34+ else if (curr_op == Operator::CONSTANT) {
35+ const glm::vec2 original_vec = token.value ;
36+ reg_eval_stack[reg_sp] = big_vec2 (original_vec.x , original_vec.y );
37+ reg_sp++;
38+ }
39+ else if (token.arity == Arity::UNARY) {
40+ reg_sp--;
41+ reg_operand_a = reg_eval_stack[reg_sp];
42+
43+ reg_math_res = interpreter.unary_ops .at (token.op )(reg_operand_a);
44+
45+ reg_eval_stack[reg_sp] = reg_math_res;
46+ reg_sp++;
47+ }
48+ else if (token.arity == Arity::BINARY) {
49+ reg_sp--;
50+ reg_operand_b = reg_eval_stack[reg_sp];
51+
52+ reg_sp--;
53+ reg_operand_a = reg_eval_stack[reg_sp];
54+
55+ reg_math_res = interpreter.binary_ops .at (token.op )(reg_operand_a, reg_operand_b);
56+
57+ reg_eval_stack[reg_sp] = reg_math_res;
58+ reg_sp++;
59+ }
60+ }
61+ reg_sp--;
62+ out_result = reg_eval_stack[reg_sp];
63+ }
64+
65+ inline const big_float HALF = big_float(" 0.5" );
66+
67+ void convert_coordinates (big_vec2& z, const ViewState* view_state) {
68+ big_float w (view_state->hp_width );
69+ big_float h (view_state->hp_height );
70+
71+ z = view_state->hp_range * (z - HALF * big_vec2 (w, h)) / h;
72+ z = z + big_vec2 (view_state->hp_shift .x , view_state->hp_shift .y );
73+ }
74+
75+ std::array<uint8_t , 3 > domain_color (const big_vec2& z) {
76+ big_float angle_bf = boost::multiprecision::atan2 (z.y , z.x );
77+ big_float mag_bf = length (z);
78+
79+ double angle = static_cast <double >(angle_bf);
80+ double mag = static_cast <double >(mag_bf);
81+
82+ double hue = angle / (2.0 * 3.14159265358979323846 );
83+ if (hue < 0.0 ) hue += 1.0 ;
84+
85+ double light = (2.0 / 3.14159265358979323846 ) * std::atan (mag);
86+ double sat = 1.0 ;
87+
88+ auto glsl_mod = [](double x, double y) { return x - y * std::floor (x / y); };
89+
90+ double r_t = std::clamp (std::abs (glsl_mod (hue * 6.0 + 0.0 , 6.0 ) - 3.0 ) - 1.0 , 0.0 , 1.0 );
91+ double g_t = std::clamp (std::abs (glsl_mod (hue * 6.0 + 4.0 , 6.0 ) - 3.0 ) - 1.0 , 0.0 , 1.0 );
92+ double b_t = std::clamp (std::abs (glsl_mod (hue * 6.0 + 2.0 , 6.0 ) - 3.0 ) - 1.0 , 0.0 , 1.0 );
93+
94+ double chroma = 1.0 - std::abs (2.0 * light - 1.0 );
95+
96+ double r = light + sat * (r_t - 0.5 ) * chroma;
97+ double g = light + sat * (g_t - 0.5 ) * chroma;
98+ double b = light + sat * (b_t - 0.5 ) * chroma;
99+
100+ return std::array<uint8_t , 3 >{static_cast <uint8_t >(r * 255.0 ), static_cast <uint8_t >(g * 255.0 ), static_cast <uint8_t >(b * 255.0 )};
101+ }
102+
103+ void render_band (int start_y, int end_y, int width, int height, unsigned char * pixel_buffer, const CPU_Interpreter& interpreter, const std::vector<TokenOperator>& stack, const ViewState* view_state) {
104+ for (int y = start_y; y < end_y; ++y) {
105+ for (int x = 0 ; x < width; ++x) {
106+
107+ big_vec2 z (big_float (x), big_float (height - y));
108+
109+ convert_coordinates (z, view_state);
110+
111+ big_vec2 result;
112+ evaluate_ast_stack (stack, z, interpreter, result);
113+
114+ std::array<uint8_t , 3 > color_val = domain_color (result);
115+
116+ int index = (y * width + x) * 4 ;
117+ pixel_buffer[index + 0 ] = color_val[0 ];
118+ pixel_buffer[index + 1 ] = color_val[1 ];
119+ pixel_buffer[index + 2 ] = color_val[2 ];
120+ pixel_buffer[index + 3 ] = 255 ;
121+ }
122+ }
123+ }
124+
125+ void dispatch_render (int width, int height, unsigned char * pixel_buffer, CPU_Interpreter& interpreter, int user_thread_limit, const std::vector<TokenOperator>& stack, const ViewState* view_state) {
126+ int hardware_threads = std::thread::hardware_concurrency ();
127+ if (hardware_threads == 0 ) hardware_threads = 4 ;
128+
129+ int num_threads = std::min (hardware_threads, user_thread_limit);
130+ if (num_threads < 1 ) num_threads = 1 ;
131+
132+ std::vector<std::thread> threads;
133+ int rows_per_thread = height / num_threads;
134+
135+ for (int i = 0 ; i < num_threads; ++i) {
136+ int start_y = i * rows_per_thread;
137+ int end_y = (i == num_threads - 1 ) ? height : start_y + rows_per_thread;
138+ threads.emplace_back (
139+ render_band,
140+ start_y, end_y, width, height,
141+ pixel_buffer, std::ref (interpreter), std::ref (stack), view_state
142+ );
143+ }
144+ for (auto & t : threads) {
145+ if (t.joinable ()) {
146+ t.join ();
147+ }
148+ }
149+ }
0 commit comments