1 | #include "ZydecoCommon.hpp" |
2 | #include "Mandelbrot.hpp" |
3 | #include "IEventHandler.hpp" |
4 | #include "IWindow.hpp" |
5 | #include "IEventMouseSubscriber.hpp" |
6 | #include "GLRenderObjectFractal.hpp" |
7 | #include "GLProgram.hpp" |
8 | #include "GLTexture.hpp" |
9 |
|
10 | static Logger LOGGER("Mandelbrot"); |
11 |
|
12 |
|
13 | ldvec3 ComplexSquare(ldvec3 in) |
14 | { |
15 | long double real_part = in.x*in.x - in.y*in.y; |
16 | long double complex_part = 2.*in.x*in.y; |
17 | return ldvec3{real_part, complex_part, in.z}; |
18 | } |
19 |
|
20 |
|
21 | Mandelbrot::Mandelbrot(IEventHandler& r_event_handler, IWindow& r_window, MandelbrotSettings *p_settings): |
22 | m_rEventHandler(r_event_handler), |
23 | m_rWindow(r_window), |
24 | m_pSettings(p_settings) |
25 | { |
26 | r_event_handler.RegisterMouseEventSubscriber(this); |
27 |
|
28 | m_windowWidth = r_window.GetWidth(); |
29 | m_windowHeight = r_window.GetHeight(); |
30 |
|
31 |
|
32 | m_pTexture = new GLTexture("Mandelbrot", nullptr, m_windowWidth, m_windowHeight); |
33 |
|
34 | m_pSettings->restart = true; |
35 | m_pRenderObject = new GLRenderObjectFractal {}; |
36 | m_pRenderObject->AddTexture(0, m_pTexture); |
37 | m_pTexture->Regenerate(m_windowWidth, m_windowHeight); |
38 | m_pRenderObject->RenderSetUniform<1, int>("texture0", {new int {0}}); |
39 | m_pRenderObject->RenderSetUniform<2, int>("screensize", {&m_windowWidth, &m_windowHeight}); |
40 | m_pRenderObject->RenderSetUniform<1, int>("it_count", {&m_pSettings->adjusted_iteration_step}); |
41 | m_pRenderObject->RenderSetUniform<1, double>("zoom", {&m_pSettings->zoom}); |
42 | m_pRenderObject->RenderSetUniform<1, float>("brightness", {&m_pSettings->brightness}); |
43 | m_pRenderObject->RenderSetUniform<1, int>("enable_interlacing", {&m_pSettings->do_interlacing}); |
44 | m_pRenderObject->RenderSetUniform<1, int>("interlace_layer", {&m_pSettings->interlace_layer}); |
45 | m_pRenderObject->RenderSetUniform<1, int>("first_interlace", {&m_pSettings->first_interlace}); |
46 | } |
47 |
|
48 | Mandelbrot::~Mandelbrot() |
49 | { |
50 | delete m_pRenderObject; |
51 | delete m_pTexture; |
52 | } |
53 |
|
54 | bool Mandelbrot::Update() |
55 | { |
56 | uint64_t updated_window_width = m_rWindow.GetWidth(); |
57 | uint64_t updated_window_height = m_rWindow.GetHeight(); |
58 | if (updated_window_width != m_windowWidth || updated_window_height != m_windowHeight) |
59 | { |
60 | m_windowWidth = updated_window_width; |
61 | m_windowHeight = updated_window_height; |
62 | m_pSettings->current_iteration = 0; |
63 | m_pSettings->interlace_layer = 0; |
64 | m_pSettings->first_interlace = 1; |
65 | m_pSettings->restart = false; |
66 | m_pTexture->Regenerate(m_windowWidth, m_windowHeight); |
67 | } |
68 | else if (m_pSettings->restart) |
69 | { |
70 | m_pSettings->current_iteration = 0; |
71 | m_pSettings->interlace_layer = 0; |
72 | m_pSettings->first_interlace = 1; |
73 | } |
74 |
|
75 | if (m_pSettings->current_iteration >= m_pSettings->adjusted_iteration_step) { return false; } |
76 |
|
77 | m_pSettings->adjusted_iteration_step = m_pSettings->iteration_step * log2(2.0 + 1./m_pSettings->zoom); |
78 |
|
79 |
|
80 | bool waiting = false; |
81 | if (m_glSyncObject != nullptr) |
82 | { |
83 | int previous_invocation_finished = 0; |
84 | glGetSynciv(m_glSyncObject, GL_SYNC_STATUS, 1, nullptr, &previous_invocation_finished); |
85 | if (previous_invocation_finished == GL_SIGNALED) |
86 | { |
87 | waiting = false; |
88 | glDeleteSync(m_glSyncObject); |
89 | m_glSyncObject = nullptr; |
90 | } |
91 | else |
92 | { |
93 | waiting = true; |
94 | } |
95 | } |
96 |
|
97 |
|
98 | if (!waiting) |
99 | { |
100 | if (m_pSettings->do_interlacing) |
101 | { |
102 | if (m_pSettings->interlace_layer == 7) |
103 | { |
104 | m_pSettings->current_iteration += m_pSettings->adjusted_iteration_step; |
105 | m_pSettings->interlace_layer = 1; |
106 | m_pSettings->first_interlace = 0; |
107 | //if (m_pSettings->current_iteration >= m_pSettings->iteration_count) { return false; } |
108 | } |
109 | else |
110 | { |
111 | m_pSettings->interlace_layer++; |
112 | } |
113 | } |
114 | else |
115 | { |
116 | m_pSettings->interlace_layer = 1; |
117 | m_pSettings->first_interlace = 1; |
118 | } |
119 |
|
120 | if (m_pSettings->restart) |
121 | { |
122 | m_pSettings->restart = false; |
123 | m_pTexture->Regenerate(m_windowWidth, m_windowHeight); |
124 | } |
125 |
|
126 | LOGGER.Log(Logger::INFO, "Dispatching compute (interlace layer {})", m_pSettings->interlace_layer); |
127 |
|
128 | int program = GLProgram::GetGLProgram("FractalCompute")->GetGLProgramID(); |
129 |
|
130 | glUseProgram(program); |
131 |
|
132 | glBindImageTexture(0, m_pTexture->m_glTextureID, 0, false, 0, GL_READ_WRITE, GL_RGBA32F); |
133 |
|
134 | glUniform1i(glGetUniformLocation(program, "texture0"), 0); |
135 | glUniform2i(glGetUniformLocation(program, "screensize"), m_windowWidth, m_windowHeight); |
136 | glUniform2d(glGetUniformLocation(program, "offset"), m_pSettings->pos_x, m_pSettings->pos_y); |
137 | glUniform1d(glGetUniformLocation(program, "zoom"), m_pSettings->zoom); |
138 | glUniform1d(glGetUniformLocation(program, "z"), m_pSettings->param_z); |
139 | glUniform1d(glGetUniformLocation(program, "discard_threshold"), m_pSettings->discard_threshold); |
140 | glUniform1i(glGetUniformLocation(program, "current_iteration"), m_pSettings->current_iteration); |
141 | glUniform1i(glGetUniformLocation(program, "it_steps"), m_pSettings->adjusted_iteration_step); |
142 | glUniform1i(glGetUniformLocation(program, "enable_interlacing"), m_pSettings->do_interlacing); |
143 | glUniform1i(glGetUniformLocation(program, "interlace_layer"), m_pSettings->interlace_layer); |
144 | glUniform1i(glGetUniformLocation(program, "first_interlace"), m_pSettings->first_interlace); |
145 |
|
146 | glDispatchCompute((updated_window_width+31)/32, (updated_window_height+31)/32, 1); |
147 |
|
148 | if (!m_pSettings->do_interlacing) |
149 | { |
150 | m_pSettings->current_iteration += m_pSettings->adjusted_iteration_step; |
151 | } |
152 |
|
153 | glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); |
154 | } |
155 |
|
156 | return false; |
157 | } |
158 |
|
159 | void Mandelbrot::OnMouseLeftDownEvent(uint64_t x, uint64_t y) |
160 | { |
161 | m_mouseDown = true; |
162 | } |
163 |
|
164 | void Mandelbrot::OnMouseLeftUpEvent(uint64_t x, uint64_t y) |
165 | { |
166 | m_mouseDown = false; |
167 | } |
168 |
|
169 | void Mandelbrot::OnMouseMiddleDownEvent(uint64_t x, uint64_t y) |
170 | { |
171 |
|
172 | } |
173 |
|
174 | void Mandelbrot::OnMouseMiddleUpEvent(uint64_t x, uint64_t y) |
175 | { |
176 |
|
177 | } |
178 |
|
179 | void Mandelbrot::OnMouseRightDownEvent(uint64_t x, uint64_t y) |
180 | { |
181 |
|
182 | } |
183 |
|
184 | void Mandelbrot::OnMouseRightUpEvent(uint64_t x, uint64_t y) |
185 | { |
186 |
|
187 | } |
188 |
|
189 | void Mandelbrot::OnMouseMoveEvent(uint64_t x, uint64_t y, int64_t dx, int64_t dy) |
190 | { |
191 | m_mousex = x; |
192 | m_mousey = y; |
193 |
|
194 | if (m_mouseDown) { |
195 | m_pSettings->pos_x += static_cast<long double>(dx) * m_pSettings->zoom; |
196 | m_pSettings->pos_y -= static_cast<long double>(dy) * m_pSettings->zoom; |
197 |
|
198 | m_pSettings->restart = true; |
199 |
|
200 | LOGGER.Log(Logger::INFO, "X, Y: <{}, {}>", m_pSettings->pos_x, m_pSettings->pos_y); |
201 | } |
202 | } |
203 |
|
204 | void Mandelbrot::OnMouseWheelScrollEvent(int64_t dx, int64_t dy) |
205 | { |
206 | float factor = static_cast<long double>(dy) / 1'000'000'000.; |
207 |
|
208 | double old_view_width = (long double)m_windowWidth * m_pSettings->zoom; |
209 | double old_view_height = (long double)m_windowHeight * m_pSettings->zoom; |
210 |
|
211 | if (dy > 0) |
212 | { |
213 | m_pSettings->zoom /= factor; |
214 | } |
215 | else if (dy < 0) |
216 | { |
217 | m_pSettings->zoom *= -factor; |
218 | } |
219 |
|
220 | long double xrel = ((long double)m_mousex / (long double)m_windowWidth) - 0.5; |
221 | long double yrel = ((long double)m_mousey / (long double)m_windowHeight) - 0.5; |
222 |
|
223 | long double new_view_width = (long double)m_windowWidth * m_pSettings->zoom; |
224 | long double new_view_height = (long double)m_windowHeight * m_pSettings->zoom; |
225 |
|
226 | long double xdelta = xrel*(new_view_width - old_view_width); |
227 | long double ydelta = yrel*(new_view_height - old_view_height); |
228 |
|
229 | m_pSettings->pos_x += xdelta; |
230 | m_pSettings->pos_y -= ydelta; |
231 |
|
232 | m_pSettings->restart = true; |
233 |
|
234 | LOGGER.Log(Logger::INFO, "Zoom level: {}", m_pSettings->zoom); |
235 | } |
236 |
|