# Stage 2.2

- Move Timer to core
- Use Timer for app_time
- Fix Deltatime Bug in App
- Add HwInfo to lib3ds (stolen from hbloader 2 pd-rewrite port)
- Add GetSystemLanguage to lib3ds
- Add Net Header for pd-net (still need to find a way to make this working)
- Add base Decoder and Player Headers for pd-sound
- Add Mp3 Decoder (useless and untested yet)
- Add GetDataDirectory to App
- Add InitFLag to App for HwInfo
- Actually write the Timer class
- Rework the UI7 Theme API to use SmartCtor
- UI7::Menu::JoinAlign: Use a loop to determinate max width for centering a group
- Add some Doctumentation around UI7::Menu
This commit is contained in:
2025-02-28 19:49:24 +01:00
parent f9a1d8aefb
commit debedf59c6
27 changed files with 840 additions and 98 deletions

View File

@ -26,6 +26,7 @@ SOFTWARE.
#include <pd/app/app.hpp>
#include <pd/core/sys.hpp>
#include <pd/lib3ds/hwinfo.hpp>
namespace PD {
int App::too;
@ -33,17 +34,17 @@ int App::too;
void App::Run() {
this->PreInit();
this->Init();
last_time = Sys::GetTime();
last_time = Sys::GetNanoTime();
while (aptMainLoop()) {
input_mgr->Update();
u64 current = Sys::GetNanoTime();
float dt = static_cast<float>(current - last_time) / 1000000.f;
app_time += dt / 1000.f;
app_time->Update();
last_time = current;
fps = 1000.f / dt;
if (runtimeflags & AppFLags_UserLoop) {
PD::TT::Beg("App_MainLoop");
if (!this->MainLoop(dt, app_time)) {
if (!this->MainLoop(dt, app_time->GetSeconds())) {
break;
}
PD::TT::End("App_MainLoop");
@ -73,6 +74,12 @@ void App::Run() {
this->PostDeinit();
}
std::string App::GetDataDirectory() {
Assert(SafeInitFlags & AppInitFlags_UnnamedOption1,
"Data Dir is not enabled!");
return "sdmc:/palladium/apps/" + name;
}
void App::PreInit() {
/// Create a Copy that won't get edit
SafeInitFlags = InitFlags;
@ -87,6 +94,9 @@ void App::PreInit() {
if (InitFlags & AppInitFlags_MountRomfs) {
romfsInit();
}
if (InitFlags & AppInitFlags_InitHwInfo) {
PD::HwInfo::Init();
}
if (InitFlags & AppInitFlags_UnnamedOption1) {
std::filesystem::create_directories("sdmc:/palladium/apps/" + name);
}
@ -103,6 +113,7 @@ void App::PreInit() {
msg_mgr = MessageMgr::New(renderer);
overlay_mgr = OverlayMgr::New(renderer, input_mgr);
}
app_time = Timer::New();
}
void App::PostDeinit() {
@ -116,6 +127,9 @@ void App::PostDeinit() {
}
gfxExit();
}
if (SafeInitFlags & AppInitFlags_InitHwInfo) {
PD::HwInfo::Deinit();
}
cfguExit();
if (SafeInitFlags & AppInitFlags_MountRomfs) {
romfsExit();

49
source/core/timer.cpp Normal file
View File

@ -0,0 +1,49 @@
/*
MIT License
Copyright (c) 2024 - 2025 tobid7
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <pd/core/timer.hpp>
namespace PD {
Timer::Timer(bool autostart) {
is_running = autostart;
Reset();
}
void Timer::Reset() {
start = Sys::GetTime();
now = start;
}
void Timer::Update() {
if (is_running) {
now = Sys::GetTime();
}
}
void Timer::Pause() { is_running = false; }
void Timer::Rseume() { is_running = true; }
bool Timer::IsRunning() const { return is_running; }
u64 Timer::Get() { return now - start; }
double Timer::GetSeconds() { return double(Get()) / 1000.0; }
} // namespace PD

50
source/lib3ds/hwinfo.cpp Normal file
View File

@ -0,0 +1,50 @@
/*
MIT License
Copyright (c) 2024 - 2025 René Amthor (tobid7)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <3ds.h>
#include <pd/lib3ds/hwinfo.hpp>
namespace PD {
namespace HwInfo {
void Init() {
mcuHwcInit();
ptmuInit();
}
void Deinit() {
mcuHwcExit();
ptmuExit();
}
bool IsCharging() {
u8 v = 0;
PTMU_GetBatteryChargeState(&v);
return v == 1;
}
int GetBatteryPercentage() {
u8 lvl = 0;
MCUHWC_GetBatteryLevel(&lvl);
return lvl;
}
int GetWifiLevel() { return osGetWifiStrength(); }
} // namespace HwInfo
} // namespace PD

79
source/lib3ds/os.cpp Normal file
View File

@ -0,0 +1,79 @@
/*
MIT License
Copyright (c) 2024 - 2025 René Amthor (tobid7)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <3ds.h>
#include <pd/lib3ds/os.hpp>
namespace PD {
namespace Ctr {
std::string GetSystemLanguage() {
u8 language = 0;
Result res = CFGU_GetSystemLanguage(&language);
if (R_FAILED(res)) {
return "en";
}
switch (language) {
case 0:
return "jp"; // Japanese
break;
case 1:
return "en"; // English
break;
case 2:
return "fr"; // French
break;
case 3:
return "de"; // German
break;
case 4:
return "it"; // Italian
break;
case 5:
return "es"; // Spanish
break;
case 6:
return "zh-CN"; // Chinese (Simplified)
break;
case 7:
return "ko"; // Korean
break;
case 8:
return "nl"; // Dutch
break;
case 9:
return "pt"; // Portuguese
break;
case 10:
return "ru"; // Russian
break;
case 11:
return "zh-TW"; // Chinese (Traditional)
break;
default:
return "en"; // Fall back to English if missing
break;
}
}
} // namespace Ctr
} // namespace PD

72
source/sound/mp3.cpp Normal file
View File

@ -0,0 +1,72 @@
/*
MIT License
Copyright (c) 2024 - 2025 René Amthor (tobid7)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <pd/sound/mp3.hpp>
namespace PD {
namespace Music {
int Mp3Decoder::Init(const std::string& path) {
int ret = 0;
int encoding = 0;
if ((ret = mpg123_init() != MPG123_OK)) {
return ret;
}
if ((handle = mpg123_new(nullptr, &ret)) == nullptr) {
return ret;
}
int cnls = 0;
long _rate = 0;
if (mpg123_open(handle, path.c_str()) != MPG123_OK ||
mpg123_getformat(handle, &_rate, &cnls, &encoding)) {
return ret;
}
rate = _rate;
channels = cnls;
mpg123_format_none(handle);
mpg123_format(handle, rate, channels, encoding);
buf_size = mpg123_outblock(handle) * 16;
return ret;
}
void Mp3Decoder::Deinit() {
mpg123_close(handle);
mpg123_delete(handle);
mpg123_exit();
}
u32 Mp3Decoder::GetSampleRate() { return rate; }
u8 Mp3Decoder::GetChannels() { return channels; }
u64 Mp3Decoder::Decode(u16* buf_address) {
size_t done = 0;
mpg123_read(handle, buf_address, buf_size, &done);
return done / sizeof(u16);
}
size_t Mp3Decoder::GetFileSamples() {
off_t len = mpg123_length(handle);
if (len != MPG123_ERR) {
return len * size_t(channels);
}
return -1; // NotExist
}
} // namespace Music
} // namespace PD

View File

@ -48,12 +48,12 @@ void Button::HandleInput(Hid::Ref inp) {
inp_done = true;
}
void Button::Draw() {
Assert(ren.get() && list.get() && linked_theme,
Assert(ren.get() && list.get() && theme,
"Did you run Container::Init correctly?");
ren->OnScreen(screen);
list->AddRectangle(pos, size, linked_theme->Get(color));
list->AddRectangle(pos, size, theme->Get(color));
list->AddText(pos + size * 0.5 - tdim * 0.5, label,
linked_theme->Get(UI7Color_Text));
theme->Get(UI7Color_Text));
}
} // namespace UI7
} // namespace PD

View File

@ -47,15 +47,15 @@ void Checkbox::HandleInput(Hid::Ref inp) {
inp_done = true;
}
void Checkbox::Draw() {
Assert(ren.get() && list.get() && linked_theme,
Assert(ren.get() && list.get() && theme,
"Did you run Container::Init correctly?");
ren->OnScreen(screen);
list->AddRectangle(pos, cbs, linked_theme->Get(color));
list->AddRectangle(pos, cbs, theme->Get(color));
if (usr_ref) {
list->AddRectangle(pos + 2, cbs - 4, linked_theme->Get(UI7Color_Checkmark));
list->AddRectangle(pos + 2, cbs - 4, theme->Get(UI7Color_Checkmark));
}
list->AddText(pos + vec2(cbs.x() + 5, cbs.y() * 0.5 - tdim.y() * 0.5), label,
linked_theme->Get(UI7Color_Text));
theme->Get(UI7Color_Text));
}
} // namespace UI7
} // namespace PD

View File

@ -26,8 +26,7 @@ SOFTWARE.
namespace PD {
namespace UI7 {
void Image::Draw() {
Assert(ren.get() && list.get() && linked_theme,
"Did you run Container::Init correctly?");
Assert(ren.get() && list.get(), "Did you run Container::Init correctly?");
Assert(img.get(), "Image is nullptr!");
ren->OnScreen(screen);
list->AddImage(pos, img);

View File

@ -26,10 +26,10 @@ SOFTWARE.
namespace PD {
namespace UI7 {
void Label::Draw() {
Assert(ren.get() && list.get() && linked_theme,
Assert(ren.get() && list.get() && theme,
"Did you run Container::Init correctly?");
ren->OnScreen(screen);
list->AddText(pos, label, linked_theme->Get(UI7Color_Text));
list->AddText(pos, label, theme->Get(UI7Color_Text));
}
} // namespace UI7
} // namespace PD

View File

@ -32,7 +32,7 @@ void UI7::Menu::Label(const std::string& label) {
ObjectPush(PD::New<UI7::Label>(label, Cursor(), this->back->ren));
r->SetPos(AlignPos(r->GetPos(), r->GetSize(), view_area, GetAlignment()));
CursorMove(r->GetSize());
r->Init(main->ren, main, linked_theme);
r->Init(main->ren, main, theme);
r->HandleScrolling(scrolling_off, view_area);
}
@ -43,7 +43,7 @@ bool UI7::Menu::Button(const std::string& label) {
if (!r) {
r = PD::New<UI7::Button>(label, Cursor(), this->back->ren);
r->SetID(id);
r->Init(main->ren, main, linked_theme);
r->Init(main->ren, main, theme);
}
ObjectPush(r);
r->SetPos(AlignPos(Cursor(), r->GetSize(), view_area, GetAlignment()));
@ -61,7 +61,7 @@ void UI7::Menu::Checkbox(const std::string& label, bool& v) {
if (!r) {
r = PD::New<UI7::Checkbox>(label, Cursor(), v, this->back->ren);
r->SetID(id);
r->Init(main->ren, main, linked_theme);
r->Init(main->ren, main, theme);
}
ObjectPush(r);
r->SetPos(AlignPos(Cursor(), r->GetSize(), view_area, GetAlignment()));
@ -74,7 +74,7 @@ void UI7::Menu::Image(Texture::Ref img, vec2 size) {
ObjectPush(PD::New<UI7::Image>(img, Cursor(), this->back->ren, size));
r->SetPos(AlignPos(r->GetPos(), r->GetSize(), view_area, GetAlignment()));
CursorMove(r->GetSize());
r->Init(main->ren, main, linked_theme);
r->Init(main->ren, main, theme);
r->HandleScrolling(scrolling_off, view_area);
}
@ -163,20 +163,19 @@ void UI7::Menu::PreHandler(UI7MenuFlags flags) {
has_touch =
main->GetRenderer()->CurrentScreen()->ScreenType() == Screen::Bottom;
if (!(flags & UI7MenuFlags_NoBackground)) {
back->AddRectangle(0, view_area.zw(),
linked_theme->Get(UI7Color_Background));
back->AddRectangle(0, view_area.zw(), theme->Get(UI7Color_Background));
}
if (!(flags & UI7MenuFlags_NoTitlebar)) {
tbh = front->GetRenderer()->TextScale() * 30.f;
front->AddRectangle(0, vec2(view_area.z(), tbh),
linked_theme->Get(UI7Color_Header));
theme->Get(UI7Color_Header));
vec2 tpos(5, tbh * 0.5 - front->ren->GetTextDimensions(name).y() * 0.5);
LITextFlags tflags = LITextFlags_None;
if (flags & UI7MenuFlags_CenterTitle) {
tpos = 0;
tflags = LITextFlags_AlignMid;
}
front->AddText(tpos, this->name, linked_theme->Get(UI7Color_Text), tflags,
front->AddText(tpos, this->name, theme->Get(UI7Color_Text), tflags,
vec2(view_area.z(), tbh));
main_area[1] = tbh;
CursorInit();
@ -287,12 +286,12 @@ void UI7::Menu::PostHandler() {
/// Rendering Stage
front->AddRectangle(vec2(screen_w - 12, tsp), vec2(slider_w * 2, szs),
linked_theme->Get(UI7Color_FrameBackground));
theme->Get(UI7Color_FrameBackground));
front->AddRectangle(vec2(screen_w - 10, tsp + 2), vec2(slider_w, szs - 4),
linked_theme->Get(UI7Color_FrameBackgroundHovered));
theme->Get(UI7Color_FrameBackgroundHovered));
front->AddRectangle(vec2(screen_w - 10, srpos + 2),
vec2(slider_w, vslider_h),
linked_theme->Get(UI7Color_Button));
theme->Get(UI7Color_Button));
}
}
TT::End("MUSR_" + name);
@ -310,7 +309,7 @@ void UI7::Menu::Separator() {
if (HandleScrolling(pos, size)) {
return;
}
main->AddRectangle(pos, size, linked_theme->Get(UI7Color_TextDead));
main->AddRectangle(pos, size, theme->Get(UI7Color_TextDead));
}
void UI7::Menu::SeparatorText(const std::string& label) {
@ -326,11 +325,11 @@ void UI7::Menu::SeparatorText(const std::string& label) {
vec2 lpos = pos + vec2((view_area.z() - 10) * 0.5 - tdim.x() * 0.5, 0);
main->AddRectangle(pos + vec2(0, tdim.y() * 0.5),
vec2(lpos.x() - pos.x() - 5, size.y()),
linked_theme->Get(UI7Color_TextDead));
theme->Get(UI7Color_TextDead));
main->AddRectangle(pos + vec2(lpos.x() + tdim.x(), tdim.y() * 0.5),
vec2(size.x() - (lpos.x() + tdim.x()), size.y()),
linked_theme->Get(UI7Color_TextDead));
main->AddText(lpos, label, linked_theme->Get(UI7Color_Text), 0,
theme->Get(UI7Color_TextDead));
main->AddText(lpos, label, theme->Get(UI7Color_Text), 0,
vec2(view_area.z(), 20));
}
@ -346,6 +345,7 @@ bool UI7::Menu::HandleScrolling(vec2& pos, const vec2& size) {
Container::Ref UI7::Menu::ObjectPush(Container::Ref obj) {
this->objects.push_back(obj);
obj->SetParent(this->tmp_parent);
return obj;
}
@ -371,6 +371,10 @@ void UI7::Menu::JoinAlign(UI7Align a) {
vec2 spos = join.front()->GetPos();
vec2 szs = join.back()->GetPos() + join.back()->GetSize() - spos;
for (auto it : join) {
szs.x() =
std::max(szs.x(), it->GetPos().x() + it->GetSize().x() - spos.x());
}
vec2 off;
if (a & UI7Align_Center) {
off[0] = (view_area[0] + view_area[2] * 0.5) - (spos[0] + szs[0] * 0.5);

View File

@ -31,7 +31,7 @@ bool UI7::Context::BeginMenu(const ID& id, UI7MenuFlags flags) {
"Menu Name Already used or\nContext::Update not called!");
auto menu = this->menus.find(id);
if (menu == this->menus.end()) {
this->menus[id] = Menu::New(id, &theme, inp);
this->menus[id] = Menu::New(id, theme, inp);
menu = this->menus.find(id);
}
this->current = menu->second;