diff --git a/Runtime/CMakeLists.txt b/Runtime/CMakeLists.txt index 2abee4871..afe0f5dcb 100644 --- a/Runtime/CMakeLists.txt +++ b/Runtime/CMakeLists.txt @@ -137,6 +137,7 @@ set(RUNTIME_SOURCES_B GCNTypes.hpp CTextureCache.hpp CTextureCache.cpp CMayaSpline.hpp CMayaSpline.cpp + ImGuiPlayerLoadouts.hpp ImGuiPlayerLoadouts.cpp ${PLAT_SRCS}) function(add_runtime_common_library name) diff --git a/Runtime/ImGuiConsole.cpp b/Runtime/ImGuiConsole.cpp index 76073a35e..be544db72 100644 --- a/Runtime/ImGuiConsole.cpp +++ b/Runtime/ImGuiConsole.cpp @@ -263,7 +263,7 @@ static void RenderEntityColumns(const ImGuiEntityEntry& entry) { } void ImGuiConsole::ShowInspectWindow(bool* isOpen) { - float initialWindowSize = 400.f * ImGui::GetIO().DisplayFramebufferScale.x; + float initialWindowSize = 400.f * aurora::get_window_size().scale; ImGui::SetNextWindowSize(ImVec2{initialWindowSize, initialWindowSize * 1.5f}, ImGuiCond_FirstUseEver); if (ImGui::Begin("Inspect", isOpen)) { @@ -383,7 +383,7 @@ bool ImGuiConsole::ShowEntityInfoWindow(TUniqueId uid) { void ImGuiConsole::ShowConsoleVariablesWindow() { // For some reason the window shows up tiny without this - float initialWindowSize = 350.f * ImGui::GetIO().DisplayFramebufferScale.x; + float initialWindowSize = 350.f * aurora::get_window_size().scale; ImGui::SetNextWindowSize(ImVec2{initialWindowSize, initialWindowSize}, ImGuiCond_FirstUseEver); if (ImGui::Begin("Console Variables", &m_showConsoleVariablesWindow)) { if (ImGui::Button("Clear")) { @@ -633,7 +633,7 @@ std::optional ImGuiConsole::ShowAboutWindow(bool canClose, std::str flags |= ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove; } if (ImGui::Begin("About", open, flags)) { - float iconSize = 128.f * ImGui::GetIO().DisplayFramebufferScale.x; + float iconSize = 128.f * aurora::get_window_size().scale; ImGui::SameLine(ImGui::GetWindowSize().x / 2 - iconSize + (iconSize / 2)); ImGui::Image(ImGuiEngine::metaforceIcon, ImVec2{iconSize, iconSize}); ImGui::PushFont(ImGuiEngine::fontLarge); @@ -942,7 +942,7 @@ void ImGuiConsole::ShowInputViewer() { } ImGui::SetNextWindowBgAlpha(0.65f); if (ImGui::Begin("Input Overlay", nullptr, windowFlags)) { - float scale = ImGui::GetIO().DisplayFramebufferScale.x; + float scale = aurora::get_window_size().scale; if (!m_controllerName.empty()) { TextCenter(m_controllerName); ImGui::Separator(); @@ -1508,7 +1508,7 @@ void ImGuiConsole::ShowItemsWindow() { void ImGuiConsole::ShowLayersWindow() { // For some reason the window shows up tiny without this - float initialWindowSize = 350.f * ImGui::GetIO().DisplayFramebufferScale.x; + float initialWindowSize = 350.f * aurora::get_window_size().scale; ImGui::SetNextWindowSize(ImVec2{initialWindowSize, initialWindowSize}, ImGuiCond_FirstUseEver); if (ImGui::Begin("Layers", &m_showLayersWindow)) { diff --git a/Runtime/ImGuiPlayerLoadouts.cpp b/Runtime/ImGuiPlayerLoadouts.cpp new file mode 100644 index 000000000..5ecae7a27 --- /dev/null +++ b/Runtime/ImGuiPlayerLoadouts.cpp @@ -0,0 +1,43 @@ +#include "Runtime/ImGuiPlayerLoadouts.hpp" +#include "Runtime/Streams/ContainerReaders.hpp" +#include "Runtime/Streams/ContainerWriters.hpp" + +#include + +#include "magic_enum.hpp" +namespace metaforce { +namespace { +logvisor::Module Log("metaforce::ImGuiPlayerLoadouts"); +constexpr u32 CurrentVersion = 1; +} // namespace +ImGuiPlayerLoadouts::Item::Item(CInputStream& in) +: type(magic_enum::enum_cast(in.Get()).value()), amount(in.ReadLong()) {} + +void ImGuiPlayerLoadouts::Item::PutTo(COutputStream& out) const { + out.Put(magic_enum::enum_name(type)); + out.Put(amount); +} +ImGuiPlayerLoadouts::LoadOut::LoadOut(CInputStream& in) : name(in.Get()) { read_vector(items, in); } + +void ImGuiPlayerLoadouts::LoadOut::PutTo(COutputStream& out) const { + out.Put(name); + write_vector(items, out); +} + +ImGuiPlayerLoadouts::ImGuiPlayerLoadouts(CInputStream& in) { + FourCC magic; + in.Get(reinterpret_cast(&magic), 4); + auto version = in.ReadLong(); + if (magic != FOURCC('LOAD') && version != CurrentVersion) { + Log.report(logvisor::Error, FMT_STRING("Incorrect loadout version, expected {} got {}"), CurrentVersion, version); + return; + } + read_vector(loadouts, in); +} +void ImGuiPlayerLoadouts::PutTo(COutputStream& out) const { + auto magic = FOURCC('LOAD'); + out.Put(reinterpret_cast(&magic), 4); + out.Put(CurrentVersion); + write_vector(loadouts, out); +} +} // namespace metaforce \ No newline at end of file diff --git a/Runtime/ImGuiPlayerLoadouts.hpp b/Runtime/ImGuiPlayerLoadouts.hpp index d76de2c58..01c309e53 100644 --- a/Runtime/ImGuiPlayerLoadouts.hpp +++ b/Runtime/ImGuiPlayerLoadouts.hpp @@ -1,23 +1,27 @@ #pragma once -#include -#include +#include "Runtime/CPlayerState.hpp" namespace metaforce { -struct ImGuiPlayerLoadouts : athena::io::DNA { - AT_DECL_DNA_YAML - struct Item : athena::io::DNA { - AT_DECL_DNA_YAML - String<-1> type; - Value amount; +struct ImGuiPlayerLoadouts { + struct Item { + CPlayerState::EItemType type = CPlayerState::EItemType::Invalid; + u32 amount = 0; + Item() = default; + explicit Item(CInputStream& in); + void PutTo(COutputStream& out) const; }; - struct LoadOut : athena::io::DNA { - AT_DECL_DNA_YAML - String<-1> name; - Value itemCount; - Vector items; + struct LoadOut{ + std::string name; + std::vector items; + LoadOut() = default; + explicit LoadOut(CInputStream& in); + void PutTo(COutputStream& out) const; }; - Value loadoutCount; - Vector loadouts; + std::vector loadouts; + + ImGuiPlayerLoadouts() = default; + explicit ImGuiPlayerLoadouts(CInputStream& in); + void PutTo(COutputStream& out) const; }; } // namespace metaforce diff --git a/Runtime/Streams/CInputStream.cpp b/Runtime/Streams/CInputStream.cpp index d3664a38b..b278746ac 100644 --- a/Runtime/Streams/CInputStream.cpp +++ b/Runtime/Streams/CInputStream.cpp @@ -89,32 +89,36 @@ u32 CInputStream::ReadBytes(void* dest, u32 len) { return curReadLen; } -u32 CInputStream::ReadBits(u32 bitCount) { - u32 ret = x20_bitOffset; - if (ret < bitCount) { - const u32 shiftAmt = bitCount - x20_bitOffset; - const u32 mask = ret == 32 ? -1 : (1 << x20_bitOffset) - 1; - u32 uVar2 = x1c_bitWord; - x20_bitOffset = 0; - u32 len = min_containing_bytes(shiftAmt); - Get(reinterpret_cast(&x1c_bitWord), len); +u32 CInputStream::ReadBits(u32 bitCount) { + u32 ret = 0; + const s32 shiftAmt = x20_bitOffset - s32(bitCount); + if (shiftAmt < 0) { + /* OR in remaining bits of cached value */ + u32 mask = bitCount == 32 ? UINT32_MAX : ((1U << bitCount) - 1); + ret |= (x1c_bitWord << u32(-shiftAmt)) & mask; + /* Load in exact number of bytes remaining */ + auto loadDiv = std::div(-shiftAmt, 8); + if (loadDiv.rem != 0) { + ++loadDiv.quot; + } + Get(reinterpret_cast(&x1c_bitWord) + 4 - loadDiv.quot, loadDiv.quot); #if METAFORCE_TARGET_BYTE_ORDER == __ORDER_LITTLE_ENDIAN__ x1c_bitWord = CBasics::SwapBytes(x1c_bitWord); #endif - - const u32 retMask = shiftAmt == 32 ? -1 : (1 << shiftAmt) - 1; - const u32 tmpOffset = x20_bitOffset; - x20_bitOffset = len * 8; - ret = ((mask & uVar2) >> (32 - ret) << shiftAmt) | (retMask & (x1c_bitWord >> (32 - shiftAmt))) << tmpOffset; - x20_bitOffset -= shiftAmt; - x1c_bitWord <<= shiftAmt; + /* New bit offset */ + x20_bitOffset = loadDiv.quot * 8 + shiftAmt; + /* OR in next bits */ + mask = (1U << u32(-shiftAmt)) - 1; + ret |= (x1c_bitWord >> x20_bitOffset) & mask; } else { + /* OR in bits of cached value */ + const u32 mask = bitCount == 32 ? UINT32_MAX : ((1U << bitCount) - 1); + ret |= (x1c_bitWord >> u32(shiftAmt)) & mask; + /* New bit offset */ x20_bitOffset -= bitCount; - ret = bitCount == 32 ? -1 : (1 << bitCount) - 1; - ret &= x1c_bitWord >> (32 - bitCount); - x1c_bitWord <<= bitCount; } + return ret; } diff --git a/Runtime/Streams/COutputStream.cpp b/Runtime/Streams/COutputStream.cpp index d1fe0798e..1281a0ba7 100644 --- a/Runtime/Streams/COutputStream.cpp +++ b/Runtime/Streams/COutputStream.cpp @@ -78,27 +78,27 @@ void COutputStream::Put(const u8* ptr, u32 len) { } void COutputStream::WriteBits(u32 val, u32 bitCount) { - const u32 bitOffset = x18_shiftRegisterOffset; - if (x18_shiftRegisterOffset < bitCount) { + const s32 shiftAmt = x18_shiftRegisterOffset - s32(bitCount); + if (shiftAmt < 0) { /* OR remaining bits to cached value */ - const u32 shiftAmt = (bitCount - x18_shiftRegisterOffset); - const u32 mask = bitOffset == 32 ? -1 : (1 << bitOffset) - 1; + const u32 mask = (1U << x18_shiftRegisterOffset) - 1; + x14_shiftRegister |= (val >> u32(-shiftAmt)) & mask; /* Write out 32-bits */ - x14_shiftRegister |= (val >> shiftAmt) & mask; - x18_shiftRegisterOffset = 0; FlushShiftRegister(); /* Cache remaining bits */ - x14_shiftRegister = (val & (shiftAmt == 32 ? -1 : (1 << shiftAmt) - 1)) << (32 - shiftAmt); - x18_shiftRegisterOffset -= shiftAmt; + x18_shiftRegisterOffset = 0x20 + shiftAmt; + x14_shiftRegister = val << x18_shiftRegisterOffset; } else { /* OR bits to cached value */ - const u32 mask = bitOffset == 0x20 ? -1 : (1 << bitOffset) - 1; - x14_shiftRegister |= (val & mask) << (bitOffset - bitCount); + const u32 mask = bitCount == 32 ? UINT32_MAX : ((1U << bitCount) - 1); + x14_shiftRegister |= (val & mask) << u32(shiftAmt); + /* New bit offset */ x18_shiftRegisterOffset -= bitCount; } + } void COutputStream::WriteChar(u8 c) { @@ -199,6 +199,14 @@ void coutput_stream_helper(const std::string& t, COutputStream& out) { } } +template <> +void coutput_stream_helper(const std::string_view& t, COutputStream& out) { + for (size_t i = 0; i < t.size() + 1; ++i) { + out.FlushShiftRegister(); + out.Put(t[i]); + } +} + u32 COutputStream::GetBitCount(u32 val) { int bits = 0; for (; val != 0; val >>= 1) { diff --git a/Runtime/Streams/COutputStream.hpp b/Runtime/Streams/COutputStream.hpp index 9e09f2738..2bd1e2c2d 100644 --- a/Runtime/Streams/COutputStream.hpp +++ b/Runtime/Streams/COutputStream.hpp @@ -86,4 +86,6 @@ template <> void coutput_stream_helper(const double& t, COutputStream& out); template <> void coutput_stream_helper(const std::string& t, COutputStream& out); +template <> +void coutput_stream_helper(const std::string_view& t, COutputStream& out); } // namespace metaforce diff --git a/Runtime/Streams/ContainerReaders.hpp b/Runtime/Streams/ContainerReaders.hpp index 1080dfb2f..2753736e9 100644 --- a/Runtime/Streams/ContainerReaders.hpp +++ b/Runtime/Streams/ContainerReaders.hpp @@ -1,7 +1,8 @@ #pragma once -#include "Runtime/rstl.hpp" #include "Runtime/Streams/CInputStream.hpp" +#include "Runtime/rstl.hpp" +#include namespace metaforce { template void read_reserved_vector(rstl::reserved_vector& v, CInputStream& in) { @@ -11,4 +12,13 @@ void read_reserved_vector(rstl::reserved_vector& v, CInputStream& in) { v[i] = in.Get(); } } + +template +void read_vector(std::vector& v, CInputStream& in) { + u32 count = in.ReadLong(); + v.reserve(count); + for (u32 i = 0; i < count; ++i) { + v.emplace_back(in.Get()); + } +} } // namespace metaforce \ No newline at end of file diff --git a/Runtime/Streams/ContainerWriters.hpp b/Runtime/Streams/ContainerWriters.hpp new file mode 100644 index 000000000..ca5330cc6 --- /dev/null +++ b/Runtime/Streams/ContainerWriters.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include "Runtime/Streams/COutputStream.hpp" +#include "Runtime/rstl.hpp" +#include +namespace metaforce { +template +void write_reserved_vector(const rstl::reserved_vector& v, COutputStream& out) { + out.Put(v.size()); + for (const auto& t : v) { + out.Put(t); + } +} + +template +void write_vector(const std::vector& v, COutputStream& out) { + out.Put(v.size()); + for (const auto& t : v) { + out.Put(t); + } +} +} // namespace metaforce \ No newline at end of file