Skip to content

Commit 983b49d

Browse files
committed
feat: split spinner and loading screen into two separate parts, so that the spinner can be reused
1 parent a5dc0d8 commit 983b49d

File tree

6 files changed

+200
-93
lines changed

6 files changed

+200
-93
lines changed

src/scenes/loading_screen/loading_screen.cpp

Lines changed: 6 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -13,38 +13,15 @@
1313

1414
#include <numbers>
1515

16+
1617
scenes::LoadingScreen::LoadingScreen(ServiceProvider* service_provider)
17-
: m_segments{
18-
{ Mino{ grid::GridPoint{ 0, 0 }, helper::TetrominoType::J }, 1.0 },
19-
{ Mino{ grid::GridPoint{ 1, 0 }, helper::TetrominoType::L }, 1.0 },
20-
{ Mino{ grid::GridPoint{ 2, 0 }, helper::TetrominoType::I }, 1.0 },
21-
{ Mino{ grid::GridPoint{ 2, 1 }, helper::TetrominoType::O }, 1.0 },
22-
{ Mino{ grid::GridPoint{ 2, 2 }, helper::TetrominoType::S }, 1.0 },
23-
{ Mino{ grid::GridPoint{ 1, 2 }, helper::TetrominoType::T }, 1.0 },
24-
{ Mino{ grid::GridPoint{ 0, 2 }, helper::TetrominoType::I }, 1.0 },
25-
{ Mino{ grid::GridPoint{ 0, 1 }, helper::TetrominoType::Z }, 1.0 },
26-
},m_logo{logo::get_logo(service_provider)} {
27-
28-
const auto [total_x_tiles, total_y_tiles] = utils::get_orientation() == utils::Orientation::Landscape
29-
? std::pair<u32, u32>{ 17, 9 }
30-
: std::pair<u32, u32>{ 9, 17 };
31-
32-
constexpr auto loading_segments_size = 3;
18+
: m_logo{ logo::get_logo(service_provider) },
19+
m_spinner{ ui::FullScreenLayout{ service_provider->window() }, true } {
3320

3421
const auto& window = service_provider->window();
3522

3623
const auto layout = window.size();
3724

38-
const u32 tile_size_x = layout.x / total_x_tiles;
39-
const u32 tile_size_y = layout.y / total_y_tiles;
40-
41-
m_tile_size = std::min(tile_size_y, tile_size_x);
42-
43-
const shapes::UPoint grid_start_offset = { (total_x_tiles - loading_segments_size) / 2,
44-
(total_y_tiles - loading_segments_size) / 2 };
45-
46-
m_start_offset = grid_start_offset * m_tile_size;
47-
4825
constexpr const auto logo_width_percentage = 0.8;
4926

5027
constexpr const auto start_x = (1.0 - logo_width_percentage) / 2.0;
@@ -58,70 +35,14 @@ scenes::LoadingScreen::LoadingScreen(ServiceProvider* service_provider)
5835
m_logo_rect = ui::RelativeLayout(window, start_x, 0.05, logo_width_percentage, logo_height_percentage).get_rect();
5936
}
6037

61-
namespace {
62-
[[nodiscard]] double elapsed_time() {
63-
return static_cast<double>(SDL_GetTicks64()) / 1000.0;
64-
}
65-
} // namespace
66-
6738

6839
void scenes::LoadingScreen::update() {
69-
70-
constexpr const auto speed = std::numbers::pi_v<double> * 1.0;
71-
constexpr const auto amplitude = 1.1;
72-
constexpr const auto scale_offset = 1.3;
73-
74-
const auto length = m_segments.size();
75-
const auto length_d = static_cast<double>(length);
76-
77-
const auto time = elapsed_time();
78-
79-
for (size_t i = 0; i < length; ++i) {
80-
81-
auto& segment = m_segments.at(i);
82-
83-
auto& scale = std::get<1>(segment);
84-
85-
const auto offset = std::numbers::pi_v<double> * 2.0 * static_cast<double>(length - i - 1) / length_d;
86-
87-
scale = std::min((amplitude * std::sin((time * speed) + offset)) + scale_offset, 1.0);
88-
}
89-
//
40+
m_spinner.update();
9041
}
9142

9243
void scenes::LoadingScreen::render(const ServiceProvider& service_provider) const {
93-
94-
service_provider.renderer().draw_rect_filled(service_provider.window().screen_rect(), Color::black());
44+
// NOTE: this already fills the background
45+
m_spinner.render(service_provider);
9546

9647
service_provider.renderer().draw_texture(m_logo, m_logo_rect);
97-
98-
constexpr const auto scale_threshold = 0.25;
99-
100-
for (const auto& [mino, scale] : m_segments) {
101-
if (scale >= scale_threshold) {
102-
const auto original_scale =
103-
static_cast<double>(m_tile_size) / static_cast<double>(grid::original_tile_size);
104-
105-
106-
const auto tile_size = static_cast<u32>(static_cast<double>(m_tile_size) * scale);
107-
108-
helper::graphics::render_mino(
109-
mino, service_provider, MinoTransparency::Solid, original_scale,
110-
[this, tile_size](const grid::GridPoint& point) -> auto {
111-
return this->to_screen_coords(point, tile_size);
112-
},
113-
{ tile_size, tile_size }
114-
);
115-
}
116-
117-
//TODO(Totto): render text here, but than we need to load the fonts before this, not in the loading thread (not that they take that long)
118-
}
119-
}
120-
121-
122-
[[nodiscard]] shapes::UPoint scenes::LoadingScreen::to_screen_coords(const grid::GridPoint& point, u32 tile_size)
123-
const {
124-
const auto start_edge = m_start_offset + point.cast<u32>() * m_tile_size;
125-
const auto inner_offset = m_tile_size - (tile_size / 2);
126-
return start_edge + shapes::UPoint{ inner_offset, inner_offset };
12748
}

src/scenes/loading_screen/loading_screen.hpp

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,25 @@
55
#include "../logo/logo.hpp"
66
#include "graphics/rect.hpp"
77
#include "manager/service_provider.hpp"
8+
#include "ui/components/spinner.hpp"
89

910
#include <vector>
1011

1112
namespace scenes {
1213

1314
struct LoadingScreen {
1415
private:
15-
std::vector<std::tuple<Mino, double>> m_segments;
1616
Texture m_logo;
17-
shapes::URect m_logo_rect;
1817

19-
u32 m_tile_size;
20-
shapes::UPoint m_start_offset;
18+
shapes::URect m_logo_rect;
19+
ui::IndeterminateSpinner m_spinner;
2120

2221
public:
2322
OOPETRIS_GRAPHICS_EXPORTED explicit LoadingScreen(ServiceProvider* service_provider);
2423

2524
OOPETRIS_GRAPHICS_EXPORTED void update();
2625

2726
OOPETRIS_GRAPHICS_EXPORTED void render(const ServiceProvider& service_provider) const;
28-
29-
private:
30-
[[nodiscard]] shapes::UPoint to_screen_coords(const grid::GridPoint& point, u32 tile_size) const;
3127
};
3228

3329
} // namespace scenes
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#pragma once
2+
3+
#include <core/game/mino.hpp>
4+
5+
#include "../logo/logo.hpp"
6+
#include "graphics/rect.hpp"
7+
#include "manager/service_provider.hpp"
8+
9+
#include <vector>
10+
11+
namespace scenes {
12+
13+
struct LoadingScreen {
14+
private:
15+
std::vector<std::tuple<Mino, double>> m_segments;
16+
Texture m_logo;
17+
shapes::URect m_logo_rect;
18+
19+
u32 m_tile_size;
20+
shapes::UPoint m_start_offset;
21+
22+
public:
23+
OOPETRIS_GRAPHICS_EXPORTED explicit LoadingScreen(ServiceProvider* service_provider);
24+
25+
OOPETRIS_GRAPHICS_EXPORTED void update();
26+
27+
OOPETRIS_GRAPHICS_EXPORTED void render(const ServiceProvider& service_provider) const;
28+
29+
private:
30+
[[nodiscard]] shapes::UPoint to_screen_coords(const grid::GridPoint& point, u32 tile_size) const;
31+
};
32+
33+
} // namespace scenes

src/ui/components/meson.build

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@ graphics_src_files += files(
1313
'link_label.hpp',
1414
'slider.cpp',
1515
'slider.hpp',
16+
'spinner.cpp',
17+
'spinner.hpp',
1618
'text_button.cpp',
1719
'text_button.hpp',
1820
'textinput.cpp',
19-
'textinput.hpp',
21+
'textinput.cpp',
2022
)

src/ui/components/spinner.cpp

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
#include <core/game/tetromino_type.hpp>
2+
#include <core/helper/point.hpp>
3+
4+
#include "game/graphic_helpers.hpp"
5+
#include "graphics/renderer.hpp"
6+
#include "helper/platform.hpp"
7+
#include "manager/service_provider.hpp"
8+
#include "spinner.hpp"
9+
#include "ui/layout.hpp"
10+
11+
#include <numbers>
12+
13+
ui::IndeterminateSpinner::IndeterminateSpinner(
14+
const Layout& layout,
15+
bool is_top_level
16+
):Widget{
17+
layout, WidgetType::Component, is_top_level
18+
},
19+
m_segments{
20+
{ Mino{ grid::GridPoint{ 0, 0 }, helper::TetrominoType::J }, 1.0 },
21+
{ Mino{ grid::GridPoint{ 1, 0 }, helper::TetrominoType::L }, 1.0 },
22+
{ Mino{ grid::GridPoint{ 2, 0 }, helper::TetrominoType::I }, 1.0 },
23+
{ Mino{ grid::GridPoint{ 2, 1 }, helper::TetrominoType::O }, 1.0 },
24+
{ Mino{ grid::GridPoint{ 2, 2 }, helper::TetrominoType::S }, 1.0 },
25+
{ Mino{ grid::GridPoint{ 1, 2 }, helper::TetrominoType::T }, 1.0 },
26+
{ Mino{ grid::GridPoint{ 0, 2 }, helper::TetrominoType::I }, 1.0 },
27+
{ Mino{ grid::GridPoint{ 0, 1 }, helper::TetrominoType::Z }, 1.0 },
28+
}{
29+
30+
const auto [total_x_tiles, total_y_tiles] = utils::get_orientation() == utils::Orientation::Landscape
31+
? std::pair<u32, u32>{ 17, 9 }
32+
: std::pair<u32, u32>{ 9, 17 };
33+
34+
constexpr auto loading_segments_size = 3;
35+
36+
const auto layout_rect = layout.get_rect();
37+
const auto layout_size = shapes::UPoint{ layout_rect.width(), layout_rect.height() };
38+
39+
const u32 tile_size_x = layout_size.x / total_x_tiles;
40+
const u32 tile_size_y = layout_size.y / total_y_tiles;
41+
42+
m_tile_size = std::min(tile_size_y, tile_size_x);
43+
44+
const shapes::UPoint grid_start_offset = { (total_x_tiles - loading_segments_size) / 2,
45+
(total_y_tiles - loading_segments_size) / 2 };
46+
47+
m_start_offset = grid_start_offset * m_tile_size;
48+
}
49+
50+
namespace {
51+
[[nodiscard]] double elapsed_time() {
52+
return static_cast<double>(SDL_GetTicks64()) / 1000.0;
53+
}
54+
} // namespace
55+
56+
57+
void ui::IndeterminateSpinner::update() {
58+
59+
constexpr const auto speed = std::numbers::pi_v<double> * 1.0;
60+
constexpr const auto amplitude = 1.1;
61+
constexpr const auto scale_offset = 1.3;
62+
63+
const auto length = m_segments.size();
64+
const auto length_d = static_cast<double>(length);
65+
66+
const auto time = elapsed_time();
67+
68+
for (size_t i = 0; i < length; ++i) {
69+
70+
auto& segment = m_segments.at(i);
71+
72+
auto& scale = std::get<1>(segment);
73+
74+
const auto offset = std::numbers::pi_v<double> * 2.0 * static_cast<double>(length - i - 1) / length_d;
75+
76+
scale = std::min((amplitude * std::sin((time * speed) + offset)) + scale_offset, 1.0);
77+
}
78+
//
79+
}
80+
81+
void ui::IndeterminateSpinner::render(const ServiceProvider& service_provider) const {
82+
83+
service_provider.renderer().draw_rect_filled(layout().get_rect(), Color::black());
84+
85+
constexpr const auto scale_threshold = 0.25;
86+
87+
for (const auto& [mino, scale] : m_segments) {
88+
if (scale >= scale_threshold) {
89+
const auto original_scale =
90+
static_cast<double>(m_tile_size) / static_cast<double>(grid::original_tile_size);
91+
92+
93+
const auto tile_size = static_cast<u32>(static_cast<double>(m_tile_size) * scale);
94+
95+
helper::graphics::render_mino(
96+
mino, service_provider, MinoTransparency::Solid, original_scale,
97+
[this, tile_size](const grid::GridPoint& point) -> auto {
98+
return this->to_screen_coords(point, tile_size);
99+
},
100+
{ tile_size, tile_size }
101+
);
102+
}
103+
104+
//TODO(Totto): render text here, but than we need to load the fonts before this, not in the loading thread (not that they take that long)
105+
}
106+
}
107+
108+
109+
[[nodiscard]] shapes::UPoint ui::IndeterminateSpinner::to_screen_coords(const grid::GridPoint& point, u32 tile_size)
110+
const {
111+
const auto start_edge = m_start_offset + point.cast<u32>() * m_tile_size;
112+
const auto inner_offset = m_tile_size - (tile_size / 2);
113+
return start_edge + shapes::UPoint{ inner_offset, inner_offset };
114+
}
115+
116+
ui::Widget::EventHandleResult ui::IndeterminateSpinner::handle_event(
117+
const std::shared_ptr<input::InputManager>& /* input_manager */,
118+
const SDL_Event& /* event */
119+
) {
120+
return false;
121+
}

src/ui/components/spinner.hpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#pragma once
2+
3+
#include <core/game/mino.hpp>
4+
5+
#include "graphics/rect.hpp"
6+
#include "manager/service_provider.hpp"
7+
#include "ui/widget.hpp"
8+
9+
#include <vector>
10+
11+
namespace ui {
12+
13+
struct IndeterminateSpinner final : public Widget {
14+
private:
15+
std::vector<std::tuple<Mino, double>> m_segments;
16+
17+
u32 m_tile_size;
18+
shapes::UPoint m_start_offset;
19+
20+
public:
21+
OOPETRIS_GRAPHICS_EXPORTED explicit IndeterminateSpinner(const Layout& layout, bool is_top_level);
22+
23+
OOPETRIS_GRAPHICS_EXPORTED void update() override;
24+
25+
OOPETRIS_GRAPHICS_EXPORTED void render(const ServiceProvider& service_provider) const override;
26+
27+
OOPETRIS_GRAPHICS_EXPORTED [[nodiscard]] EventHandleResult
28+
handle_event(const std::shared_ptr<input::InputManager>& input_manager, const SDL_Event& event) override;
29+
30+
private:
31+
[[nodiscard]] shapes::UPoint to_screen_coords(const grid::GridPoint& point, u32 tile_size) const;
32+
};
33+
34+
} // namespace ui

0 commit comments

Comments
 (0)