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