diff --git a/libultraship/libultraship/GameOverlay.cpp b/libultraship/libultraship/GameOverlay.cpp new file mode 100644 index 000000000..70f3abf9f --- /dev/null +++ b/libultraship/libultraship/GameOverlay.cpp @@ -0,0 +1,150 @@ +#include "GameOverlay.h" + +#include "Cvar.h" +#include "File.h" +#include "Archive.h" +#include "ResourceMgr.h" +#include "SohConsole.h" +#include "SohImGuiImpl.h" +#include "TextureMod.h" +#include "Lib/ImGui/imgui_internal.h" + +void Ship::GameOverlay::LoadFont(const std::string& name, const std::string& path, float fontSize) { + ImGuiIO& io = ImGui::GetIO(); + std::shared_ptr base = GlobalCtx2::GetInstance()->GetResourceManager()->GetArchive(); + std::shared_ptr font = std::make_shared(); + base->LoadFile(normalize(path), false, font); + if (font->bIsLoaded) { + char* font_data = new char[font->dwBufferSize]; + memcpy(font_data, font->buffer.get(), font->dwBufferSize); + Fonts[name] = io.Fonts->AddFontFromMemoryTTF(font_data, font->dwBufferSize, fontSize); + } +} + +void Ship::GameOverlay::TextDraw(float x, float y, bool shadow, const char* fmt, ...) IM_FMTARGS(5) { + char buf[1024]; + va_list args; + va_start(args, fmt); + vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args); + buf[IM_ARRAYSIZE(buf) - 1] = 0; + va_end(args); + + ImGui::PushFont(Fonts[this->CurrentFont]); + if (shadow) { + ImGui::SetCursorPos(ImVec2(x + 1, y + 1)); + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(.0f, .0f, .0f, 255)); + ImGui::Text(buf, args); + } + ImGui::PopStyleColor(); + ImGui::SetCursorPos(ImVec2(x, y)); + ImGui::Text(buf, args); + ImGui::PopFont(); +} + +float Ship::GameOverlay::GetScreenWidth() { + const ImGuiViewport* viewport = ImGui::GetMainViewport(); + return viewport->Size.x; +} + +float Ship::GameOverlay::GetScreenHeight() { + const ImGuiViewport* viewport = ImGui::GetMainViewport(); + return viewport->Size.y; +} + +float Ship::GameOverlay::GetStringWidth(const char* text) { + return ImGui::CalcTextSize(text).x; +} + +void Ship::GameOverlay::Init() { + this->LoadFont("Press Start 2P", "assets/ship_of_harkinian/fonts/PressStart2P-Regular.ttf", 12.0f); + if(!this->Fonts.empty()) { + this->CurrentFont = CVar_GetString("gOverlayFont", ImStrdup(this->Fonts.begin()->first.c_str())); + } + SohImGui::console->Commands["overlay"] = { OverlayCommand, "Draw an overlay using a cvar value" }; +} + +void Ship::GameOverlay::DrawSettings() { + ImGui::Text("Overlays Text Font"); + if (ImGui::BeginCombo("##TextFont", this->CurrentFont.c_str())) { + for (auto& [name, font] : this->Fonts) { + if (ImGui::Selectable(name.c_str(), name == this->CurrentFont)) { + this->CurrentFont = name; + CVar_SetString("gOverlayFont", ImStrdup(name.c_str())); + SohImGui::needs_save = true; + } + + } + ImGui::EndCombo(); + } +} + + +void Ship::GameOverlay::Draw() { + const ImGuiViewport* viewport = ImGui::GetMainViewport(); + + ImGui::SetNextWindowPos(viewport->Pos, ImGuiCond_Always); + ImGui::SetNextWindowSize(viewport->Size, ImGuiCond_Always); + ImGui::Begin("SoHOverlay", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBackground | + ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoInputs); + + float textY = 50; + for (auto &[key, overlay] : this->RegisteredOverlays) { + + if (overlay.type == OverlayType::TEXT) { + const char* text = ImStrdup(key.c_str()); + const CVar* var = CVar_GetVar(text); + + switch (var->type) { + case CVAR_TYPE_FLOAT: + this->TextDraw(30, textY, true, "%s %.2f", text, var->value.valueFloat); + break; + case CVAR_TYPE_S32: + this->TextDraw(30, textY, true, "%s %d", text, var->value.valueS32); + break; + case CVAR_TYPE_STRING: + this->TextDraw(30, textY, true, "%s %s", text, var->value.valueStr); + break; + } + + free((void*) text); + textY += 30; + } + } + + ImGui::End(); +} + + +bool Ship::OverlayCommand(const std::vector& args) { + if (args.size() < 3) { + return CMD_FAILED; + } + + if (CVar_GetVar(args[2].c_str()) != nullptr) { + const char* key = args[2].c_str(); + GameOverlay* overlay = SohImGui::overlay; + if (args[1] == "add") { + if (!overlay->RegisteredOverlays.contains(args[2])) { + overlay->RegisteredOverlays[args[2]] = { + OverlayType::TEXT, + key + }; + INFO("Added overlay: %s ", key); + } else { + ERROR("Overlay already exists: %s", key); + } + } + else if (args[1] == "remove") { + if (overlay->RegisteredOverlays.contains(args[2])) { + overlay->RegisteredOverlays.erase(args[2]); + INFO("Removed overlay: %s ", key); + } else { + ERROR("Overlay not found: %s ", key); + } + } + } else { + ERROR("CVar %s does not exist", args[2].c_str()); + } + + return CMD_SUCCESS; +} diff --git a/libultraship/libultraship/GameOverlay.h b/libultraship/libultraship/GameOverlay.h new file mode 100644 index 000000000..02e672b8a --- /dev/null +++ b/libultraship/libultraship/GameOverlay.h @@ -0,0 +1,37 @@ +#pragma once +#include +#include + +#include "Lib/ImGui/imgui.h" +#include +#include + +enum class OverlayType { + TEXT, IMAGE +}; + +struct Overlay { + OverlayType type; + const char* value; +}; + +namespace Ship { + class GameOverlay { + public: + std::unordered_map RegisteredOverlays; + std::unordered_map Fonts; + std::string CurrentFont = "Default"; + void Init(); + void Draw(); + void DrawSettings(); + static float GetScreenWidth(); + static float GetScreenHeight(); + static float GetStringWidth(const char* text); + private: + void TextDraw(float x, float y, bool shadow, const char* text, ...); + void LoadFont(const std::string& name, const std::string& path, float fontSize); + }; + + static bool OverlayCommand(const std::vector& args); +} + diff --git a/libultraship/libultraship/SohConsole.cpp b/libultraship/libultraship/SohConsole.cpp index 330326e72..6b19a268b 100644 --- a/libultraship/libultraship/SohConsole.cpp +++ b/libultraship/libultraship/SohConsole.cpp @@ -26,32 +26,6 @@ static bool ClearCommand(const std::vector&) { return CMD_SUCCESS; } -static bool OverlayCommand(const std::vector& args) { - SohImGui::console->Log[SohImGui::console->selected_channel].clear(); - if(args.size() < 3) { - return CMD_FAILED; - } - - if(CVar_GetVar(args[2].c_str()) != nullptr) { - const char* key = ImStrdup(args[2].c_str()); - if (args[1] == "add") { - if (std::ranges::find(SohImGui::CustomTexts, key) == SohImGui::CustomTexts.end()) { - SohImGui::CustomTexts.push_back(key); - INFO("Added overlay: %s ", key); - } - } else if (args[1] == "remove") { - if (std::ranges::find(SohImGui::CustomTexts, key) != SohImGui::CustomTexts.end()) { - SohImGui::CustomTexts.push_back(key); - INFO("Removed overlay: %s ", key); - } - } else { - return CMD_FAILED; - } - } - - return CMD_SUCCESS; -} - std::string toLowerCase(std::string in) { std::string cpy(in); std::ranges::transform(cpy, cpy.begin(), [](unsigned char c) { return std::tolower(c); }); @@ -110,7 +84,6 @@ void Console::Init() { this->Commands["clear"] = { ClearCommand, "Clear the console history" }; this->Commands["bind"] = { BindCommand, "Binds key to commands" }; this->Commands["bind-toggle"] = { BindToggleCommand, "Bind key as a bool toggle" }; - this->Commands["overlay"] = { OverlayCommand, "Overlay cvar value" }; } void Console::Update() { @@ -253,7 +226,7 @@ void Console::Draw() { ImGui::EndChild(); // Renders input textfield - constexpr ImGuiInputTextFlags flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CallbackEdit | + constexpr ImGuiInputTextFlags flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CallbackEdit | ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory; ImGui::PushItemWidth(-1); if(ImGui::InputTextWithHint("CMDInput", ">", this->InputBuffer, MAX_BUFFER_SIZE, flags, &Console::CallbackStub, this)) { diff --git a/libultraship/libultraship/SohImGuiImpl.cpp b/libultraship/libultraship/SohImGuiImpl.cpp index 8d2c0f8b5..b35c41e31 100644 --- a/libultraship/libultraship/SohImGuiImpl.cpp +++ b/libultraship/libultraship/SohImGuiImpl.cpp @@ -18,6 +18,7 @@ #include "TextureMod.h" #include "Window.h" #include "Cvar.h" +#include "GameOverlay.h" #include "Texture.h" #include "../Fast3D/gfx_pc.h" #include "Lib/stb/stb_image.h" @@ -53,13 +54,13 @@ bool oldCursorState = true; OSContPad* pads; std::map DefaultAssets; -std::map Fonts; namespace SohImGui { WindowImpl impl; ImGuiIO* io; Console* console = new Console; + GameOverlay* overlay = new GameOverlay; bool p_open = false; bool needs_save = false; std::vector CustomTexts; @@ -300,19 +301,12 @@ namespace SohImGui { io = &ImGui::GetIO(); io->ConfigFlags |= ImGuiConfigFlags_DockingEnable; io->Fonts->AddFontDefault(); - std::shared_ptr base = GlobalCtx2::GetInstance()->GetResourceManager()->GetArchive(); - std::shared_ptr font = std::make_shared(); - base->LoadFile("assets\\ship_of_harkinian\\fonts\\PressStart2P-Regular.ttf", false, font); - if(font->bIsLoaded) { - char* font_data = new char[font->dwBufferSize]; - memcpy(font_data, font->buffer.get(), font->dwBufferSize); - Fonts["Player2"] = io->Fonts->AddFontFromMemoryTTF(font_data, font->dwBufferSize, 14.0f); - } if (UseViewports()) { io->ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; } console->Init(); + overlay->Init(); ImGuiWMInit(); ImGuiBackendInit(); @@ -476,49 +470,7 @@ namespace SohImGui { } } - #define TextDraw(x, y, shadow, text, ...) { \ - ImGui::PushFont(Fonts["Player2"]); \ - if(shadow) { \ - ImGui::SetCursorPos(ImVec2(x + 1, y + 1)); \ - ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(.0f, .0f, .0f, 255)); \ - ImGui::Text(text, __VA_ARGS__); \ - } \ - ImGui::PopStyleColor(); \ - ImGui::SetCursorPos(ImVec2(x, y)); \ - ImGui::Text(text, __VA_ARGS__); \ - ImGui::PopFont(); \ - } \ - - void DrawCustomText() { - const ImGuiViewport* viewport = ImGui::GetMainViewport(); - - ImGui::SetNextWindowPos(viewport->Pos, ImGuiCond_Always); - ImGui::SetNextWindowSize(viewport->Size, ImGuiCond_Always); - ImGui::Begin("SoHOverlay", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBackground | - ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoInputs); - - for (int xId = 0; xId < CustomTexts.size(); xId++) { - const char* text = CustomTexts[xId]; - const CVar* var = CVar_GetVar(text); - int textY = 50 + (xId * 30); - - switch (var->type) { - case CVAR_TYPE_FLOAT: - TextDraw(30, textY, true, "%s %.2f", text, var->value.valueFloat); - break; - case CVAR_TYPE_S32: - TextDraw(30, textY, true, "%s %d", text, var->value.valueS32); - break; - case CVAR_TYPE_STRING: - TextDraw(30, textY, true, "%s %s", text, var->value.valueStr); - break; - } - } - - ImGui::End(); - } - - void DrawMainMenuAndCalculateGameSize() { + void DrawMainMenuAndCalculateGameSize() { console->Update(); ImGuiBackendNewFrame(); ImGuiWMNewFrame(); @@ -652,6 +604,7 @@ namespace SohImGui { } ImGui::EndCombo(); } + overlay->DrawSettings(); ImGui::EndMenu(); } @@ -825,7 +778,7 @@ namespace SohImGui { size = ImVec2(sw, size.y); } - DrawCustomText(); + overlay->Draw(); } void DrawFramebufferAndGameInput() { diff --git a/libultraship/libultraship/SohImGuiImpl.h b/libultraship/libultraship/SohImGuiImpl.h index 387fb179f..dd0ec9fd3 100644 --- a/libultraship/libultraship/SohImGuiImpl.h +++ b/libultraship/libultraship/SohImGuiImpl.h @@ -1,5 +1,6 @@ #pragma once +#include "GameOverlay.h" #include "Lib/ImGui/imgui.h" #include "SohConsole.h" @@ -58,7 +59,8 @@ namespace SohImGui { } CustomWindow; extern Console* console; - extern std::vector CustomTexts; + extern Ship::GameOverlay* overlay; + extern bool needs_save; void Init(WindowImpl window_impl); void Update(EventImpl event); diff --git a/libultraship/libultraship/libultraship.vcxproj b/libultraship/libultraship/libultraship.vcxproj index 3bf81a67d..b3448e7b0 100644 --- a/libultraship/libultraship/libultraship.vcxproj +++ b/libultraship/libultraship/libultraship.vcxproj @@ -256,6 +256,7 @@ + @@ -343,6 +344,7 @@ + diff --git a/libultraship/libultraship/libultraship.vcxproj.filters b/libultraship/libultraship/libultraship.vcxproj.filters index 5079d826e..8ac4f0afb 100644 --- a/libultraship/libultraship/libultraship.vcxproj.filters +++ b/libultraship/libultraship/libultraship.vcxproj.filters @@ -88,6 +88,9 @@ {bd6557f1-9480-413b-b0cd-843f8efc1939} + + {3285ab8a-06d8-4dac-9af9-efb2a9723ab1} + @@ -339,6 +342,9 @@ Source Files\CustomImpl + + Source Files\CustomImpl\Overlay + @@ -629,5 +635,8 @@ Source Files\Resources + + Source Files\CustomImpl\Overlay + \ No newline at end of file