feat(renderer): added dynamic font loading based on lang requirements (#2738)

Related YimMenu/Translations#117
Closes #2723

Changes made:
 - Renderer class was changed to a static instance
 - Some throw code was removed because of change of instantiation of the renderer
 - Fonts are dynamically loaded based on the language requirements
 - renderer files have been moved to make the root directory less messy
 - Added a font mgr to improve the ease of adding more language support
This commit is contained in:
Andreas Maerten 2024-02-21 21:26:29 +01:00 committed by GitHub
parent b1caff97fe
commit 1064077b9c
18 changed files with 426 additions and 296 deletions

View File

@ -2,58 +2,58 @@
namespace big
{
bool file_manager::init(const std::filesystem::path& base_dir)
{
m_base_dir = base_dir;
file_manager::ensure_folder_exists(m_base_dir);
bool file_manager::init(const std::filesystem::path& base_dir)
{
m_base_dir = base_dir;
file_manager::ensure_folder_exists(m_base_dir);
return true;
}
return true;
}
const std::filesystem::path& file_manager::get_base_dir()
{
return m_base_dir;
}
const std::filesystem::path& file_manager::get_base_dir()
{
return m_base_dir;
}
file file_manager::get_project_file(std::filesystem::path file_path)
{
if (file_path.is_absolute())
throw std::invalid_argument("Project files are relative to the BaseDir, don't use absolute paths!");
if (file_path.string().contains(".."))
{
if (file_path.is_absolute())
throw std::invalid_argument("Project files are relative to the BaseDir, don't use absolute paths!");
if (file_path.string().contains(".."))
throw std::invalid_argument("Relative path traversal is not allowed, refrain from using \"..\" in file paths.");
return file_manager::ensure_file_can_be_created(m_base_dir / file_path);
}
return file_manager::ensure_file_can_be_created(m_base_dir / file_path);
}
folder file_manager::get_project_folder(std::filesystem::path folder_path)
{
if (folder_path.is_absolute())
throw std::invalid_argument("Project folders are relative to the BaseDir, don't use absolute paths!");
if (folder_path.string().contains(".."))
{
if (folder_path.is_absolute())
throw std::invalid_argument("Project folders are relative to the BaseDir, don't use absolute paths!");
if (folder_path.string().contains(".."))
throw std::invalid_argument("Relative path traversal is not allowed, refrain from using \"..\" in folder paths.");
return file_manager::ensure_folder_exists(m_base_dir / folder_path);
}
return file_manager::ensure_folder_exists(m_base_dir / folder_path);
}
std::filesystem::path file_manager::ensure_file_can_be_created(const std::filesystem::path file_path)
{
file_manager::ensure_folder_exists(file_path.parent_path());
{
file_manager::ensure_folder_exists(file_path.parent_path());
return file_path;
}
return file_path;
}
std::filesystem::path file_manager::ensure_folder_exists(const std::filesystem::path folder_path)
{
bool create_path = !exists(folder_path);
{
bool create_path = !exists(folder_path);
if (!create_path && !is_directory(folder_path))
{
remove(folder_path);
create_path = true;
}
if (create_path)
create_directories(folder_path);
if (!create_path && !is_directory(folder_path))
{
remove(folder_path);
create_path = true;
}
if (create_path)
create_directories(folder_path);
return folder_path;
}
return folder_path;
}
}

View File

@ -2,7 +2,7 @@
#include "common.hpp"
#include "natives.hpp"
#include "renderer.hpp"
#include "renderer/renderer.hpp"
#include "script.hpp"
#include "views/view.hpp"
@ -14,35 +14,35 @@ namespace big
m_is_open(false),
m_override_mouse(false)
{
g_renderer->add_dx_callback(view::gta_data, -1);
g_renderer->add_dx_callback(view::notifications, -2);
g_renderer->add_dx_callback(view::overlay, -3);
g_renderer->add_dx_callback(view::cmd_executor, -4);
g_renderer->add_dx_callback(
g_renderer.add_dx_callback(view::gta_data, -1);
g_renderer.add_dx_callback(view::notifications, -2);
g_renderer.add_dx_callback(view::overlay, -3);
g_renderer.add_dx_callback(view::cmd_executor, -4);
g_renderer.add_dx_callback(
[this] {
dx_on_tick();
},
-5);
g_renderer->add_wndproc_callback([this](HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
g_renderer.add_wndproc_callback([this](HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
wndproc(hwnd, msg, wparam, lparam);
});
g_renderer->add_wndproc_callback([](HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
g_renderer.add_wndproc_callback([](HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
if (g.cmd_executor.enabled && msg == WM_KEYUP && wparam == VK_ESCAPE)
{
g.cmd_executor.enabled = false;
}
});
g_renderer->add_dx_callback(view::vehicle_control, 3);
g_renderer->add_dx_callback(esp::draw, 2); // TODO: move to ESP service
g_renderer->add_dx_callback(view::context_menu, 1);
g_renderer.add_dx_callback(view::vehicle_control, 3);
g_renderer.add_dx_callback(esp::draw, 2); // TODO: move to ESP service
g_renderer.add_dx_callback(view::context_menu, 1);
dx_init();
g_gui = this;
g_renderer->rescale(g.window.gui_scale);
g_renderer.rescale(g.window.gui_scale);
}
gui::~gui()

View File

@ -1,5 +1,5 @@
#include "hooking/hooking.hpp"
#include "renderer.hpp"
#include "renderer/renderer.hpp"
#include "script.hpp"
namespace big
@ -8,9 +8,9 @@ namespace big
{
if (g_running && ((flags & (UINT)DXGI_PRESENT_TEST) != (UINT)DXGI_PRESENT_TEST))
{
g_renderer->on_present();
g_renderer.on_present();
}
return g_hooking->m_swapchain_hook.get_original<decltype(&swapchain_present)>(swapchain_present_index)(this_, sync_interval, flags);
}
}
}

View File

@ -1,5 +1,5 @@
#include "hooking/hooking.hpp"
#include "renderer.hpp"
#include "renderer/renderer.hpp"
#include "script.hpp"
namespace big
@ -8,13 +8,13 @@ namespace big
{
if (g_running)
{
g_renderer->pre_reset();
g_renderer.pre_reset();
const auto result = g_hooking->m_swapchain_hook.get_original<decltype(&swapchain_resizebuffers)>(swapchain_resizebuffers_index)(this_, buffer_count, width, height, new_format, swapchain_flags);
if (SUCCEEDED(result))
{
g_renderer->post_reset();
g_renderer.post_reset();
}
return result;

View File

@ -1,5 +1,5 @@
#include "hooking/hooking.hpp"
#include "renderer.hpp"
#include "renderer/renderer.hpp"
#include "script.hpp"
namespace big
@ -8,7 +8,7 @@ namespace big
{
if (g_running)
{
g_renderer->wndproc(hwnd, msg, wparam, lparam);
g_renderer.wndproc(hwnd, msg, wparam, lparam);
}
return CallWindowProcW(g_hooking->m_og_wndproc, hwnd, msg, wparam, lparam);

View File

@ -10,7 +10,7 @@
#include "native_hooks/native_hooks.hpp"
#include "pointers.hpp"
#include "rage/gameSkeleton.hpp"
#include "renderer.hpp"
#include "renderer/renderer.hpp"
#include "script_mgr.hpp"
#include "services/api/api_service.hpp"
#include "services/context_menu/context_menu_service.hpp"
@ -159,10 +159,10 @@ BOOL APIENTRY DllMain(HMODULE hmod, DWORD reason, PVOID)
LOG(INFO) << "Yim's Menu Initializing";
LOGF(INFO, "Git Info\n\tBranch:\t{}\n\tHash:\t{}\n\tDate:\t{}", version::GIT_BRANCH, version::GIT_SHA1, version::GIT_DATE);
// more tech debt, YAY!
// more tech debt, YAY!
if (is_proton())
{
LOG(INFO) << "Running on proton!";
LOG(INFO) << "Running on proton!";
}
else
{
@ -195,7 +195,7 @@ BOOL APIENTRY DllMain(HMODULE hmod, DWORD reason, PVOID)
auto byte_patch_manager_instance = std::make_unique<byte_patch_manager>();
LOG(INFO) << "Byte Patch Manager initialized.";
auto renderer_instance = std::make_unique<renderer>();
g_renderer.init();
LOG(INFO) << "Renderer initialized.";
auto gui_instance = std::make_unique<gui>();
@ -327,7 +327,7 @@ BOOL APIENTRY DllMain(HMODULE hmod, DWORD reason, PVOID)
fiber_pool_instance.reset();
LOG(INFO) << "Fiber pool uninitialized.";
renderer_instance.reset();
g_renderer.destroy();
LOG(INFO) << "Renderer uninitialized.";
byte_patch_manager_instance.reset();

View File

@ -1,219 +0,0 @@
#include "renderer.hpp"
#include "common.hpp"
#include "file_manager.hpp"
#include "fonts/fonts.hpp"
#include "gui.hpp"
#include "pointers.hpp"
#include <backends/imgui_impl_dx11.h>
#include <backends/imgui_impl_win32.h>
#include <imgui.h>
#include <imgui_internal.h>
IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
namespace big
{
renderer::renderer() :
m_dxgi_swapchain(*g_pointers->m_gta.m_swapchain)
{
if (m_dxgi_swapchain->GetDevice(__uuidof(ID3D11Device), reinterpret_cast<void**>(&m_d3d_device)) < 0)
{
throw std::runtime_error("Failed to get D3D device.");
}
m_d3d_device->GetImmediateContext(&m_d3d_device_context);
auto file_path = g_file_manager.get_project_file("./imgui.ini").get_path();
ImGuiContext* ctx = ImGui::CreateContext();
static std::string path = file_path.make_preferred().string();
ctx->IO.IniFilename = path.c_str();
ImGui_ImplDX11_Init(m_d3d_device, m_d3d_device_context);
ImGui_ImplWin32_Init(g_pointers->m_hwnd);
const auto fonts_folder = std::filesystem::path(std::getenv("SYSTEMROOT")) / "Fonts";
file font_file(fonts_folder / "msyh.ttc");
if (!font_file.exists())
font_file = file(fonts_folder / "msyh.ttf");
if (*g_pointers->m_gta.m_language == 8)
{
font_file = file(fonts_folder / "malgun.ttf");
if (!font_file.exists())
{
LOG(WARNING) << "Korean language detected, but failed to find Korean font, you may not be able to read the menu!";
}
}
if (!font_file.exists())
{
LOG(WARNING) << "Failed to find msyh font, falling back to Arial!";
font_file = file(fonts_folder / "arial.ttf");
}
auto font_file_stream = std::ifstream(font_file.get_path(), std::ios::binary | std::ios::ate);
const auto font_data_size = static_cast<int>(font_file_stream.tellg());
const auto font_data = std::make_unique<uint8_t[]>(font_data_size);
font_file_stream.seekg(0);
font_file_stream.read(reinterpret_cast<char*>(font_data.get()), font_data_size);
font_file_stream.close();
auto& io = ImGui::GetIO();
{
ImFontConfig fnt_cfg{};
fnt_cfg.FontDataOwnedByAtlas = false;
strcpy(fnt_cfg.Name, "Fnt20px");
io.Fonts->AddFontFromMemoryTTF(const_cast<uint8_t*>(font_storopia),
sizeof(font_storopia),
20.f,
&fnt_cfg,
io.Fonts->GetGlyphRangesDefault());
fnt_cfg.MergeMode = true;
if (*g_pointers->m_gta.m_language == 8)
io.Fonts->AddFontFromMemoryTTF(font_data.get(), font_data_size, 20.f, &fnt_cfg, ImGui::GetIO().Fonts->GetGlyphRangesKorean());
else
io.Fonts->AddFontFromMemoryTTF(font_data.get(), font_data_size, 20.f, &fnt_cfg, ImGui::GetIO().Fonts->GetGlyphRangesChineseSimplifiedCommon());
io.Fonts->AddFontFromMemoryTTF(font_data.get(), font_data_size, 20.f, &fnt_cfg, ImGui::GetIO().Fonts->GetGlyphRangesCyrillic());
io.Fonts->Build();
}
{
ImFontConfig fnt_cfg{};
fnt_cfg.FontDataOwnedByAtlas = false;
strcpy(fnt_cfg.Name, "Fnt28px");
g.window.font_title = io.Fonts->AddFontFromMemoryTTF(const_cast<uint8_t*>(font_storopia), sizeof(font_storopia), 28.f, &fnt_cfg);
fnt_cfg.MergeMode = true;
if (*g_pointers->m_gta.m_language == 8)
io.Fonts->AddFontFromMemoryTTF(font_data.get(), font_data_size, 28.f, &fnt_cfg, ImGui::GetIO().Fonts->GetGlyphRangesKorean());
else
io.Fonts->AddFontFromMemoryTTF(font_data.get(), font_data_size, 28.f, &fnt_cfg, ImGui::GetIO().Fonts->GetGlyphRangesChineseSimplifiedCommon());
io.Fonts->AddFontFromMemoryTTF(font_data.get(), font_data_size, 28.f, &fnt_cfg, ImGui::GetIO().Fonts->GetGlyphRangesCyrillic());
io.Fonts->Build();
}
{
ImFontConfig fnt_cfg{};
fnt_cfg.FontDataOwnedByAtlas = false;
strcpy(fnt_cfg.Name, "Fnt24px");
g.window.font_sub_title = io.Fonts->AddFontFromMemoryTTF(const_cast<uint8_t*>(font_storopia), sizeof(font_storopia), 24.f, &fnt_cfg);
fnt_cfg.MergeMode = true;
if (*g_pointers->m_gta.m_language == 8)
io.Fonts->AddFontFromMemoryTTF(font_data.get(), font_data_size, 24.f, &fnt_cfg, ImGui::GetIO().Fonts->GetGlyphRangesKorean());
else
io.Fonts->AddFontFromMemoryTTF(font_data.get(), font_data_size, 24.f, &fnt_cfg, ImGui::GetIO().Fonts->GetGlyphRangesChineseSimplifiedCommon());
io.Fonts->AddFontFromMemoryTTF(font_data.get(), font_data_size, 24.f, &fnt_cfg, ImGui::GetIO().Fonts->GetGlyphRangesCyrillic());
io.Fonts->Build();
}
{
ImFontConfig fnt_cfg{};
fnt_cfg.FontDataOwnedByAtlas = false;
strcpy(fnt_cfg.Name, "Fnt18px");
g.window.font_small = io.Fonts->AddFontFromMemoryTTF(const_cast<uint8_t*>(font_storopia), sizeof(font_storopia), 18.f, &fnt_cfg);
fnt_cfg.MergeMode = true;
if (*g_pointers->m_gta.m_language == 8)
io.Fonts->AddFontFromMemoryTTF(font_data.get(), font_data_size, 18.f, &fnt_cfg, ImGui::GetIO().Fonts->GetGlyphRangesKorean());
else
io.Fonts->AddFontFromMemoryTTF(font_data.get(), font_data_size, 18.f, &fnt_cfg, ImGui::GetIO().Fonts->GetGlyphRangesChineseSimplifiedCommon());
io.Fonts->AddFontFromMemoryTTF(font_data.get(), font_data_size, 18.f, &fnt_cfg, ImGui::GetIO().Fonts->GetGlyphRangesCyrillic());
io.Fonts->Build();
}
{
ImFontConfig font_icons_cfg{};
font_icons_cfg.FontDataOwnedByAtlas = false;
std::strcpy(font_icons_cfg.Name, "Icons");
g.window.font_icon = io.Fonts->AddFontFromMemoryTTF(const_cast<uint8_t*>(font_icons), sizeof(font_icons), 24.f, &font_icons_cfg);
}
g_renderer = this;
}
renderer::~renderer()
{
g_renderer = nullptr;
ImGui_ImplWin32_Shutdown();
ImGui_ImplDX11_Shutdown();
ImGui::DestroyContext();
}
bool renderer::add_dx_callback(dx_callback callback, uint32_t priority)
{
if (!m_dx_callbacks.insert({priority, callback}).second)
{
LOG(WARNING) << "Duplicate priority given on DX Callback!";
return false;
}
return true;
}
void renderer::add_wndproc_callback(wndproc_callback callback)
{
m_wndproc_callbacks.emplace_back(callback);
}
void renderer::on_present()
{
new_frame();
for (const auto& cb : m_dx_callbacks | std::views::values)
cb();
end_frame();
}
void renderer::rescale(float rel_size)
{
pre_reset();
g_gui->restore_default_style();
if (rel_size != 1.0f)
ImGui::GetStyle().ScaleAllSizes(rel_size);
ImGui::GetStyle().MouseCursorScale = 1.0f;
ImGui::GetIO().FontGlobalScale = rel_size;
post_reset();
}
void renderer::pre_reset()
{
ImGui_ImplDX11_InvalidateDeviceObjects();
}
void renderer::post_reset()
{
ImGui_ImplDX11_CreateDeviceObjects();
}
void renderer::wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
for (const auto& cb : m_wndproc_callbacks)
cb(hwnd, msg, wparam, lparam);
ImGui_ImplWin32_WndProcHandler(hwnd, msg, wparam, lparam);
}
void renderer::new_frame()
{
ImGui_ImplDX11_NewFrame();
ImGui_ImplWin32_NewFrame();
ImGui::NewFrame();
}
void renderer::end_frame()
{
ImGui::Render();
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
}
}

View File

@ -0,0 +1,15 @@
#pragma once
namespace big
{
enum class eAlphabetType
{
LATIN, // default - always built
CHINESE,
CYRILLIC,
KOREAN,
JAPANESE,
LAST_ALPHABET_TYPE
};
NLOHMANN_JSON_SERIALIZE_ENUM(eAlphabetType, {{eAlphabetType::LATIN, "latin"}, {eAlphabetType::CHINESE, "chinese"}, {eAlphabetType::CYRILLIC, "cyrillic"}, {eAlphabetType::KOREAN, "korean"}, {eAlphabetType::JAPANESE, "japanese"}})
}

141
src/renderer/font_mgr.cpp Normal file
View File

@ -0,0 +1,141 @@
#include "font_mgr.hpp"
#include "fonts/fonts.hpp"
#include "renderer.hpp"
#include "thread_pool.hpp"
namespace big
{
font_mgr::font_mgr(std::vector<std::pair<float, ImFont**>> extra_font_sizes) :
m_extra_font_sizes(extra_font_sizes),
m_require_extra(eAlphabetType::LATIN),
m_fonts({
{eAlphabetType::CHINESE, {"msyh.ttc", "msyh.ttf", "arial.ttf"}},
{eAlphabetType::CYRILLIC, {"msyh.ttc", "msyh.ttf", "arial.ttf"}},
{eAlphabetType::JAPANESE, {"msyh.ttc", "msyh.ttf", "arial.ttf"}},
{eAlphabetType::KOREAN, {"malgun.ttf", "arial.ttf"}},
})
{
}
bool font_mgr::can_use()
{
return m_update_lock.try_lock();
}
void font_mgr::release_use()
{
m_update_lock.unlock();
}
void font_mgr::rebuild()
{
m_update_lock.lock();
g_renderer.pre_reset();
const auto extra_font_file = get_available_font_file_for_alphabet_type();
if (m_require_extra != eAlphabetType::LATIN && !extra_font_file.exists())
{
LOG(WARNING) << "Could not find an appropriate font for the current language!";
}
const auto extra_glyph_range = get_imgui_alphabet_type();
auto& io = ImGui::GetIO();
io.Fonts->Clear();
// default font size
{
ImFontConfig fnt_cfg{};
fnt_cfg.FontDataOwnedByAtlas = false;
strcpy(fnt_cfg.Name, "Fnt20px");
io.Fonts->AddFontFromMemoryTTF(const_cast<uint8_t*>(font_storopia),
sizeof(font_storopia),
20.f,
&fnt_cfg,
io.Fonts->GetGlyphRangesDefault());
if (m_require_extra != eAlphabetType::LATIN && extra_font_file.exists())
{
fnt_cfg.MergeMode = true;
io.Fonts->AddFontFromFileTTF(extra_font_file.get_path().string().c_str(), 20.f, &fnt_cfg, extra_glyph_range);
}
io.Fonts->Build();
}
// any other font sizes we need to support
for (auto [size, font_ptr] : m_extra_font_sizes)
{
ImFontConfig fnt_cfg{};
fnt_cfg.FontDataOwnedByAtlas = false;
strcpy(fnt_cfg.Name, std::format("Fnt{}px", (int)size).c_str());
*font_ptr = io.Fonts->AddFontFromMemoryTTF(const_cast<uint8_t*>(font_storopia),
sizeof(font_storopia),
size,
&fnt_cfg,
io.Fonts->GetGlyphRangesDefault());
if (m_require_extra != eAlphabetType::LATIN && extra_font_file.exists())
{
fnt_cfg.MergeMode = true;
io.Fonts->AddFontFromFileTTF(extra_font_file.get_path().string().c_str(), size, &fnt_cfg, extra_glyph_range);
}
io.Fonts->Build();
}
// icons blueh
{
ImFontConfig font_icons_cfg{};
font_icons_cfg.FontDataOwnedByAtlas = false;
std::strcpy(font_icons_cfg.Name, "Icons");
g.window.font_icon = ImGui::GetIO().Fonts->AddFontFromMemoryTTF(const_cast<uint8_t*>(font_icons), sizeof(font_icons), 24.f, &font_icons_cfg);
}
g_renderer.post_reset();
m_update_lock.unlock();
}
void font_mgr::update_required_alphabet_type(eAlphabetType type)
{
m_require_extra = type;
g_thread_pool->push([this]
{
rebuild();
});
}
file font_mgr::get_available_font_file_for_alphabet_type()
{
static const auto fonts_folder = std::filesystem::path(std::getenv("SYSTEMROOT")) / "Fonts";
const auto& fonts = m_fonts.find(m_require_extra);
if (fonts == m_fonts.end())
return {};
for (const auto& font : fonts->second)
{
auto font_file = file(fonts_folder / font);
if (font_file.exists())
{
return font_file;
}
}
return {};
}
const ImWchar* font_mgr::get_imgui_alphabet_type()
{
auto& io = ImGui::GetIO();
switch (m_require_extra)
{
case eAlphabetType::CHINESE: return io.Fonts->GetGlyphRangesChineseFull();
case eAlphabetType::CYRILLIC: return io.Fonts->GetGlyphRangesCyrillic();
case eAlphabetType::JAPANESE: return io.Fonts->GetGlyphRangesJapanese();
case eAlphabetType::KOREAN: return io.Fonts->GetGlyphRangesKorean();
default:
case eAlphabetType::LATIN: return io.Fonts->GetGlyphRangesDefault();
}
}
}

39
src/renderer/font_mgr.hpp Normal file
View File

@ -0,0 +1,39 @@
#pragma once
#include "alphabet_types.hpp"
namespace big
{
class font_mgr final
{
private:
const std::vector<std::pair<float, ImFont**>> m_extra_font_sizes;
// each alphabet type should have a couple of fallback fonts
const std::unordered_map<eAlphabetType, std::vector<std::string>> m_fonts;
// extra alphabet types that may be required to be added to the atlas
eAlphabetType m_require_extra;
// prevent crashes when doing thread unsafe actions
std::mutex m_update_lock;
public:
font_mgr(std::vector<std::pair<float, ImFont**>> extra_font_sizes = {{28.f, &g.window.font_title},
{24.f, &g.window.font_sub_title},
{18.f, &g.window.font_small}});
virtual ~font_mgr() = default;
bool can_use();
void release_use();
/**
* @brief Updates the required underlying glyph ranges to be loaded into the font atlas. Fonts will be updated on the next frame.
*
* @param type
*/
void update_required_alphabet_type(eAlphabetType type);
private:
void rebuild();
file get_available_font_file_for_alphabet_type();
const ImWchar* get_imgui_alphabet_type();
};
}

133
src/renderer/renderer.cpp Normal file
View File

@ -0,0 +1,133 @@
#include "renderer.hpp"
#include "file_manager.hpp"
#include "fonts/fonts.hpp"
#include "gui.hpp"
#include "pointers.hpp"
#include <backends/imgui_impl_dx11.h>
#include <backends/imgui_impl_win32.h>
#include <imgui.h>
#include <imgui_internal.h>
IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
namespace big
{
renderer::renderer() :
m_font_mgr()
{
}
bool renderer::init()
{
if (!g_pointers->m_gta.m_swapchain || !*g_pointers->m_gta.m_swapchain)
{
LOG(FATAL) << "Invalid swapchain ptr";
return false;
}
m_dxgi_swapchain = *g_pointers->m_gta.m_swapchain;
if (m_dxgi_swapchain->GetDevice(__uuidof(ID3D11Device), reinterpret_cast<void**>(&m_d3d_device)) < 0)
{
LOG(FATAL) << "Failed to get D3D device.";
return false;
}
m_d3d_device->GetImmediateContext(&m_d3d_device_context);
auto file_path = g_file_manager.get_project_file("./imgui.ini").get_path();
ImGuiContext* ctx = ImGui::CreateContext();
static std::string path = file_path.make_preferred().string();
ctx->IO.IniFilename = path.c_str();
ImGui_ImplDX11_Init(m_d3d_device, m_d3d_device_context);
ImGui_ImplWin32_Init(g_pointers->m_hwnd);
return true;
}
void renderer::destroy()
{
ImGui_ImplWin32_Shutdown();
ImGui_ImplDX11_Shutdown();
ImGui::DestroyContext();
}
bool renderer::add_dx_callback(dx_callback callback, uint32_t priority)
{
if (!m_dx_callbacks.insert({priority, callback}).second)
{
LOG(WARNING) << "Duplicate priority given on DX Callback!";
return false;
}
return true;
}
void renderer::add_wndproc_callback(wndproc_callback callback)
{
m_wndproc_callbacks.emplace_back(callback);
}
void renderer::on_present()
{
if (m_font_mgr.can_use())
{
new_frame();
for (const auto& cb : m_dx_callbacks | std::views::values)
cb();
end_frame();
m_font_mgr.release_use();
}
}
void renderer::rescale(float rel_size)
{
pre_reset();
g_gui->restore_default_style();
if (rel_size != 1.0f)
ImGui::GetStyle().ScaleAllSizes(rel_size);
ImGui::GetStyle().MouseCursorScale = 1.0f;
ImGui::GetIO().FontGlobalScale = rel_size;
post_reset();
}
void renderer::pre_reset()
{
ImGui_ImplDX11_InvalidateDeviceObjects();
}
void renderer::post_reset()
{
ImGui_ImplDX11_CreateDeviceObjects();
}
void renderer::wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
for (const auto& cb : m_wndproc_callbacks)
cb(hwnd, msg, wparam, lparam);
ImGui_ImplWin32_WndProcHandler(hwnd, msg, wparam, lparam);
}
void renderer::new_frame()
{
ImGui_ImplDX11_NewFrame();
ImGui_ImplWin32_NewFrame();
ImGui::NewFrame();
}
void renderer::end_frame()
{
ImGui::Render();
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
}
}

View File

@ -1,5 +1,6 @@
#pragma once
#include "common.hpp"
#include "font_mgr.hpp"
namespace big
{
@ -10,7 +11,15 @@ namespace big
{
public:
explicit renderer();
~renderer();
~renderer() = default;
font_mgr& get_font_mgr()
{
return m_font_mgr;
}
bool init();
void destroy();
/**
* @brief Add a callback function to draw your ImGui content in
@ -48,7 +57,9 @@ namespace big
std::map<uint32_t, dx_callback> m_dx_callbacks;
std::vector<wndproc_callback> m_wndproc_callbacks;
font_mgr m_font_mgr;
};
inline renderer* g_renderer{};
inline auto g_renderer = renderer();
}

View File

@ -4,7 +4,7 @@
#include "gui.hpp"
#include "network/ChatData.hpp"
#include "pointers.hpp"
#include "renderer.hpp"
#include "renderer/renderer.hpp"
#include "util/teleport.hpp"
namespace big
@ -37,7 +37,7 @@ namespace big
register_hotkey("waypoint", g.settings.hotkeys.teleport_waypoint, RAGE_JOAAT("waypointtp"));
register_hotkey("highlighttp", g.settings.hotkeys.teleport_selected, RAGE_JOAAT("highlighttp"));
g_renderer->add_wndproc_callback([this](HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
g_renderer.add_wndproc_callback([this](HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
wndproc(static_cast<eKeyState>(msg), wparam);
});
@ -115,4 +115,4 @@ namespace big
}
}
}
}
}

View File

@ -1,4 +1,5 @@
#pragma once
#include "renderer/alphabet_types.hpp"
#include "translation_entry.hpp"
namespace big
@ -7,12 +8,13 @@ namespace big
{
public:
int version = -1;
eAlphabetType alphabet_type = eAlphabetType::LATIN;
std::string selected_language;
std::string fallback_default_language;
std::map<std::string, translation_entry> fallback_languages;
bool default_language_set = false;
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(local_index, version, selected_language, fallback_default_language, fallback_languages, default_language_set)
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(local_index, version, alphabet_type, selected_language, fallback_default_language, fallback_languages, default_language_set)
};
}
}

View File

@ -12,4 +12,4 @@ namespace big
NLOHMANN_DEFINE_TYPE_INTRUSIVE(remote_index, version, default_lang, translations)
};
}
}

View File

@ -1,13 +1,16 @@
#pragma once
#include "renderer/alphabet_types.hpp"
namespace big
{
class translation_entry
{
public:
// default to latin as most languages make use of it
eAlphabetType alphabet_type = eAlphabetType::LATIN;
std::string name;
std::string file;
NLOHMANN_DEFINE_TYPE_INTRUSIVE(translation_entry, name, file)
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(translation_entry, alphabet_type, name, file)
};
}
}

View File

@ -4,6 +4,7 @@
#include "file_manager.hpp"
#include "http_client/http_client.hpp"
#include "pointers.hpp"
#include "renderer/renderer.hpp"
#include "thread_pool.hpp"
namespace big
@ -140,6 +141,10 @@ namespace big
}
}
// local index is saved below so this is prime location to update a value and be sure to have it persisted!
m_local_index.alphabet_type = m_remote_index.translations[m_local_index.selected_language].alphabet_type;
g_renderer.get_font_mgr().update_required_alphabet_type(m_local_index.alphabet_type);
save_local_index();
}

View File

@ -1,5 +1,5 @@
#include "gui.hpp"
#include "renderer.hpp"
#include "renderer/renderer.hpp"
#include "views/view.hpp"
namespace big
@ -8,7 +8,7 @@ namespace big
{
components::sub_title("SETTINGS_UI_SCALE"_T);
if (ImGui::SliderFloat("##gui-scale", &g.window.gui_scale, 0.75f, 1.5f, "%.2f"))
g_renderer->rescale(g.window.gui_scale);
g_renderer.rescale(g.window.gui_scale);
components::sub_title("SETTINGS_UI_COLOR"_T);
static ImVec4 col_gui = ImGui::ColorConvertU32ToFloat4(g.window.background_color);
@ -86,4 +86,4 @@ namespace big
}
}
}
}