Index

zydeco / a4d3636

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

Latest Commit

{#}TimeHashSubjectAuthor#(+)(-)GPG?
916 Nov 2023 11:11a4d3636Fractal ViewerJosh Stockin12350G

Blob @ zydeco / src / game / Mandelbrot.cpp

text/plain7888 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 "GLTexture.hpp"
9
10static Logger LOGGER("Mandelbrot");
11
12
13ldvec3 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
21Mandelbrot::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
48Mandelbrot::~Mandelbrot()
49{
50 delete m_pRenderObject;
51 delete m_pTexture;
52}
53
54bool 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
159void Mandelbrot::OnMouseLeftDownEvent(uint64_t x, uint64_t y)
160{
161 m_mouseDown = true;
162}
163
164void Mandelbrot::OnMouseLeftUpEvent(uint64_t x, uint64_t y)
165{
166 m_mouseDown = false;
167}
168
169void Mandelbrot::OnMouseMiddleDownEvent(uint64_t x, uint64_t y)
170{
171
172}
173
174void Mandelbrot::OnMouseMiddleUpEvent(uint64_t x, uint64_t y)
175{
176
177}
178
179void Mandelbrot::OnMouseRightDownEvent(uint64_t x, uint64_t y)
180{
181
182}
183
184void Mandelbrot::OnMouseRightUpEvent(uint64_t x, uint64_t y)
185{
186
187}
188
189void 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
204void 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