Implemented overlay command and api (#289)

* Added overlay command

* Moved Overlays to GameOverlay

* Added custom text size calculation

* Fixed string cvar load and added fipps font
This commit is contained in:
KiritoDev 2022-05-11 12:35:03 -05:00 committed by GitHub
parent ea78c7ea1e
commit fe3e534938
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 259 additions and 2 deletions

View File

@ -0,0 +1,186 @@
#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<Archive> base = GlobalCtx2::GetInstance()->GetResourceManager()->GetArchive();
std::shared_ptr<File> font = std::make_shared<File>();
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 CalculateTextSize(text).x;
}
ImVec2 Ship::GameOverlay::CalculateTextSize(const char* text, const char* text_end, bool hide_text_after_double_hash, float wrap_width) {
ImGuiContext& g = *GImGui;
const char* text_display_end;
if (hide_text_after_double_hash)
text_display_end = ImGui::FindRenderedTextEnd(text, text_end); // Hide anything after a '##' string
else
text_display_end = text_end;
GameOverlay* overlay = SohImGui::overlay;
ImFont* font = overlay->CurrentFont == "Default" ? g.Font : overlay->Fonts[overlay->CurrentFont];
const float font_size = font->FontSize;
if (text == text_display_end)
return ImVec2(0.0f, font_size);
ImVec2 text_size = font->CalcTextSizeA(font_size, FLT_MAX, wrap_width, text, text_display_end, NULL);
// Round
// FIXME: This has been here since Dec 2015 (7b0bf230) but down the line we want this out.
// FIXME: Investigate using ceilf or e.g.
// - https://git.musl-libc.org/cgit/musl/tree/src/math/ceilf.c
// - https://embarkstudios.github.io/rust-gpu/api/src/libm/math/ceilf.rs.html
text_size.x = IM_FLOOR(text_size.x + 0.99999f);
return text_size;
}
void Ship::GameOverlay::Init() {
this->LoadFont("Press Start 2P", "assets/ship_of_harkinian/fonts/PressStart2P-Regular.ttf", 12.0f);
this->LoadFont("Fipps", "assets/ship_of_harkinian/fonts/Fipps-Regular.otf", 32.0f);
const std::string DefaultFont = this->Fonts.begin()->first;
if(!this->Fonts.empty()) {
const std::string font = CVar_GetString("gOverlayFont", ImStrdup(DefaultFont.c_str()));
for (auto& [name, _] : this->Fonts) {
if (font.starts_with(name)) {
this->CurrentFont = name;
break;
}
this->CurrentFont = DefaultFont;
}
}
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<std::string>& 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;
}

View File

@ -0,0 +1,38 @@
#pragma once
#include <string>
#include <vector>
#include "Lib/ImGui/imgui.h"
#include <map>
#include <unordered_map>
enum class OverlayType {
TEXT, IMAGE
};
struct Overlay {
OverlayType type;
const char* value;
};
namespace Ship {
class GameOverlay {
public:
std::unordered_map<std::string, Overlay> RegisteredOverlays;
std::unordered_map<std::string, ImFont*> Fonts;
std::string CurrentFont = "Default";
void Init();
void Draw();
void DrawSettings();
static float GetScreenWidth();
static float GetScreenHeight();
static float GetStringWidth(const char* text);
static ImVec2 CalculateTextSize(const char* text, const char* text_end = NULL, bool hide_text_after_double_hash = false, float wrap_width = -1.0f);
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<std::string>& args);
}

View File

