diff --git a/assets/romfs/theme/bubble1.png b/assets/romfs/theme/bubble1.png new file mode 100644 index 0000000..ade1b14 Binary files /dev/null and b/assets/romfs/theme/bubble1.png differ diff --git a/assets/romfs/theme/bubble2.png b/assets/romfs/theme/bubble2.png new file mode 100644 index 0000000..52e16fa Binary files /dev/null and b/assets/romfs/theme/bubble2.png differ diff --git a/assets/romfs/theme/bubble3.png b/assets/romfs/theme/bubble3.png new file mode 100644 index 0000000..6da1e76 Binary files /dev/null and b/assets/romfs/theme/bubble3.png differ diff --git a/sphaira/CMakeLists.txt b/sphaira/CMakeLists.txt index 2931c66..da25b21 100644 --- a/sphaira/CMakeLists.txt +++ b/sphaira/CMakeLists.txt @@ -57,6 +57,7 @@ add_executable(sphaira source/ui/sidebar.cpp source/ui/widget.cpp source/ui/list.cpp + source/ui/bubbles.cpp source/app.cpp source/download.cpp diff --git a/sphaira/include/ui/bubbles.hpp b/sphaira/include/ui/bubbles.hpp new file mode 100644 index 0000000..2114d44 --- /dev/null +++ b/sphaira/include/ui/bubbles.hpp @@ -0,0 +1,10 @@ +#include "ui/types.hpp" +#include "ui/object.hpp" + +namespace sphaira::ui::bubble { + +void Init(); +void Draw(NVGcontext* vg, Theme* theme); +void Exit(); + +} // namespace sphaira::ui::bubble diff --git a/sphaira/source/app.cpp b/sphaira/source/app.cpp index 954e698..7174670 100644 --- a/sphaira/source/app.cpp +++ b/sphaira/source/app.cpp @@ -1,6 +1,7 @@ #include "ui/menus/main_menu.hpp" #include "ui/error_box.hpp" #include "ui/option_box.hpp" +#include "ui/bubbles.hpp" #include "app.hpp" #include "log.hpp" @@ -975,6 +976,7 @@ void App::Draw() { } m_notif_manager.Draw(vg, &m_theme); + ui::bubble::Draw(vg, &m_theme); nvgResetTransform(vg); nvgEndFrame(this->vg); @@ -1350,6 +1352,9 @@ App::App(const char* argv0) { } } + // soon (tm) + // ui::bubble::Init(); + App::Push(std::make_shared()); log_write("finished app constructor\n"); } @@ -1373,6 +1378,8 @@ App::~App() { i18n::exit(); curl::Exit(); + ui::bubble::Exit(); + // this has to be called before any cleanup to ensure the lifetime of // nvg is still active as some widgets may need to free images. m_widgets.clear(); diff --git a/sphaira/source/ui/bubbles.cpp b/sphaira/source/ui/bubbles.cpp new file mode 100644 index 0000000..f7e580e --- /dev/null +++ b/sphaira/source/ui/bubbles.cpp @@ -0,0 +1,115 @@ +#include "ui/types.hpp" +#include "ui/object.hpp" +#include "ui/nvg_util.hpp" +#include "app.hpp" + +namespace sphaira::ui::bubble { +namespace { + +constexpr auto MAX_BUBBLES = 20; + +struct Bubble { + int start_x; + int texture; + int x,y,w,h; + int y_inc; + float sway_inc; + float sway; + bool sway_right_flag; +}; + +Bubble bubbles[MAX_BUBBLES]{}; +int g_textures[3]; +bool g_is_init = false; + +void setup_bubble(Bubble *bubble) { + // setup normal vars. + bubble->texture = (randomGet64() % std::size(g_textures)); + bubble->start_x = randomGet64() % (int)SCREEN_WIDTH; + bubble->x = bubble->start_x; + bubble->y = (int)SCREEN_HEIGHT - ( randomGet64() % 60 ); + const int size = (randomGet64() % 50) + 40; + bubble->w = size; + bubble->h = size; + bubble->y_inc = (randomGet64() % 5) + 1; + bubble->sway_inc = ((randomGet64() % 6) + 3) / 10; + bubble->sway = 0; +} + +void setup_bubbles(void) { + for (auto& bubble : bubbles) { + setup_bubble(&bubble); + } +} + +void update_bubbles(void) { + for (auto& bubble : bubbles) { + if (bubble.y + bubble.h < 0) { + setup_bubble(&bubble); + } else { + bubble.y -= bubble.y_inc; + + if (bubble.sway_right_flag) { + bubble.x = bubble.start_x + (bubble.sway -= bubble.sway_inc); + if (bubble.sway <= 0) { + bubble.sway_right_flag = false; + } + } else { + bubble.x = bubble.start_x + (bubble.sway += bubble.sway_inc); + if (bubble.sway > 30) { + bubble.sway_right_flag = true; + } + } + } + } +} + +} // namespace + +void Init() { + if (g_is_init) { + return; + } + + if (R_SUCCEEDED(romfsInit())) { + ON_SCOPE_EXIT(romfsExit()); + + auto vg = App::GetVg(); + g_textures[0] = nvgCreateImage(vg, "romfs:/theme/bubble1.png", 0); + g_textures[1] = nvgCreateImage(vg, "romfs:/theme/bubble2.png", 0); + g_textures[2] = nvgCreateImage(vg, "romfs:/theme/bubble3.png", 0); + + setup_bubbles(); + g_is_init = true; + } +} + +void Draw(NVGcontext* vg, Theme* theme) { + if (!g_is_init) { + return; + } + + update_bubbles(); + + for (auto& bubble : bubbles) { + gfx::drawImage(vg, bubble.x, bubble.y, bubble.w, bubble.h, g_textures[bubble.texture]); + } +} + +void Exit() { + if (!g_is_init) { + return; + } + + auto vg = App::GetVg(); + for (auto& texture : g_textures) { + if (texture) { + nvgDeleteImage(vg, texture); + texture = 0; + } + } + + g_is_init = false; +} + +} // namespace sphaira::ui::bubble