summaryrefslogtreecommitdiffhomepage
path: root/main/draw.cpp
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2022-10-26 03:51:18 +0200
committerStanislaw Halik <sthalik@misaki.pl>2022-10-26 03:51:18 +0200
commit8aae71d17c3927af76fae980cd0f04f93c628abd (patch)
treef62e1ecc6562ed9cdafa12106322ffd2bb1ea67b /main/draw.cpp
parenta1b8d914bf457dd4508ca37610219ced93303292 (diff)
a
Diffstat (limited to 'main/draw.cpp')
-rw-r--r--main/draw.cpp139
1 files changed, 139 insertions, 0 deletions
diff --git a/main/draw.cpp b/main/draw.cpp
new file mode 100644
index 00000000..f1d4e4d8
--- /dev/null
+++ b/main/draw.cpp
@@ -0,0 +1,139 @@
+#include "main-impl.hpp"
+#include "floormat/app.hpp"
+#include "src/camera-offset.hpp"
+#include <Magnum/GL/DefaultFramebuffer.h>
+
+namespace floormat {
+
+void main_impl::recalc_viewport(Vector2i size) noexcept
+{
+ update_window_state();
+ GL::defaultFramebuffer.setViewport({{}, size });
+ _msaa_framebuffer.detach(GL::Framebuffer::ColorAttachment{0});
+ _msaa_renderbuffer = Magnum::GL::Renderbuffer{};
+ _msaa_renderbuffer.setStorageMultisample(s.msaa_samples, GL::RenderbufferFormat::RGBA8, size);
+ _msaa_framebuffer.setViewport({{}, size });
+ _msaa_framebuffer.attachRenderbuffer(GL::Framebuffer::ColorAttachment{0}, _msaa_renderbuffer);
+ _shader.set_scale(Vector2{size});
+ app.on_viewport_event(size);
+}
+
+global_coords main_impl::pixel_to_tile(Vector2d position) const noexcept
+{
+ constexpr Vector2d pixel_size{dTILE_SIZE[0], dTILE_SIZE[1]};
+ constexpr Vector2d half{.5, .5};
+ const Vector2d px = position - Vector2d{windowSize()}*.5 - _shader.camera_offset()*.5;
+ const Vector2d vec = tile_shader::unproject(px) / pixel_size + half;
+ const auto x = (std::int32_t)std::floor(vec[0]), y = (std::int32_t)std::floor(vec[1]);
+ return { x, y };
+}
+
+auto main_impl::get_draw_bounds() const noexcept -> draw_bounds
+{
+
+ using limits = std::numeric_limits<std::int16_t>;
+ auto x0 = limits::max(), x1 = limits::min(), y0 = limits::max(), y1 = limits::min();
+
+ for (const auto win = Vector2d(windowSize());
+ auto p : {pixel_to_tile(Vector2d{0, 0}).chunk(),
+ pixel_to_tile(Vector2d{win[0]-1, 0}).chunk(),
+ pixel_to_tile(Vector2d{0, win[1]-1}).chunk(),
+ pixel_to_tile(Vector2d{win[0]-1, win[1]-1}).chunk()})
+ {
+ x0 = std::min(x0, p.x);
+ x1 = std::max(x1, p.x);
+ y0 = std::min(y0, p.y);
+ y1 = std::max(y1, p.y);
+ }
+ return {x0, x1, y0, y1};
+}
+
+void main_impl::draw_world() noexcept
+{
+ auto [minx, maxx, miny, maxy] = get_draw_bounds();
+
+ for (std::int16_t y = miny; y <= maxy; y++)
+ for (std::int16_t x = minx; x <= maxx; x++)
+ {
+ if (const chunk_coords c = {x, y}; !_world.contains(c))
+ app.maybe_initialize_chunk(c, _world[c]);
+ const chunk_coords c{x, y};
+ const with_shifted_camera_offset o{_shader, c};
+ _floor_mesh.draw(_shader, _world[c]);
+ }
+
+ for (std::int16_t y = miny; y <= maxy; y++)
+ for (std::int16_t x = minx; x <= maxx; x++)
+ {
+ const chunk_coords c{x, y};
+ const with_shifted_camera_offset o{_shader, c};
+ _wall_mesh.draw(_shader, _world[c]);
+ }
+}
+
+void main_impl::drawEvent()
+{
+ float dt = timeline.previousFrameDuration();
+ if (dt > 0)
+ {
+ const float RC1 = dt_expected.do_sleep ? 1.f : 1.f/15,
+ RC2 = dt_expected.do_sleep ? 1.f/15 : 1.f/60;
+ const float alpha1 = dt/(dt + RC1);
+ const float alpha2 = dt/(dt + RC2);
+
+ _frame_time1 = _frame_time1*(1-alpha1) + alpha1*dt;
+ _frame_time2 = _frame_time1*(1-alpha2) + alpha2*dt;
+ constexpr float max_deviation = 5 * 1e-3f;
+ if (std::fabs(_frame_time1 - _frame_time2) > max_deviation)
+ _frame_time1 = _frame_time2;
+ }
+ else
+ {
+ swapBuffers();
+ timeline.nextFrame();
+ }
+
+ dt = std::clamp(dt, 1e-5f, std::fmaxf(1e-1f, dt_expected.value));
+
+ app.update(dt);
+ _shader.set_tint({1, 1, 1, 1});
+
+ {
+ GL::defaultFramebuffer.clear(GL::FramebufferClear::Color);
+#ifndef FM_SKIP_MSAA
+ _msaa_framebuffer.clear(GL::FramebufferClear::Color);
+ _msaa_framebuffer.bind();
+#endif
+ draw_world();
+ app.draw_msaa();
+#ifndef FM_SKIP_MSAA
+ GL::defaultFramebuffer.bind();
+ GL::Framebuffer::blit(_msaa_framebuffer, GL::defaultFramebuffer, {{}, windowSize()}, GL::FramebufferBlit::Color);
+#endif
+ }
+
+ app.draw();
+
+ swapBuffers();
+ redraw();
+
+ if (dt_expected.do_sleep)
+ {
+ constexpr float eps = 1e-3f;
+ const float Δt൦ = timeline.currentFrameDuration(), sleep_secs = dt_expected.value - Δt൦ - dt_expected.jitter;
+ if (sleep_secs > eps)
+ std::this_thread::sleep_for(std::chrono::nanoseconds((long long)(sleep_secs * 1e9f)));
+ //fm_debug("jitter:%.1f sleep:%.0f", dt_expected.jitter*1000, sleep_secs*1000);
+ const float Δt = timeline.currentFrameDuration() - dt_expected.value;
+ constexpr float α = .1f;
+ dt_expected.jitter = std::fmax(dt_expected.jitter + Δt * α,
+ dt_expected.jitter * (1-α) + Δt * α);
+ dt_expected.jitter = std::copysignf(std::fminf(dt_expected.value, std::fabsf(dt_expected.jitter)), dt_expected.jitter);
+ }
+ else
+ dt_expected.jitter = 0;
+ timeline.nextFrame();
+}
+
+} // namespace floormat
+