@ -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"
@ -59,8 +60,10 @@ namespace SohImGui {
WindowImpl impl;
ImGuiIO* io;
Console* console = new Console;
GameOverlay* overlay = new GameOverlay;
bool p_open = false;
bool needs_save = false;
std::vector<const char*> CustomTexts;
int SelectedLanguage = CVar_GetS32("gLanguages", 0); //Default Language to 0=English 1=German 2=French
float kokiri_col[3] = { 0.118f, 0.41f, 0.106f };
float goron_col[3] = { 0.392f, 0.078f, 0.0f };
@ -323,10 +326,13 @@ namespace SohImGui {
ImGui::SetCurrentContext(ctx);
io = &ImGui::GetIO();
io->ConfigFlags |= ImGuiConfigFlags_DockingEnable;
io->Fonts->AddFontDefault();
if (UseViewports()) {
io->ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
}
console->Init();
overlay->Init();
ImGuiWMInit();
ImGuiBackendInit();
@ -490,7 +496,7 @@ namespace SohImGui {
}
}
void DrawMainMenuAndCalculateGameSize() {
void DrawMainMenuAndCalculateGameSize() {
console->Update();
ImGuiBackendNewFrame();
ImGuiWMNewFrame();
@ -624,6 +630,7 @@ namespace SohImGui {
}
ImGui::EndCombo();
}
overlay->DrawSettings();
ImGui::EndMenu();
}
@ -800,6 +807,8 @@ namespace SohImGui {
pos = ImVec2(size.x / 2 - sw / 2, 0);
size = ImVec2(sw, size.y);
}
overlay->Draw();
}
void DrawFramebufferAndGameInput() {

View File

@ -1,5 +1,6 @@
#pragma once
#include "GameOverlay.h"
#include "Lib/ImGui/imgui.h"
#include "SohConsole.h"
@ -58,6 +59,8 @@ namespace SohImGui {
} CustomWindow;
extern Console* console;
extern Ship::GameOverlay* overlay;
extern bool needs_save;
void Init(WindowImpl window_impl);
void Update(EventImpl event);

View File

@ -256,6 +256,7 @@
<ClCompile Include="Blob.cpp" />
<ClCompile Include="Cvar.cpp" />
<ClCompile Include="Environment.cpp" />
<ClCompile Include="GameOverlay.cpp" />
<ClCompile Include="GameSettings.cpp" />
<ClCompile Include="Lib\ImGui\backends\imgui_impl_dx11.cpp" />
<ClCompile Include="Lib\ImGui\backends\imgui_impl_win32.cpp" />
@ -343,6 +344,7 @@
<ClInclude Include="Blob.h" />
<ClInclude Include="Cvar.h" />
<ClInclude Include="Environment.h" />
<ClInclude Include="GameOverlay.h" />
<ClInclude Include="GameSettings.h" />
<ClInclude Include="GameVersions.h" />
<ClInclude Include="Lib\ImGui\backends\imgui_impl_dx11.h" />

View File

@ -88,6 +88,9 @@
<Filter Include="Source Files\Logging">
<UniqueIdentifier>{bd6557f1-9480-413b-b0cd-843f8efc1939}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\CustomImpl\Overlay">
<UniqueIdentifier>{3285ab8a-06d8-4dac-9af9-efb2a9723ab1}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Factories\MaterialFactory.cpp">
@ -339,6 +342,9 @@
<ClCompile Include="GameSettings.cpp">
<Filter>Source Files\CustomImpl</Filter>
</ClCompile>
<ClCompile Include="GameOverlay.cpp">
<Filter>Source Files\CustomImpl\Overlay</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Lib\tinyxml2\tinyxml2.h">
@ -629,5 +635,8 @@
<ClInclude Include="GameVersions.h">
<Filter>Source Files\Resources</Filter>
</ClInclude>
<ClInclude Include="GameOverlay.h">
<Filter>Source Files\CustomImpl\Overlay</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -421,6 +421,14 @@ template <typename Numeric> bool is_number(const std::string& s) {
return ((std::istringstream(s) >> n >> std::ws).eof());
}
char* Strdup(const char* src) {
const unsigned len = strlen(src) + 1;
char* newstr = static_cast<char*>(malloc(len));
if (newstr)
memcpy(newstr, src, len);
return newstr;
}
void DebugConsole_LoadCVars()
{
if (File::Exists("cvars.cfg")) {
@ -431,7 +439,9 @@ void DebugConsole_LoadCVars()
if (line.empty()) continue;
if (cfg.size() < 2) continue;
if (cfg[1].find("\"") != std::string::npos) {
CVar_SetString(cfg[0].c_str(), const_cast<char*>(cfg[1].c_str()));
std::string value(cfg[1]);
value.erase(std::ranges::remove(value, '\"').begin(), value.end());
CVar_SetString(cfg[0].c_str(), Strdup(value.c_str()));
}
if (is_number<float>(cfg[1])) {
CVar_SetFloat(cfg[0].c_str(), std::stof(cfg[1]));