Index

zydeco / fractal

Experiment in graphics programming, C++, OpenGL, simulation techniques.

Latest Commit

{#}TimeHashSubjectAuthor#(+)(-)GPG?
1008 Dec 2023 15:215a717feFractal renderer update for articleJosh Stockin13530G

Blob @ zydeco / src / game / Mandelbrot.cpp

text/plain8244 bytesdownload raw
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
11static Logger LOGGER("Mandelbrot");
12
13
14ldvec3 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
22Mandelbrot::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
61Mandelbrot::~Mandelbrot()
62{
63 delete m_pRenderObject;
64 delete m_pTexture;
65}
66
67bool 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
164void Mandelbrot::OnMouseLeftDownEvent(uint64_t x, uint64_t y)
165{
166 m_mouseDown = true;
167}
168
169void Mandelbrot::OnMouseLeftUpEvent(uint64_t x, uint64_t y)
170{
171 m_mouseDown = false;
172}
173
174void Mandelbrot::OnMouseMiddleDownEvent(uint64_t x, uint64_t y)
175{
176
177}
178
179void Mandelbrot::OnMouseMiddleUpEvent(uint64_t x, uint64_t y)
180{
181
182}
183
184void Mandelbrot::OnMouseRightDownEvent(uint64_t x, uint64_t y)
185{
186
187}
188
189void Mandelbrot::OnMouseRightUpEvent(uint64_t x, uint64_t y)
190{
191
192}
193
194void 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
209void 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