diff --git a/src/application.cpp b/src/application.cpp index 50962edb..74776a06 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -4,9 +4,14 @@ #include "helper/message_box.hpp" #include "helper/sleep.hpp" #include "input/input.hpp" +#include "manager/music_manager.hpp" +#include "scenes/loading_screen/loading_screen.hpp" #include "scenes/scene.hpp" +#include "ui/layout.hpp" #include +#include +#include #include #include #include @@ -35,9 +40,6 @@ Application::Application(std::shared_ptr&& window, const std::vector(m_window) }, - m_settings_manager{ this }, m_target_framerate{ m_command_line_arguments.target_fps } { initialize(); } catch (const helper::GeneralError& general_error) { @@ -156,7 +158,7 @@ void Application::handle_event(const SDL_Event& event) { // this global event handlers (atm only one) are special cases, they receive all inputs if they are not handled by the scenes explicitly - if (m_music_manager.handle_event(m_input_manager, event)) { + if (m_music_manager->handle_event(m_input_manager, event)) { return; } } @@ -249,32 +251,121 @@ void Application::render() const { void Application::initialize() { - load_resources(); - push_scene(scenes::create_scene(*this, SceneId::MainMenu, ui::FullScreenLayout{ *m_window })); + auto loading_screen = scenes::LoadingScreen{ this }; + + const auto start_time = SDL_GetTicks64(); + + const std::future load_everything = std::async(std::launch::async, [this] { + this->m_music_manager = std::make_unique(this, num_audio_channels); + + this->m_input_manager = std::make_shared(this->m_window); + + this->m_settings_manager = std::make_unique(this); + + this->m_font_manager = std::make_unique(); + + this->load_resources(); #ifdef DEBUG_BUILD - m_fps_text = std::make_unique( - this, "FPS: ?", font_manager().get(FontId::Default), Color::white(), - std::pair{ 0.95, 0.95 }, - ui::Alignment{ ui::AlignmentHorizontal::Middle, ui::AlignmentVertical::Center }, - ui::RelativeLayout{ window(), 0.0, 0.0, 0.1, 0.05 }, false - ); + m_fps_text = std::make_unique( + this, "FPS: ?", font_manager().get(FontId::Default), Color::white(), + std::pair{ 0.95, 0.95 }, + ui::Alignment{ ui::AlignmentHorizontal::Middle, ui::AlignmentVertical::Center }, + ui::RelativeLayout{ window(), 0.0, 0.0, 0.1, 0.05 }, false + ); #endif #if defined(_HAVE_DISCORD_SDK) - if (m_settings_manager.settings().discord) { - auto discord_instance = DiscordInstance::initialize(); - if (not discord_instance.has_value()) { - spdlog::warn( - "Error initializing the discord instance, it might not be running: {}", discord_instance.error() - ); - } else { - m_discord_instance = std::move(discord_instance.value()); - m_discord_instance->after_setup(); + if (m_settings_manager->settings().discord) { + auto discord_instance = DiscordInstance::initialize(); + if (not discord_instance.has_value()) { + spdlog::warn( + "Error initializing the discord instance, it might not be running: {}", discord_instance.error() + ); + } else { + m_discord_instance = std::move(discord_instance.value()); + m_discord_instance->after_setup(); + } } - } #endif + }); + + + using namespace std::chrono_literals; + + const auto sleep_time = m_target_framerate.has_value() ? std::chrono::duration_cast(1s) + / m_target_framerate.value() + : 0s; + auto start_execution_time = std::chrono::steady_clock::now(); + + + bool finished_loading = false; + + // this is a duplicate of below in some cases, but it's just for the loading screen and can't be factored out easily + // this also only uses a subset of all things, the real event loop uses, so that nothing breaks while doing multithreading + // the only things usable are: (since NOT accessed (writing) via the loading thread and already initialized): + // - m_command_line_arguments + // - m_window + // - m_renderer + // - m_target_framerate + + while ((not finished_loading) and m_is_running +#if defined(__CONSOLE__) + and console::inMainLoop() +#endif + ) { + + // we can't use the normal event loop, so we have to do it manually + SDL_Event event; + while (SDL_PollEvent(&event) != 0) { + if (event.type == SDL_QUIT) { + m_is_running = false; + } + } + + loading_screen.update(); + // this service_provider only guarantees the renderer + the window to be accessible without race conditions + loading_screen.render(*this); + + // present and wait (depending if vsync is on or not, this has to be done manually) + m_renderer.present(); + + if (m_target_framerate.has_value()) { + + const auto now = std::chrono::steady_clock::now(); + const auto runtime = (now - start_execution_time); + if (runtime < sleep_time) { + //TODO(totto): use SDL_DelayNS in sdl >= 3.0 + helper::sleep_nanoseconds(sleep_time - runtime); + start_execution_time = std::chrono::steady_clock::now(); + } else { + start_execution_time = now; + } + } + // end waiting + + // wait until is faster, since it just compares two time_points instead of getting now() and than adding the wait-for argument + finished_loading = + load_everything.wait_until(std::chrono::system_clock::time_point::min()) == std::future_status::ready; + } + + + const auto duration = std::chrono::milliseconds(SDL_GetTicks64() - start_time); + + // we can reach this via SDL_QUIT or (not console::inMainLoop()) + if (not finished_loading) { + + spdlog::debug("Aborted loading after {}", duration); + + // just exit immediately, without cleaning up, since than we would have to cancel the loading thread somehow, which is way rto complicated, let the OS clean up our mess we create her xD + std::exit(0); + } + + + spdlog::debug("Took {} to load", duration); + + push_scene(scenes::create_scene(*this, SceneId::MainMenu, ui::FullScreenLayout{ *m_window })); } void Application::load_resources() { @@ -292,7 +383,7 @@ void Application::load_resources() { }; for (const auto& [font_id, path] : fonts) { const auto font_path = utils::get_assets_folder() / "fonts" / path; - m_font_manager.load(font_id, font_path, fonts_size); + m_font_manager->load(font_id, font_path, fonts_size); } } diff --git a/src/application.hpp b/src/application.hpp index 34a713b3..c21f5ca2 100644 --- a/src/application.hpp +++ b/src/application.hpp @@ -21,16 +21,18 @@ struct Application final : public EventListener, public ServiceProvider { private: static constexpr auto num_audio_channels = u8{ 2 }; + bool m_is_running{ true }; CommandLineArguments m_command_line_arguments; std::shared_ptr m_window; Renderer m_renderer; - bool m_is_running{ true }; - MusicManager m_music_manager; - std::shared_ptr m_input_manager; - SettingsManager m_settings_manager; - FontManager m_font_manager; helper::optional m_target_framerate; + // these fields are initalized asynchronously in a separate thread + std::unique_ptr m_music_manager; + std::shared_ptr m_input_manager; + std::unique_ptr m_settings_manager; + std::unique_ptr m_font_manager; + #ifdef DEBUG_BUILD std::unique_ptr m_fps_text{ nullptr }; @@ -74,29 +76,35 @@ struct Application final : public EventListener, public ServiceProvider { } FontManager& font_manager() override { - return m_font_manager; + return *m_font_manager; } - const FontManager& font_manager() const override { - return m_font_manager; + + [[nodiscard]] const FontManager& font_manager() const override { + return *m_font_manager; } CommandLineArguments& command_line_arguments() override { return m_command_line_arguments; } - const CommandLineArguments& command_line_arguments() const override { + + [[nodiscard]] const CommandLineArguments& command_line_arguments() const override { return m_command_line_arguments; } + SettingsManager& settings_manager() override { - return m_settings_manager; + return *m_settings_manager; } - const SettingsManager& settings_manager() const override { - return m_settings_manager; + + [[nodiscard]] const SettingsManager& settings_manager() const override { + return *m_settings_manager; } + MusicManager& music_manager() override { - return m_music_manager; + return *m_music_manager; } - const MusicManager& music_manager() const override { - return m_music_manager; + + [[nodiscard]] const MusicManager& music_manager() const override { + return *m_music_manager; } [[nodiscard]] const Renderer& renderer() const override { diff --git a/src/helper/clock_source.cpp b/src/helper/clock_source.cpp index 732415bd..f003e28c 100644 --- a/src/helper/clock_source.cpp +++ b/src/helper/clock_source.cpp @@ -6,7 +6,7 @@ namespace { [[nodiscard]] double elapsed_time() { - return static_cast(SDL_GetTicks()) / 1000.0; + return static_cast(SDL_GetTicks64()) / 1000.0; } } // namespace diff --git a/src/scenes/loading_screen/loading_screen.cpp b/src/scenes/loading_screen/loading_screen.cpp new file mode 100644 index 00000000..35b53046 --- /dev/null +++ b/src/scenes/loading_screen/loading_screen.cpp @@ -0,0 +1,126 @@ +#include "loading_screen.hpp" +#include "game/graphic_helpers.hpp" +#include "game/tetromino_type.hpp" +#include "graphics/point.hpp" +#include "graphics/rect.hpp" +#include "graphics/renderer.hpp" +#include "graphics/window.hpp" +#include "helper/platform.hpp" +#include "manager/service_provider.hpp" +#include "scenes/logo/logo.hpp" +#include "ui/layout.hpp" + +#include + +scenes::LoadingScreen::LoadingScreen(ServiceProvider* service_provider) + : m_segments{ + { Mino{ Mino::GridPoint{ 0, 0 }, helper::TetrominoType::J }, 1.0 }, + { Mino{ Mino::GridPoint{ 1, 0 }, helper::TetrominoType::L }, 1.0 }, + { Mino{ Mino::GridPoint{ 2, 0 }, helper::TetrominoType::I }, 1.0 }, + { Mino{ Mino::GridPoint{ 2, 1 }, helper::TetrominoType::O }, 1.0 }, + { Mino{ Mino::GridPoint{ 2, 2 }, helper::TetrominoType::S }, 1.0 }, + { Mino{ Mino::GridPoint{ 1, 2 }, helper::TetrominoType::T }, 1.0 }, + { Mino{ Mino::GridPoint{ 0, 2 }, helper::TetrominoType::I }, 1.0 }, + { Mino{ Mino::GridPoint{ 0, 1 }, helper::TetrominoType::Z }, 1.0 }, +},m_logo{logo::get_logo(service_provider)} { + + const auto [total_x_tiles, total_y_tiles] = utils::get_orientation() == utils::Orientation::Landscape + ? std::pair{ 17, 9 } + : std::pair{ 9, 17 }; + + constexpr auto loading_segments_size = 3; + + const auto& window = service_provider->window(); + + const auto layout = window.size(); + + const u32 tile_size_x = layout.x / total_x_tiles; + const u32 tile_size_y = layout.y / total_y_tiles; + + m_tile_size = std::min(tile_size_y, tile_size_x); + + const shapes::UPoint grid_start_offset = { (total_x_tiles - loading_segments_size) / 2, + (total_y_tiles - loading_segments_size) / 2 }; + + m_start_offset = grid_start_offset * m_tile_size; + + constexpr const auto logo_width_percentage = 0.8; + + constexpr const auto start_x = (1.0 - logo_width_percentage) / 2.0; + + const auto window_ratio = static_cast(layout.x) / static_cast(layout.y); + + const auto logo_ratio = static_cast(logo::height) / static_cast(logo::width) * window_ratio; + + const auto logo_height_percentage = logo_width_percentage * logo_ratio; + + m_logo_rect = ui::RelativeLayout(window, start_x, 0.05, logo_width_percentage, logo_height_percentage).get_rect(); +} + +namespace { + [[nodiscard]] double elapsed_time() { + return static_cast(SDL_GetTicks64()) / 1000.0; + } +} // namespace + + +void scenes::LoadingScreen::update() { + + constexpr const auto speed = std::numbers::pi_v * 1.0; + constexpr const auto amplitude = 1.1; + constexpr const auto scale_offset = 1.3; + + const auto length = m_segments.size(); + const auto length_d = static_cast(length); + + const auto time = elapsed_time(); + + for (size_t i = 0; i < length; ++i) { + + auto& segment = m_segments.at(i); + + auto& scale = std::get<1>(segment); + + const auto offset = std::numbers::pi_v * 2.0 * static_cast(length - i - 1) / length_d; + + scale = std::min(amplitude * std::sin(time * speed + offset) + scale_offset, 1.0); + } + // +} + +void scenes::LoadingScreen::render(const ServiceProvider& service_provider) const { + + service_provider.renderer().draw_rect_filled(service_provider.window().screen_rect(), Color::black()); + + service_provider.renderer().draw_texture(m_logo, m_logo_rect); + + constexpr const auto scale_threshold = 0.25; + + for (const auto& [mino, scale] : m_segments) { + if (scale >= scale_threshold) { + const auto original_scale = + static_cast(m_tile_size) / static_cast(grid::original_tile_size); + + + const auto tile_size = static_cast(static_cast(m_tile_size) * scale); + + helper::graphics::render_mino( + mino, service_provider, MinoTransparency::Solid, original_scale, + [this, tile_size](const Mino::GridPoint& point) -> auto { + return this->to_screen_coords(point, tile_size); + }, + { tile_size, tile_size } + ); + } + + //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) + } +} + + +[[nodiscard]] shapes::UPoint scenes::LoadingScreen::to_screen_coords(const Mino::GridPoint& point, u32 tile_size) + const { + const auto start_edge = m_start_offset + point.cast() * m_tile_size; + const auto inner_offset = m_tile_size - tile_size / 2; + return start_edge + shapes::UPoint{ inner_offset, inner_offset }; +} diff --git a/src/scenes/loading_screen/loading_screen.hpp b/src/scenes/loading_screen/loading_screen.hpp new file mode 100644 index 00000000..5fc114c6 --- /dev/null +++ b/src/scenes/loading_screen/loading_screen.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include "../logo/logo.hpp" +#include "game/mino.hpp" +#include "graphics/rect.hpp" +#include "manager/service_provider.hpp" + +#include + +namespace scenes { + + struct LoadingScreen { + private: + std::vector> m_segments; + Texture m_logo; + shapes::URect m_logo_rect; + + u32 m_tile_size; + shapes::UPoint m_start_offset; + + public: + explicit LoadingScreen(ServiceProvider* service_provider); + + void update(); + + void render(const ServiceProvider& service_provider) const; + + private: + [[nodiscard]] shapes::UPoint to_screen_coords(const Mino::GridPoint& point, u32 tile_size) const; + }; + +} // namespace scenes diff --git a/src/scenes/loading_screen/meson.build b/src/scenes/loading_screen/meson.build new file mode 100644 index 00000000..f21ea09a --- /dev/null +++ b/src/scenes/loading_screen/meson.build @@ -0,0 +1,4 @@ +graphics_src_files += files( + 'loading_screen.cpp', + 'loading_screen.hpp', +) diff --git a/src/scenes/logo/logo.cpp b/src/scenes/logo/logo.cpp new file mode 100644 index 00000000..add3a065 --- /dev/null +++ b/src/scenes/logo/logo.cpp @@ -0,0 +1,147 @@ + +#include "logo.hpp" +#include "game/graphic_helpers.hpp" +#include "game/mino.hpp" +#include "graphics/point.hpp" +#include "graphics/renderer.hpp" + +#include + + +[[nodiscard]] Texture logo::get_logo(const ServiceProvider* service_provider, double scale) { + + constexpr const Mino::GridPoint offset_o2{ 5, 0 }; + constexpr const auto offset_p3 = offset_o2 + Mino::GridPoint{ 5, 0 }; + constexpr const auto offset_e4 = offset_p3 + Mino::GridPoint{ 4, 0 }; + constexpr const auto offset_t5 = offset_e4 + Mino::GridPoint{ 4, 0 }; + constexpr const auto offset_r6 = offset_t5 + Mino::GridPoint{ 6, 0 }; + constexpr const auto offset_i7 = offset_r6 + Mino::GridPoint{ 4, 0 }; + constexpr const auto offset_s8 = offset_i7 + Mino::GridPoint{ 2, 0 }; + + const std::vector minos{ + // O + Mino{ Mino::GridPoint{ 0, 0 }, helper::TetrominoType::J }, + Mino{ Mino::GridPoint{ 1, 0 }, helper::TetrominoType::J }, + Mino{ Mino::GridPoint{ 2, 0 }, helper::TetrominoType::L }, + Mino{ Mino::GridPoint{ 3, 0 }, helper::TetrominoType::L }, + Mino{ Mino::GridPoint{ 3, 1 }, helper::TetrominoType::L }, + Mino{ Mino::GridPoint{ 3, 2 }, helper::TetrominoType::L }, + Mino{ Mino::GridPoint{ 3, 3 }, helper::TetrominoType::Z }, + Mino{ Mino::GridPoint{ 3, 4 }, helper::TetrominoType::I }, + Mino{ Mino::GridPoint{ 2, 4 }, helper::TetrominoType::I }, + Mino{ Mino::GridPoint{ 1, 4 }, helper::TetrominoType::I }, + Mino{ Mino::GridPoint{ 0, 4 }, helper::TetrominoType::I }, + Mino{ Mino::GridPoint{ 0, 3 }, helper::TetrominoType::S }, + Mino{ Mino::GridPoint{ 0, 2 }, helper::TetrominoType::J }, + Mino{ Mino::GridPoint{ 0, 1 }, helper::TetrominoType::J }, + // O + Mino{ Mino::GridPoint{ 0, 0 } + offset_o2, helper::TetrominoType::O }, + Mino{ Mino::GridPoint{ 1, 0 } + offset_o2, helper::TetrominoType::O }, + Mino{ Mino::GridPoint{ 2, 0 } + offset_o2, helper::TetrominoType::S }, + Mino{ Mino::GridPoint{ 3, 0 } + offset_o2, helper::TetrominoType::I }, + Mino{ Mino::GridPoint{ 3, 1 } + offset_o2, helper::TetrominoType::J }, + Mino{ Mino::GridPoint{ 3, 2 } + offset_o2, helper::TetrominoType::J }, + Mino{ Mino::GridPoint{ 3, 3 } + offset_o2, helper::TetrominoType::S }, + Mino{ Mino::GridPoint{ 3, 4 } + offset_o2, helper::TetrominoType::L }, + Mino{ Mino::GridPoint{ 2, 4 } + offset_o2, helper::TetrominoType::S }, + Mino{ Mino::GridPoint{ 1, 4 } + offset_o2, helper::TetrominoType::S }, + Mino{ Mino::GridPoint{ 0, 4 } + offset_o2, helper::TetrominoType::I }, + Mino{ Mino::GridPoint{ 0, 3 } + offset_o2, helper::TetrominoType::Z }, + Mino{ Mino::GridPoint{ 0, 2 } + offset_o2, helper::TetrominoType::Z }, + Mino{ Mino::GridPoint{ 0, 1 } + offset_o2, helper::TetrominoType::O }, + // P + Mino{ Mino::GridPoint{ 0, 0 } + offset_p3, helper::TetrominoType::Z }, + Mino{ Mino::GridPoint{ 1, 0 } + offset_p3, helper::TetrominoType::Z }, + Mino{ Mino::GridPoint{ 2, 0 } + offset_p3, helper::TetrominoType::I }, + Mino{ Mino::GridPoint{ 2, 1 } + offset_p3, helper::TetrominoType::Z }, + Mino{ Mino::GridPoint{ 2, 2 } + offset_p3, helper::TetrominoType::L }, + Mino{ Mino::GridPoint{ 1, 2 } + offset_p3, helper::TetrominoType::T }, + Mino{ Mino::GridPoint{ 0, 2 } + offset_p3, helper::TetrominoType::T }, + Mino{ Mino::GridPoint{ 0, 1 } + offset_p3, helper::TetrominoType::T }, + Mino{ Mino::GridPoint{ 0, 3 } + offset_p3, helper::TetrominoType::T }, + Mino{ Mino::GridPoint{ 0, 4 } + offset_p3, helper::TetrominoType::S }, + // E + Mino{ Mino::GridPoint{ 0, 0 } + offset_e4, helper::TetrominoType::O }, + Mino{ Mino::GridPoint{ 1, 0 } + offset_e4, helper::TetrominoType::O }, + Mino{ Mino::GridPoint{ 2, 0 } + offset_e4, helper::TetrominoType::Z }, + Mino{ Mino::GridPoint{ 0, 1 } + offset_e4, helper::TetrominoType::O }, + Mino{ Mino::GridPoint{ 0, 2 } + offset_e4, helper::TetrominoType::O }, + Mino{ Mino::GridPoint{ 1, 2 } + offset_e4, helper::TetrominoType::J }, + Mino{ Mino::GridPoint{ 2, 2 } + offset_e4, helper::TetrominoType::L }, + Mino{ Mino::GridPoint{ 0, 3 } + offset_e4, helper::TetrominoType::T }, + Mino{ Mino::GridPoint{ 0, 4 } + offset_e4, helper::TetrominoType::T }, + Mino{ Mino::GridPoint{ 1, 4 } + offset_e4, helper::TetrominoType::T }, + Mino{ Mino::GridPoint{ 2, 4 } + offset_e4, helper::TetrominoType::S }, + // T + Mino{ Mino::GridPoint{ 0, 0 } + offset_t5, helper::TetrominoType::L }, + Mino{ Mino::GridPoint{ 1, 0 } + offset_t5, helper::TetrominoType::L }, + Mino{ Mino::GridPoint{ 2, 0 } + offset_t5, helper::TetrominoType::Z }, + Mino{ Mino::GridPoint{ 3, 0 } + offset_t5, helper::TetrominoType::Z }, + Mino{ Mino::GridPoint{ 4, 0 } + offset_t5, helper::TetrominoType::I }, + Mino{ Mino::GridPoint{ 2, 1 } + offset_t5, helper::TetrominoType::T }, + Mino{ Mino::GridPoint{ 2, 2 } + offset_t5, helper::TetrominoType::T }, + Mino{ Mino::GridPoint{ 2, 3 } + offset_t5, helper::TetrominoType::T }, + Mino{ Mino::GridPoint{ 2, 4 } + offset_t5, helper::TetrominoType::S }, + // R + Mino{ Mino::GridPoint{ 0, 0 } + offset_r6, helper::TetrominoType::J }, + Mino{ Mino::GridPoint{ 1, 0 } + offset_r6, helper::TetrominoType::J }, + Mino{ Mino::GridPoint{ 2, 0 } + offset_r6, helper::TetrominoType::I }, + Mino{ Mino::GridPoint{ 2, 1 } + offset_r6, helper::TetrominoType::Z }, + Mino{ Mino::GridPoint{ 2, 2 } + offset_r6, helper::TetrominoType::L }, + Mino{ Mino::GridPoint{ 1, 2 } + offset_r6, helper::TetrominoType::T }, + Mino{ Mino::GridPoint{ 0, 2 } + offset_r6, helper::TetrominoType::J }, + Mino{ Mino::GridPoint{ 0, 1 } + offset_r6, helper::TetrominoType::J }, + Mino{ Mino::GridPoint{ 0, 3 } + offset_r6, helper::TetrominoType::T }, + Mino{ Mino::GridPoint{ 1, 3 } + offset_r6, helper::TetrominoType::O }, + Mino{ Mino::GridPoint{ 0, 4 } + offset_r6, helper::TetrominoType::S }, + Mino{ Mino::GridPoint{ 2, 4 } + offset_r6, helper::TetrominoType::S }, + // I + Mino{ Mino::GridPoint{ 0, 0 } + offset_i7, helper::TetrominoType::Z }, + Mino{ Mino::GridPoint{ 0, 1 } + offset_i7, helper::TetrominoType::O }, + Mino{ Mino::GridPoint{ 0, 2 } + offset_i7, helper::TetrominoType::O }, + Mino{ Mino::GridPoint{ 0, 3 } + offset_i7, helper::TetrominoType::O }, + Mino{ Mino::GridPoint{ 0, 4 } + offset_i7, helper::TetrominoType::S }, + // S + Mino{ Mino::GridPoint{ 0, 0 } + offset_s8, helper::TetrominoType::Z }, + Mino{ Mino::GridPoint{ 1, 0 } + offset_s8, helper::TetrominoType::Z }, + Mino{ Mino::GridPoint{ 2, 0 } + offset_s8, helper::TetrominoType::I }, + Mino{ Mino::GridPoint{ 2, 2 } + offset_s8, helper::TetrominoType::L }, + Mino{ Mino::GridPoint{ 1, 2 } + offset_s8, helper::TetrominoType::L }, + Mino{ Mino::GridPoint{ 0, 2 } + offset_s8, helper::TetrominoType::J }, + Mino{ Mino::GridPoint{ 0, 1 } + offset_s8, helper::TetrominoType::I }, + Mino{ Mino::GridPoint{ 2, 3 } + offset_s8, helper::TetrominoType::T }, + Mino{ Mino::GridPoint{ 0, 4 } + offset_s8, helper::TetrominoType::S }, + Mino{ Mino::GridPoint{ 1, 4 } + offset_s8, helper::TetrominoType::O }, + Mino{ Mino::GridPoint{ 2, 4 } + offset_s8, helper::TetrominoType::I }, + }; + + const auto tile_size = static_cast(static_cast(grid::original_tile_size) * scale); + + + const shapes::UPoint total_size{ tile_size * logo::width, tile_size * logo::height }; + + const auto original_scale = static_cast(tile_size) / static_cast(grid::original_tile_size); + + + const auto& renderer = service_provider->renderer(); + + auto texture = renderer.get_texture_for_render_target(total_size); + + + renderer.set_render_target(texture); + renderer.clear(); + + for (const auto& mino : minos) { + helper::graphics::render_mino( + mino, *service_provider, MinoTransparency::Solid, original_scale, + [tile_size](const Mino::GridPoint& point) -> auto { return point.cast() * tile_size; }, + { tile_size, tile_size } + ); + } + + + renderer.reset_render_target(); + + + return texture; +} diff --git a/src/scenes/logo/logo.hpp b/src/scenes/logo/logo.hpp new file mode 100644 index 00000000..1f5ea6c4 --- /dev/null +++ b/src/scenes/logo/logo.hpp @@ -0,0 +1,14 @@ +#pragma once + + +#include "graphics/texture.hpp" +#include "manager/service_provider.hpp" + + +namespace logo { + constexpr const auto width = 33; + constexpr const auto height = 5; + + [[nodiscard]] Texture get_logo(const ServiceProvider* service_provider, double scale = 1.0); + +} // namespace logo diff --git a/src/scenes/logo/meson.build b/src/scenes/logo/meson.build new file mode 100644 index 00000000..65358428 --- /dev/null +++ b/src/scenes/logo/meson.build @@ -0,0 +1,4 @@ +graphics_src_files += files( + 'logo.cpp', + 'logo.hpp', +) diff --git a/src/scenes/meson.build b/src/scenes/meson.build index 8eef60a4..daf05632 100644 --- a/src/scenes/meson.build +++ b/src/scenes/meson.build @@ -1,6 +1,8 @@ graphics_src_files += files('scene.cpp', 'scene.hpp', 'scene_id.hpp') subdir('about_page') +subdir('loading_screen') +subdir('logo') subdir('main_menu') subdir('multiplayer_menu') subdir('play_select_menu')