refactor: enhance menu visuals with MicaBlur support and improved font handling

This commit is contained in:
EricPlayZ
2026-04-07 23:02:09 +03:00
parent 1a86cab144
commit f8c0b80e10
35 changed files with 2277 additions and 304 deletions
+4 -1
View File
@@ -1,4 +1,7 @@
_IDAScripts/.env
# Full Font Awesome TTF (optional local download for regenerating subset; embed is in repo)
EGameTools/deps/fonts/fa-solid-900.ttf
_IDAScripts/.env
_IDAScripts/generated/*.json
# Ultimate-ASI-Loader
+4 -2
View File
@@ -30,6 +30,7 @@
<ClCompile Include="src\GamePH\GamePH_Hooks.cpp" />
<ClCompile Include="src\ImGui_impl\D3D11_impl.cpp" />
<ClCompile Include="src\ImGui_impl\D3D12_impl.cpp" />
<ClCompile Include="src\ImGui_impl\D3D12_MicaBlur.cpp" />
<ClCompile Include="src\ImGui_impl\DeferredActions.cpp" />
<ClCompile Include="src\ImGui_impl\NextFrameTask.cpp" />
<ClCompile Include="src\ImGui_impl\Win32_impl.cpp" />
@@ -63,6 +64,7 @@
<ClInclude Include="include\EGT\Menu\Debug.h" />
<ClInclude Include="include\EGT\Menu\Init.h" />
<ClInclude Include="include\EGT\Menu\Menu.h" />
<ClInclude Include="include\EGT\Menu\MenuIcons.h" />
<ClInclude Include="include\EGT\Menu\Misc.h" />
<ClInclude Include="include\EGT\Menu\Player.h" />
<ClInclude Include="include\EGT\Menu\Teleport.h" />
@@ -152,7 +154,7 @@
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>DebugFastLink</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<AdditionalDependencies>DbgHelp.lib;Version.lib;EGameSDK.lib;libMinHook-x64-v141-mdd.lib;engine_x64_rwdi.lib;freetype-mdd.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>DbgHelp.lib;Version.lib;EGameSDK.lib;libMinHook-x64-v141-mdd.lib;engine_x64_rwdi.lib;freetype-mdd.lib;d3d12.lib;d3dcompiler.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OptimizeReferences>
</OptimizeReferences>
<EnableCOMDATFolding>
@@ -193,7 +195,7 @@
<GenerateDebugInformation>DebugFull</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<AdditionalLibraryDirectories>..\EGameSDK\deps\MinHook\lib;deps\freetype\lib;..\EGameSDK\deps\game_libs;$(SolutionDir)$(Platform)\$(Configuration)\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>DbgHelp.lib;Version.lib;EGameSDK.lib;libMinHook-x64-v141-mdd.lib;engine_x64_rwdi.lib;freetype-md.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>DbgHelp.lib;Version.lib;EGameSDK.lib;libMinHook-x64-v141-mdd.lib;engine_x64_rwdi.lib;freetype-md.lib;d3d12.lib;d3dcompiler.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
<ImportLibrary />
<AdditionalOptions>/NOIMPLIB /NOEXP %(AdditionalOptions)</AdditionalOptions>
<AssemblyDebug>true</AssemblyDebug>
+9
View File
@@ -120,6 +120,9 @@
<ClCompile Include="src\ImGui_impl\D3D12_impl.cpp">
<Filter>src\ImGui_impl</Filter>
</ClCompile>
<ClCompile Include="src\ImGui_impl\D3D12_MicaBlur.cpp">
<Filter>src\ImGui_impl</Filter>
</ClCompile>
<ClCompile Include="src\ImGui_impl\Win32_impl.cpp">
<Filter>src\ImGui_impl</Filter>
</ClCompile>
@@ -182,6 +185,9 @@
<ClInclude Include="include\EGT\ImGui_impl\D3D12_impl.h">
<Filter>include\ImGui_impl</Filter>
</ClInclude>
<ClInclude Include="include\EGT\ImGui_impl\D3D12_MicaBlur.h">
<Filter>include\ImGui_impl</Filter>
</ClInclude>
<ClInclude Include="include\EGT\ImGui_impl\Win32_impl.h">
<Filter>include\ImGui_impl</Filter>
</ClInclude>
@@ -194,6 +200,9 @@
<ClInclude Include="include\EGT\Menu\Menu.h">
<Filter>include\Menu</Filter>
</ClInclude>
<ClInclude Include="include\EGT\Menu\MenuIcons.h">
<Filter>include\Menu</Filter>
</ClInclude>
<ClInclude Include="include\EGT\Menu\Misc.h">
<Filter>include\Menu</Filter>
</ClInclude>
@@ -17,6 +17,7 @@ UseTPPModel=1
FirstTimeRunning=1
HasSeenChangelog=0
Opacity=99
MicaBlurStrength=92
Scale=1
[Menu:Keybinds]
AllowGrappleHookInSafezoneToggleKey=VK_NONE
+12 -2
View File
@@ -2,6 +2,7 @@
#include <ranges>
#include <ImGui\imgui_hotkey.h>
#include <ImGui\imgui_internal.h>
#include <ImGui\imguiex.h>
#include <EGSDK\Utils\Time.h>
#include <EGSDK\Utils\Values.h>
#include <EGSDK\Core\Core.h>
@@ -496,9 +497,18 @@ namespace ImGui {
}
SameLine(0.0f);
const auto hotkeyBtnWidth = [&](const char* txt) -> float {
if (window->SkipItems)
return 0.0f;
const float avail = GetContentRegionAvail().x;
const ImVec2 ts = CalcTextSize(txt, nullptr, true);
const float want = ts.x + g.Style.FramePadding.x * 2.0f;
return (avail > 1.0f) ? ImMin(want, avail) : want;
};
if (GetActiveID() == id) {
PushStyleColor(ImGuiCol_Button, GetColorU32(ImGuiCol_ButtonActive));
Button("...", ImVec2(0.0f, 0.0f));
Button("...", ImVec2(hotkeyBtnWidth("..."), 0.0f));
PopStyleColor();
GetCurrentContext()->ActiveIdAllowOverlap = true;
@@ -508,7 +518,7 @@ namespace ImGui {
ClearActiveID();
} else
SetActiveID(id, GetCurrentWindow());
} else if (Button(key->ToStringKeyMap().data(), ImVec2(0.0f, 0.0f))) {
} else if (ButtonSmooth(key->ToStringKeyMap().data(), ImVec2(hotkeyBtnWidth(key->ToStringKeyMap().data()), 0.0f))) {
isAnyHotkeyBtnClicked = true;
SetActiveID(id, GetCurrentWindow());
}
+3 -2
View File
@@ -6641,10 +6641,11 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
if (hovered || selected)
{
const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
RenderFrame(bb.Min, bb.Max, col, false, 0.0f);
const float rounding = ImMin(style.FrameRounding, bb.GetHeight() * 0.5f);
RenderFrame(bb.Min, bb.Max, col, false, rounding);
}
if (g.NavId == id)
RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_Compact | ImGuiNavHighlightFlags_NoRounding);
RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_Compact);
if (span_all_columns)
{
+274 -28
View File
@@ -1,3 +1,6 @@
#include <cmath>
#include <cstdarg>
#include <unordered_map>
#include <ImGui\imgui_hotkey.h>
#include <ImGui\imgui_internal.h>
#include <EGSDK\GamePH\GamePH_Misc.h>
@@ -5,6 +8,124 @@ namespace ImGui {
static ImGuiStyle defImGuiStyle{};
static size_t tabIndex = 1;
/// Defined below; used by helpers in the anonymous namespace before this TU's definition line.
void SetItemTooltipAnimated(const char* fmt, ...);
/// Check path matches `RenderCheckMark`; `t` in [0,1] is distance along the stroke (draw + uncheck retract).
/// Single `PathStroke` so the bend gets a proper join (avoids gaps from two `AddLine` calls).
static void RenderCheckMarkProgress(ImDrawList* draw_list, ImVec2 pos, ImU32 col, float sz, float t) {
t = ImClamp(t, 0.0f, 1.0f);
if (t <= 0.0f)
return;
const float thickness = ImMax(sz / 5.0f, 1.0f);
const float inner = sz - thickness * 0.5f;
pos += ImVec2(thickness * 0.25f, thickness * 0.25f);
const float third = inner / 3.0f;
const float bx = pos.x + third;
const float by = pos.y + inner - third * 0.5f;
const ImVec2 p0(bx - third, by - third);
const ImVec2 p1(bx, by);
const ImVec2 p2(bx + third * 2.0f, by - third * 2.0f);
float dx = p1.x - p0.x, dy = p1.y - p0.y;
const float d01 = ImSqrt(dx * dx + dy * dy);
dx = p2.x - p1.x;
dy = p2.y - p1.y;
const float d12 = ImSqrt(dx * dx + dy * dy);
const float total = d01 + d12;
if (total < 1.0f)
return;
const float dist = t * total;
draw_list->PathClear();
draw_list->PathLineTo(p0);
if (dist <= d01 + 1e-5f) {
const float u = ImClamp(dist / d01, 0.0f, 1.0f);
draw_list->PathLineTo(ImVec2(p0.x + (p1.x - p0.x) * u, p0.y + (p1.y - p0.y) * u));
} else {
draw_list->PathLineTo(p1);
const float u = ImClamp((dist - d01) / d12, 0.0f, 1.0f);
draw_list->PathLineTo(ImVec2(p1.x + (p2.x - p1.x) * u, p1.y + (p2.y - p1.y) * u));
}
draw_list->PathStroke(col, 0, thickness);
}
/// Visible label (before ##) on the left; call before SameLine control. Optional tooltip on the label.
static void InlineFormLabel(const char* label, const char* tooltip) {
ImGuiWindow* window = GetCurrentWindow();
if (!window || window->SkipItems)
return;
const char* label_end = FindRenderedTextEnd(label);
if (label_end <= label)
return;
AlignTextToFramePadding();
TextUnformatted(label, label_end);
if (tooltip && *tooltip)
SetItemTooltipAnimated("%s", tooltip);
SameLine(0.0f, GetStyle().ItemInnerSpacing.x);
}
static void SetNextItemWidthRemainder() {
const float w = GetContentRegionAvail().x;
SetNextItemWidth(w > 1.0f ? w : -1.0f);
}
bool SliderFloatStacked(const char* label, float* v, float v_min, float v_max, const char* format, ImGuiSliderFlags flags, const char* tooltip) {
PushID(label);
InlineFormLabel(label, tooltip);
SetNextItemWidthRemainder();
const bool ch = SliderFloat("##stk", v, v_min, v_max, format, flags);
if (FindRenderedTextEnd(label) <= label && tooltip && *tooltip)
SetItemTooltipAnimated("%s", tooltip);
PopID();
return ch;
}
bool SliderFloat3Stacked(const char* label, float v[3], float v_min, float v_max, const char* format, ImGuiSliderFlags flags) {
PushID(label);
InlineFormLabel(label, nullptr);
SetNextItemWidthRemainder();
const bool ch = SliderFloat3("##sf3", v, v_min, v_max, format, flags);
PopID();
return ch;
}
bool SliderIntStacked(const char* label, int* v, int v_min, int v_max, const char* format, ImGuiSliderFlags flags, const char* tooltip) {
PushID(label);
InlineFormLabel(label, tooltip);
SetNextItemWidthRemainder();
const bool ch = SliderInt("##stk", v, v_min, v_max, format, flags);
if (FindRenderedTextEnd(label) <= label && tooltip && *tooltip)
SetItemTooltipAnimated("%s", tooltip);
PopID();
return ch;
}
bool DragIntStacked(const char* label, int* v, float v_speed, int v_min, int v_max, const char* format, ImGuiSliderFlags flags) {
PushID(label);
InlineFormLabel(label, nullptr);
SetNextItemWidthRemainder();
const bool ch = DragInt("##dstk", v, v_speed, v_min, v_max, format, flags);
PopID();
return ch;
}
bool ComboStacked(const char* label, int* current_item, const char* const items[], int items_count, int popup_max_height_in_items) {
PushID(label);
InlineFormLabel(label, nullptr);
SetNextItemWidthRemainder();
const bool ch = Combo("##cb", current_item, items, items_count, popup_max_height_in_items);
PopID();
return ch;
}
bool InputFloat3Stacked(const char* label, float v[3], const char* format, ImGuiInputTextFlags flags) {
PushID(label);
InlineFormLabel(label, nullptr);
SetNextItemWidthRemainder();
const bool ch = InputFloat3("##if3", v, format, flags);
PopID();
return ch;
}
static void FormatString(char* buffer, size_t bufferSize, const char* fmt, va_list args) {
vsnprintf(buffer, bufferSize, fmt, args);
}
@@ -50,24 +171,137 @@ namespace ImGui {
EndTabBar();
tabIndex = 1;
}
void SetItemTooltipAnimated(const char* fmt, ...) {
ImGuiContext& imguiContext = *GImGui;
if (!IsItemHovered(ImGuiHoveredFlags_ForTooltip))
return;
const float delay = imguiContext.Style.HoverDelayShort + imguiContext.Style.HoverStationaryDelay * 0.35f;
float fade = ImClamp((imguiContext.HoveredIdTimer - delay) / 0.1f, 0.0f, 1.0f);
fade = fade * fade * (3.0f - 2.0f * fade);
if (fade < 0.02f)
return;
va_list args;
va_start(args, fmt);
BeginTooltip();
PushStyleVar(ImGuiStyleVar_Alpha, GetStyle().Alpha * fade);
TextV(fmt, args);
PopStyleVar();
EndTooltip();
va_end(args);
}
bool ButtonSmooth(const char* label, const ImVec2& size_arg) {
ImGuiContext& imguiContext = *GImGui;
PushID(label);
const ImGuiID smoothId = GetID("##smb");
const int slot = static_cast<int>(smoothId & 127);
static float buttonBlendBySlot[128]{};
static bool buttonWasHoveredBySlot[128]{};
static bool buttonWasHeldBySlot[128]{};
const float dt = ImMin(imguiContext.IO.DeltaTime, 0.08f);
const float smoothingStep = 1.0f - std::exp(-22.0f * dt);
const bool wasHot = buttonWasHoveredBySlot[slot] || buttonWasHeldBySlot[slot];
const float target = wasHot ? 1.0f : 0.0f;
float& buttonBlend = buttonBlendBySlot[slot];
buttonBlend += (target - buttonBlend) * smoothingStep;
const ImVec4 b = GetStyleColorVec4(ImGuiCol_Button);
const ImVec4 h = GetStyleColorVec4(ImGuiCol_ButtonHovered);
const ImVec4 a = GetStyleColorVec4(ImGuiCol_ButtonActive);
const ImVec4 mid(ImLerp(b.x, h.x, buttonBlend), ImLerp(b.y, h.y, buttonBlend), ImLerp(b.z, h.z, buttonBlend), ImLerp(b.w, h.w, buttonBlend));
PushStyleColor(ImGuiCol_Button, mid);
PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(ImLerp(mid.x, a.x, buttonBlend * 0.4f), ImLerp(mid.y, a.y, buttonBlend * 0.4f), ImLerp(mid.z, a.z, buttonBlend * 0.4f), ImLerp(mid.w, a.w, buttonBlend * 0.4f)));
PushStyleColor(ImGuiCol_ButtonActive, a);
const bool pressed = Button(label, size_arg);
PopStyleColor(3);
PopID();
buttonWasHoveredBySlot[slot] = IsItemHovered();
buttonWasHeldBySlot[slot] = IsItemActive();
return pressed;
}
bool Button(const char* label, const char* tooltip, const ImVec2& size) {
bool btn = Button(label, size);
bool btn = ButtonSmooth(label, size);
if (tooltip)
SetItemTooltip(tooltip);
SetItemTooltipAnimated("%s", tooltip);
return btn;
}
bool ButtonHotkey(const char* label, KeyBindOption* v, const char* tooltip, const ImVec2& size) {
bool btn = Button(label, size);
bool btn = ButtonSmooth(label, size);
if (tooltip)
SetItemTooltip(tooltip);
SetItemTooltipAnimated("%s", tooltip);
Hotkey(std::string(label + std::string("##ToggleKey")), v);
return btn;
}
bool Checkbox(const char* label, bool* v, const char* tooltip) {
bool checkbox = Checkbox(label, v);
SetItemTooltip(tooltip);
if (tooltip && *tooltip)
SetItemTooltipAnimated("%s", tooltip);
return checkbox;
}
static ImVec4 BuildCheckboxFrameColor(ImGuiID id, bool hovered, bool held, ImGuiContext& imguiContext) {
static std::unordered_map<ImGuiID, float> checkboxFrameBlendById;
static std::unordered_map<ImGuiID, unsigned int> checkboxFrameLastDrawFrameById;
const unsigned int frameCount = static_cast<unsigned int>(imguiContext.FrameCount);
const auto lastFrameIt = checkboxFrameLastDrawFrameById.find(id);
const bool wasDrawnLastFrame = (lastFrameIt != checkboxFrameLastDrawFrameById.end() && lastFrameIt->second + 1u == frameCount);
checkboxFrameLastDrawFrameById[id] = frameCount;
const float deltaSeconds = ImMin(imguiContext.IO.DeltaTime, 0.08f);
const float frameSmoothingStep = 1.0f - std::exp(-20.0f * deltaSeconds);
const float targetBlend = (held && hovered) ? 1.0f : (hovered ? 0.68f : 0.0f);
float& frameBlend = checkboxFrameBlendById[id];
if (!wasDrawnLastFrame)
frameBlend = targetBlend;
else
frameBlend += (targetBlend - frameBlend) * frameSmoothingStep;
const ImVec4 frameBase = GetStyleColorVec4(ImGuiCol_FrameBg);
const ImVec4 frameHover = GetStyleColorVec4(ImGuiCol_FrameBgHovered);
const ImVec4 frameActive = GetStyleColorVec4(ImGuiCol_FrameBgActive);
ImVec4 frameColor = ImVec4(
ImLerp(frameBase.x, frameHover.x, frameBlend),
ImLerp(frameBase.y, frameHover.y, frameBlend),
ImLerp(frameBase.z, frameHover.z, frameBlend),
ImLerp(frameBase.w, frameHover.w, frameBlend));
if (held && hovered) {
frameColor = ImVec4(
ImLerp(frameColor.x, frameActive.x, 0.85f),
ImLerp(frameColor.y, frameActive.y, 0.85f),
ImLerp(frameColor.z, frameActive.z, 0.85f),
ImLerp(frameColor.w, frameActive.w, 0.85f));
}
return frameColor;
}
static void DrawCheckboxMarkAnimated(ImGuiWindow* window, const ImRect& checkboxRect, ImGuiID id, bool isChecked, ImGuiContext& imguiContext) {
const ImU32 checkColor = GetColorU32(ImGuiCol_CheckMark);
static std::unordered_map<ImGuiID, float> checkmarkStrokeBlendById;
static std::unordered_map<ImGuiID, unsigned int> checkmarkStrokeLastDrawFrameById;
const unsigned int frameCount = static_cast<unsigned int>(imguiContext.FrameCount);
const auto lastFrameIt = checkmarkStrokeLastDrawFrameById.find(id);
const bool wasDrawnLastFrame = (lastFrameIt != checkmarkStrokeLastDrawFrameById.end() && lastFrameIt->second + 1u == frameCount);
checkmarkStrokeLastDrawFrameById[id] = frameCount;
const float deltaSeconds = ImMin(imguiContext.IO.DeltaTime, 0.08f);
const float checkmarkSmoothingStep = 1.0f - std::exp(-16.0f * deltaSeconds);
float& checkmarkStrokeBlend = checkmarkStrokeBlendById[id];
const float checkmarkTargetBlend = isChecked ? 1.0f : 0.0f;
if (!wasDrawnLastFrame)
checkmarkStrokeBlend = checkmarkTargetBlend;
else
checkmarkStrokeBlend += (checkmarkTargetBlend - checkmarkStrokeBlend) * checkmarkSmoothingStep;
if (checkmarkStrokeBlend > 0.001f) {
const float checkboxSize = checkboxRect.GetWidth();
const float markPadding = ImMax(1.0f, IM_FLOOR(checkboxSize / 6.0f));
const float markSize = checkboxSize - markPadding * 2.0f;
RenderCheckMarkProgress(window->DrawList, checkboxRect.Min + ImVec2(markPadding, markPadding), checkColor, markSize, checkmarkStrokeBlend);
}
}
bool Checkbox(const char* label, Option* v) {
ImGui::BeginDisabled(v->IsUnsupportedGameVer());
@@ -77,8 +311,8 @@ namespace ImGui {
return false;
}
ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style;
ImGuiContext& imguiContext = *GImGui;
const ImGuiStyle& style = imguiContext.Style;
const ImGuiID id = window->GetID(label);
const ImVec2 label_size = CalcTextSize(label, NULL, true);
@@ -87,7 +321,7 @@ namespace ImGui {
const ImRect total_bb(pos, pos + ImVec2(square_sz + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), label_size.y + style.FramePadding.y * 2.0f));
ItemSize(total_bb, style.FramePadding.y);
if (!ItemAdd(total_bb, id)) {
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (v->GetValue() ? ImGuiItemStatusFlags_Checked : 0));
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, imguiContext.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (v->GetValue() ? ImGuiItemStatusFlags_Checked : 0));
ImGui::EndDisabled();
return false;
}
@@ -101,26 +335,26 @@ namespace ImGui {
const ImRect check_bb(pos, pos + ImVec2(square_sz, square_sz));
RenderNavHighlight(total_bb, id);
RenderFrame(check_bb.Min, check_bb.Max, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding);
ImU32 check_col = GetColorU32(ImGuiCol_CheckMark);
bool mixed_value = (g.LastItemData.InFlags & ImGuiItemFlags_MixedValue) != 0;
const ImVec4 cFrame = BuildCheckboxFrameColor(id, hovered, held, imguiContext);
RenderFrame(check_bb.Min, check_bb.Max, ColorConvertFloat4ToU32(cFrame), true, style.FrameRounding);
const ImU32 check_col_base = GetColorU32(ImGuiCol_CheckMark);
bool mixed_value = (imguiContext.LastItemData.InFlags & ImGuiItemFlags_MixedValue) != 0;
if (mixed_value) {
// Undocumented tristate/mixed/indeterminate checkbox (#2644)
// This may seem awkwardly designed because the aim is to make ImGuiItemFlags_MixedValue supported by all widgets (not just checkbox)
ImVec2 pad(ImMax(1.0f, IM_FLOOR(square_sz / 3.6f)), ImMax(1.0f, IM_FLOOR(square_sz / 3.6f)));
window->DrawList->AddRectFilled(check_bb.Min + pad, check_bb.Max - pad, check_col, style.FrameRounding);
} else if (v->GetValue()) {
const float pad = ImMax(1.0f, IM_FLOOR(square_sz / 6.0f));
RenderCheckMark(window->DrawList, check_bb.Min + ImVec2(pad, pad), check_col, square_sz - pad * 2.0f);
}
window->DrawList->AddRectFilled(check_bb.Min + pad, check_bb.Max - pad, check_col_base, style.FrameRounding);
} else
DrawCheckboxMarkAnimated(window, check_bb, id, v->GetValue(), imguiContext);
ImVec2 label_pos = ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y);
if (g.LogEnabled)
if (imguiContext.LogEnabled)
LogRenderedText(&label_pos, mixed_value ? "[~]" : v->GetValue() ? "[x]" : "[ ]");
if (label_size.x > 0.0f)
RenderText(label_pos, label);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (v->GetValue() ? ImGuiItemStatusFlags_Checked : 0));
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, imguiContext.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (v->GetValue() ? ImGuiItemStatusFlags_Checked : 0));
ImGui::EndDisabled();
return pressed;
}
@@ -129,7 +363,7 @@ namespace ImGui {
std::string finalTooltip = v->IsUnsupportedGameVer() ? "Option is disabled because it does not support v" + EGSDK::GamePH::GameVerToStr(v->IsUnsupportedGameVer()) : tooltip ? tooltip : "";
if (!finalTooltip.empty())
SetItemTooltip(finalTooltip.c_str());
SetItemTooltipAnimated("%s", finalTooltip.c_str());
return checkbox;
}
@@ -139,16 +373,10 @@ namespace ImGui {
return checkbox;
}
bool SliderInt(const char* label, const char* tooltip, int* v, int v_min, int v_max, const char* format, ImGuiSliderFlags flags) {
const bool sliderInt = SliderInt(label, v, v_min, v_max, format, flags);
if (tooltip)
SetItemTooltip(tooltip);
return sliderInt;
return SliderIntStacked(label, v, v_min, v_max, format, flags, tooltip);
}
bool SliderFloat(const char* label, const char* tooltip, float* v, float v_min, float v_max, const char* format, ImGuiSliderFlags flags) {
const bool sliderFloat = SliderFloat(label, v, v_min, v_max, format, flags);
if (tooltip)
SetItemTooltip(tooltip);
return sliderFloat;
return SliderFloatStacked(label, v, v_min, v_max, format, flags, tooltip);
}
static const float CalculateIndentation(const float window_width, const float text_width, const float min_indentation) {
const float indentation = (window_width - text_width) * 0.5f;
@@ -214,7 +442,7 @@ namespace ImGui {
button_indentation = min_indentation;
SameLine(button_indentation);
return Button(label, size);
return ButtonSmooth(label, size);
NewLine();
}
void SeparatorTextColored(const char* label, ImU32 col) {
@@ -222,6 +450,24 @@ namespace ImGui {
SeparatorText(label);
PopStyleColor();
}
void SeparatorTextSection(const char* label, bool leadingGap) {
if (leadingGap)
Dummy(ImVec2(0.0f, GetStyle().ItemSpacing.y * 0.45f));
const ImGuiStyle& st = GetStyle();
const ImVec4& base = st.Colors[ImGuiCol_Text];
const ImVec4& pop = st.Colors[ImGuiCol_SliderGrab];
// Strong lean on accent: default Text is cool (high B); a shallow lerp reads magenta with rose accents.
constexpr float accentStrength = 0.82f;
const ImVec4 mix(ImLerp(base.x, pop.x, accentStrength), ImLerp(base.y, pop.y, accentStrength), ImLerp(base.z, pop.z, accentStrength), 1.0f);
PushStyleColor(ImGuiCol_Text, ColorConvertFloat4ToU32(mix));
SeparatorText(label);
PopStyleColor();
}
void SeparatorTextSectionColored(const char* label, ImU32 col, bool leadingGap) {
if (leadingGap)
Dummy(ImVec2(0.0f, GetStyle().ItemSpacing.y * 0.45f));
SeparatorTextColored(label, col);
}
static void DisplaySimplePopupMessageBase(const char* popupTitle, const char* fmt, va_list args) {
if (ImGui::BeginPopupModal(popupTitle, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::TextV(fmt, args);
+15
View File
@@ -6,6 +6,10 @@ namespace ImGui {
extern void StyleScaleAllSizes(ImGuiStyle* style, const float scale_factor, ImGuiStyle* defStyle = nullptr);
extern void SpanNextTabAcrossWidth(const float width, const size_t tabs = 1);
extern void EndTabBarEx();
/// Standard `Button` with smoothed hover/active frame colors (same signature as Dear ImGui `Button`).
extern bool ButtonSmooth(const char* label, const ImVec2& size = ImVec2(0, 0));
/// Tooltip with short fade-in after hover delay (uses `HoveredIdTimer`).
extern void SetItemTooltipAnimated(const char* fmt, ...);
extern bool Button(const char* label, const char* tooltip, const ImVec2& size = ImVec2(0, 0));
extern bool ButtonHotkey(const char* label, KeyBindOption* v, const char* tooltip = nullptr, const ImVec2& size = ImVec2(0, 0));
extern bool Checkbox(const char* label, bool* v, const char* tooltip);
@@ -14,10 +18,21 @@ namespace ImGui {
extern bool CheckboxHotkey(const char* label, KeyBindOption* v, const char* tooltip = nullptr);
extern bool SliderInt(const char* label, const char* tooltip, int* v, int v_min, int v_max, const char* format = "%d", ImGuiSliderFlags flags = 0);
extern bool SliderFloat(const char* label, const char* tooltip, float* v, float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0);
/// Form helpers: visible label (text before ##) on the left, widget on the same row using remaining width (internal id uses ##… only).
extern bool SliderFloatStacked(const char* label, float* v, float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0, const char* tooltip = nullptr);
extern bool SliderFloat3Stacked(const char* label, float v[3], float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0);
extern bool SliderIntStacked(const char* label, int* v, int v_min, int v_max, const char* format = "%d", ImGuiSliderFlags flags = 0, const char* tooltip = nullptr);
extern bool DragIntStacked(const char* label, int* v, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", ImGuiSliderFlags flags = 0);
extern bool ComboStacked(const char* label, int* current_item, const char* const items[], int items_count, int popup_max_height_in_items = -1);
extern bool InputFloat3Stacked(const char* label, float v[3], const char* format = "%.3f", ImGuiInputTextFlags flags = 0);
extern void TextCentered(const char* fmt, ...);
extern void TextCenteredColored(const char* fmt, ImU32 col, ...);
extern bool ButtonCentered(const char* label, const ImVec2 size = ImVec2(0.0f, 0.0f));
extern void SeparatorTextColored(const char* text, ImU32 col);
/// `SeparatorText` with optional small gap before it (use `leadingGap = false` for the first header in a tab).
extern void SeparatorTextSection(const char* label, bool leadingGap = true);
extern void SeparatorTextSectionColored(const char* label, ImU32 col, bool leadingGap = true);
extern void DisplaySimplePopupMessage(const char* popupTitle, const char* fmt, ...);
extern void DisplaySimplePopupMessageCentered(const char* popupTitle, const char* fmt, ...);
extern void DisplaySimplePopupMessage(float itemWidth, float scale, const char* popupTitle, const char* fmt, ...);
@@ -1,4 +1,4 @@
const uint8_t g_FontRudaBold[] = {
const uint8_t fontRudaBold[] = {
0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x47, 0x44, 0x45, 0x46,
0x04, 0xCD, 0x04, 0xB4, 0x00, 0x00, 0x01, 0xC4, 0x00, 0x00, 0x00, 0x58, 0x47, 0x50, 0x4F, 0x53,
0xF9, 0x65, 0xA7, 0x92, 0x00, 0x00, 0x32, 0x18, 0x00, 0x00, 0x14, 0x00, 0x47, 0x53, 0x55, 0x42,
@@ -0,0 +1,16 @@
--- a/imgui_widgets.cpp
+++ b/imgui_widgets.cpp
@@ -6641,10 +6641,11 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
if (hovered || selected)
{
const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
- RenderFrame(bb.Min, bb.Max, col, false, 0.0f);
+ const float rounding = ImMin(style.FrameRounding, bb.GetHeight() * 0.5f);
+ RenderFrame(bb.Min, bb.Max, col, false, rounding);
}
if (g.NavId == id)
- RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_Compact | ImGuiNavHighlightFlags_NoRounding);
+ RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_Compact);
if (span_all_columns)
{
@@ -0,0 +1,11 @@
--- a/imconfig.h
+++ b/imconfig.h
@@ -76,7 +76,7 @@
//---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui)
// Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided).
// On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'.
-//#define IMGUI_ENABLE_FREETYPE
+#define IMGUI_ENABLE_FREETYPE
//---- Use FreeType+lunasvg library to render OpenType SVG fonts (SVGinOT)
// Requires lunasvg headers to be available in the include path + program to be linked with the lunasvg library (not provided).
+65
View File
@@ -0,0 +1,65 @@
# ImGui local changes (EGameTools)
## Baseline snapshot (exact upstream match)
Vendored core ImGui is based on upstream commit:
- `8a14b71f2284bbc13fd2900ecefe3f346618702b`
- Commit title: `Version 1.90.4 WIP`
- Version macros at that commit: `IMGUI_VERSION "1.90.4 WIP"`, `IMGUI_VERSION_NUM 19031`
Compared against that exact commit, EGameTools has only 2 intentional deltas:
1. `imgui_widgets.cpp` (`Selectable()` rounded/nav tweak)
2. `imconfig.h` (`IMGUI_ENABLE_FREETYPE` enabled)
## Patches (re-apply after replacing `deps/ImGui` from upstream)
- `001-selectable-rounded-nav.patch`
- file: `imgui_widgets.cpp`
- purpose: rounds `Selectable()` header background and keeps nav highlight rounded (drops `ImGuiNavHighlightFlags_NoRounding`)
- `002-enable-freetype.patch`
- file: `imconfig.h`
- purpose: enables `#define IMGUI_ENABLE_FREETYPE` automatically
### Apply patches
From `EGameTools/deps/ImGui`:
```bat
git apply --check patches\001-selectable-rounded-nav.patch
git apply --check patches\002-enable-freetype.patch
git apply patches\001-selectable-rounded-nav.patch
git apply patches\002-enable-freetype.patch
```
Or run the helper:
```bat
cd EGameTools\deps\ImGui\patches
apply-local-imgui-patches.bat
```
### FreeType options
- **Automatic (recommended):** apply `patches/002-enable-freetype.patch`
- **Manual:** edit `imconfig.h` and uncomment:
- `//#define IMGUI_ENABLE_FREETYPE`
If patch `002` fails on future versions, the line/block likely moved; manually enable it or refresh the patch hunk.
### Files that are not upstream ImGui
Keep these when updating:
- `imguiex.cpp`, `imguiex.h`
- `imguiex_animation.*`
- `imgui_hotkey.*`
- project-specific assets under `deps/ImGui`
### Suggested upgrade workflow
1. Replace upstream files from the branch/commit you want.
2. Re-apply `001` and `002` patches.
3. Reconcile `imguiex` / `imgui_hotkey` if API changed.
4. Build and fix compile errors.
@@ -0,0 +1,58 @@
@echo off
setlocal
REM Run this script from EGameTools\deps\ImGui\patches
REM or from EGameTools\deps\ImGui.
set "ROOT=%~dp0.."
if exist "%~dp0\001-selectable-rounded-nav.patch" (
set "PATCH_DIR=%~dp0"
) else if exist "%ROOT%\patches\001-selectable-rounded-nav.patch" (
set "PATCH_DIR=%ROOT%\patches\"
) else (
echo [ERROR] Could not locate patch files.
echo Expected 001-selectable-rounded-nav.patch near this script.
exit /b 1
)
set "P1=%PATCH_DIR%001-selectable-rounded-nav.patch"
set "P2=%PATCH_DIR%002-enable-freetype.patch"
echo [INFO] Using patch directory:
echo %PATCH_DIR%
echo.
echo [STEP] Checking patch 001...
git apply --check "%P1%"
if errorlevel 1 (
echo [ERROR] Patch 001 check failed.
echo If this is expected, verify imgui_widgets.cpp baseline and patch context.
exit /b 1
)
echo [STEP] Checking patch 002...
git apply --check "%P2%"
if errorlevel 1 (
echo [ERROR] Patch 002 check failed.
echo If FreeType is already enabled, this is expected.
echo You can enable it manually in imconfig.h if needed.
exit /b 1
)
echo [STEP] Applying patch 001...
git apply "%P1%"
if errorlevel 1 (
echo [ERROR] Failed applying patch 001.
exit /b 1
)
echo [STEP] Applying patch 002...
git apply "%P2%"
if errorlevel 1 (
echo [ERROR] Failed applying patch 002.
exit /b 1
)
echo.
echo [OK] Applied local ImGui patches successfully.
exit /b 0
@@ -0,0 +1,173 @@
const unsigned char fontAwesomeSolidSubset[] = {
0x00, 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x80, 0x00, 0x03, 0x00, 0x20, 0x4F, 0x53, 0x2F, 0x32,
0x42, 0xE4, 0x53, 0xDC, 0x00, 0x00, 0x08, 0x24, 0x00, 0x00, 0x00, 0x60, 0x63, 0x6D, 0x61, 0x70,
0xD2, 0x5E, 0xA5, 0x00, 0x00, 0x00, 0x08, 0x84, 0x00, 0x00, 0x00, 0x6C, 0x67, 0x6C, 0x79, 0x66,
0x3A, 0xE6, 0x22, 0x85, 0x00, 0x00, 0x00, 0xAC, 0x00, 0x00, 0x06, 0xC2, 0x68, 0x65, 0x61, 0x64,
0x27, 0xBC, 0x1A, 0x67, 0x00, 0x00, 0x07, 0xA4, 0x00, 0x00, 0x00, 0x36, 0x68, 0x68, 0x65, 0x61,
0x04, 0x4C, 0x02, 0x32, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x24, 0x68, 0x6D, 0x74, 0x78,
0x11, 0x00, 0x00, 0x21, 0x00, 0x00, 0x07, 0xDC, 0x00, 0x00, 0x00, 0x24, 0x6C, 0x6F, 0x63, 0x61,
0x06, 0xCA, 0x08, 0x3D, 0x00, 0x00, 0x07, 0x90, 0x00, 0x00, 0x00, 0x14, 0x6D, 0x61, 0x78, 0x70,
0x00, 0x20, 0x01, 0x91, 0x00, 0x00, 0x07, 0x70, 0x00, 0x00, 0x00, 0x20, 0x6E, 0x61, 0x6D, 0x65,
0x1D, 0x7D, 0x38, 0x79, 0x00, 0x00, 0x08, 0xF0, 0x00, 0x00, 0x01, 0x98, 0x70, 0x6F, 0x73, 0x74,
0xFF, 0xDE, 0x00, 0x19, 0x00, 0x00, 0x0A, 0x88, 0x00, 0x00, 0x00, 0x20, 0x00, 0x03, 0x00, 0x00,
0xFF, 0xE0, 0x02, 0x40, 0x01, 0xA0, 0x00, 0x41, 0x00, 0x4D, 0x00, 0x5B, 0x00, 0x00, 0x01, 0x26,
0x27, 0x06, 0x07, 0x15, 0x31, 0x21, 0x31, 0x22, 0x07, 0x06, 0x15, 0x15, 0x31, 0x14, 0x17, 0x16,
0x33, 0x33, 0x31, 0x16, 0x17, 0x16, 0x07, 0x07, 0x31, 0x06, 0x17, 0x16, 0x33, 0x33, 0x31, 0x36,
0x37, 0x37, 0x31, 0x33, 0x31, 0x32, 0x37, 0x36, 0x37, 0x37, 0x31, 0x33, 0x31, 0x32, 0x37, 0x37,
0x31, 0x33, 0x31, 0x32, 0x37, 0x36, 0x35, 0x35, 0x31, 0x34, 0x27, 0x26, 0x23, 0x23, 0x31, 0x35,
0x07, 0x23, 0x33, 0x23, 0x37, 0x31, 0x33, 0x31, 0x07, 0x31, 0x06, 0x23, 0x27, 0x21, 0x21, 0x21,
0x16, 0x17, 0x06, 0x07, 0x21, 0x31, 0x26, 0x27, 0x36, 0x37, 0x02, 0x10, 0x02, 0x16, 0x16, 0x02,
0xFE, 0x40, 0x0E, 0x09, 0x09, 0x09, 0x09, 0x0E, 0x0A, 0x10, 0x09, 0x09, 0x03, 0x28, 0x03, 0x09,
0x09, 0x10, 0x60, 0x18, 0x07, 0x1A, 0x68, 0x13, 0x0E, 0x0E, 0x06, 0x1B, 0x1F, 0x0D, 0x0A, 0x16,
0x43, 0x0E, 0x09, 0x09, 0x09, 0x09, 0x0E, 0x10, 0xCF, 0x5C, 0x5C, 0x5C, 0x10, 0x69, 0x15, 0x02,
0x05, 0xF2, 0x01, 0x80, 0xFE, 0x80, 0x01, 0x80, 0x0F, 0x01, 0x01, 0x0F, 0xFE, 0x80, 0x0F, 0x01,
0x01, 0x0F, 0x01, 0x88, 0x16, 0x02, 0x02, 0x16, 0x08, 0x09, 0x09, 0x0E, 0x70, 0x0E, 0x09, 0x09,
0x01, 0x0B, 0x0C, 0x10, 0xA0, 0x0F, 0x0D, 0x0C, 0x01, 0x17, 0x68, 0x0A, 0x0A, 0x11, 0x4B, 0x09,
0x17, 0x09, 0x09, 0x0E, 0x50, 0x0E, 0x09, 0x09, 0x08, 0xF8, 0x40, 0x3B, 0x05, 0xB0, 0x01, 0x0F,
0x0F, 0x01, 0x01, 0x0F, 0x0F, 0x01, 0x00, 0x02, 0x00, 0x00, 0xFF, 0xC0, 0x01, 0xC0, 0x01, 0xC0,
0x00, 0x1A, 0x00, 0x30, 0x00, 0x00, 0x37, 0x32, 0x37, 0x31, 0x31, 0x36, 0x37, 0x36, 0x35, 0x34,
0x27, 0x26, 0x27, 0x26, 0x23, 0x22, 0x07, 0x06, 0x07, 0x06, 0x15, 0x14, 0x17, 0x16, 0x17, 0x16,
0x33, 0x07, 0x06, 0x07, 0x31, 0x31, 0x06, 0x07, 0x14, 0x17, 0x16, 0x33, 0x21, 0x31, 0x32, 0x37,
0x36, 0x35, 0x26, 0x27, 0x26, 0x27, 0x23, 0xE0, 0x23, 0x1D, 0x1D, 0x12, 0x11, 0x11, 0x12, 0x1D,
0x1D, 0x23, 0x23, 0x1D, 0x1D, 0x12, 0x11, 0x11, 0x12, 0x1D, 0x1D, 0x23, 0x2E, 0x4B, 0x33, 0x32,
0x02, 0x09, 0x08, 0x0D, 0x01, 0x84, 0x0D, 0x08, 0x09, 0x02, 0x32, 0x33, 0x4B, 0x5C, 0xC0, 0x11,
0x11, 0x1E, 0x1E, 0x22, 0x22, 0x1E, 0x1E, 0x11, 0x11, 0x11, 0x11, 0x1E, 0x1E, 0x22, 0x22, 0x1E,
0x1E, 0x11, 0x11, 0x30, 0x02, 0x32, 0x33, 0x4B, 0x0D, 0x08, 0x09, 0x09, 0x08, 0x0D, 0x4B, 0x33,
0x32, 0x02, 0x00, 0x02, 0x00, 0x0C, 0xFF, 0xC0, 0x01, 0xF4, 0x01, 0xC0, 0x00, 0x60, 0x00, 0x6D,
0x00, 0x00, 0x01, 0x16, 0x07, 0x07, 0x31, 0x16, 0x15, 0x14, 0x07, 0x17, 0x31, 0x16, 0x07, 0x06,
0x07, 0x07, 0x31, 0x06, 0x07, 0x06, 0x27, 0x27, 0x31, 0x06, 0x07, 0x07, 0x31, 0x06, 0x07, 0x06,
0x23, 0x22, 0x27, 0x26, 0x27, 0x27, 0x31, 0x26, 0x27, 0x07, 0x31, 0x06, 0x27, 0x26, 0x27, 0x27,
0x31, 0x26, 0x27, 0x26, 0x37, 0x37, 0x31, 0x26, 0x35, 0x34, 0x37, 0x27, 0x31, 0x26, 0x37, 0x36,
0x37, 0x37, 0x31, 0x36, 0x37, 0x36, 0x17, 0x17, 0x31, 0x36, 0x37, 0x37, 0x31, 0x36, 0x37, 0x36,
0x33, 0x32, 0x17, 0x16, 0x17, 0x17, 0x31, 0x16, 0x17, 0x37, 0x31, 0x36, 0x17, 0x16, 0x17, 0x17,
0x31, 0x16, 0x17, 0x07, 0x36, 0x37, 0x36, 0x27, 0x26, 0x27, 0x06, 0x07, 0x06, 0x17, 0x16, 0x17,
0x01, 0xF0, 0x04, 0x0A, 0x2C, 0x02, 0x02, 0x2C, 0x0A, 0x04, 0x07, 0x09, 0x05, 0x0A, 0x0C, 0x0A,
0x0E, 0x38, 0x14, 0x18, 0x0C, 0x04, 0x0F, 0x14, 0x16, 0x16, 0x15, 0x0E, 0x04, 0x0C, 0x18, 0x14,
0x38, 0x0E, 0x0A, 0x0D, 0x09, 0x05, 0x09, 0x07, 0x04, 0x0A, 0x2C, 0x02, 0x02, 0x2C, 0x0A, 0x04,
0x07, 0x09, 0x05, 0x09, 0x0D, 0x0A, 0x0E, 0x38, 0x14, 0x18, 0x0C, 0x04, 0x0F, 0x14, 0x16, 0x16,
0x15, 0x0E, 0x04, 0x0C, 0x18, 0x14, 0x38, 0x0E, 0x0A, 0x0D, 0x0A, 0x04, 0x09, 0x07, 0xF0, 0x2D,
0x18, 0x16, 0x16, 0x18, 0x2D, 0x2D, 0x18, 0x16, 0x16, 0x18, 0x2D, 0x01, 0x19, 0x0E, 0x0A, 0x28,
0x0C, 0x0D, 0x0D, 0x0C, 0x28, 0x0A, 0x0E, 0x12, 0x11, 0x08, 0x10, 0x0F, 0x0B, 0x04, 0x12, 0x10,
0x09, 0x3A, 0x0E, 0x03, 0x04, 0x04, 0x03, 0x0E, 0x3A, 0x09, 0x10, 0x12, 0x04, 0x0B, 0x0F, 0x10,
0x08, 0x11, 0x11, 0x0F, 0x0A, 0x27, 0x0D, 0x0D, 0x0D, 0x0C, 0x28, 0x0A, 0x0E, 0x12, 0x11, 0x08,
0x10, 0x0F, 0x0B, 0x04, 0x12, 0x10, 0x0A, 0x39, 0x0E, 0x03, 0x04, 0x04, 0x03, 0x0E, 0x39, 0x0A,
0x10, 0x12, 0x04, 0x0B, 0x0F, 0x10, 0x08, 0x11, 0x12, 0xA9, 0x01, 0x27, 0x28, 0x28, 0x27, 0x01,
0x01, 0x27, 0x28, 0x28, 0x27, 0x01, 0x00, 0x02, 0x00, 0x00, 0xFF, 0xE0, 0x02, 0x00, 0x01, 0xA0,
0x00, 0x25, 0x00, 0x40, 0x00, 0x00, 0x13, 0x07, 0x37, 0x07, 0x23, 0x31, 0x06, 0x07, 0x06, 0x07,
0x11, 0x31, 0x16, 0x17, 0x16, 0x17, 0x21, 0x31, 0x36, 0x37, 0x36, 0x37, 0x11, 0x31, 0x26, 0x27,
0x26, 0x27, 0x23, 0x31, 0x27, 0x31, 0x26, 0x27, 0x23, 0x31, 0x06, 0x07, 0x17, 0x32, 0x17, 0x31,
0x31, 0x16, 0x17, 0x16, 0x15, 0x14, 0x07, 0x06, 0x07, 0x06, 0x23, 0x22, 0x27, 0x26, 0x27, 0x26,
0x35, 0x34, 0x37, 0x36, 0x37, 0x36, 0x33, 0x95, 0x0A, 0x0A, 0x0A, 0x4B, 0x1B, 0x12, 0x12, 0x01,
0x01, 0x12, 0x12, 0x1B, 0x01, 0x80, 0x1B, 0x12, 0x12, 0x01, 0x01, 0x12, 0x12, 0x1B, 0x4B, 0x0A,
0x0C, 0x22, 0x7A, 0x22, 0x0C, 0x6B, 0x1A, 0x16, 0x16, 0x0D, 0x0D, 0x0D, 0x0D, 0x16, 0x16, 0x1A,
0x1A, 0x16, 0x16, 0x0D, 0x0D, 0x0D, 0x0D, 0x16, 0x16, 0x1A, 0x01, 0x7F, 0x1F, 0x1F, 0x1F, 0x01,
0x12, 0x12, 0x1B, 0xFF, 0x00, 0x1B, 0x12, 0x12, 0x01, 0x01, 0x12, 0x12, 0x1B, 0x01, 0x00, 0x1B,
0x12, 0x12, 0x01, 0x1F, 0x1F, 0x02, 0x02, 0x1F, 0x7F, 0x0D, 0x0D, 0x16, 0x17, 0x19, 0x19, 0x17,
0x16, 0x0D, 0x0D, 0x0D, 0x0D, 0x16, 0x17, 0x19, 0x19, 0x17, 0x16, 0x0D, 0x0D, 0x00, 0x00, 0x09,
0x00, 0x00, 0xFF, 0xBF, 0x02, 0x00, 0x01, 0xC1, 0x00, 0x0C, 0x00, 0x1A, 0x00, 0x24, 0x00, 0x34,
0x00, 0x3E, 0x00, 0x4C, 0x00, 0x5B, 0x00, 0x63, 0x00, 0x6D, 0x00, 0x00, 0x25, 0x14, 0x07, 0x23,
0x31, 0x26, 0x35, 0x34, 0x37, 0x33, 0x31, 0x16, 0x15, 0x37, 0x33, 0x23, 0x33, 0x16, 0x15, 0x14,
0x07, 0x23, 0x31, 0x36, 0x35, 0x34, 0x27, 0x37, 0x23, 0x33, 0x23, 0x26, 0x27, 0x16, 0x17, 0x16,
0x17, 0x23, 0x23, 0x33, 0x23, 0x36, 0x37, 0x36, 0x37, 0x36, 0x17, 0x36, 0x17, 0x16, 0x17, 0x16,
0x17, 0x23, 0x23, 0x33, 0x23, 0x36, 0x37, 0x36, 0x37, 0x06, 0x07, 0x07, 0x33, 0x23, 0x33, 0x06,
0x15, 0x14, 0x17, 0x23, 0x31, 0x26, 0x35, 0x34, 0x37, 0x17, 0x26, 0x27, 0x33, 0x31, 0x06, 0x07,
0x06, 0x07, 0x06, 0x27, 0x06, 0x27, 0x26, 0x27, 0x27, 0x16, 0x17, 0x26, 0x27, 0x26, 0x27, 0x33,
0x21, 0x06, 0x07, 0x31, 0x31, 0x06, 0x07, 0x36, 0x37, 0x33, 0x01, 0x60, 0x03, 0xBA, 0x03, 0x03,
0xBA, 0x03, 0x1D, 0x7B, 0x7B, 0x7B, 0x08, 0x08, 0x7B, 0x03, 0x03, 0x70, 0x74, 0x74, 0x74, 0x10,
0x28, 0x3C, 0x2D, 0x2C, 0x17, 0x95, 0xB0, 0xB0, 0xB0, 0x09, 0x12, 0x10, 0x11, 0x11, 0x0B, 0x0B,
0x11, 0x11, 0x10, 0x12, 0x09, 0xD1, 0x74, 0x74, 0x74, 0x17, 0x2C, 0x2D, 0x3C, 0x28, 0x10, 0x7F,
0x7B, 0x7B, 0x7B, 0x03, 0x03, 0x7B, 0x08, 0x08, 0xBB, 0x12, 0x09, 0xB0, 0x09, 0x12, 0x10, 0x11,
0x11, 0x0B, 0x0B, 0x11, 0x11, 0x10, 0x3C, 0x10, 0x28, 0x3C, 0x2D, 0x2C, 0x17, 0x74, 0x01, 0x66,
0x17, 0x2C, 0x2D, 0x3B, 0x27, 0x10, 0x74, 0xC0, 0x21, 0x1F, 0x1F, 0x21, 0x21, 0x1F, 0x1F, 0x21,
0x40, 0x1F, 0x21, 0x21, 0x1F, 0x1F, 0x21, 0x21, 0x1F, 0x20, 0x62, 0x36, 0x11, 0x27, 0x28, 0x38,
0x37, 0x28, 0x23, 0x10, 0x0F, 0x01, 0x01, 0x0F, 0x10, 0x23, 0x28, 0x37, 0x38, 0x28, 0x27, 0x11,
0x36, 0x62, 0x20, 0x1F, 0x21, 0x21, 0x1F, 0x1F, 0x21, 0x21, 0x1F, 0xFF, 0x28, 0x37, 0x37, 0x28,
0x23, 0x10, 0x0F, 0x01, 0x01, 0x0F, 0x10, 0x23, 0x5F, 0x62, 0x36, 0x11, 0x27, 0x28, 0x38, 0x38,
0x28, 0x27, 0x11, 0x36, 0x62, 0x00, 0x00, 0x01, 0x00, 0x0D, 0xFF, 0xED, 0x01, 0xB5, 0x01, 0x95,
0x00, 0x13, 0x00, 0x00, 0x01, 0x36, 0x27, 0x26, 0x07, 0x05, 0x31, 0x06, 0x17, 0x16, 0x17, 0x33,
0x31, 0x15, 0x31, 0x16, 0x17, 0x16, 0x37, 0x13, 0x01, 0xAE, 0x07, 0x0E, 0x10, 0x13, 0xFE, 0xA0,
0x17, 0x04, 0x06, 0x19, 0xB0, 0x02, 0x18, 0x19, 0x0B, 0x90, 0x01, 0x64, 0x13, 0x10, 0x0E, 0x07,
0x90, 0x0B, 0x19, 0x18, 0x02, 0xB0, 0x19, 0x06, 0x04, 0x17, 0x01, 0x60, 0x00, 0x03, 0x00, 0x08,
0x00, 0x80, 0x01, 0xC0, 0x01, 0x00, 0x00, 0x0C, 0x00, 0x19, 0x00, 0x26, 0x00, 0x00, 0x37, 0x36,
0x37, 0x36, 0x17, 0x16, 0x17, 0x06, 0x07, 0x06, 0x27, 0x26, 0x27, 0x33, 0x36, 0x37, 0x36, 0x17,
0x16, 0x17, 0x06, 0x07, 0x06, 0x27, 0x26, 0x27, 0x37, 0x16, 0x17, 0x16, 0x07, 0x06, 0x07, 0x26,
0x27, 0x26, 0x37, 0x36, 0x37, 0x08, 0x01, 0x1B, 0x1C, 0x1C, 0x1B, 0x01, 0x01, 0x1B, 0x1C, 0x1C,
0x1B, 0x01, 0xA0, 0x01, 0x1B, 0x1C, 0x1C, 0x1B, 0x01, 0x01, 0x1B, 0x1C, 0x1C, 0x1B, 0x01, 0xD8,
0x20, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x20, 0xC0, 0x20, 0x10, 0x10,
0x10, 0x10, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20,
0x10, 0x10, 0x10, 0x10, 0x20, 0x38, 0x01, 0x1B, 0x1C, 0x1C, 0x1B, 0x01, 0x01, 0x1B, 0x1C, 0x1C,
0x1B, 0x01, 0x00, 0x02, 0x00, 0x00, 0xFF, 0xC0, 0x02, 0x00, 0x01, 0xC0, 0x00, 0x18, 0x00, 0x8B,
0x00, 0x00, 0x01, 0x16, 0x17, 0x31, 0x31, 0x16, 0x17, 0x15, 0x31, 0x14, 0x07, 0x06, 0x23, 0x23,
0x31, 0x22, 0x27, 0x26, 0x35, 0x35, 0x31, 0x36, 0x37, 0x36, 0x37, 0x07, 0x36, 0x33, 0x31, 0x31,
0x32, 0x17, 0x17, 0x31, 0x16, 0x17, 0x30, 0x15, 0x36, 0x33, 0x33, 0x31, 0x32, 0x17, 0x34, 0x37,
0x37, 0x31, 0x36, 0x33, 0x32, 0x17, 0x16, 0x15, 0x14, 0x07, 0x07, 0x31, 0x06, 0x07, 0x16, 0x17,
0x33, 0x31, 0x32, 0x17, 0x16, 0x15, 0x14, 0x07, 0x06, 0x23, 0x23, 0x31, 0x14, 0x07, 0x16, 0x17,
0x17, 0x31, 0x16, 0x15, 0x14, 0x07, 0x06, 0x23, 0x22, 0x27, 0x27, 0x31, 0x06, 0x07, 0x35, 0x31,
0x26, 0x27, 0x06, 0x07, 0x15, 0x31, 0x26, 0x27, 0x07, 0x31, 0x06, 0x23, 0x22, 0x27, 0x26, 0x35,
0x34, 0x37, 0x37, 0x31, 0x36, 0x37, 0x26, 0x35, 0x23, 0x31, 0x22, 0x27, 0x26, 0x35, 0x34, 0x37,
0x36, 0x33, 0x33, 0x31, 0x36, 0x37, 0x26, 0x27, 0x27, 0x31, 0x26, 0x35, 0x34, 0x37, 0x01, 0x00,
0x29, 0x1B, 0x1B, 0x01, 0x08, 0x08, 0x0C, 0x88, 0x0C, 0x08, 0x08, 0x01, 0x1B, 0x1B, 0x29, 0xD7,
0x0A, 0x0D, 0x0D, 0x0A, 0x40, 0x01, 0x01, 0x15, 0x1A, 0x70, 0x1A, 0x16, 0x01, 0x40, 0x0A, 0x0D,
0x0D, 0x0A, 0x09, 0x09, 0x40, 0x01, 0x01, 0x09, 0x02, 0x40, 0x0E, 0x09, 0x09, 0x09, 0x09, 0x0E,
0x40, 0x0F, 0x03, 0x03, 0x40, 0x09, 0x09, 0x0A, 0x0D, 0x0D, 0x0A, 0x3F, 0x25, 0x35, 0x01, 0x0F,
0x0F, 0x01, 0x35, 0x25, 0x3F, 0x0A, 0x0D, 0x0D, 0x0A, 0x09, 0x09, 0x40, 0x03, 0x03, 0x0F, 0x40,
0x0E, 0x09, 0x09, 0x09, 0x09, 0x0E, 0x40, 0x02, 0x09, 0x01, 0x01, 0x40, 0x09, 0x09, 0x01, 0xC0,
0x01, 0x1B, 0x1B, 0x29, 0x04, 0x0C, 0x08, 0x08, 0x08, 0x08, 0x0C, 0x04, 0x29, 0x1B, 0x1B, 0x01,
0x69, 0x09, 0x09, 0x40, 0x01, 0x01, 0x01, 0x0C, 0x0C, 0x02, 0x01, 0x40, 0x09, 0x09, 0x0A, 0x0D,
0x0D, 0x0A, 0x40, 0x01, 0x01, 0x12, 0x15, 0x09, 0x09, 0x0E, 0x0E, 0x09, 0x09, 0x25, 0x20, 0x02,
0x02, 0x40, 0x0A, 0x0D, 0x0D, 0x0A, 0x09, 0x09, 0x3F, 0x21, 0x06, 0xEF, 0x0F, 0x01, 0x01, 0x0F,
0xEF, 0x06, 0x21, 0x3F, 0x09, 0x09, 0x0A, 0x0D, 0x0D, 0x0A, 0x40, 0x02, 0x02, 0x20, 0x25, 0x09,
0x09, 0x0E, 0x0E, 0x09, 0x09, 0x15, 0x12, 0x01, 0x01, 0x40, 0x0A, 0x0D, 0x0D, 0x0A, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00, 0x09, 0x01, 0x8F, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x00, 0xBB, 0x01, 0x55, 0x01, 0xB1, 0x02, 0x4D, 0x02, 0x70,
0x02, 0xB3, 0x03, 0x61, 0x00, 0x01, 0x00, 0x00, 0x03, 0x05, 0x03, 0x00, 0x42, 0xAB, 0x62, 0xF1,
0x5F, 0x0F, 0x3C, 0xF5, 0x00, 0x0B, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE1, 0x8D, 0x6B, 0x75,
0x00, 0x00, 0x00, 0x00, 0xE1, 0x8D, 0x6B, 0x75, 0xFF, 0xF3, 0xFF, 0xB5, 0x02, 0x8B, 0x01, 0xCB,
0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00,
0x02, 0x40, 0x00, 0x00, 0x01, 0xC0, 0x00, 0x00, 0x02, 0x00, 0x00, 0x0C, 0x02, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x01, 0xC0, 0x00, 0x0D, 0x01, 0xC0, 0x00, 0x08, 0x02, 0x00, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00, 0x01, 0xCB, 0xFF, 0xB5, 0x00, 0x00, 0x02, 0x80, 0xFF, 0xF3, 0xFF, 0xF3,
0x02, 0x8B, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x09, 0x00, 0x04, 0x02, 0x03, 0x03, 0x84, 0x00, 0x05, 0x00, 0x00, 0x01, 0x4C,
0x01, 0x66, 0x00, 0x00, 0x00, 0x47, 0x01, 0x4C, 0x01, 0x66, 0x00, 0x00, 0x00, 0xF5, 0x00, 0x19,
0x00, 0x84, 0x00, 0x00, 0x02, 0x00, 0x09, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x57,
0x53, 0x4D, 0x00, 0x80, 0xE1, 0x9B, 0xF1, 0x88, 0x01, 0xCB, 0xFF, 0xB5, 0x00, 0x00, 0x01, 0xCB,
0x00, 0x4B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x41, 0x01, 0xAF, 0x00, 0x00,
0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x14,
0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x04, 0x00, 0x58, 0x00, 0x00, 0x00, 0x12,
0x00, 0x10, 0x00, 0x03, 0x00, 0x02, 0xE1, 0x9B, 0xF0, 0x07, 0xF0, 0x13, 0xF0, 0x30, 0xF0, 0xAC,
0xF1, 0x24, 0xF1, 0x41, 0xF1, 0x88, 0xFF, 0xFF, 0x00, 0x00, 0xE1, 0x9B, 0xF0, 0x07, 0xF0, 0x13,
0xF0, 0x30, 0xF0, 0xAC, 0xF1, 0x24, 0xF1, 0x41, 0xF1, 0x88, 0xFF, 0xFF, 0x1E, 0x66, 0x0F, 0xFB,
0x0F, 0xF0, 0x0F, 0xD4, 0x0F, 0x59, 0x0E, 0xE2, 0x0E, 0xC6, 0x0E, 0x80, 0x00, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x07, 0x00, 0x5A, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x00, 0x00, 0x34,
0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x01, 0x00, 0x32, 0x00, 0x34, 0x00, 0x03,
0x00, 0x01, 0x04, 0x09, 0x00, 0x02, 0x00, 0x0A, 0x00, 0x66, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09,
0x00, 0x03, 0x00, 0x3E, 0x00, 0x70, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x04, 0x00, 0x32,
0x00, 0x34, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x05, 0x00, 0x64, 0x00, 0xAE, 0x00, 0x03,
0x00, 0x01, 0x04, 0x09, 0x00, 0x06, 0x00, 0x2C, 0x01, 0x12, 0x00, 0x43, 0x00, 0x6F, 0x00, 0x70,
0x00, 0x79, 0x00, 0x72, 0x00, 0x69, 0x00, 0x67, 0x00, 0x68, 0x00, 0x74, 0x00, 0x20, 0x00, 0x28,
0x00, 0x63, 0x00, 0x29, 0x00, 0x20, 0x00, 0x46, 0x00, 0x6F, 0x00, 0x6E, 0x00, 0x74, 0x00, 0x20,
0x00, 0x41, 0x00, 0x77, 0x00, 0x65, 0x00, 0x73, 0x00, 0x6F, 0x00, 0x6D, 0x00, 0x65, 0x00, 0x46,
0x00, 0x6F, 0x00, 0x6E, 0x00, 0x74, 0x00, 0x20, 0x00, 0x41, 0x00, 0x77, 0x00, 0x65, 0x00, 0x73,
0x00, 0x6F, 0x00, 0x6D, 0x00, 0x65, 0x00, 0x20, 0x00, 0x36, 0x00, 0x20, 0x00, 0x46, 0x00, 0x72,
0x00, 0x65, 0x00, 0x65, 0x00, 0x20, 0x00, 0x53, 0x00, 0x6F, 0x00, 0x6C, 0x00, 0x69, 0x00, 0x64,
0x00, 0x53, 0x00, 0x6F, 0x00, 0x6C, 0x00, 0x69, 0x00, 0x64, 0x00, 0x46, 0x00, 0x6F, 0x00, 0x6E,
0x00, 0x74, 0x00, 0x20, 0x00, 0x41, 0x00, 0x77, 0x00, 0x65, 0x00, 0x73, 0x00, 0x6F, 0x00, 0x6D,
0x00, 0x65, 0x00, 0x20, 0x00, 0x36, 0x00, 0x20, 0x00, 0x46, 0x00, 0x72, 0x00, 0x65, 0x00, 0x65,
0x00, 0x20, 0x00, 0x53, 0x00, 0x6F, 0x00, 0x6C, 0x00, 0x69, 0x00, 0x64, 0x00, 0x2D, 0x00, 0x36,
0x00, 0x2E, 0x00, 0x35, 0x00, 0x2E, 0x00, 0x31, 0x00, 0x56, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73,
0x00, 0x69, 0x00, 0x6F, 0x00, 0x6E, 0x00, 0x20, 0x00, 0x37, 0x00, 0x37, 0x00, 0x33, 0x00, 0x2E,
0x00, 0x30, 0x00, 0x31, 0x00, 0x31, 0x00, 0x37, 0x00, 0x31, 0x00, 0x38, 0x00, 0x37, 0x00, 0x35,
0x00, 0x20, 0x00, 0x28, 0x00, 0x46, 0x00, 0x6F, 0x00, 0x6E, 0x00, 0x74, 0x00, 0x20, 0x00, 0x41,
0x00, 0x77, 0x00, 0x65, 0x00, 0x73, 0x00, 0x6F, 0x00, 0x6D, 0x00, 0x65, 0x00, 0x20, 0x00, 0x76,
0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6F, 0x00, 0x6E, 0x00, 0x3A, 0x00, 0x20,
0x00, 0x36, 0x00, 0x2E, 0x00, 0x35, 0x00, 0x2E, 0x00, 0x31, 0x00, 0x29, 0x00, 0x46, 0x00, 0x6F,
0x00, 0x6E, 0x00, 0x74, 0x00, 0x41, 0x00, 0x77, 0x00, 0x65, 0x00, 0x73, 0x00, 0x6F, 0x00, 0x6D,
0x00, 0x65, 0x00, 0x36, 0x00, 0x46, 0x00, 0x72, 0x00, 0x65, 0x00, 0x65, 0x00, 0x2D, 0x00, 0x53,
0x00, 0x6F, 0x00, 0x6C, 0x00, 0x69, 0x00, 0x64, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xDB, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
Binary file not shown.
@@ -1,4 +1,4 @@
const char g_PlayerVariablesSCRFile[] = {
const char defaultPlayerVariablesScr[] = {
0x73, 0x75, 0x62, 0x20, 0x6D, 0x61, 0x69, 0x6E, 0x28, 0x29, 0x0D, 0x0A, 0x7B, 0x0D, 0x0A, 0x09,
0x50, 0x61, 0x72, 0x61, 0x6D, 0x28, 0x22, 0x41, 0x6E, 0x69, 0x6D, 0x47, 0x72, 0x61, 0x70, 0x68,
0x5F, 0x42, 0x61, 0x6E, 0x6B, 0x4E, 0x61, 0x6D, 0x65, 0x22, 0x2C, 0x20, 0x22, 0x70, 0x6C, 0x61,
@@ -0,0 +1,13 @@
#pragma once
#include <d3d12.h>
namespace EGT::ImGui_impl::D3D12_MicaBlur {
/// Create PSOs / root signatures (idempotent). Safe to call once after `d3d12Device` is valid.
bool EnsureInitialized(ID3D12Device* device);
void ReleaseGpuResources();
/// Copy back buffer → blur → composite lerp (sharp vs blurred) under the menu rect. Leaves `backBuffer` in RENDER_TARGET.
void RenderBackdrop(ID3D12GraphicsCommandList* cmdList, ID3D12Resource* backBuffer, const D3D12_CPU_DESCRIPTOR_HANDLE& backBufferRtv, UINT fullWidth, UINT fullHeight,
float menuMinX, float menuMinY, float menuMaxX, float menuMaxY, float backdropStrength);
}
+9
View File
@@ -1,6 +1,15 @@
#pragma once
struct ImFont;
namespace EGT::Menu {
extern void FirstTimeRunning();
extern void InitImGui();
/// Rebuild font atlas at `Menu::scale` and invalidate GPU font texture. Call once per frame before `ImGui_ImplDX11/DX12_NewFrame()`.
extern void SyncMenuFontsBeforeImGuiNewFrame();
/// Slightly larger Ruda font for the version label (same atlas; null before first sync).
extern ImFont* MenuVersionFont();
}
+33
View File
@@ -1,10 +1,14 @@
#pragma once
#include <string>
#include <set>
#include <ImGui\imgui.h>
#include <ImGui\imgui_hotkey.h>
#include <EGT\Core\core.h>
namespace EGT::Menu {
/// Sentinel index for the sidebar "Settings" panel (not a registered MenuTab).
inline constexpr int settingsPanelTabIndex = -1;
class MenuTab {
public:
MenuTab(std::string_view name, int tabIndex) : tabName(name), tabIndex(tabIndex) { GetInstances()->insert({ tabIndex, this}); };
@@ -24,7 +28,18 @@ namespace EGT::Menu {
extern ImTextureID EGTLogoTexture;
extern ImGui::KeyBindOption menuToggle;
/// Panel / ImGui translucency (0–100%).
extern float opacity;
/// Child / inset panels (ImGuiCol_ChildBg alpha × 100; 50 ≈ default glass).
extern float childPanelAlpha;
/// Sliders, inputs, combo chrome (ImGuiCol_FrameBg* alpha × 100).
extern float frameAlpha;
/// Popups / tooltips root (ImGuiCol_PopupBg alpha × 100).
extern float popupAlpha;
/// Strength of the decorative Mica gradient wash drawn under ImGui (0–100%).
extern float micaWashStrength;
/// DX12 backdrop blur strength (0–100%). Independent from `opacity`.
extern float micaBlurStrength;
extern float scale;
extern ImGui::Option firstTimeRunning;
@@ -32,5 +47,23 @@ namespace EGT::Menu {
extern int currentTabIndex;
/// Copy committed `scale` into the settings slider draft (call after fonts/config are ready).
extern void InitMenuScaleDraftToCommitted();
/// Style scale, per-channel alphas, and font global scale for the current committed `Menu::scale`.
extern void PushScaledMenuStyles();
/// Call once per frame before `ImGui::NewFrame()` (even when the menu is closed) so open/close edges are visible to animation state.
extern void UpdateMenuVisibilityAnimFromPoll();
/// True while the menu should be drawn (open or mid close fade-out).
extern bool MenuAnimNeedsFrame();
/// Screen-space backdrop for DX12 Mica (updated while the main menu is visible). Top-left origin, inclusive min / exclusive max.
extern bool GetMenuBackdropRectPx(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY);
/// Menu open fade × (`micaBlurStrength` as 0–1). Drives DX12 frosted composite, not panel alpha.
extern float GetMicaBackdropFade();
extern void Render();
}
+14
View File
@@ -0,0 +1,14 @@
#pragma once
// UTF-8 sequences for Font Awesome 6 Free (solid) glyphs merged in InitImGui().
// Subset font: deps/fonts/fa-solid-900-subset.ttf (generated; see deps/fonts/).
namespace EGT::MenuIcons {
inline constexpr const char iconUser[] = "\xEF\x80\x87"; // fa-user (Player)
inline constexpr const char iconGun[] = "\xEE\x86\x9B"; // fa-gun (Weapon)
inline constexpr const char iconCamera[] = "\xEF\x80\xB0"; // fa-camera (Camera)
inline constexpr const char iconLocationArrow[] = "\xEF\x84\xA4"; // fa-location-arrow (Teleport)
inline constexpr const char iconEllipsis[] = "\xEF\x85\x81"; // fa-ellipsis (Misc)
inline constexpr const char iconGlobe[] = "\xEF\x82\xAC"; // fa-globe (World)
inline constexpr const char iconBug[] = "\xEF\x86\x88"; // fa-bug (Debug)
inline constexpr const char iconGear[] = "\xEF\x80\x93"; // fa-gear (Settings)
}
@@ -1,4 +1,4 @@
const unsigned char g_EGTWhiteLogo[] = {
const unsigned char egtWhiteLogoPng[] = {
0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52,
0x00, 0x00, 0x04, 0x6A, 0x00, 0x00, 0x01, 0x96, 0x08, 0x06, 0x00, 0x00, 0x00, 0x20, 0xDF, 0x65,
0xC3, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0B, 0x13, 0x00, 0x00, 0x0B,
+5
View File
@@ -42,6 +42,11 @@ namespace EGT::Config {
static void InitializeConfigVariables() {
configVariablesDefault = std::vector<ConfigEntry>({
{ "Menu", "Opacity", Menu::opacity, &Menu::opacity, Float },
{ "Menu", "ChildPanelAlpha", Menu::childPanelAlpha, &Menu::childPanelAlpha, Float },
{ "Menu", "FrameAlpha", Menu::frameAlpha, &Menu::frameAlpha, Float },
{ "Menu", "PopupAlpha", Menu::popupAlpha, &Menu::popupAlpha, Float },
{ "Menu", "MicaWashStrength", Menu::micaWashStrength, &Menu::micaWashStrength, Float },
{ "Menu", "MicaBlurStrength", Menu::micaBlurStrength, &Menu::micaBlurStrength, Float },
{ "Menu", "Scale", Menu::scale, &Menu::scale, Float },
{ "Menu", "FirstTimeRunning", Menu::firstTimeRunning.GetValue(), &Menu::firstTimeRunning, OPTION },
{ "Menu", "HasSeenChangelog", Menu::hasSeenChangelog.GetValue(), &Menu::hasSeenChangelog, OPTION },
+4 -2
View File
@@ -9,8 +9,8 @@
#include <EGT\ImGui_impl\Win32_impl.h>
#include <EGT\ImGui_impl\DeferredActions.h>
#include <EGT\ImGui_impl\NextFrameTask.h>
#include <EGT\Menu\Menu.h>
#include <EGT\Menu\Init.h>
#include <EGT\Menu\Menu.h>
namespace EGT::ImGui_impl {
namespace D3D11 {
@@ -82,12 +82,14 @@ namespace EGT::ImGui_impl {
static void RenderImGui(IDXGISwapChain* pSwapChain) {
InitImGuiRendering(pSwapChain);
Menu::SyncMenuFontsBeforeImGuiNewFrame();
ImGui_ImplDX11_NewFrame();
ImGui_ImplWin32_NewFrame();
Menu::UpdateMenuVisibilityAnimFromPoll();
ImGui::NewFrame();
Menu::FirstTimeRunning();
if (Menu::menuToggle.GetValue())
if (Menu::MenuAnimNeedsFrame())
Menu::Render();
ImGui::EndFrame();
@@ -0,0 +1,555 @@
#include <EGT/ImGui_impl/D3D12_MicaBlur.h>
#include <d3dcompiler.h>
#include <spdlog/spdlog.h>
#include <algorithm>
#include <cmath>
#include <cstring>
#pragma comment(lib, "d3d12.lib")
#pragma comment(lib, "d3dcompiler.lib")
namespace EGT::ImGui_impl::D3D12_MicaBlur {
static const char* micaHlslSource = R"(
struct PSIn { float4 pos : SV_POSITION; };
PSIn vs_full(uint vid : SV_VertexID) {
PSIn o;
float2 uv = float2((vid << 1) & 2, vid & 2);
o.pos = float4(uv * float2(2.0f, -2.0f) + float2(-1.0f, 1.0f), 0.0f, 1.0f);
return o;
}
cbuffer CBDown : register(b0) { float2 sceneTextureSize; float2 padding0; }
Texture2D sceneTexture : register(t0);
SamplerState linearSampler : register(s0);
float4 ps_down(PSIn inp) : SV_Target {
float2 p = inp.pos.xy;
float2 suv = (p * 2.0f + float2(0.5f, 0.5f)) / sceneTextureSize;
return sceneTexture.SampleLevel(linearSampler, suv, 0);
}
cbuffer CBBlur : register(b0) { float4 blurPassParams; } // (invW, invH, dirX, dirY) dir = (1,0) horiz or (0,1) vert
Texture2D blurSourceTexture : register(t0);
float4 ps_blur(PSIn inp) : SV_Target {
float2 invSz = blurPassParams.xy;
float2 dir = blurPassParams.zw;
float2 uv = (inp.pos.xy + float2(0.5f, 0.5f)) * invSz;
float2 off = float2(dir.x * invSz.x, dir.y * invSz.y);
float4 c = blurSourceTexture.SampleLevel(linearSampler, uv, 0) * 0.227027f;
c += blurSourceTexture.SampleLevel(linearSampler, uv + off, 0) * 0.316216f;
c += blurSourceTexture.SampleLevel(linearSampler, uv - off, 0) * 0.316216f;
c += blurSourceTexture.SampleLevel(linearSampler, uv + off * 2.0f, 0) * 0.070270f;
c += blurSourceTexture.SampleLevel(linearSampler, uv - off * 2.0f, 0) * 0.070270f;
return c;
}
cbuffer CBComp : register(b0) { float2 backbufferSize; float blurMix; float menuFade; }
Texture2D sharpBackbufferTexture : register(t0);
Texture2D blurredTexture : register(t1);
float4 ps_comp(PSIn inp) : SV_Target {
float2 uv = inp.pos.xy / backbufferSize;
float3 sharp = sharpBackbufferTexture.SampleLevel(linearSampler, uv, 0).rgb;
float3 blur = blurredTexture.SampleLevel(linearSampler, uv, 0).rgb;
float t = saturate(blurMix * menuFade);
return float4(lerp(sharp, blur, t), 1.0f);
}
)";
struct GpuSize {
UINT width = 0;
UINT height = 0;
UINT blurWidth = 0;
UINT blurHeight = 0;
};
static ID3D12Device* micaD3dDevice = nullptr;
static ID3D12RootSignature* rootSignatureDownsample = nullptr;
static ID3D12RootSignature* rootSignatureBlur = nullptr;
static ID3D12RootSignature* rootSignatureComposite = nullptr;
static ID3D12PipelineState* pipelineStateDownsample = nullptr;
static ID3D12PipelineState* pipelineStateBlur = nullptr;
static ID3D12PipelineState* pipelineStateComposite = nullptr;
static ID3D12Resource* sceneCopyTexture = nullptr;
static ID3D12Resource* blurTextureA = nullptr;
static ID3D12Resource* blurTextureB = nullptr;
static ID3D12DescriptorHeap* srvHeap = nullptr;
static ID3D12DescriptorHeap* rtvHeap = nullptr;
static UINT srvDescriptorStride = 0;
static UINT rtvDescriptorStride = 0;
static D3D12_CPU_DESCRIPTOR_HANDLE cpuSrvScene{};
static D3D12_CPU_DESCRIPTOR_HANDLE cpuSrvBlurA{};
static D3D12_CPU_DESCRIPTOR_HANDLE cpuSrvBlurB{};
static D3D12_CPU_DESCRIPTOR_HANDLE cpuRtvA{};
static D3D12_CPU_DESCRIPTOR_HANDLE cpuRtvB{};
static D3D12_GPU_DESCRIPTOR_HANDLE gpuSrvScene{};
static D3D12_GPU_DESCRIPTOR_HANDLE gpuSrvBlurA{};
static D3D12_GPU_DESCRIPTOR_HANDLE gpuSrvBlurB{};
static GpuSize micaTextureSizes{};
static bool shadersCompiledOk = false;
static D3D12_RESOURCE_STATES sceneCopyResourceState = D3D12_RESOURCE_STATE_COMMON;
static D3D12_RESOURCE_STATES blurTextureAResourceState = D3D12_RESOURCE_STATE_COMMON;
static D3D12_RESOURCE_STATES blurTextureBResourceState = D3D12_RESOURCE_STATE_COMMON;
template <typename T>
static void SafeRelease(T*& p) {
if (p) {
p->Release();
p = nullptr;
}
}
static void ReleaseShaderBlobs(ID3DBlob*& vertexShaderBlob, ID3DBlob*& downsamplePixelBlob, ID3DBlob*& blurPixelBlob, ID3DBlob*& compositePixelBlob) {
SafeRelease(vertexShaderBlob);
SafeRelease(downsamplePixelBlob);
SafeRelease(blurPixelBlob);
SafeRelease(compositePixelBlob);
}
static void ReleasePipelineAndSignatureObjects() {
SafeRelease(pipelineStateDownsample);
SafeRelease(pipelineStateBlur);
SafeRelease(pipelineStateComposite);
SafeRelease(rootSignatureDownsample);
SafeRelease(rootSignatureBlur);
SafeRelease(rootSignatureComposite);
}
static bool Compile(const char* entry, const char* target, ID3DBlob** out) {
ID3DBlob* err = nullptr;
const HRESULT hr = D3DCompile(micaHlslSource, std::strlen(micaHlslSource), nullptr, nullptr, nullptr, entry, target, D3DCOMPILE_OPTIMIZATION_LEVEL3, 0, out, &err);
if (FAILED(hr)) {
if (err) {
SPDLOG_ERROR("D3D12 Mica: D3DCompile failed ({}): {}", entry, static_cast<const char*>(err->GetBufferPointer()));
err->Release();
} else
SPDLOG_ERROR("D3D12 Mica: D3DCompile failed ({}) HRESULT={:#x}", entry, static_cast<unsigned>(hr));
return false;
}
return true;
}
static bool CreateRs1Srv(ID3D12Device* dev, ID3D12RootSignature** outRs) {
D3D12_DESCRIPTOR_RANGE range{};
range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
range.NumDescriptors = 1;
range.BaseShaderRegister = 0;
range.RegisterSpace = 0;
range.OffsetInDescriptorsFromTableStart = 0;
D3D12_ROOT_PARAMETER param[2]{};
param[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
param[0].Constants.ShaderRegister = 0;
param[0].Constants.RegisterSpace = 0;
param[0].Constants.Num32BitValues = 4;
param[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
param[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
param[1].DescriptorTable.NumDescriptorRanges = 1;
param[1].DescriptorTable.pDescriptorRanges = &range;
param[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
D3D12_STATIC_SAMPLER_DESC samp{};
samp.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
samp.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
samp.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
samp.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
samp.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER;
samp.MaxLOD = D3D12_FLOAT32_MAX;
samp.ShaderRegister = 0;
samp.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
D3D12_ROOT_SIGNATURE_DESC desc{};
desc.NumParameters = 2;
desc.pParameters = param;
desc.NumStaticSamplers = 1;
desc.pStaticSamplers = &samp;
desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_NONE;
ID3DBlob* ser = nullptr;
if (FAILED(D3D12SerializeRootSignature(&desc, D3D_ROOT_SIGNATURE_VERSION_1, &ser, nullptr)))
return false;
const HRESULT hr = dev->CreateRootSignature(0, ser->GetBufferPointer(), ser->GetBufferSize(), IID_PPV_ARGS(outRs));
ser->Release();
return SUCCEEDED(hr);
}
static bool CreateRs2Srv(ID3D12Device* dev, ID3D12RootSignature** outRs) {
D3D12_DESCRIPTOR_RANGE ranges[2]{};
for (int i = 0; i < 2; ++i) {
ranges[i].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
ranges[i].NumDescriptors = 1;
ranges[i].BaseShaderRegister = static_cast<UINT>(i);
ranges[i].RegisterSpace = 0;
ranges[i].OffsetInDescriptorsFromTableStart = (i == 0) ? 0 : D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
}
D3D12_ROOT_PARAMETER param[2]{};
param[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
param[0].Constants.ShaderRegister = 0;
param[0].Constants.RegisterSpace = 0;
param[0].Constants.Num32BitValues = 4;
param[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
param[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
param[1].DescriptorTable.NumDescriptorRanges = 2;
param[1].DescriptorTable.pDescriptorRanges = ranges;
param[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
D3D12_STATIC_SAMPLER_DESC samp{};
samp.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
samp.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
samp.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
samp.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
samp.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER;
samp.MaxLOD = D3D12_FLOAT32_MAX;
samp.ShaderRegister = 0;
samp.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
D3D12_ROOT_SIGNATURE_DESC desc{};
desc.NumParameters = 2;
desc.pParameters = param;
desc.NumStaticSamplers = 1;
desc.pStaticSamplers = &samp;
desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_NONE;
ID3DBlob* ser = nullptr;
if (FAILED(D3D12SerializeRootSignature(&desc, D3D_ROOT_SIGNATURE_VERSION_1, &ser, nullptr)))
return false;
const HRESULT hr = dev->CreateRootSignature(0, ser->GetBufferPointer(), ser->GetBufferSize(), IID_PPV_ARGS(outRs));
ser->Release();
return SUCCEEDED(hr);
}
static bool CreatePso(ID3D12Device* dev, ID3D12RootSignature* rs, ID3DBlob* vs, ID3DBlob* ps, ID3D12PipelineState** outPso) {
D3D12_GRAPHICS_PIPELINE_STATE_DESC pso{};
pso.pRootSignature = rs;
pso.VS = { vs->GetBufferPointer(), vs->GetBufferSize() };
pso.PS = { ps->GetBufferPointer(), ps->GetBufferSize() };
pso.BlendState.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
pso.SampleMask = UINT_MAX;
pso.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID;
pso.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;
pso.RasterizerState.DepthClipEnable = TRUE;
pso.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
pso.NumRenderTargets = 1;
pso.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
pso.SampleDesc.Count = 1;
pso.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
return SUCCEEDED(dev->CreateGraphicsPipelineState(&pso, IID_PPV_ARGS(outPso)));
}
static void Transition(ID3D12GraphicsCommandList* cmd, ID3D12Resource* res, D3D12_RESOURCE_STATES before, D3D12_RESOURCE_STATES after) {
D3D12_RESOURCE_BARRIER b{};
b.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
b.Transition.pResource = res;
b.Transition.StateBefore = before;
b.Transition.StateAfter = after;
b.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
cmd->ResourceBarrier(1, &b);
}
static void CreateSrvRtvForTexture(ID3D12Device* dev, ID3D12Resource* tex, D3D12_CPU_DESCRIPTOR_HANDLE srvCpu, D3D12_CPU_DESCRIPTOR_HANDLE rtvCpu, DXGI_FORMAT fmt) {
D3D12_SHADER_RESOURCE_VIEW_DESC srv{};
srv.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
srv.Format = fmt;
srv.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
srv.Texture2D.MipLevels = 1;
srv.Texture2D.MostDetailedMip = 0;
srv.Texture2D.PlaneSlice = 0;
srv.Texture2D.ResourceMinLODClamp = 0.0f;
dev->CreateShaderResourceView(tex, &srv, srvCpu);
D3D12_RENDER_TARGET_VIEW_DESC rtv{};
rtv.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
rtv.Format = fmt;
rtv.Texture2D.MipSlice = 0;
rtv.Texture2D.PlaneSlice = 0;
dev->CreateRenderTargetView(tex, &rtv, rtvCpu);
}
bool EnsureInitialized(ID3D12Device* incomingDevice) {
if (!incomingDevice)
return false;
if (shadersCompiledOk)
return true;
micaD3dDevice = incomingDevice;
// If a previous initialization attempt failed part-way, clear leftovers
// before trying again so we never overwrite and leak COM pointers.
ReleasePipelineAndSignatureObjects();
ID3DBlob* vsBlob = nullptr;
if (!Compile("vs_full", "vs_5_0", &vsBlob))
return false;
ID3DBlob *psDown = nullptr, *psBlur = nullptr, *psComp = nullptr;
if (!Compile("ps_down", "ps_5_0", &psDown) || !Compile("ps_blur", "ps_5_0", &psBlur) || !Compile("ps_comp", "ps_5_0", &psComp)) {
ReleaseShaderBlobs(vsBlob, psDown, psBlur, psComp);
return false;
}
if (!CreateRs1Srv(incomingDevice, &rootSignatureDownsample) || !CreateRs1Srv(incomingDevice, &rootSignatureBlur) || !CreateRs2Srv(incomingDevice, &rootSignatureComposite)) {
ReleaseShaderBlobs(vsBlob, psDown, psBlur, psComp);
SafeRelease(rootSignatureDownsample);
SafeRelease(rootSignatureBlur);
SafeRelease(rootSignatureComposite);
return false;
}
if (!CreatePso(incomingDevice, rootSignatureDownsample, vsBlob, psDown, &pipelineStateDownsample) || !CreatePso(incomingDevice, rootSignatureBlur, vsBlob, psBlur, &pipelineStateBlur) || !CreatePso(incomingDevice, rootSignatureComposite, vsBlob, psComp, &pipelineStateComposite)) {
ReleaseShaderBlobs(vsBlob, psDown, psBlur, psComp);
ReleasePipelineAndSignatureObjects();
return false;
}
ReleaseShaderBlobs(vsBlob, psDown, psBlur, psComp);
shadersCompiledOk = true;
SPDLOG_INFO("D3D12 Mica: shaders and PSOs initialized");
return true;
}
/// Scene copy + blur textures and their SRV/RTV heaps only. PSOs/root signatures stay valid across resize.
static void ReleaseMicaTextureResources() {
SafeRelease(sceneCopyTexture);
SafeRelease(blurTextureA);
SafeRelease(blurTextureB);
SafeRelease(srvHeap);
SafeRelease(rtvHeap);
micaTextureSizes = {};
cpuSrvScene = {};
cpuSrvBlurA = {};
cpuSrvBlurB = {};
cpuRtvA = {};
cpuRtvB = {};
gpuSrvScene = {};
gpuSrvBlurA = {};
gpuSrvBlurB = {};
sceneCopyResourceState = D3D12_RESOURCE_STATE_COMMON;
blurTextureAResourceState = D3D12_RESOURCE_STATE_COMMON;
blurTextureBResourceState = D3D12_RESOURCE_STATE_COMMON;
}
void ReleaseGpuResources() {
ReleasePipelineAndSignatureObjects();
ReleaseMicaTextureResources();
shadersCompiledOk = false;
}
static bool EnsureTextures(ID3D12Device* dev, UINT widthPx, UINT heightPx) {
if (widthPx == 0 || heightPx == 0)
return false;
const UINT blurWidthPx = (widthPx + 1) / 2;
const UINT blurHeightPx = (heightPx + 1) / 2;
if (sceneCopyTexture && micaTextureSizes.width == widthPx && micaTextureSizes.height == heightPx)
return true;
// Do not call ReleaseGpuResources() here: that drops PSOs/root signatures and clears shadersCompiledOk,
// but this path only rebuilds size-dependent resources. Pipelines are independent of texture dimensions.
ReleaseMicaTextureResources();
D3D12_HEAP_PROPERTIES heapDefault{};
heapDefault.Type = D3D12_HEAP_TYPE_DEFAULT;
heapDefault.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
heapDefault.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
heapDefault.CreationNodeMask = 1;
heapDefault.VisibleNodeMask = 1;
auto makeBlurTex = [&](UINT textureWidth, UINT textureHeight, ID3D12Resource** out) {
D3D12_RESOURCE_DESC td{};
td.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
td.Width = textureWidth;
td.Height = textureHeight;
td.DepthOrArraySize = 1;
td.MipLevels = 1;
td.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
td.SampleDesc.Count = 1;
td.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
td.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
return SUCCEEDED(dev->CreateCommittedResource(&heapDefault, D3D12_HEAP_FLAG_NONE, &td, D3D12_RESOURCE_STATE_COMMON, nullptr, IID_PPV_ARGS(out)));
};
D3D12_RESOURCE_DESC tdScene{};
tdScene.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
tdScene.Width = widthPx;
tdScene.Height = heightPx;
tdScene.DepthOrArraySize = 1;
tdScene.MipLevels = 1;
tdScene.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
tdScene.SampleDesc.Count = 1;
tdScene.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
tdScene.Flags = D3D12_RESOURCE_FLAG_NONE;
if (FAILED(dev->CreateCommittedResource(&heapDefault, D3D12_HEAP_FLAG_NONE, &tdScene, D3D12_RESOURCE_STATE_COMMON, nullptr, IID_PPV_ARGS(&sceneCopyTexture))))
return false;
if (!makeBlurTex(blurWidthPx, blurHeightPx, &blurTextureA))
return false;
if (!makeBlurTex(blurWidthPx, blurHeightPx, &blurTextureB))
return false;
srvDescriptorStride = dev->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
rtvDescriptorStride = dev->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
D3D12_DESCRIPTOR_HEAP_DESC srvDesc{};
srvDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
srvDesc.NumDescriptors = 4;
srvDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
srvDesc.NodeMask = 1;
if (FAILED(dev->CreateDescriptorHeap(&srvDesc, IID_PPV_ARGS(&srvHeap))))
return false;
D3D12_DESCRIPTOR_HEAP_DESC rtvDesc{};
rtvDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
rtvDesc.NumDescriptors = 2;
rtvDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
rtvDesc.NodeMask = 1;
if (FAILED(dev->CreateDescriptorHeap(&rtvDesc, IID_PPV_ARGS(&rtvHeap))))
return false;
cpuSrvScene = srvHeap->GetCPUDescriptorHandleForHeapStart();
cpuSrvBlurA = cpuSrvScene;
cpuSrvBlurA.ptr += static_cast<SIZE_T>(srvDescriptorStride);
cpuSrvBlurB = cpuSrvBlurA;
cpuSrvBlurB.ptr += static_cast<SIZE_T>(srvDescriptorStride);
gpuSrvScene = srvHeap->GetGPUDescriptorHandleForHeapStart();
gpuSrvBlurA = gpuSrvScene;
gpuSrvBlurA.ptr += static_cast<UINT64>(srvDescriptorStride);
gpuSrvBlurB = gpuSrvBlurA;
gpuSrvBlurB.ptr += static_cast<UINT64>(srvDescriptorStride);
cpuRtvA = rtvHeap->GetCPUDescriptorHandleForHeapStart();
cpuRtvB = cpuRtvA;
cpuRtvB.ptr += static_cast<SIZE_T>(rtvDescriptorStride);
CreateSrvRtvForTexture(dev, blurTextureA, cpuSrvBlurA, cpuRtvA, DXGI_FORMAT_R8G8B8A8_UNORM);
CreateSrvRtvForTexture(dev, blurTextureB, cpuSrvBlurB, cpuRtvB, DXGI_FORMAT_R8G8B8A8_UNORM);
D3D12_SHADER_RESOURCE_VIEW_DESC srvScene{};
srvScene.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
srvScene.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
srvScene.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
srvScene.Texture2D.MipLevels = 1;
dev->CreateShaderResourceView(sceneCopyTexture, &srvScene, cpuSrvScene);
micaTextureSizes.width = widthPx;
micaTextureSizes.height = heightPx;
micaTextureSizes.blurWidth = blurWidthPx;
micaTextureSizes.blurHeight = blurHeightPx;
return true;
}
void RenderBackdrop(ID3D12GraphicsCommandList* cmdList, ID3D12Resource* backBuffer, const D3D12_CPU_DESCRIPTOR_HANDLE& backBufferRtv, UINT fullWidth, UINT fullHeight, float menuMinX, float menuMinY,
float menuMaxX, float menuMaxY, float backdropStrength) {
if (!shadersCompiledOk || !cmdList || !backBuffer || fullWidth == 0 || fullHeight == 0)
return;
if (backdropStrength < 0.02f)
return;
if (menuMaxX <= menuMinX + 2.0f || menuMaxY <= menuMinY + 2.0f)
return;
ID3D12Device* dev = micaD3dDevice;
if (!dev)
return;
if (!EnsureTextures(dev, fullWidth, fullHeight))
return;
const float mx0 = std::max(0.0f, menuMinX);
const float my0 = std::max(0.0f, menuMinY);
const float mx1 = std::min(static_cast<float>(fullWidth), menuMaxX);
const float my1 = std::min(static_cast<float>(fullHeight), menuMaxY);
if (mx1 <= mx0 + 1.0f || my1 <= my0 + 1.0f)
return;
const LONG scL = static_cast<LONG>(mx0);
const LONG scT = static_cast<LONG>(my0);
const LONG scR = static_cast<LONG>(std::ceil(mx1));
const LONG scB = static_cast<LONG>(std::ceil(my1));
Transition(cmdList, sceneCopyTexture, sceneCopyResourceState, D3D12_RESOURCE_STATE_COPY_DEST);
sceneCopyResourceState = D3D12_RESOURCE_STATE_COPY_DEST;
Transition(cmdList, backBuffer, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
cmdList->CopyResource(sceneCopyTexture, backBuffer);
Transition(cmdList, backBuffer, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
Transition(cmdList, sceneCopyTexture, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
sceneCopyResourceState = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
Transition(cmdList, blurTextureA, blurTextureAResourceState, D3D12_RESOURCE_STATE_RENDER_TARGET);
blurTextureAResourceState = D3D12_RESOURCE_STATE_RENDER_TARGET;
D3D12_VIEWPORT vpBlur{};
vpBlur.Width = static_cast<float>(micaTextureSizes.blurWidth);
vpBlur.Height = static_cast<float>(micaTextureSizes.blurHeight);
vpBlur.MinDepth = 0.0f;
vpBlur.MaxDepth = 1.0f;
D3D12_RECT rectBlur{ 0, 0, static_cast<LONG>(micaTextureSizes.blurWidth), static_cast<LONG>(micaTextureSizes.blurHeight) };
const float clearC[4] = { 0, 0, 0, 0 };
cmdList->RSSetViewports(1, &vpBlur);
cmdList->RSSetScissorRects(1, &rectBlur);
cmdList->OMSetRenderTargets(1, &cpuRtvA, FALSE, nullptr);
cmdList->ClearRenderTargetView(cpuRtvA, clearC, 0, nullptr);
ID3D12DescriptorHeap* heaps[] = { srvHeap };
cmdList->SetDescriptorHeaps(1, heaps);
cmdList->SetGraphicsRootSignature(rootSignatureDownsample);
cmdList->SetPipelineState(pipelineStateDownsample);
float downC[4] = { static_cast<float>(fullWidth), static_cast<float>(fullHeight), 0, 0 };
cmdList->SetGraphicsRoot32BitConstants(0, 4, downC, 0);
cmdList->SetGraphicsRootDescriptorTable(1, gpuSrvScene);
cmdList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
cmdList->DrawInstanced(3, 1, 0, 0);
Transition(cmdList, blurTextureA, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
blurTextureAResourceState = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
const float invW = 1.0f / static_cast<float>(micaTextureSizes.blurWidth);
const float invH = 1.0f / static_cast<float>(micaTextureSizes.blurHeight);
auto blurPass = [&](D3D12_GPU_DESCRIPTOR_HANDLE srcGpuSrv, D3D12_CPU_DESCRIPTOR_HANDLE dstRtv, ID3D12Resource* dstRes, D3D12_RESOURCE_STATES& dstState, float dirX, float dirY) {
Transition(cmdList, dstRes, dstState, D3D12_RESOURCE_STATE_RENDER_TARGET);
dstState = D3D12_RESOURCE_STATE_RENDER_TARGET;
cmdList->OMSetRenderTargets(1, &dstRtv, FALSE, nullptr);
cmdList->ClearRenderTargetView(dstRtv, clearC, 0, nullptr);
cmdList->SetGraphicsRootSignature(rootSignatureBlur);
cmdList->SetPipelineState(pipelineStateBlur);
float bp[4] = { invW, invH, dirX, dirY };
cmdList->SetGraphicsRoot32BitConstants(0, 4, bp, 0);
cmdList->SetGraphicsRootDescriptorTable(1, srcGpuSrv);
cmdList->DrawInstanced(3, 1, 0, 0);
Transition(cmdList, dstRes, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
dstState = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
};
blurPass(gpuSrvBlurA, cpuRtvB, blurTextureB, blurTextureBResourceState, 1.0f, 0.0f);
blurPass(gpuSrvBlurB, cpuRtvA, blurTextureA, blurTextureAResourceState, 0.0f, 1.0f);
blurPass(gpuSrvBlurA, cpuRtvB, blurTextureB, blurTextureBResourceState, 1.0f, 0.0f);
blurPass(gpuSrvBlurB, cpuRtvA, blurTextureA, blurTextureAResourceState, 0.0f, 1.0f);
D3D12_VIEWPORT vpFull{};
vpFull.Width = static_cast<float>(fullWidth);
vpFull.Height = static_cast<float>(fullHeight);
vpFull.MinDepth = 0.0f;
vpFull.MaxDepth = 1.0f;
D3D12_RECT scMenu{ scL, scT, scR, scB };
cmdList->RSSetViewports(1, &vpFull);
cmdList->RSSetScissorRects(1, &scMenu);
cmdList->OMSetRenderTargets(1, &backBufferRtv, FALSE, nullptr);
cmdList->SetDescriptorHeaps(1, heaps);
cmdList->SetGraphicsRootSignature(rootSignatureComposite);
cmdList->SetPipelineState(pipelineStateComposite);
float compC[4] = { static_cast<float>(fullWidth), static_cast<float>(fullHeight), 0.92f, backdropStrength };
cmdList->SetGraphicsRoot32BitConstants(0, 4, compC, 0);
cmdList->SetGraphicsRootDescriptorTable(1, gpuSrvScene);
cmdList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
cmdList->DrawInstanced(3, 1, 0, 0);
}
}
+30 -1
View File
@@ -4,6 +4,7 @@
#include <dxgi1_4.h>
#include <d3d12.h>
#include <spdlog\spdlog.h>
#include <ImGui\imgui.h>
#include <ImGui\backends\imgui_impl_dx12.h>
#include <ImGui\backends\imgui_impl_win32.h>
#include <EGSDK\Utils\Memory.h>
@@ -13,6 +14,7 @@
#include <EGT\ImGui_impl\NextFrameTask.h>
#include <EGT\Menu\Menu.h>
#include <EGT\Menu\Init.h>
#include <EGT\ImGui_impl\D3D12_MicaBlur.h>
namespace EGT::ImGui_impl {
namespace D3D12 {
@@ -47,6 +49,7 @@ namespace EGT::ImGui_impl {
}
}
static void CleanupRenderTarget() {
D3D12_MicaBlur::ReleaseGpuResources();
if (!frameContext)
return;
@@ -123,6 +126,8 @@ namespace EGT::ImGui_impl {
Menu::InitImGui();
ImGui_ImplDX12_InvalidateDeviceObjects();
D3D12_MicaBlur::EnsureInitialized(d3d12Device);
init = true;
}
}
@@ -134,12 +139,14 @@ namespace EGT::ImGui_impl {
if (!d3d12CommandQueue || !frameContext[0].main_render_target_resource)
return;
Menu::SyncMenuFontsBeforeImGuiNewFrame();
ImGui_ImplDX12_NewFrame();
ImGui_ImplWin32_NewFrame();
Menu::UpdateMenuVisibilityAnimFromPoll();
ImGui::NewFrame();
Menu::FirstTimeRunning();
if (Menu::menuToggle.GetValue())
if (Menu::MenuAnimNeedsFrame())
Menu::Render();
ImGui::Render();
@@ -162,6 +169,28 @@ namespace EGT::ImGui_impl {
d3d12CommandList->ResourceBarrier(1, &barrier);
d3d12CommandList->OMSetRenderTargets(1, &frameContext[backBufferIdx].main_render_target_descriptor, FALSE, NULL);
{
float mx0 = 0.0f, my0 = 0.0f, mx1 = 0.0f, my1 = 0.0f;
if (Menu::GetMenuBackdropRectPx(&mx0, &my0, &mx1, &my1)) {
D3D12_MicaBlur::EnsureInitialized(d3d12Device);
DXGI_SWAP_CHAIN_DESC scd{};
pSwapChain->GetDesc(&scd);
const UINT bbW = scd.BufferDesc.Width;
const UINT bbH = scd.BufferDesc.Height;
const ImGuiIO& io = ImGui::GetIO();
const float dsx = io.DisplaySize.x > 1.0f ? io.DisplaySize.x : 1.0f;
const float dsy = io.DisplaySize.y > 1.0f ? io.DisplaySize.y : 1.0f;
const float sx = static_cast<float>(bbW) / dsx;
const float sy = static_cast<float>(bbH) / dsy;
mx0 *= sx;
mx1 *= sx;
my0 *= sy;
my1 *= sy;
D3D12_MicaBlur::RenderBackdrop(d3d12CommandList, frameContext[backBufferIdx].main_render_target_resource, frameContext[backBufferIdx].main_render_target_descriptor, bbW, bbH, mx0, my0, mx1, my1, Menu::GetMicaBackdropFade());
}
}
d3d12CommandList->SetDescriptorHeaps(1, &d3d12DescriptorHeapImGuiRender);
ImGui_ImplDX12_RenderDrawData(ImGui::GetDrawData(), d3d12CommandList);
+9 -19
View File
@@ -10,7 +10,6 @@
#include <EGSDK\GamePH\GamePH_Misc.h>
#include <EGSDK\Offsets.h>
#include <EGT\Menu\Camera.h>
#include <EGT\Menu\Menu.h>
namespace EGT::Menu {
namespace Camera {
@@ -315,7 +314,7 @@ namespace EGT::Menu {
HandleToggles();
}
void Tab::Render() {
ImGui::SeparatorText("First Person Camera");
ImGui::SeparatorTextSection("First Person Camera", false);
auto pCVideoSettings = EGSDK::Engine::CVideoSettings::Get();
ImGui::BeginDisabled(!pCVideoSettings || EGSDK::Utils::Values::are_samef(baseFOV, 0.0f) || goProMode.GetValue() || isZoomingIn);
if (ImGui::SliderFloat("FOV##FirstPerson", "First person camera field of view", &firstPersonFOV, 20.0f, 160.0f, "%.0f") && pCVideoSettings)
@@ -324,18 +323,14 @@ namespace EGT::Menu {
firstPersonFOV = pCVideoSettings->extraFOV + baseFOV;
ImGui::EndDisabled();
ImGui::BeginDisabled(freeCam.GetChangesAreDisabled());
ImGui::SetNextItemWidth(400.0f * Menu::scale);
ImGui::SliderFloat3("Camera Offset (XYZ)", reinterpret_cast<float*>(&cameraOffset), -0.5f, 0.5f, "%.2fm");
ImGui::SliderFloat3Stacked("Camera Offset (XYZ)", reinterpret_cast<float*>(&cameraOffset), -0.5f, 0.5f, "%.2fm");
ImGui::EndDisabled();
ImGui::CheckboxHotkey("Zoom In", &firstPersonZoomIn, "Allows zooming in with the specified hotkey and changing zoom level with the mouse wheel");
ImGui::SeparatorText("Third Person Camera");
ImGui::SeparatorTextSection("Third Person Camera");
ImGui::BeginDisabled(thirdPersonCamera.GetChangesAreDisabled());
ImGui::CheckboxHotkey("Enabled##ThirdPerson", &thirdPersonCamera, "Enables the third person camera");
ImGui::EndDisabled();
ImGui::SameLine();
ImGui::BeginDisabled(tpUseTPPModel.GetChangesAreDisabled());
ImGui::CheckboxHotkey("Use Third Person Player (TPP) Model", &tpUseTPPModel, "Uses Aiden's TPP (Third Person Player) model while the third person camera is enabled");
ImGui::EndDisabled();
@@ -343,17 +338,14 @@ namespace EGT::Menu {
ImGui::BeginDisabled(EGSDK::Utils::Values::are_samef(baseFOV, 0.0f));
ImGui::SliderFloat("FOV##ThirdPerson", "Third person camera field of view", &thirdPersonFOV, 20.0f, 160.0f, "%.0f");
ImGui::EndDisabled();
ImGui::SliderFloat("Distance behind player", &thirdPersonDistanceBehindPlayer, 1.0f, 10.0f, "%.2fm");
ImGui::SliderFloat("Height above player", &thirdPersonHeightAbovePlayer, 1.0f, 3.0f, "%.2fm");
ImGui::SliderFloat("Horizontal distance from player", &thirdPersonHorizontalDistanceFromPlayer, -2.0f, 2.0f, "%.2fm");
ImGui::SliderFloatStacked("Distance behind player", &thirdPersonDistanceBehindPlayer, 1.0f, 10.0f, "%.2fm");
ImGui::SliderFloatStacked("Height above player", &thirdPersonHeightAbovePlayer, 1.0f, 3.0f, "%.2fm");
ImGui::SliderFloatStacked("Horizontal distance from player", &thirdPersonHorizontalDistanceFromPlayer, -2.0f, 2.0f, "%.2fm");
ImGui::SeparatorText("Free Camera");
ImGui::SeparatorTextSection("Free Camera");
ImGui::BeginDisabled(freeCam.GetChangesAreDisabled() || photoMode.GetValue());
ImGui::CheckboxHotkey("Enabled##FreeCam", &freeCam, "Enables free camera which allows you to travel anywhere with the camera");
ImGui::EndDisabled();
ImGui::SameLine();
ImGui::BeginDisabled(teleportPlayerToCamera.GetChangesAreDisabled());
ImGui::CheckboxHotkey("Teleport Player to Camera", &teleportPlayerToCamera, "Teleports the player to the camera while Free Camera is activated");
ImGui::EndDisabled();
@@ -361,18 +353,16 @@ namespace EGT::Menu {
ImGui::BeginDisabled(EGSDK::Utils::Values::are_samef(baseFOV, 0.0f));
ImGui::SliderFloat("FOV##FreeCam", "Free camera field of view", &freeCamFOV, 20.0f, 160.0f, "%.0f");
ImGui::EndDisabled();
ImGui::SliderFloat("Speed##FreeCam", &freeCamSpeed, 0.1f, 200.0f, "%.2fx", ImGuiSliderFlags_AlwaysClamp);
ImGui::SliderFloatStacked("Speed##FreeCam", &freeCamSpeed, 0.1f, 200.0f, "%.2fx", ImGuiSliderFlags_AlwaysClamp);
ImGui::SeparatorText("Misc");
ImGui::SeparatorTextSection("Misc");
ImGui::BeginDisabled(goProMode.GetValue());
ImGui::SliderFloat("Lens Distortion", "Default game value is 20%", goProMode.GetValue() ? &altLensDistortion : &lensDistortion, 0.0f, 100.0f, "%.1f%%");
ImGui::EndDisabled();
ImGui::CheckboxHotkey("GoPro Mode *", &goProMode, "Makes the camera behave similar to a GoPro mounted on the forehead");
ImGui::SameLine();
ImGui::CheckboxHotkey("Disable Safezone FOV Reduction", &disableSafezoneFOVReduction, "Disables the FOV reduction that happens while you're in a safezone");
ImGui::CheckboxHotkey("Disable Photo Mode Limits", &disablePhotoModeLimits, "Disables the invisible box while in Photo Mode");
ImGui::SameLine();
ImGui::CheckboxHotkey("Disable Head Correction", &disableHeadCorrection, "Disables centering of the player's hands to the center of the camera");
ImGui::Separator();
+15 -29
View File
@@ -73,7 +73,6 @@ namespace EGT::Menu {
#endif
static void RenderClassAddrPair(const std::pair<std::string_view, void*(*)()>* pair) {
const float maxInputTextWidth = ImGui::CalcTextSize("0x0000000000000000").x;
static std::string labelID{};
labelID = "##DebugAddrInputText" + std::string(pair->first);
@@ -86,15 +85,10 @@ namespace EGT::Menu {
static std::string addrString{};
addrString = ss.str();
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ((ImGui::GetFrameHeight() - ImGui::GetTextLineHeight()) / 2.0f));
ImGui::Text(pair->first.data());
ImGui::SameLine();
ImGui::SetCursorPosY(ImGui::GetCursorPosY() - ((ImGui::GetFrameHeight() - ImGui::GetTextLineHeight()) / 2.0f));
ImGui::SetNextItemWidth(maxInputTextWidth);
ImGui::TextUnformatted(pair->first.data(), pair->first.data() + pair->first.size());
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
ImGui::PushStyleColor(ImGuiCol_Text, pair->second() ? IM_COL32(0, 255, 0, 255) : IM_COL32(255, 0, 0, 255));
ImGui::InputText(labelID.c_str(), const_cast<char*>(addrString.c_str()), strlen(addrString.c_str()), ImGuiInputTextFlags_ReadOnly);
ImGui::InputText(labelID.c_str(), addrString.data(), addrString.size() + 1, ImGuiInputTextFlags_ReadOnly);
ImGui::PopStyleColor();
}
@@ -232,7 +226,6 @@ namespace EGT::Menu {
};
static void RenderHexPtrRow(const char* label, const void* ptr) {
const float maxInputTextWidth = ImGui::CalcTextSize("0x0000000000000000").x;
const std::string labelID = std::string("##InvDbgHex") + label;
std::stringstream ss{};
@@ -244,18 +237,14 @@ namespace EGT::Menu {
static std::string addrString{};
addrString = ss.str();
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ((ImGui::GetFrameHeight() - ImGui::GetTextLineHeight()) / 2.0f));
ImGui::Text("%s", label);
ImGui::SameLine();
ImGui::SetCursorPosY(ImGui::GetCursorPosY() - ((ImGui::GetFrameHeight() - ImGui::GetTextLineHeight()) / 2.0f));
ImGui::SetNextItemWidth(maxInputTextWidth);
ImGui::TextUnformatted(label);
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
ImGui::PushStyleColor(ImGuiCol_Text, ptr ? IM_COL32(0, 255, 0, 255) : IM_COL32(255, 0, 0, 255));
ImGui::InputText(labelID.c_str(), const_cast<char*>(addrString.c_str()), addrString.size() + 1, ImGuiInputTextFlags_ReadOnly);
ImGui::InputText(labelID.c_str(), addrString.data(), addrString.size() + 1, ImGuiInputTextFlags_ReadOnly);
ImGui::PopStyleColor();
}
static void RenderUnionFieldRow(const char* label, const char* classShortName, void* basePtr, uint64_t fieldOffset) {
const float maxInputTextWidth = ImGui::CalcTextSize("0x0000000000000000 -> TimeWeather\\CSystem+0xFFFFFFFF").x;
static std::string labelID{};
labelID = "##UnionFld" + std::string(label);
@@ -270,13 +259,10 @@ namespace EGT::Menu {
const ImU32 col = !basePtr ? IM_COL32(255, 0, 0, 255)
: (fieldOffset == 0 ? IM_COL32(255, 200, 0, 255) : IM_COL32(0, 255, 0, 255));
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ((ImGui::GetFrameHeight() - ImGui::GetTextLineHeight()) / 2.0f));
ImGui::Text("%s", label);
ImGui::SameLine();
ImGui::SetCursorPosY(ImGui::GetCursorPosY() - ((ImGui::GetFrameHeight() - ImGui::GetTextLineHeight()) / 2.0f));
ImGui::SetNextItemWidth(maxInputTextWidth);
ImGui::TextUnformatted(label);
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
ImGui::PushStyleColor(ImGuiCol_Text, col);
ImGui::InputText(labelID.c_str(), const_cast<char*>(line.c_str()), line.size() + 1, ImGuiInputTextFlags_ReadOnly);
ImGui::InputText(labelID.c_str(), line.data(), line.size() + 1, ImGuiInputTextFlags_ReadOnly);
ImGui::PopStyleColor();
}
@@ -304,7 +290,7 @@ namespace EGT::Menu {
RenderHexPtrRow("InventoryItem (GetCurrentWeapon(0))", invItem);
RenderHexPtrRow("ItemDescWithContext (GetItemDescCtx)", itemCtx);
ImGui::SeparatorText("ItemDescWithContext base offset##InvDbg");
ImGui::SeparatorTextSection("ItemDescWithContext base offset##InvDbg");
ImGui::TextUnformatted("SDK hardcodes InventoryItem+0x40 in InventoryItem.cpp; compare with GetItemDescCtx() after vtable checks.");
RenderHexPtrRow("InventoryItem + 0x40 (no vtable check)", itemCtxByFixedOffset);
if (invItem && itemCtx && itemCtxByFixedOffset != itemCtx) {
@@ -314,7 +300,7 @@ namespace EGT::Menu {
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(IM_COL32(0, 200, 100, 255)), "+0x40 matches GetItemDescCtx.");
}
ImGui::SeparatorText("Union fields (DynamicField)##InvDbg");
ImGui::SeparatorTextSection("Union fields (DynamicField)##InvDbg");
ImGui::PushID("InvDbgUnionRows");
RenderUnionFieldRow("InventoryMoney::oldWorldMoney", "InventoryMoney", invMoney,
EGSDK::OffsetManager::GetOffset(EGSDK::ClassHelpers::GetOffsetNameFromClassMember(&EGSDK::GamePH::InventoryMoney::oldWorldMoney)));
@@ -328,11 +314,11 @@ namespace EGT::Menu {
void Tab::Init() {}
void Tab::Update() {}
void Tab::Render() {
ImGui::SeparatorText("Misc##Debug");
ImGui::SeparatorTextSection("Misc##Debug", false);
if (ImGui::Checkbox("Disable Vftable Scanning", &disableVftableScanning, "Disables the vftable scanning for classes that are used in the game and used to validate a class in memory; this option is used for debugging purposes"))
EGSDK::ClassHelpers::SetIsVftableScanningDisabled(disableVftableScanning.GetValue());
ImGui::Checkbox("Enable Debugging Console *", &enableDebuggingConsole, "Enables EGameTools' debugging console that shows up when starting up the game; this option is used for debugging purposes");
ImGui::SeparatorText("Class addresses##Debug");
ImGui::SeparatorTextSection("Class addresses##Debug");
if (ImGui::CollapsingHeader("GamePH", ImGuiTreeNodeFlags_None)) {
ImGui::Indent();
for (auto& pair : GamePHClassAddrMap)
@@ -345,7 +331,7 @@ namespace EGT::Menu {
RenderClassAddrPair(&pair);
ImGui::Unindent();
}
ImGui::SeparatorText("Union field addresses (Class+offset)##Debug");
ImGui::SeparatorTextSection("Union field addresses (Class+offset)##Debug");
ImGui::TextUnformatted("Read-only: ClassName+field offset from OffsetManager (patterns) or compile-time StaticBuffer layout; when the instance exists, resolved address is appended.");
if (ImGui::CollapsingHeader("GamePH##UnionFields", ImGuiTreeNodeFlags_None)) {
ImGui::Indent();
@@ -357,7 +343,7 @@ namespace EGT::Menu {
RenderUnionFieldList(kEngineUnionFields);
ImGui::Unindent();
}
ImGui::SeparatorText("InventoryMoney / ItemDescWithContext (live)##Debug");
ImGui::SeparatorTextSection("InventoryMoney / ItemDescWithContext (live)##Debug");
if (ImGui::CollapsingHeader("Pointer chain & offset probe##InvDbg", ImGuiTreeNodeFlags_None)) {
ImGui::Indent();
RenderInventoryItemContextOffsetProbe();
+119 -72
View File
@@ -1,8 +1,12 @@
#include <cmath>
#include <filesystem>
#include <fstream>
#include <spdlog\spdlog.h>
#include <ImGui\backends\imgui_impl_dx11.h>
#include <ImGui\backends\imgui_impl_dx12.h>
#include <ImGui\imguiex.h>
#include <ImGui\misc\fonts\Ruda-Bold.embed>
#include <fonts\fa-solid-900-subset.embed>
#include <EGSDK\Core\Core.h>
#include <EGSDK\GamePH\GamePH_Misc.h>
#include <EGSDK\Utils\Files.h>
@@ -13,6 +17,51 @@
#include <EGT\Textures\EGTWhiteLogo.embed>
namespace EGT::Menu {
static ImFont* menuVersionFont = nullptr;
static float lastFontAtlasScale = -1.0f;
static void LoadMenuFontAtlas(float menuScale) {
ImGuiIO& io = ImGui::GetIO();
const float menuFontSize = (12.0f + 6.0f) * menuScale;
io.Fonts->Clear();
menuVersionFont = nullptr;
ImFontConfig fontConfig{};
fontConfig.FontDataOwnedByAtlas = false;
io.FontDefault = io.Fonts->AddFontFromMemoryTTF((void*)fontRudaBold, sizeof(fontRudaBold), menuFontSize, &fontConfig);
ImFontConfig iconsConfig{};
iconsConfig.MergeMode = true;
iconsConfig.FontDataOwnedByAtlas = false;
iconsConfig.PixelSnapH = true;
iconsConfig.GlyphMinAdvanceX = menuFontSize * 0.92f;
iconsConfig.GlyphOffset = ImVec2(0.0f, 2.0f);
static const ImWchar iconRanges[] = { 0xE19B, 0xE19B, 0xF007, 0xF188, 0 };
io.Fonts->AddFontFromMemoryTTF((void*)fontAwesomeSolidSubset, sizeof(fontAwesomeSolidSubset), menuFontSize, &iconsConfig, iconRanges);
ImFontConfig verCfg{};
verCfg.FontDataOwnedByAtlas = false;
menuVersionFont = io.Fonts->AddFontFromMemoryTTF((void*)fontRudaBold, sizeof(fontRudaBold), menuFontSize * 1.25f, &verCfg);
io.Fonts->Build();
}
void SyncMenuFontsBeforeImGuiNewFrame() {
if (std::fabs(static_cast<double>(scale - lastFontAtlasScale)) < 1.0e-4)
return;
lastFontAtlasScale = scale;
LoadMenuFontAtlas(scale);
if (EGSDK::Core::rendererAPI == 11)
ImGui_ImplDX11_InvalidateDeviceObjects();
else if (EGSDK::Core::rendererAPI == 12)
ImGui_ImplDX12_InvalidateDeviceObjects();
}
ImFont* MenuVersionFont() {
return menuVersionFont ? menuVersionFont : ImGui::GetFont();
}
static std::string welcomeTitle{};
static std::string changelogTitle{};
@@ -70,23 +119,19 @@ namespace EGT::Menu {
ImGui::Spacing(ImVec2(0.0f, 5.0f));
ImGui::TextCentered("I will not bore you with what this mod is about, so let's get right to teaching you how to use it!");
ImGui::SeparatorTextColored("Menu Toggle", IM_COL32(200, 0, 0, 255));
ImGui::NewLine();
ImGui::SeparatorTextSection("Menu Toggle", false);
ImGui::TextCentered("The default key for opening/closing the menu is F5. You can use your mouse to navigate the menu.");
ImGui::TextCentered("To change it, you can open up the menu and change the hotkey by clicking the hotkey button for \"Menu Toggle Key\" and then pressing a key on your keyboard.");
ImGui::SeparatorTextColored("FreeCam", IM_COL32(200, 0, 0, 255));
ImGui::NewLine();
ImGui::SeparatorTextSection("FreeCam");
ImGui::TextCentered("While using FreeCam, you can press Shift or Alt to boost your speed or slow you down respectively.");
ImGui::TextCentered("You can also use the scroll wheel to change FreeCam speed while FreeCam is enabled.");
ImGui::SeparatorTextColored("Menu Sliders", IM_COL32(200, 0, 0, 255));
ImGui::NewLine();
ImGui::SeparatorTextSection("Menu Sliders");
ImGui::TextCentered("To manually change the value of a slider option, hold \"CTRL\" while clicking the slider.");
ImGui::TextCentered("This will let you input a value manually into the slider, which can also go beyond the option's slider limit, given I allow the option to do so.");
ImGui::SeparatorTextColored("Custom File Loading", IM_COL32(200, 0, 0, 255));
ImGui::NewLine();
ImGui::SeparatorTextSection("Custom File Loading");
ImGui::TextCentered("The mod always creates a folder \"EGameTools\\UserModFiles\" inside the same folder as the game executable (exe) or in the same folder as the mod file.");
ImGui::TextCentered("This folder is used for custom file loading. It can load .PAKs and it can also load files extracted from these .PAKs. The latter has only been tested with a few mods that change some .scr files, .gpufx files, and other files included inside .PAK game archives, or files such as .rpack files.");
ImGui::TextCentered("If you put .PAKs inside this folder, they can be named whatever. If you put any other kind of files, they must have the same names as the ones from the game files, otherwise the game won't know it should load those files. Files in subfolders of the \"EGameTools\\UserModFiles\" folder will automatically be detected, so you can sort all your mods in different folders!");
@@ -106,17 +151,14 @@ namespace EGT::Menu {
ImGui::Spacing(ImVec2(0.0f, 5.0f));
ImGui::TextCentered("If you want to officially include one of your mods as part of EGameTools, please contact me on NexusMods or on Discord (@EricPlayZ).");
ImGui::SeparatorTextColored("Game Variables Reloading", IM_COL32(200, 0, 0, 255));
ImGui::NewLine();
ImGui::SeparatorTextSection("Game Variables Reloading");
ImGui::TextCentered("You can also reload Player Variables from a file specified by you, or reload Jump Parameters from \"EGameTools\\UserModFiles\".");
ImGui::SeparatorTextColored("Hotkeys", IM_COL32(200, 0, 0, 255));
ImGui::NewLine();
ImGui::SeparatorTextSection("Hotkeys");
ImGui::TextCentered("Most mod menu options are toggleable by a hotkey that you can change by clicking the hotkey button for the respective option and then pressing a key on your keyboard.");
ImGui::TextCentered("To change those hotkeys through the config file, visit the \"Virtual-Key Codes\" page from Microsoft which contains a list of all virtual key codes. Simply write the name of the keycode you want to use for each hotkey and save the config file.");
ImGui::SeparatorTextColored("Config", IM_COL32(200, 0, 0, 255));
ImGui::NewLine();
ImGui::SeparatorTextSection("Config");
ImGui::TextCentered("A config file \"EGameTools.ini\" is stored in the same folder as the game executable (exe) or in the same folder as the mod file.");
ImGui::TextCentered("The config file stores the mod menu's options and hotkeys.");
@@ -126,12 +168,10 @@ namespace EGT::Menu {
ImGui::TextCentered("You DO NOT NEED to restart the game for the changes in the config to be applied!");
ImGui::TextCentered("If you want to regenerate the config file, delete it and it will automatically be regenerated.");
ImGui::SeparatorTextColored("Logging", IM_COL32(200, 0, 0, 255));
ImGui::NewLine();
ImGui::SeparatorTextSection("Logging");
ImGui::TextCentered("Log files will be stored in the EGameTools folder as \"log.x.txt\", x being the number of the previous log file. The most recent log file will be called \"log.txt\".");
ImGui::SeparatorTextColored("Multiplayer", IM_COL32(200, 0, 0, 255));
ImGui::NewLine();
ImGui::SeparatorTextSection("Multiplayer");
ImGui::TextCentered("Currently, this mod has been designed with singleplayer in mind. That means certain features might glitch out or completely stop working in multiplayer.");
ImGui::TextCentered("If that happens, please open a bug report!");
@@ -191,8 +231,7 @@ namespace EGT::Menu {
return;
}
ImGui::StyleScaleAllSizes(&ImGui::GetStyle(), scale, &defStyle);
ImGui::GetIO().FontGlobalScale = scale;
PushScaledMenuStyles();
minWndSize = defMinWndSize * scale;
maxWndSize = defMaxWndSize * scale;
@@ -223,69 +262,77 @@ namespace EGT::Menu {
ImGuiStyle* style = &ImGui::GetStyle();
style->WindowTitleAlign = ImVec2(0.5f, 0.5f);
style->WindowPadding = ImVec2(13, 13);
style->WindowRounding = 5.0f;
style->ChildRounding = 4.0f;
style->FramePadding = ImVec2(4, 4);
style->FrameRounding = 4.0f;
style->ItemSpacing = ImVec2(10, 6);
style->WindowPadding = ImVec2(16, 14);
style->WindowRounding = 12.0f;
style->ChildRounding = 10.0f;
style->ChildBorderSize = 1.0f;
style->FramePadding = ImVec2(8, 5);
style->FrameRounding = 8.0f;
style->TabRounding = 8.0f;
style->ItemSpacing = ImVec2(10, 8);
style->ItemInnerSpacing = ImVec2(8, 6);
style->IndentSpacing = 25.0f;
style->ScrollbarSize = 15.0f;
style->ScrollbarRounding = 9.0f;
style->GrabMinSize = 5.0f;
style->GrabRounding = 3.0f;
style->ScrollbarSize = 14.0f;
style->ScrollbarRounding = 11.0f;
style->GrabMinSize = 6.0f;
style->GrabRounding = 5.0f;
style->Colors[ImGuiCol_Text] = ImVec4(0.80f, 0.80f, 0.83f, 1.00f);
style->Colors[ImGuiCol_TextDisabled] = ImVec4(0.24f, 0.23f, 0.29f, 1.00f);
style->Colors[ImGuiCol_WindowBg] = ImVec4(0.06f, 0.05f, 0.07f, 1.00f);
style->Colors[ImGuiCol_ChildBg] = ImVec4(0.07f, 0.07f, 0.09f, 1.00f);
style->Colors[ImGuiCol_PopupBg] = ImVec4(0.07f, 0.07f, 0.09f, 1.00f);
style->Colors[ImGuiCol_Border] = ImVec4(0.80f, 0.80f, 0.83f, 0.88f);
// Cool gray chrome; accents = orange-red / blood red (blue kept below green so nothing reads magenta).
style->Colors[ImGuiCol_Text] = ImVec4(0.94f, 0.95f, 0.98f, 1.00f);
style->Colors[ImGuiCol_TextDisabled] = ImVec4(0.48f, 0.50f, 0.58f, 1.00f);
style->Colors[ImGuiCol_WindowBg] = ImVec4(0.060f, 0.065f, 0.100f, 1.00f);
style->Colors[ImGuiCol_ChildBg] = ImVec4(0.078f, 0.082f, 0.118f, 0.50f);
style->Colors[ImGuiCol_PopupBg] = ImVec4(0.078f, 0.082f, 0.118f, 0.72f);
style->Colors[ImGuiCol_Border] = ImVec4(0.30f, 0.31f, 0.38f, 0.40f);
style->Colors[ImGuiCol_BorderShadow] = ImVec4(0.92f, 0.91f, 0.88f, 0.00f);
style->Colors[ImGuiCol_FrameBg] = ImVec4(0.10f, 0.09f, 0.12f, 1.00f);
style->Colors[ImGuiCol_FrameBgHovered] = ImVec4(0.24f, 0.23f, 0.29f, 1.00f);
style->Colors[ImGuiCol_FrameBgActive] = ImVec4(0.4705f, 0.0784f, 0.1176f, 1.00f);
style->Colors[ImGuiCol_TitleBg] = ImVec4(0.10f, 0.09f, 0.12f, 1.00f);
style->Colors[ImGuiCol_TitleBgCollapsed] = ImVec4(1.00f, 0.98f, 0.95f, 0.75f);
style->Colors[ImGuiCol_TitleBgActive] = ImVec4(0.07f, 0.07f, 0.09f, 1.00f);
style->Colors[ImGuiCol_MenuBarBg] = ImVec4(0.13f, 0.12f, 0.15f, 1.00f);
style->Colors[ImGuiCol_ScrollbarBg] = ImVec4(0.10f, 0.09f, 0.12f, 1.00f);
style->Colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.5882f, 0.0784f, 0.1176f, 1.00f);
style->Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(1.0f, 0.0784f, 0.1176f, 1.00f);
style->Colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.4705f, 0.0784f, 0.1176f, 1.00f);
style->Colors[ImGuiCol_CheckMark] = ImVec4(1.0f, 0.0784f, 0.1176f, 1.00f);
style->Colors[ImGuiCol_SliderGrab] = ImVec4(1.0f, 0.0784f, 0.1176f, 1.00f);
style->Colors[ImGuiCol_SliderGrabActive] = ImVec4(1.0f, 0.0784f, 0.1176f, 1.00f);
style->Colors[ImGuiCol_Button] = ImVec4(0.10f, 0.09f, 0.12f, 1.00f);
style->Colors[ImGuiCol_ButtonHovered] = ImVec4(1.0f, 0.0784f, 0.1176f, 1.00f);
style->Colors[ImGuiCol_ButtonActive] = ImVec4(0.4705f, 0.0784f, 0.1176f, 1.00f);
style->Colors[ImGuiCol_Header] = ImVec4(0.5882f, 0.0784f, 0.1176f, 1.00f);
style->Colors[ImGuiCol_HeaderHovered] = ImVec4(1.0f, 0.0784f, 0.1176f, 1.00f);
style->Colors[ImGuiCol_HeaderActive] = ImVec4(0.4705f, 0.0784f, 0.1176f, 1.00f);
style->Colors[ImGuiCol_Tab] = ImVec4(0.5882f, 0.0784f, 0.1176f, 1.00f);
style->Colors[ImGuiCol_TabHovered] = ImVec4(0.4705f, 0.0784f, 0.1176f, 1.00f);
style->Colors[ImGuiCol_TabActive] = ImVec4(1.0f, 0.0784f, 0.1176f, 1.00f);
style->Colors[ImGuiCol_FrameBg] = ImVec4(0.11f, 0.10f, 0.145f, 0.70f);
style->Colors[ImGuiCol_FrameBgHovered] = ImVec4(0.22f, 0.17f, 0.16f, 0.85f);
style->Colors[ImGuiCol_FrameBgActive] = ImVec4(0.34f, 0.10f, 0.07f, 1.00f);
style->Colors[ImGuiCol_TitleBg] = ImVec4(0.078f, 0.082f, 0.118f, 1.00f);
style->Colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.060f, 0.065f, 0.100f, 0.92f);
style->Colors[ImGuiCol_TitleBgActive] = ImVec4(0.050f, 0.055f, 0.090f, 1.00f);
style->Colors[ImGuiCol_MenuBarBg] = ImVec4(0.085f, 0.080f, 0.120f, 1.00f);
style->Colors[ImGuiCol_ScrollbarBg] = ImVec4(0.060f, 0.058f, 0.090f, 1.00f);
style->Colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.72f, 0.12f, 0.06f, 1.00f);
style->Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(1.00f, 0.30f, 0.08f, 1.00f);
style->Colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.48f, 0.08f, 0.03f, 1.00f);
style->Colors[ImGuiCol_CheckMark] = ImVec4(0.98f, 0.28f, 0.06f, 1.00f);
style->Colors[ImGuiCol_SliderGrab] = ImVec4(0.98f, 0.26f, 0.05f, 1.00f);
style->Colors[ImGuiCol_SliderGrabActive] = ImVec4(0.62f, 0.12f, 0.03f, 1.00f);
style->Colors[ImGuiCol_Button] = ImVec4(0.11f, 0.10f, 0.145f, 1.00f);
style->Colors[ImGuiCol_ButtonHovered] = ImVec4(0.92f, 0.26f, 0.08f, 1.00f);
style->Colors[ImGuiCol_ButtonActive] = ImVec4(0.26f, 0.09f, 0.06f, 1.00f);
style->Colors[ImGuiCol_Header] = ImVec4(0.10f, 0.11f, 0.15f, 1.00f);
style->Colors[ImGuiCol_HeaderHovered] = ImVec4(0.16f, 0.12f, 0.17f, 1.00f);
style->Colors[ImGuiCol_HeaderActive] = ImVec4(0.13f, 0.10f, 0.14f, 1.00f);
style->Colors[ImGuiCol_Tab] = ImVec4(0.10f, 0.11f, 0.15f, 1.00f);
style->Colors[ImGuiCol_TabHovered] = ImVec4(0.48f, 0.14f, 0.08f, 1.00f);
style->Colors[ImGuiCol_TabActive] = ImVec4(0.14f, 0.13f, 0.19f, 1.00f);
style->Colors[ImGuiCol_TabUnfocused] = ImVec4(0.08f, 0.08f, 0.12f, 1.00f);
style->Colors[ImGuiCol_TabUnfocusedActive] = ImVec4(0.18f, 0.13f, 0.16f, 1.00f);
style->Colors[ImGuiCol_Separator] = ImVec4(0.28f, 0.28f, 0.32f, 0.50f);
style->Colors[ImGuiCol_SeparatorHovered] = ImVec4(0.78f, 0.20f, 0.08f, 0.55f);
style->Colors[ImGuiCol_SeparatorActive] = ImVec4(0.95f, 0.28f, 0.10f, 0.72f);
style->Colors[ImGuiCol_ResizeGrip] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
style->Colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.56f, 0.56f, 0.58f, 1.00f);
style->Colors[ImGuiCol_ResizeGripActive] = ImVec4(0.06f, 0.05f, 0.07f, 1.00f);
style->Colors[ImGuiCol_PlotLines] = ImVec4(0.40f, 0.39f, 0.38f, 0.63f);
style->Colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.25f, 1.00f, 0.00f, 1.00f);
style->Colors[ImGuiCol_PlotHistogram] = ImVec4(0.40f, 0.39f, 0.38f, 0.63f);
style->Colors[ImGuiCol_PlotHistogramHovered] = ImVec4(0.25f, 1.00f, 0.00f, 1.00f);
style->Colors[ImGuiCol_TextSelectedBg] = ImVec4(0.5882f, 0.0784f, 0.1176f, 1.00f);
style->Colors[ImGuiCol_ModalWindowDimBg] = ImVec4(1.00f, 0.98f, 0.95f, 0.73f);
style->Colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.52f, 0.50f, 0.58f, 1.00f);
style->Colors[ImGuiCol_ResizeGripActive] = ImVec4(0.35f, 0.33f, 0.40f, 1.00f);
style->Colors[ImGuiCol_PlotLines] = ImVec4(0.55f, 0.45f, 0.55f, 0.70f);
style->Colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.98f, 0.30f, 0.08f, 1.00f);
style->Colors[ImGuiCol_PlotHistogram] = ImVec4(0.52f, 0.42f, 0.52f, 0.68f);
style->Colors[ImGuiCol_PlotHistogramHovered] = ImVec4(0.95f, 0.26f, 0.07f, 1.00f);
style->Colors[ImGuiCol_TextSelectedBg] = ImVec4(0.42f, 0.09f, 0.04f, 0.55f);
style->Colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.02f, 0.025f, 0.05f, 0.72f);
defStyle = *style;
LoadMenuFontAtlas(scale);
lastFontAtlasScale = scale;
InitMenuScaleDraftToCommitted();
ImGuiIO& io = ImGui::GetIO();
ImFontConfig fontConfig{};
fontConfig.FontDataOwnedByAtlas = false;
io.FontDefault = io.Fonts->AddFontFromMemoryTTF((void*)g_FontRudaBold, sizeof(g_FontRudaBold), 12.0f + 6.0f, &fontConfig);
io.Fonts->Build();
io.FontGlobalScale = 1.0f;
SPDLOG_INFO("Loading EGameTools logo texture");
EGTLogoTexture = EGT::Utils::Texture::LoadImGuiTexture(g_EGTWhiteLogo, sizeof(g_EGTWhiteLogo));
EGTLogoTexture = EGT::Utils::Texture::LoadImGuiTexture(egtWhiteLogoPng, sizeof(egtWhiteLogoPng));
SPDLOG_INFO("Loaded EGameTools logo");
}
}
+661 -38
View File
@@ -1,80 +1,703 @@
#include <algorithm>
#include <cmath>
#include <limits>
#include <string>
#include <unordered_map>
#include <ImGui\imgui_hotkey.h>
#include <ImGui\imgui_internal.h>
#include <ImGui\imguiex.h>
#include <EGSDK\Core\Core.h>
#include <EGSDK\GamePH\GamePH_Misc.h>
#include <EGSDK\GamePH\GamePH_Hooks.h>
#include <EGT\Menu\Init.h>
#include <EGT\Menu\Menu.h>
#include <EGT\Menu\MenuIcons.h>
#include <EGT\Core\Core.h>
namespace EGT::Menu {
const std::string title = "EGameTools (" + std::string(MOD_VERSION_STR) + ")";
ImGuiStyle defStyle{};
ImTextureID EGTLogoTexture{};
static constexpr ImVec2 defEGTLogoSize = ImVec2(278.0f, 100.0f);
static constexpr ImVec2 defEGTLogoSize = ImVec2(220.0f, 79.0f);
static ImVec2 EGTLogoSize = defEGTLogoSize;
static constexpr ImGuiWindowFlags windowFlags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoScrollbar;
static constexpr ImVec2 defMinWndSize = ImVec2(575.0f, 725.0f);
static constexpr ImGuiWindowFlags windowFlags =
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse;
static constexpr ImVec2 defMinWndSize = ImVec2(700.0f, 640.0f);
static ImVec2 minWndSize = defMinWndSize;
static constexpr ImVec2 defMaxWndSize = ImVec2(900.0f, 725.0f);
static constexpr ImVec2 defMaxWndSize = ImVec2(1180.0f, 920.0f);
static ImVec2 maxWndSize = defMaxWndSize;
static constexpr ImVec2 defDefaultWndSize = ImVec2(820.0f, 720.0f);
static constexpr float defSidebarWidth = 220.0f;
ImGui::KeyBindOption menuToggle{ false, VK_F5 };
float opacity = 99.0f;
float childPanelAlpha = 50.0f;
float frameAlpha = 70.0f;
float popupAlpha = 72.0f;
float micaWashStrength = 100.0f;
float micaBlurStrength = 92.0f;
float scale = 1.0f;
static float lastScaleForMainWindow = -1.0f;
/// Draft for the menu scale slider; `scale` commits on release so fonts/layout do not thrash each frame while dragging.
static float menuScaleDraft = 1.0f;
/// Avoid `SetNextWindowSize(..., Always)` while dragging menu scale — resizing reflows the window and fights the slider under the cursor.
static bool menuScaleSliderDragThisFrame = false;
static bool menuScaleSliderDragLastFrame = false;
ImGui::Option firstTimeRunning{ true };
ImGui::Option hasSeenChangelog{ false };
int currentTabIndex = 0;
void Render() {
/// Wall-clock durations (seconds). Progress uses `deltaSeconds / duration` so frame rate does not change total time.
static constexpr float menuOpenDurationSec = 0.28f;
static constexpr float tabCrossfadeDurationSec = 0.34f;
static constexpr float tabCrossSlideInPx = 12.0f;
static constexpr int settingsNavId = 999001;
static float menuOpenLinear = 0.0f;
static bool menuWasOpenLastPoll = false;
static bool backdropRectValid = false;
static float backdropMinX = 0.0f;
static float backdropMinY = 0.0f;
static float backdropMaxX = 0.0f;
static float backdropMaxY = 0.0f;
/// Tab crossfade: A = outgoing panel, B = incoming; t in [0,1]. Stable index updates when t reaches 1.
static int tabCrossFromIndex = 0;
static int tabCrossToIndex = 0;
static float tabCrossProgress = 1.0f;
static int tabStableIndex = std::numeric_limits<int>::min();
static bool tabScrollNeedsReset = false;
static bool tabWasCrossfadingLastFrame = false;
/// Smooth vertical scroll for a scrolling child (`NoScrollWithMouse` so Dear ImGui leaves `MouseWheel` for us until EndFrame).
static void ApplySmoothScrollAfterTabChildContent(float deltaSeconds, bool scrollWasReset, bool clearAllTargets) {
static std::unordered_map<ImGuiID, float> targetScrollByWindowId;
if (clearAllTargets)
targetScrollByWindowId.clear();
ImGuiWindow* w = ImGui::GetCurrentWindow();
if (!w || w->ScrollMax.y <= 0.0f)
return;
const ImGuiID wid = w->ID;
const float cur = ImGui::GetScrollY();
const float maxScroll = ImGui::GetScrollMaxY();
auto it = targetScrollByWindowId.find(wid);
if (scrollWasReset || it == targetScrollByWindowId.end()) {
targetScrollByWindowId[wid] = cur;
it = targetScrollByWindowId.find(wid);
}
float& tgt = it->second;
tgt = ImClamp(tgt, 0.0f, maxScroll);
ImGuiIO& io = ImGui::GetIO();
if (io.MouseWheel != 0.0f && ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) {
const float max_step = w->InnerRect.GetHeight() * 0.67f;
const float scroll_step = ImTrunc(ImMin(5.0f * w->CalcFontSize(), max_step));
tgt -= io.MouseWheel * scroll_step;
tgt = ImClamp(tgt, 0.0f, maxScroll);
}
const float smooth = 1.0f - std::exp(-16.0f * deltaSeconds);
ImGui::SetScrollY(cur + (tgt - cur) * smooth);
}
bool MenuAnimNeedsFrame() {
return menuToggle.value || menuOpenLinear > 0.0001f;
}
bool GetMenuBackdropRectPx(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) {
if (!backdropRectValid || !outMinX || !outMinY || !outMaxX || !outMaxY)
return false;
*outMinX = backdropMinX;
*outMinY = backdropMinY;
*outMaxX = backdropMaxX;
*outMaxY = backdropMaxY;
return true;
}
float GetMicaBackdropFade() {
return menuOpenLinear * (micaBlurStrength / 100.0f);
}
void UpdateMenuVisibilityAnimFromPoll() {
const bool open = menuToggle.value;
if (open && !menuWasOpenLastPoll) {
menuOpenLinear = 0.0f;
tabStableIndex = std::numeric_limits<int>::min();
tabCrossProgress = 1.0f;
}
menuWasOpenLastPoll = open;
}
static ImVec4 LerpColor4(const ImVec4& a, const ImVec4& b, float t) {
return ImVec4(ImLerp(a.x, b.x, t), ImLerp(a.y, b.y, t), ImLerp(a.z, b.z, t), ImLerp(a.w, b.w, t));
}
static void ApplyMenuColorAlphas(ImGuiStyle& menuStyle) {
const ImGuiStyle& defaultStyle = defStyle;
const float childAlphaNormalized = ImClamp(childPanelAlpha * 0.01f, 0.0f, 1.0f);
menuStyle.Colors[ImGuiCol_ChildBg] = ImVec4(
defaultStyle.Colors[ImGuiCol_ChildBg].x,
defaultStyle.Colors[ImGuiCol_ChildBg].y,
defaultStyle.Colors[ImGuiCol_ChildBg].z,
childAlphaNormalized);
const float frameAlphaNormalized = ImClamp(frameAlpha * 0.01f, 0.0f, 1.0f);
const float defaultFrameBgAlpha = defaultStyle.Colors[ImGuiCol_FrameBg].w;
menuStyle.Colors[ImGuiCol_FrameBg] = defaultStyle.Colors[ImGuiCol_FrameBg];
menuStyle.Colors[ImGuiCol_FrameBg].w = frameAlphaNormalized;
menuStyle.Colors[ImGuiCol_FrameBgHovered] = defaultStyle.Colors[ImGuiCol_FrameBgHovered];
menuStyle.Colors[ImGuiCol_FrameBgActive] = defaultStyle.Colors[ImGuiCol_FrameBgActive];
if (defaultFrameBgAlpha > 1e-5f) {
menuStyle.Colors[ImGuiCol_FrameBgHovered].w =
ImMin(1.0f, frameAlphaNormalized * (defaultStyle.Colors[ImGuiCol_FrameBgHovered].w / defaultFrameBgAlpha));
menuStyle.Colors[ImGuiCol_FrameBgActive].w =
ImMin(1.0f, frameAlphaNormalized * (defaultStyle.Colors[ImGuiCol_FrameBgActive].w / defaultFrameBgAlpha));
}
const float popupAlphaNormalized = ImClamp(popupAlpha * 0.01f, 0.0f, 1.0f);
menuStyle.Colors[ImGuiCol_PopupBg] = defaultStyle.Colors[ImGuiCol_PopupBg];
menuStyle.Colors[ImGuiCol_PopupBg].w = popupAlphaNormalized;
}
void InitMenuScaleDraftToCommitted() {
menuScaleDraft = scale;
}
void PushScaledMenuStyles() {
ImGui::StyleScaleAllSizes(&ImGui::GetStyle(), scale, &defStyle);
ImGui::GetIO().FontGlobalScale = scale;
ApplyMenuColorAlphas(ImGui::GetStyle());
ImGui::GetIO().FontGlobalScale = 1.0f;
}
/// Win11-ish Mica approximation: cool vertical depth + light top wash (no OS blur in ImGui).
static void DrawMenuMicaBase(ImDrawList* dl, const ImRect& work, const ImGuiStyle& style, float menuOpenFade) {
if (!dl || work.GetWidth() < 2.0f || work.GetHeight() < 2.0f)
return;
const ImVec4& wb = style.Colors[ImGuiCol_WindowBg];
const float a = 0.092f * menuOpenFade;
// Neutral cool-gray depth only (red stays on accents in the style sheet).
const ImVec4 tl(ImLerp(wb.x, 0.12f, 0.52f), ImLerp(wb.y, 0.11f, 0.48f), ImLerp(wb.z, 0.168f, 0.62f), a);
const ImVec4 tr(ImLerp(wb.x, 0.088f, 0.42f), ImLerp(wb.y, 0.09f, 0.45f), ImLerp(wb.z, 0.14f, 0.55f), a * 0.94f);
const ImVec4 br(ImLerp(wb.x, 0.058f, 0.42f), ImLerp(wb.y, 0.048f, 0.38f), ImLerp(wb.z, 0.062f, 0.48f), a * 1.06f);
const ImVec4 bl(ImLerp(wb.x, 0.045f, 0.55f), ImLerp(wb.y, 0.044f, 0.52f), ImLerp(wb.z, 0.058f, 0.58f), a * 1.02f);
dl->AddRectFilledMultiColor(work.Min, work.Max, ImGui::ColorConvertFloat4ToU32(tl), ImGui::ColorConvertFloat4ToU32(tr), ImGui::ColorConvertFloat4ToU32(br),
ImGui::ColorConvertFloat4ToU32(bl));
}
/// Extra depth on child panels (nav rail / tab area) — thin vertical light bias like layered acrylic.
static void DrawMicaChildWash(ImDrawList* dl, const ImRect& inner, const ImGuiStyle& style, float menuOpenFade) {
if (!dl || inner.GetWidth() < 2.0f || inner.GetHeight() < 2.0f)
return;
const ImVec4& cb = style.Colors[ImGuiCol_ChildBg];
const float a = 0.088f * menuOpenFade;
const ImVec4 top(ImMin(1.0f, cb.x * 1.08f), ImMin(1.0f, cb.y * 1.06f), ImMin(1.0f, cb.z * 1.11f), a);
const ImVec4 bot(cb.x * 0.91f, cb.y * 0.92f, ImMin(1.0f, cb.z * 0.96f), a * 0.86f);
dl->AddRectFilledMultiColor(inner.Min, inner.Max, ImGui::ColorConvertFloat4ToU32(top), ImGui::ColorConvertFloat4ToU32(top),
ImGui::ColorConvertFloat4ToU32(bot), ImGui::ColorConvertFloat4ToU32(bot));
}
/// Soft outer aura for elevated cards (tab panel, nav rail) — W11-style ambient glow, not a hard border.
static void DrawElevatedPanelAura(ImDrawList* dl, const ImRect& bb, float rounding, float scaleUi, const ImGuiStyle& style, float fade) {
if (!dl || fade < 0.02f || bb.GetWidth() < 2.0f)
return;
ImVec4 c = LerpColor4(style.Colors[ImGuiCol_Border], style.Colors[ImGuiCol_SliderGrab], 0.10f);
c = LerpColor4(c, style.Colors[ImGuiCol_WindowBg], 0.62f);
const float maxEx = ImMax(7.0f * scaleUi, 4.2f);
const int rings = 18;
const float peakA = 0.022f * fade;
for (int i = 0; i < rings; ++i) {
const float ex = maxEx * (float)(rings - 1 - i) / (float)(rings - 1);
const float u = maxEx > 1e-4f ? ex / maxEx : 0.0f;
const float env = std::exp(-2.85f * u * u);
const float a = peakA * env;
if (a < 0.0009f)
continue;
const ImRect r(bb.Min.x - ex, bb.Min.y - ex, bb.Max.x + ex, bb.Max.y + ex);
const float rnd = ImMin(rounding + ex * 0.46f, r.GetHeight() * 0.5f);
dl->AddRectFilled(r.Min, r.Max, ImGui::ColorConvertFloat4ToU32(ImVec4(c.x, c.y, c.z, a)), rnd);
}
}
static void DrawMicaColumnSheen(ImDrawList* dl, float xCenter, float y0, float y1, float menuOpenFade, const ImGuiStyle& style) {
if (!dl || y1 <= y0 + 1.0f || menuOpenFade < 0.03f)
return;
const ImVec4& acc = style.Colors[ImGuiCol_Border];
const int alpha = (int)(20.0f * menuOpenFade);
const int alphaHi = (int)(32.0f * menuOpenFade);
const float half = ImMax(1.0f, 1.25f * scale);
const ImU32 edge = IM_COL32((int)(acc.x * 255.0f), (int)(acc.y * 255.0f), (int)(acc.z * 255.0f), alpha);
const ImU32 mid = IM_COL32(235, 238, 248, alphaHi);
// col_up_left, col_up_right, col_bottom_right, col_bottom_left
dl->AddRectFilledMultiColor(ImVec2(xCenter - half, y0), ImVec2(xCenter, y1), edge, mid, mid, edge);
dl->AddRectFilledMultiColor(ImVec2(xCenter, y0), ImVec2(xCenter + half, y1), mid, edge, edge, mid);
}
/// Backlight behind the nav row: visible but smooth (stacked shells + envelope); theme accent.
static void DrawNavPillGlow(ImDrawList* dl, const ImRect& bb, float blend, bool selected, float scaleUi, const ImGuiStyle& style) {
if (blend < 0.02f || !dl)
return;
const ImVec4& bgRail = style.Colors[ImGuiCol_ChildBg];
ImVec4 accent = LerpColor4(style.Colors[ImGuiCol_FrameBgActive], style.Colors[ImGuiCol_SliderGrab], selected ? 0.42f : 0.16f);
accent = LerpColor4(accent, bgRail, 0.26f);
const float strength = blend * (selected ? 1.0f : 0.40f);
const float rounding = ImMin(style.FrameRounding, bb.GetHeight() * 0.5f);
const float maxEx = ImMax(6.5f * scaleUi, 4.0f);
const int rings = selected ? 22 : 14;
const float peakA = selected ? 0.038f : 0.016f;
for (int i = 0; i < rings; ++i) {
const float ex = maxEx * (float)(rings - 1 - i) / (float)(rings - 1);
const float u = maxEx > 1e-4f ? ex / maxEx : 0.0f;
const float env = std::exp(-2.75f * u * u);
const float a = ImClamp(peakA * strength * env, 0.0f, 1.0f);
if (a < 0.001f)
continue;
const ImRect r(bb.Min.x - ex, bb.Min.y - ex, bb.Max.x + ex, bb.Max.y + ex);
const float rnd = ImMin(rounding + ex * 0.50f, r.GetHeight() * 0.5f);
dl->AddRectFilled(r.Min, r.Max, ImGui::ColorConvertFloat4ToU32(ImVec4(accent.x, accent.y, accent.z, a)), rnd);
}
}
static size_t NavHighlightSlot(int navId) {
if (navId == settingsNavId)
return 15u;
return static_cast<size_t>(std::clamp(navId, 0, 14));
}
/// Smooth nav-row fill (mouse hover, keyboard focus, selected). Drawn under text; Selectable uses transparent Header colors.
static bool NavRowSelectable(int id, const char* iconUtf8, const char* label, bool selected, float rowH, float deltaSeconds, const ImGuiStyle& style) {
ImGuiWindow* window = ImGui::GetCurrentWindow();
if (!window || window->SkipItems)
return false;
const size_t slot = NavHighlightSlot(id);
static float navBlendBySlot[16]{};
static bool navWasMouseHoverBySlot[16]{};
static bool navWasFocusedBySlot[16]{};
static bool navWasSelectedBySlot[16]{};
const bool wasSelected = navWasSelectedBySlot[slot];
navWasSelectedBySlot[slot] = selected;
const bool wasHot = navWasMouseHoverBySlot[slot] || navWasFocusedBySlot[slot];
const float target = selected ? 1.0f : (wasHot ? 0.55f : 0.0f);
// Leaving selection: decay quickly so the old row does not stay “active” through the tab crossfade.
const float k = selected ? (1.0f - std::exp(-20.0f * deltaSeconds)) : (1.0f - std::exp(-72.0f * deltaSeconds));
float& blend = navBlendBySlot[slot];
if (wasSelected && !selected)
blend *= 0.25f;
blend += (target - blend) * k;
ImGui::PushID(id);
std::string row(iconUtf8);
row.append(" ");
row.append(label);
ImVec2 label_size = ImGui::CalcTextSize(row.c_str(), nullptr, true);
ImVec2 pos = window->DC.CursorPos;
pos.y += window->DC.CurrLineTextBaseOffset;
const float min_x = pos.x;
const float max_x = window->WorkRect.Max.x;
// Gap between nav rail inner edge and the rounded row (not extra window padding).
const float pillInset = IM_TRUNC(style.ItemSpacing.x * 0.55f);
// Space between row outline and icon/label.
const float labelPadX = IM_TRUNC(style.FramePadding.x + style.ItemSpacing.x * 0.65f);
ImRect bb(min_x + pillInset, pos.y, max_x - pillInset, pos.y + rowH);
{
const float spacing_y = style.ItemSpacing.y;
const float spacing_U = IM_TRUNC(spacing_y * 0.50f);
bb.Min.y -= spacing_U;
bb.Max.y += (spacing_y - spacing_U);
}
// Shrink the pill vertically so adjacent rows show a strip of child bg between highlights.
const float pillVInset = 4.0f * scale;
bb.Min.y += pillVInset;
bb.Max.y -= pillVInset;
if (blend > 0.001f) {
DrawNavPillGlow(window->DrawList, bb, blend, selected, scale, style);
const ImVec4& bg = style.Colors[ImGuiCol_ChildBg];
const ImVec4 cEnd = LerpColor4(style.Colors[ImGuiCol_FrameBgHovered], style.Colors[ImGuiCol_FrameBgActive], selected ? 1.0f : 0.0f);
const ImVec4 cMix = LerpColor4(bg, cEnd, blend);
const float rounding = ImMin(style.FrameRounding, bb.GetHeight() * 0.5f);
window->DrawList->AddRectFilled(bb.Min, bb.Max, ImGui::ColorConvertFloat4ToU32(cMix), rounding);
}
// `min_x` / `max_x` use `DC.CursorPos` + `WorkRect` (absolute). `SetCursorPosX` expects window-local X
// (see ImGui::SetCursorPosX: CursorPos.x = Pos.x - Scroll.x + local_x).
const float lineLocalMinX = min_x - window->Pos.x + window->Scroll.x;
const float contentW = max_x - min_x;
const float pillW = contentW - 2.0f * pillInset;
const float selW = ImMax(1.0f, pillW - 2.0f * labelPadX);
ImGui::SetCursorPosX(lineLocalMinX + pillInset + labelPadX);
const bool clicked = ImGui::Selectable(row.c_str(), selected, ImGuiSelectableFlags_None, ImVec2(selW, rowH));
navWasMouseHoverBySlot[slot] = ImGui::IsItemHovered();
navWasFocusedBySlot[slot] = ImGui::IsItemFocused();
ImGui::PopID();
return clicked;
}
static MenuTab* FindTabByIndex(int idx) {
for (const auto& tab : *MenuTab::GetInstances()) {
if (tab.first == idx)
return tab.second;
}
return nullptr;
}
static void EnsureValidTabIndex() {
if (currentTabIndex == settingsPanelTabIndex)
return;
const auto* tabs = MenuTab::GetInstances();
if (tabs->empty())
return;
if (FindTabByIndex(currentTabIndex))
return;
currentTabIndex = tabs->begin()->first;
}
static const char* SectionIconUtf8(int tabIndex) {
switch (tabIndex) {
case 0: return EGT::MenuIcons::iconUser;
case 1: return EGT::MenuIcons::iconGun;
case 2: return EGT::MenuIcons::iconCamera;
case 3: return EGT::MenuIcons::iconLocationArrow;
case 4: return EGT::MenuIcons::iconEllipsis;
case 5: return EGT::MenuIcons::iconGlobe;
case 6: return EGT::MenuIcons::iconBug;
default: return EGT::MenuIcons::iconEllipsis;
}
}
static void RenderSettingsPanel() {
ImGui::SeparatorTextSection("Menu", false);
ImGui::Hotkey("Menu Toggle Key", &menuToggle);
ImGui::SeparatorTextSection("Appearance");
ImGui::SliderFloatStacked("Main window opacity", &opacity, 0.0f, 100.0f, "%.0f%%", ImGuiSliderFlags_AlwaysClamp, nullptr);
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled))
ImGui::SetTooltip("Opacity of the root menu window background.");
if (EGSDK::Core::rendererAPI == 12) {
ImGui::SliderFloatStacked("Backdrop blur", &micaBlurStrength, 0.0f, 100.0f, "%.0f%%", ImGuiSliderFlags_AlwaysClamp, nullptr);
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled))
ImGui::SetTooltip("GPU frosted-glass blur behind the menu (DirectX 12 only). Independent from panel opacity.");
} else {
ImGui::BeginDisabled();
ImGui::SliderFloatStacked("Backdrop blur", &micaBlurStrength, 0.0f, 100.0f, "%.0f%%", ImGuiSliderFlags_AlwaysClamp, nullptr);
ImGui::EndDisabled();
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled))
ImGui::SetTooltip("Backdrop blur is only available when the game uses DirectX 12.");
}
ImGui::SliderFloatStacked("Inset / child alpha", &childPanelAlpha, 0.0f, 100.0f, "%.0f%%", ImGuiSliderFlags_AlwaysClamp, nullptr);
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled))
ImGui::SetTooltip("Opacity of sidebar and tab panel fills. 50% matches the default glass look.");
ImGui::SliderFloatStacked("Input / frame alpha", &frameAlpha, 0.0f, 100.0f, "%.0f%%", ImGuiSliderFlags_AlwaysClamp, nullptr);
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled))
ImGui::SetTooltip("Opacity of sliders, combos, and text fields. 70% matches the default theme.");
ImGui::SliderFloatStacked("Popup alpha", &popupAlpha, 0.0f, 100.0f, "%.0f%%", ImGuiSliderFlags_AlwaysClamp, nullptr);
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled))
ImGui::SetTooltip("Opacity of popup and tooltip backgrounds.");
ImGui::SliderFloatStacked("Mica wash strength", &micaWashStrength, 0.0f, 100.0f, "%.0f%%", ImGuiSliderFlags_AlwaysClamp, nullptr);
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled))
ImGui::SetTooltip("Strength of the decorative gradient wash drawn behind the UI (not the GPU blur).");
ImGui::SeparatorTextSection("Layout");
ImGui::PushID("##EGTMenuScale");
ImGui::SliderFloatStacked("Menu scale", &menuScaleDraft, 1.0f, 2.5f, "%.2fx", ImGuiSliderFlags_AlwaysClamp, nullptr);
if (ImGui::IsItemDeactivatedAfterEdit())
scale = menuScaleDraft;
if (!ImGui::IsItemActive())
menuScaleDraft = scale;
if (ImGui::IsItemActive())
menuScaleSliderDragThisFrame = true;
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled))
ImGui::SetTooltip("Release the slider to apply scale (rebuilds fonts and default window size). Prevents layout glitches while dragging.");
ImGui::PopID();
ImGui::SeparatorTextSection("Game");
if (EGSDK::Core::IsGameVerCompatible()) {
ImGui::TextDisabled("Your game version is supported by this build.");
} else {
ImGui::TextColored(ImVec4(0.95f, 0.28f, 0.28f, 1.0f), "Incompatible game version (v%s) detected!",
EGSDK::GamePH::GameVerToStr(EGSDK::Core::gameVer).c_str());
ImGui::TextColored(ImVec4(0.95f, 0.28f, 0.28f, 1.0f), "Supported versions: %s",
EGSDK::Core::GetSupportedGameVersionsStr().c_str());
}
}
static void RenderTabPanelByIndex(int tabIndex) {
if (tabIndex == settingsPanelTabIndex) {
RenderSettingsPanel();
return;
}
MenuTab* active = FindTabByIndex(tabIndex);
ImGui::BeginDisabled(!EGSDK::GamePH::Hooks::didOnPostUpdateHookExecute);
if (active)
active->Render();
ImGui::EndDisabled();
}
static void UpdateBackdropRectFromWindow(ImGuiWindow* menuWindow) {
const ImRect outer(menuWindow->OuterRectClipped.Min, menuWindow->OuterRectClipped.Max);
backdropRectValid = outer.GetWidth() > 2.0f && outer.GetHeight() > 2.0f;
if (backdropRectValid) {
backdropMinX = outer.Min.x;
backdropMinY = outer.Min.y;
backdropMaxX = outer.Max.x;
backdropMaxY = outer.Max.y;
}
}
static void RenderOneTabLayer(int tabIndex, float layerAlpha, float slidePx) {
const float alphaBeforeTab = ImGui::GetStyle().Alpha;
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, alphaBeforeTab * layerAlpha);
ImGui::Dummy(ImVec2(0.0f, slidePx));
ImGui::PushItemWidth(-1.0f);
RenderTabPanelByIndex(tabIndex);
ImGui::PopItemWidth();
ImGui::PopStyleVar();
}
static void RenderTabContentArea(ImGuiWindow* menuWindow, const ImGuiStyle& style, float deltaSeconds, float micaWashFade, float menuShow, const ImVec2& tabScreenPos, const ImVec2& tabChildSize) {
if (tabStableIndex == std::numeric_limits<int>::min()) {
tabStableIndex = currentTabIndex;
tabCrossFromIndex = tabCrossToIndex = currentTabIndex;
tabCrossProgress = 1.0f;
}
if (currentTabIndex != tabCrossToIndex && tabCrossProgress < 1.0f - 1e-4f) {
tabCrossFromIndex = (tabCrossProgress < 0.5f) ? tabCrossFromIndex : tabCrossToIndex;
tabCrossToIndex = currentTabIndex;
tabCrossProgress = 0.0f;
tabScrollNeedsReset = true;
} else if (currentTabIndex != tabStableIndex && tabCrossProgress >= 1.0f - 1e-4f) {
tabCrossFromIndex = tabStableIndex;
tabCrossToIndex = currentTabIndex;
tabCrossProgress = 0.0f;
tabScrollNeedsReset = true;
}
tabCrossProgress = std::fmin(1.0f, tabCrossProgress + deltaSeconds / tabCrossfadeDurationSec);
if (tabCrossProgress >= 1.0f - 1e-4f) {
tabStableIndex = currentTabIndex;
tabCrossFromIndex = tabCrossToIndex = currentTabIndex;
}
const float easedProgress = tabCrossProgress * tabCrossProgress * (3.0f - 2.0f * tabCrossProgress);
const float alphaIn = easedProgress;
const float slideIn = (1.0f - easedProgress) * tabCrossSlideInPx * scale;
const bool crossfading = (tabCrossProgress < 1.0f - 1e-4f) && (tabCrossFromIndex != tabCrossToIndex);
const bool exitingCrossfade = tabWasCrossfadingLastFrame && !crossfading;
const bool resetTabScroll = tabScrollNeedsReset;
const bool scrollHardReset = resetTabScroll || exitingCrossfade;
constexpr ImGuiWindowFlags tabChildWinFlags = ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoScrollbar;
constexpr ImGuiWindowFlags tabCrossWinFlags = ImGuiWindowFlags_NoScrollbar;
if (crossfading) {
ImGui::SetCursorScreenPos(tabScreenPos);
ImGui::PushID("tabCross");
ImGui::BeginChild("##TabCross", tabChildSize, ImGuiChildFlags_Border, tabCrossWinFlags);
if (ImGuiWindow* tabWindow = ImGui::GetCurrentWindow())
DrawMicaChildWash(tabWindow->DrawList, ImRect(tabWindow->InnerRect.Min, tabWindow->InnerRect.Max), style, micaWashFade);
if (resetTabScroll)
ImGui::SetScrollY(0.0f);
RenderOneTabLayer(tabCrossToIndex, alphaIn, slideIn);
ImGui::EndChild();
ImGui::PopID();
tabScrollNeedsReset = false;
const ImRect tabPanelBounds(tabScreenPos, ImVec2(tabScreenPos.x + tabChildSize.x, tabScreenPos.y + tabChildSize.y));
DrawElevatedPanelAura(menuWindow->DrawList, tabPanelBounds, style.ChildRounding, scale, style, menuShow);
} else {
ImGui::SetCursorScreenPos(tabScreenPos);
ImGui::BeginChild("##TabContent", tabChildSize, ImGuiChildFlags_Border, tabChildWinFlags);
if (ImGuiWindow* tabWindow = ImGui::GetCurrentWindow())
DrawMicaChildWash(tabWindow->DrawList, ImRect(tabWindow->InnerRect.Min, tabWindow->InnerRect.Max), style, micaWashFade);
if (scrollHardReset)
ImGui::SetScrollY(0.0f);
tabScrollNeedsReset = false;
RenderOneTabLayer(currentTabIndex, 1.0f, 0.0f);
ApplySmoothScrollAfterTabChildContent(deltaSeconds, scrollHardReset, exitingCrossfade);
ImGui::EndChild();
DrawElevatedPanelAura(menuWindow->DrawList, ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax()), style.ChildRounding, scale, style, menuShow);
}
tabWasCrossfadingLastFrame = crossfading;
}
static void RenderNavRail(ImGuiWindow* menuWindow, const ImGuiStyle& style, float deltaSeconds, float micaWashFade, float menuShow, float navWidth, float navRailY, float bodyHeight, float navRowHeight, float navRowSideGutter, int settingsNavIdValue) {
ImGui::SetCursorScreenPos(ImVec2(menuWindow->WorkRect.Min.x, navRailY));
ImGui::BeginChild("##NavRail", ImVec2(navWidth, bodyHeight), ImGuiChildFlags_Border, ImGuiWindowFlags_None);
if (ImGuiWindow* navWindow = ImGui::GetCurrentWindow())
DrawMicaChildWash(navWindow->DrawList, ImRect(navWindow->InnerRect.Min, navWindow->InnerRect.Max), style, micaWashFade);
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(8.0f, 12.0f * scale));
ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.0f, 0.5f));
ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.0f, 0.0f, 0.0f, 0.0f));
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.0f, 0.0f, 0.0f, 0.0f));
ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.0f, 0.0f, 0.0f, 0.0f));
ImGui::Spacing();
const float sectionLabelX = ImGui::GetCursorPosX() + navRowSideGutter;
ImGui::SetCursorPosX(sectionLabelX);
ImGui::TextDisabled("SECTIONS");
for (const auto& tab : *MenuTab::GetInstances()) {
const std::string label(tab.second->tabName);
if (NavRowSelectable(tab.first, SectionIconUtf8(tab.first), label.c_str(), currentTabIndex == tab.first, navRowHeight, deltaSeconds, style))
currentTabIndex = tab.first;
}
const float settingsBlockHeight = navRowHeight + style.ItemSpacing.y * 3.0f + style.SeparatorTextBorderSize;
const float flexibleNavSpace = ImGui::GetContentRegionAvail().y - settingsBlockHeight;
if (flexibleNavSpace > 1.0f)
ImGui::Dummy(ImVec2(0.0f, flexibleNavSpace));
ImGui::Separator();
ImGui::Spacing();
if (NavRowSelectable(settingsNavIdValue, EGT::MenuIcons::iconGear, "Settings", currentTabIndex == settingsPanelTabIndex, navRowHeight, deltaSeconds, style))
currentTabIndex = settingsPanelTabIndex;
ImGui::PopStyleColor(3);
ImGui::PopStyleVar(2);
ImGui::EndChild();
DrawElevatedPanelAura(menuWindow->DrawList, ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax()), style.ChildRounding, scale, style, menuShow);
}
void Render() {
PushScaledMenuStyles();
minWndSize = defMinWndSize * scale;
maxWndSize = defMaxWndSize * scale;
EGTLogoSize = defEGTLogoSize * scale;
const ImGuiStyle& menuStyle = ImGui::GetStyle();
const float deltaSeconds = std::fmin(ImGui::GetIO().DeltaTime, 0.08f);
const float menuGutter = menuStyle.ItemSpacing.x; // horizontal gap between nav column and tab panel
ImGui::SetNextWindowBgAlpha(static_cast<float>(opacity) / 100.0f);
EnsureValidTabIndex();
const bool wantFrame = menuToggle.value || menuOpenLinear > 0.0001f;
if (!wantFrame) {
backdropRectValid = false;
menuScaleSliderDragThisFrame = false;
menuScaleSliderDragLastFrame = false;
return;
}
menuScaleSliderDragThisFrame = false;
if (menuToggle.value)
menuOpenLinear = std::fmin(1.0f, menuOpenLinear + deltaSeconds / menuOpenDurationSec);
else
menuOpenLinear = std::fmax(0.0f, menuOpenLinear - deltaSeconds / menuOpenDurationSec);
const float menuShow = menuOpenLinear;
const float userBgAlpha = static_cast<float>(opacity) / 100.0f;
const float openA = userBgAlpha * menuShow;
ImGui::SetNextWindowBgAlpha(openA);
const bool deferWinResizeForScaleDrag = menuScaleSliderDragLastFrame;
if (!deferWinResizeForScaleDrag && std::fabs(scale - lastScaleForMainWindow) > 1.0e-4f) {
lastScaleForMainWindow = scale;
ImGui::SetNextWindowSize(defDefaultWndSize * scale, ImGuiCond_Always);
} else
ImGui::SetNextWindowSize(defDefaultWndSize * scale, ImGuiCond_FirstUseEver);
ImGui::SetNextWindowPos(ImVec2(ImGui::GetIO().DisplaySize.x * 0.5f, ImGui::GetIO().DisplaySize.y * 0.5f), ImGuiCond_FirstUseEver, ImVec2(0.5f, 0.5f));
ImGui::SetNextWindowSizeConstraints(minWndSize, maxWndSize);
ImGui::Begin(title.c_str(), &menuToggle.value, windowFlags); {
ImGui::SetCursorPosX((ImGui::GetWindowWidth() / 2.0f) - (EGTLogoSize.x / 2.0f));
ImGui::Image(EGTLogoTexture, EGTLogoSize);
const float footerHeight = ImGui::GetFrameHeightWithSpacing() * 3.0f + (!EGSDK::Core::IsGameVerCompatible() ? (ImGui::CalcTextSize("").y * 2.0f) + GImGui->Style.FramePadding.y + GImGui->Style.ItemSpacing.y : 0.0f) + GImGui->Style.WindowPadding.y * 2.0f + GImGui->Style.FramePadding.y * 2.0f;
const float remainingHeight = ImGui::GetContentRegionAvail().y - footerHeight;
bool showWindow = menuToggle.value || (menuOpenLinear > 0.0001f);
ImGui::Begin("EGameTools##MainMenu", &showWindow, windowFlags);
if (!showWindow)
menuToggle.value = false;
{
const float alphaBeforeMenu = ImGui::GetStyle().Alpha;
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, alphaBeforeMenu * menuShow);
if (ImGui::BeginTabBar("##MainTabBar")) {
for (auto& tab : *MenuTab::GetInstances()) {
static float childWidth = 0.0f;
ImGuiWindow* const menuWnd = ImGui::GetCurrentWindow();
UpdateBackdropRectFromWindow(menuWnd);
const float micaWashFade = menuShow * ImClamp(micaWashStrength * 0.01f, 0.0f, 1.0f);
DrawMenuMicaBase(menuWnd->DrawList, ImRect(menuWnd->WorkRect.Min, menuWnd->WorkRect.Max), menuStyle, micaWashFade);
ImGui::SpanNextTabAcrossWidth(childWidth, MenuTab::GetInstances()->size());
if (ImGui::BeginTabItem(tab.second->tabName.data())) {
ImGui::SetNextWindowBgAlpha(static_cast<float>(opacity) / 100.0f);
ImGui::SetNextWindowSizeConstraints(ImVec2(EGSDK::Core::IsGameVerCompatible() ? minWndSize.x - GImGui->Style.WindowPadding.x * 2.0f : std::fmax(minWndSize.x - GImGui->Style.WindowPadding.x * 2.0f, ImGui::CalcTextSize(std::string("Compatible game versions: %s" + EGSDK::Core::GetSupportedGameVersionsStr()).c_str()).x), remainingHeight), ImVec2(maxWndSize.x - GImGui->Style.WindowPadding.x * 2.0f, remainingHeight));
const float navRowH = 36.0f * scale;
ImGui::BeginDisabled(!EGSDK::GamePH::Hooks::didOnPostUpdateHookExecute);
if (ImGui::BeginChild("##TabChild", ImVec2(0.0f, 0.0f), ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_Border)) {
currentTabIndex = tab.first;
childWidth = ImGui::GetItemRectSize().x;
tab.second->Render();
ImGui::EndChild();
}
ImGui::EndDisabled();
ImGui::EndTabItem();
}
float maxNavLabelW = ImGui::CalcTextSize("SECTIONS").x;
{
const std::string settingsRow = std::string(EGT::MenuIcons::iconGear) + " Settings";
maxNavLabelW = std::fmax(maxNavLabelW, ImGui::CalcTextSize(settingsRow.c_str()).x);
}
for (const auto& tab : *MenuTab::GetInstances()) {
const std::string label(tab.second->tabName);
const std::string row = std::string(SectionIconUtf8(tab.first)) + " " + label;
maxNavLabelW = std::fmax(maxNavLabelW, ImGui::CalcTextSize(row.c_str()).x);
}
// Match NavRowSelectable: pill inset from rail + padding inside pill for icon/label.
const float navPillInset = IM_TRUNC(menuStyle.ItemSpacing.x * 0.55f);
const float navLabelPadX = IM_TRUNC(menuStyle.FramePadding.x + menuStyle.ItemSpacing.x * 0.65f);
const float navRowSideGutter = navPillInset + navLabelPadX;
const float minNavW = std::fmax(
std::fmax(defSidebarWidth * scale, maxNavLabelW + navRowSideGutter * 2.0f + menuStyle.WindowPadding.x * 2.0f + menuStyle.ChildBorderSize * 2.0f + 8.0f * scale),
EGTLogoSize.x + menuStyle.WindowPadding.x * 2.0f + menuStyle.ChildBorderSize * 2.0f + 4.0f * scale);
// Brand: fixed layout (no “optical centering” math). Same horizontal inset as ##NavRail content; symmetric
// WindowPadding.y above logo and below version; then menuGutter (column rhythm) before the nav child.
const ImVec2 workMin = menuWnd->WorkRect.Min;
const float workBottom = menuWnd->WorkRect.Max.y;
const float workRight = menuWnd->WorkRect.Max.x;
const float colLeft = workMin.x;
const float navW = minNavW;
const float tabX = colLeft + navW + menuGutter;
const float tabW = std::fmax(1.0f, workRight - tabX);
const float railPad = menuStyle.WindowPadding.x + menuStyle.ChildBorderSize;
const float innerLeft = colLeft + railPad;
const float innerW = std::fmax(1.0f, navW - 2.0f * railPad);
ImFont* const verFont = MenuVersionFont();
const float verFontSize = verFont->FontSize;
const char* const verStr = MOD_VERSION_STR;
const ImVec2 verSz = verFont->CalcTextSizeA(verFontSize, FLT_MAX, 0.0f, verStr);
const float padY = menuStyle.WindowPadding.y;
const float stackH = EGTLogoSize.y + menuStyle.ItemSpacing.y + verSz.y;
const float headerBandH = padY + stackH + padY;
const float navRailY = workMin.y + headerBandH + menuGutter;
const float bodyH = std::fmax(1.0f, workBottom - navRailY);
const float tabFullH = workBottom - workMin.y;
DrawMicaColumnSheen(menuWnd->DrawList, tabX - menuGutter * 0.48f, navRailY, workBottom, menuShow, menuStyle);
const float logoY = workMin.y + padY;
const float logoX = innerLeft + (innerW - EGTLogoSize.x) * 0.5f;
const float verY = logoY + EGTLogoSize.y + menuStyle.ItemSpacing.y;
const float verX = innerLeft + (innerW - verSz.x) * 0.5f;
{
ImGui::SetCursorScreenPos(workMin);
ImGui::InvisibleButton("##BrandDrag", ImVec2(navW, headerBandH));
if (ImGui::IsItemActive() && ImGui::IsMouseDragging(ImGuiMouseButton_Left, 0.0f)) {
ImGuiWindow* root = ImGui::GetCurrentWindow()->RootWindow;
if (root)
ImGui::StartMouseMovingWindow(root);
}
ImGui::EndTabBarEx();
ImDrawList* dl = ImGui::GetWindowDrawList();
dl->AddImage(EGTLogoTexture, ImVec2(logoX, logoY), ImVec2(logoX + EGTLogoSize.x - 4.0f, logoY + EGTLogoSize.y));
dl->AddText(verFont, verFontSize, ImVec2(verX, verY), ImGui::GetColorU32(ImGuiCol_TextDisabled), verStr);
}
ImGui::Hotkey("Menu Toggle Key", &menuToggle);
ImGui::SliderFloat("Menu Opacity", &opacity, 0.0f, 100.0f, "%.1f%%", ImGuiSliderFlags_AlwaysClamp);
ImGui::SliderFloat("Menu Scale", &scale, 1.0f, 2.5f, "%.1f%%", ImGuiSliderFlags_AlwaysClamp);
if (!EGSDK::Core::IsGameVerCompatible()) {
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(IM_COL32(200, 0, 0, 255)), "Incompatible game version (v%s) detected!", EGSDK::GamePH::GameVerToStr(EGSDK::Core::gameVer).c_str());
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(IM_COL32(200, 0, 0, 255)), "Compatible game versions: %s", EGSDK::Core::GetSupportedGameVersionsStr().c_str());
}
ImGui::SetCursorScreenPos(ImVec2(tabX, workMin.y));
const ImVec2 tabScreen0 = ImGui::GetCursorScreenPos();
const ImVec2 tabChildSize(tabW, tabFullH);
RenderTabContentArea(menuWnd, menuStyle, deltaSeconds, micaWashFade, menuShow, tabScreen0, tabChildSize);
RenderNavRail(menuWnd, menuStyle, deltaSeconds, micaWashFade, menuShow, navW, navRailY, bodyH, navRowH, navRowSideGutter, settingsNavId);
ImGui::PopStyleVar(); // ImGuiStyleVar_Alpha from menu open fade (Push at start of block)
ImGui::End();
}
menuScaleSliderDragLastFrame = menuScaleSliderDragThisFrame;
}
}
}
+3 -5
View File
@@ -56,22 +56,20 @@ namespace EGT::Menu {
gameDI_PH->blockPauseGameOnPlayerAfk = disableGamePauseWhileAFK.GetValue();
}
void Tab::Render() {
ImGui::SeparatorText("Misc##Misc");
ImGui::SeparatorTextSection("Misc##Misc", false);
ImGui::CheckboxHotkey("Disable Game Pause While AFK", &disableGamePauseWhileAFK, "Prevents the game from pausing while you're afk");
ImGui::SameLine();
ImGui::BeginDisabled(disableHUD.GetChangesAreDisabled());
ImGui::CheckboxHotkey("Disable HUD", &disableHUD, "Disables the entire HUD, including any sort of menus like the pause menu");
ImGui::EndDisabled();
ImGui::CheckboxHotkey("Disable TAA", &disableTAA, "Disables the TAA/anti-aliasing (only works if you have upscaling disabled)");
ImGui::SeparatorText("Scripting##Misc");
ImGui::SeparatorTextSection("Scripting##Misc");
cVarsList.Render();
ImGui::SeparatorText("Game Checks##Misc");
ImGui::SeparatorTextSection("Game Checks##Misc");
if (ImGui::Checkbox("Disable Savegame CRC Check *", &disableSavegameCRCCheck, "Stops the game from falsely saying your savegame is corrupt whenever you modify it outside of the game using a save editor"))
disableSavegameCRCCheck.GetValue() ? EGT::GamePH::Hooks::SaveGameCRCBoolCheckHook.Enable() : EGT::GamePH::Hooks::SaveGameCRCBoolCheckHook.Disable();
ImGui::SameLine();
ImGui::Checkbox("Disable Data PAKs CRC Check *", &disableDataPAKsCRCCheck, "Stops the game from scanning data PAKs, which allows you to use data PAK mods in multiplayer as well");
ImGui::Checkbox("Increase Data PAKs Limit *", &increaseDataPAKsLimit, "Allows you to add more than 8 data PAKs, e.g. data8.pak, data9.pak, data10.pak, etc, up to 200 PAKs in total");
ImGui::Separator();
+7 -15
View File
@@ -20,7 +20,6 @@
#include <EGT\GamePH\GamePH_Hooks.h>
#include <EGT\Config\Config.h>
#include <EGT\Menu\Camera.h>
#include <EGT\Menu\Menu.h>
#include <EGT\Menu\Player.h>
#include <EGT\Menu\VarList.h>
@@ -146,7 +145,7 @@ namespace EGT::Menu {
return;
}
std::string tempvarsSCR = g_PlayerVariablesSCRFile;
std::string tempvarsSCR = defaultPlayerVariablesScr;
std::istringstream iss(tempvarsSCR);
std::string line{};
@@ -426,10 +425,10 @@ namespace EGT::Menu {
HandleToggles();
}
void Tab::Render() {
ImGui::SeparatorText("Misc");
ImGui::SeparatorTextSection("Misc", false);
auto playerHealthModule = EGSDK::GamePH::PlayerHealthModule::Get();
ImGui::BeginDisabled(!playerHealthModule);
if (ImGui::SliderFloat("Player Health", &playerHealth, 0.0f, playerMaxHealth, "%.2f") && playerHealthModule)
if (ImGui::SliderFloatStacked("Player Health", &playerHealth, 0.0f, playerMaxHealth, "%.2f") && playerHealthModule)
playerHealthModule->health = playerHealth;
else if (playerHealthModule)
playerHealth = playerHealthModule->health;
@@ -437,18 +436,17 @@ namespace EGT::Menu {
auto playerInfectionModule = EGSDK::GamePH::PlayerInfectionModule::Get();
ImGui::BeginDisabled(!playerInfectionModule);
if (ImGui::SliderFloat("Player Immunity", &playerImmunity, 0.0f, playerMaxImmunity, "%.2f") && playerInfectionModule)
if (ImGui::SliderFloatStacked("Player Immunity", &playerImmunity, 0.0f, playerMaxImmunity, "%.2f") && playerInfectionModule)
playerInfectionModule->immunity = playerImmunity / 100.0f;
else if (playerInfectionModule)
playerImmunity = playerInfectionModule->immunity * 100.0f;
ImGui::EndDisabled();
ImGui::BeginDisabled(isMoneyInteractionDisabled());
UpdateMoney(!ImGui::DragInt("Old World Money", &oldWorldMoney, 2.0f, 0, 999999999));
UpdateMoney(!ImGui::DragIntStacked("Old World Money", &oldWorldMoney, 2.0f, 0, 999999999));
ImGui::EndDisabled();
ImGui::CheckboxHotkey("God Mode", &godMode, "Makes the player invincible");
ImGui::SameLine();
ImGui::BeginDisabled(freezePlayer.GetChangesAreDisabled());
ImGui::CheckboxHotkey("Freeze Player", &freezePlayer, "Freezes player position");
ImGui::EndDisabled();
@@ -475,22 +473,16 @@ namespace EGT::Menu {
}
ImGui::CheckboxHotkey("Unlimited Immunity", &unlimitedImmunity, "Stops immunity from draining");
ImGui::SameLine();
ImGui::CheckboxHotkey("Unlimited Stamina", &unlimitedStamina, "Stops stamina from draining");
ImGui::CheckboxHotkey("Unlimited Items", &unlimitedItems, "Stops the game from lowering the amount of items such as consumables / throwables when using them, alongside other inventory items such as ammo, lockpicks and other items;\nWARNING: This will not stop the item from getting removed from your inventory if you drop the entire amount\nCurrently, if the amount of item is 1, it will still drop from your inventory unfortunately");
ImGui::SameLine();
ImGui::CheckboxHotkey("One-Hit Kill", &oneHitKill, "Makes the player one-hit kill EVERYTHING and EVERYONE RAWRRR");
ImGui::CheckboxHotkey("Invisible to Enemies", &invisibleToEnemies, "Makes the player invisible to the enemies");
ImGui::SameLine();
ImGui::CheckboxHotkey("Disable Out of Bounds Timer", &disableOutOfBoundsTimer, "Disables the timer that runs when out of map bounds or mission bounds");
ImGui::CheckboxHotkey("Nightrunner Mode", &nightrunnerMode, "Makes Aiden super-human/infected");
ImGui::SameLine();
ImGui::CheckboxHotkey("One-handed Mode", &oneHandedMode, "Removes Aiden's left hand");
ImGui::CheckboxHotkey("Disable Safezone Restrictions", &disableSafezoneRestrictions, "Disables all player restrictions inside a safezone, such as no jumping, climbing, weapons, etc; credits to @Synsteric on Discord for finding how to add this feature!");
ImGui::SeparatorText("Player Jump Parameters");
ImGui::SeparatorTextSection("Player Jump Parameters");
ImGui::CheckboxHotkey("Disable Air Control", &disableAirControl, "Disables the ability to change the player's direction of momentum while jumping (in-air)");
if (ImGui::Button("Reload Jump Params", "Reloads jump_parameters.scr from any mod located inside EGameTools\\UserModFiles")) {
if (EGSDK::Utils::Files::FileExistsInDir("jump_parameters.scr", "EGameTools\\UserModFiles")) {
@@ -500,7 +492,7 @@ namespace EGT::Menu {
ImGui::OpenPopup("Failed reloading player jump parameters.");
}
ImGui::SeparatorText("Player Variables");
ImGui::SeparatorTextSection("Player Variables");
ImGui::Checkbox("Enabled##vars", &playerVariables, "Shows the list of player variables");
HandlePlayerVariablesList();
HandlePlayerVariablesDialogs();
+78 -42
View File
@@ -1,3 +1,4 @@
#include <cmath>
#include <spdlog\spdlog.h>
#include <ImGui\imgui_hotkey.h>
#include <ImGui\imguiex.h>
@@ -7,6 +8,7 @@
#include <EGSDK\GamePH\PlayerDI_PH.h>
#include <EGSDK\GamePH\LevelDI.h>
#include <EGT\Menu\Camera.h>
#include <EGT\Menu\Menu.h>
#include <EGT\Menu\Player.h>
#include <EGT\Menu\Teleport.h>
@@ -341,37 +343,66 @@ namespace EGT::Menu {
HotkeysUpdate();
}
void Tab::Render() {
ImGui::SeparatorText("Saved Locations##Teleport");
ImGui::SetNextItemWidth(672.0f * Menu::scale);
ImGui::ListBox("##SavedTPLocationsListBox", &selectedTPLocation, savedTeleportLocationNamesPtrs.data(), static_cast<int>(savedTeleportLocationNamesPtrs.size()), 5);
ImGui::BeginDisabled(isTeleportationDisabled() || selectedTPLocation < 0 || selectedTPLocation >= savedTeleportLocations.size());
if (ImGui::ButtonHotkey("Teleport to Selected Location", &teleportToSelectedLocation, "Teleports player to selected location from the saved locations list"))
TeleportPlayerTo(savedTeleportLocations[selectedTPLocation].pos, savedTeleportLocations[selectedTPLocation].orientation);
ImGui::EndDisabled();
ImGui::SameLine();
ImGui::BeginDisabled(isTeleportationDisabled());
ImGui::SameLine();
if (ImGui::Button("Save Current Location"))
ImGui::OpenPopup("Give the location a name");
ImGui::EndDisabled();
ImGui::SameLine();
ImGui::BeginDisabled(selectedTPLocation < 0 || selectedTPLocation >= savedTeleportLocations.size() || isTeleportationDisabled());
if (ImGui::Button("Overwrite Selected Location"))
SaveTeleportLocation(savedTeleportLocations[selectedTPLocation].name.c_str(), true);
ImGui::EndDisabled();
ImGui::BeginDisabled(selectedTPLocation < 0 || selectedTPLocation >= savedTeleportLocations.size());
if (ImGui::Button("Remove Selected Location")) {
savedTeleportLocations.erase(savedTeleportLocations.begin() + selectedTPLocation);
UpdateTeleportLocationVisualNames();
selectedTPLocation = -1;
ImGui::SeparatorTextSection("Saved Locations##Teleport", false);
{
const ImGuiStyle& tpSt = ImGui::GetStyle();
const float lh = ImGui::GetTextLineHeightWithSpacing();
const float listH = lh * 5.5f + tpSt.FramePadding.y * 2.0f + 6.0f;
const float listW = std::fmax(80.0f, ImGui::GetContentRegionAvail().x - 8.0f);
ImGui::PushItemWidth(listW);
if (ImGui::BeginListBox("##SavedTPLocationsListBox", ImVec2(0.0f, listH))) {
ImGuiListClipper clipper;
const int n = static_cast<int>(savedTeleportLocationNamesPtrs.size());
clipper.Begin(n, lh);
while (clipper.Step()) {
for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) {
ImGui::PushID(i);
const bool sel = (i == selectedTPLocation);
if (ImGui::Selectable(savedTeleportLocationNamesPtrs[static_cast<size_t>(i)], sel))
selectedTPLocation = i;
if (sel)
ImGui::SetItemDefaultFocus();
ImGui::PopID();
}
}
ImGui::EndListBox();
}
ImGui::PopItemWidth();
}
ImGui::EndDisabled();
ImGui::SeparatorText("Custom##Teleport");
{
const float btnW = ImGui::GetContentRegionAvail().x;
ImGui::BeginDisabled(isTeleportationDisabled() || selectedTPLocation < 0 || selectedTPLocation >= savedTeleportLocations.size());
if (ImGui::ButtonHotkey("Teleport to Selected Location", &teleportToSelectedLocation, "Teleports player to selected location from the saved locations list", ImVec2(btnW, 0.0f)))
TeleportPlayerTo(savedTeleportLocations[selectedTPLocation].pos, savedTeleportLocations[selectedTPLocation].orientation);
ImGui::EndDisabled();
}
{
const float btnW = ImGui::GetContentRegionAvail().x;
ImGui::BeginDisabled(isTeleportationDisabled());
if (ImGui::Button("Save Current Location", nullptr, ImVec2(btnW, 0.0f)))
ImGui::OpenPopup("Give the location a name");
ImGui::EndDisabled();
}
{
const float btnW = ImGui::GetContentRegionAvail().x;
ImGui::BeginDisabled(selectedTPLocation < 0 || selectedTPLocation >= savedTeleportLocations.size() || isTeleportationDisabled());
if (ImGui::Button("Overwrite Selected Location", nullptr, ImVec2(btnW, 0.0f)))
SaveTeleportLocation(savedTeleportLocations[selectedTPLocation].name.c_str(), true);
ImGui::EndDisabled();
}
{
const float btnW = ImGui::GetContentRegionAvail().x;
ImGui::BeginDisabled(selectedTPLocation < 0 || selectedTPLocation >= savedTeleportLocations.size());
if (ImGui::Button("Remove Selected Location", nullptr, ImVec2(btnW, 0.0f))) {
savedTeleportLocations.erase(savedTeleportLocations.begin() + selectedTPLocation);
UpdateTeleportLocationVisualNames();
selectedTPLocation = -1;
}
ImGui::EndDisabled();
}
ImGui::SeparatorTextSection("Custom##Teleport");
ImGui::BeginDisabled(isTeleportationDisabled());
auto playerCharacter = EGSDK::Engine::CBulletPhysicsCharacter::Get();
auto freeCam = EGSDK::GamePH::FreeCamera::Get();
@@ -381,22 +412,27 @@ namespace EGT::Menu {
ImGui::Text("Free Camera Position: %s", GetFormattedPosition(freeCam && Camera::freeCam.GetValue() ? freeCam->GetPosition(&camPos) : nullptr).data());
ImGui::Text("Waypoint Position: %s", GetFormattedPosition(waypointIsSet && *waypointIsSet && !waypointCoords.isDefault() ? &waypointCoords : nullptr).data());
ImGui::SetNextItemWidth(500.0f * Menu::scale);
ImGui::InputFloat3("Teleport Coords (XYZ)", reinterpret_cast<float*>(&teleportCoords), "%.2fm");
ImGui::EndDisabled();
ImGui::BeginDisabled(isTeleportationDisabled() || !waypointIsSet || !*waypointIsSet);
if (ImGui::ButtonHotkey("Teleport to Waypoint", &teleportToWaypoint, "Teleports player to waypoint.\nWARNING: If the waypoint is selected to track an object/item on the map, Teleport to Waypoint will not work, if so just set the waypoint nearby instead.\nWARNING: Your player height won't change when teleporting, so make sure you catch yourself if you fall under the map because of the teleportation"))
justTeleportedToWaypoint = TeleportPlayerTo(waypointCoords);
ImGui::InputFloat3Stacked("Teleport Coords (XYZ)", reinterpret_cast<float*>(&teleportCoords), "%.2fm");
ImGui::EndDisabled();
{
const float btnW = ImGui::GetContentRegionAvail().x;
ImGui::BeginDisabled(isTeleportationDisabled() || !waypointIsSet || !*waypointIsSet);
if (ImGui::ButtonHotkey("Teleport to Waypoint", &teleportToWaypoint, "Teleports player to waypoint.\nWARNING: If the waypoint is selected to track an object/item on the map, Teleport to Waypoint will not work, if so just set the waypoint nearby instead.\nWARNING: Your player height won't change when teleporting, so make sure you catch yourself if you fall under the map because of the teleportation", ImVec2(btnW, 0.0f)))
justTeleportedToWaypoint = TeleportPlayerTo(waypointCoords);
ImGui::EndDisabled();
}
ImGui::BeginDisabled(isTeleportationDisabled());
ImGui::SameLine();
if (ImGui::ButtonHotkey("Teleport to Coords", &teleportToCoords, "Teleports player to the coords specified in the input boxes above"))
TeleportPlayerTo(teleportCoords);
ImGui::SameLine();
if (ImGui::Button("Get Player Coords"))
SyncPlayerCoordsToTPCoords();
{
const float btnW = ImGui::GetContentRegionAvail().x;
if (ImGui::ButtonHotkey("Teleport to Coords", &teleportToCoords, "Teleports player to the coords specified in the input boxes above", ImVec2(btnW, 0.0f)))
TeleportPlayerTo(teleportCoords);
}
{
const float btnW = ImGui::GetContentRegionAvail().x;
if (ImGui::Button("Get Player Coords", nullptr, ImVec2(btnW, 0.0f)))
SyncPlayerCoordsToTPCoords();
}
ImGui::EndDisabled();
HandleDialogs();
+65 -31
View File
@@ -24,13 +24,18 @@ namespace EGT {
ImGui::Checkbox("Restore variables to saved variables", &restoreVarsToSavedVarsEnabled, "Sets whether or not \"Restore variables to default\" should restore variables to the ones saved by \"Save current variables as default\"");
//ImGui::Checkbox("Debug Mode", &debugEnabled, "Shows text boxes alongside player variables, which will show the address in memory of each variable");
ImGui::BeginDisabled(!VarManagerT::AreAnyCustomVarsPresent() || VarManagerT::AreAllCustomVarsManagedByBool());
if (ImGui::Button("Restore variables to default"))
RestoreVarsToDefault();
ImGui::EndDisabled();
ImGui::SameLine();
if (ImGui::Button("Save current variables as default", "Saves the current variables as default for whenever you use \"Restore variables to default\""))
SaveVarsAsDefault();
{
const float btnW = ImGui::GetContentRegionAvail().x;
ImGui::BeginDisabled(!VarManagerT::AreAnyCustomVarsPresent() || VarManagerT::AreAllCustomVarsManagedByBool());
if (ImGui::Button("Restore variables to default", nullptr, ImVec2(btnW, 0.0f)))
RestoreVarsToDefault();
ImGui::EndDisabled();
}
{
const float btnW = ImGui::GetContentRegionAvail().x;
if (ImGui::Button("Save current variables as default", "Saves the current variables as default for whenever you use \"Restore variables to default\"", ImVec2(btnW, 0.0f)))
SaveVarsAsDefault();
}
ImGui::Separator();
ImGui::InputTextWithHint("##SearchFilter", "Search variables...", searchFilter, sizeof(searchFilter));
@@ -155,16 +160,42 @@ namespace EGT {
if (!var)
return;
ImGui::PushID(varPtr);
const ImGuiStyle& style = ImGui::GetStyle();
const float restoreWidth = ImGui::CalcTextSize("Restore").x + style.FramePadding.x * 2.0f + style.CellPadding.x * 2.0f;
constexpr ImGuiTableFlags rowFlags = ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_NoPadOuterX | ImGuiTableFlags_NoBordersInBody;
if (!ImGui::BeginTable("##varRow", 3, rowFlags)) {
ImGui::PopID();
return;
}
ImGui::TableSetupColumn("name", ImGuiTableColumnFlags_WidthStretch, 0.34f);
ImGui::TableSetupColumn("value", ImGuiTableColumnFlags_WidthStretch, 0.56f);
ImGui::TableSetupColumn("restore", ImGuiTableColumnFlags_WidthFixed, restoreWidth);
ImGui::TableNextRow();
ImGui::TableNextColumn();
{
const float wrapX = ImGui::GetCursorPos().x + ImGui::GetContentRegionAvail().x;
ImGui::PushTextWrapPos(wrapX);
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted(var->GetName());
ImGui::PopTextWrapPos();
}
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(-1.0f);
ImGui::BeginDisabled(var->IsManagedByBool());
bool valuePresent = true;
switch (var->GetType()) {
case EGSDK::Engine::VarType::String:
{
static char buffer[256];
//std::strncpy(buffer, value->c_str(), sizeof(buffer) - 1);
//buffer[sizeof(buffer) - 1] = '\0';
ImGui::BeginDisabled();
if (ImGui::InputText(var->GetName(), buffer, sizeof(buffer)))
if (ImGui::InputText("##str", buffer, sizeof(buffer)))
var->SetValueFromList(std::string(buffer));
ImGui::EndDisabled();
ImGui::SetItemTooltip("STRING VARIABLES NOT IMPLEMENTED");
@@ -174,11 +205,11 @@ namespace EGT {
{
auto value = var->GetValue<float>();
if (!value) {
ImGui::EndDisabled();
return;
valuePresent = false;
break;
}
float newValue = *value;
if (ImGui::InputFloat(var->GetName(), &newValue))
if (ImGui::InputFloat("##f", &newValue))
var->SetValueFromList(newValue);
break;
}
@@ -186,11 +217,11 @@ namespace EGT {
{
auto value = var->GetValue<int>();
if (!value) {
ImGui::EndDisabled();
return;
valuePresent = false;
break;
}
auto newValue = *value;
if (ImGui::InputInt(var->GetName(), &newValue))
if (ImGui::InputInt("##i", &newValue))
var->SetValueFromList(newValue);
break;
}
@@ -198,11 +229,11 @@ namespace EGT {
{
auto value = var->GetValue<vec3>();
if (!value) {
ImGui::EndDisabled();
return;
valuePresent = false;
break;
}
auto newValue = *value;
if (ImGui::InputFloat3(var->GetName(), reinterpret_cast<float*>(&newValue)))
if (ImGui::InputFloat3("##v3", reinterpret_cast<float*>(&newValue)))
var->SetValueFromList(newValue);
break;
}
@@ -210,11 +241,11 @@ namespace EGT {
{
auto value = var->GetValue<vec4>();
if (!value) {
ImGui::EndDisabled();
return;
valuePresent = false;
break;
}
auto newValue = *value;
if (ImGui::InputFloat4(var->GetName(), reinterpret_cast<float*>(&newValue)))
if (ImGui::InputFloat4("##v4", reinterpret_cast<float*>(&newValue)))
var->SetValueFromList(newValue);
break;
}
@@ -222,29 +253,32 @@ namespace EGT {
{
auto value = var->GetValue<bool>();
if (!value) {
ImGui::EndDisabled();
return;
valuePresent = false;
break;
}
bool newValue = *value;
if (ImGui::Checkbox(var->GetName(), &newValue))
if (ImGui::Checkbox("##b", &newValue))
var->SetValueFromList(newValue);
break;
}
default:
valuePresent = false;
break;
}
if (!valuePresent)
ImGui::TextUnformatted("—");
ImGui::EndDisabled();
ImGui::SameLine();
std::string restoreBtnName = "Restore##" + std::string(var->GetName());
ImGui::BeginDisabled(!var->HasCustomValue() || var->IsManagedByBool());
if (ImGui::Button(restoreBtnName.c_str(), "Restores variable to default"))
ImGui::TableNextColumn();
ImGui::BeginDisabled(!valuePresent || !var->HasCustomValue() || var->IsManagedByBool());
if (ImGui::Button("Restore", "Restores variable to default", ImVec2(-1.0f, 0.0f)))
RestoreVarToDefault(varPtr);
ImGui::EndDisabled();
//if (debugEnabled)
// RenderDebugInfo(playerVarPtr);
ImGui::EndTable();
ImGui::PopID();
}
template class VarList<EGSDK::GamePH::PlayerVariables>;
+2 -4
View File
@@ -98,17 +98,15 @@ namespace EGT::Menu {
PlayerVarsUpdate();
}
void Tab::Render() {
ImGui::SeparatorText("Current Weapon##Weapon");
ImGui::SeparatorTextSection("Current Weapon##Weapon", false);
ImGui::BeginDisabled(isWeaponInteractionDisabled() || currentWeaponDurability <= 0.0f);
UpdateWeaponDurability(!ImGui::SliderFloat("Weapon Durability", "Currently only works while your weapon is physically equipped in your hand", &currentWeaponDurability, 0.1f, 999.0f, "%.2f", ImGuiSliderFlags_AlwaysClamp));
ImGui::EndDisabled();
ImGui::SeparatorText("Misc##Weapon");
ImGui::SeparatorTextSection("Misc##Weapon");
ImGui::CheckboxHotkey("Unlimited Durability", &unlimitedDurability, "Enables unlimited durability for all weapons");
ImGui::SameLine();
ImGui::CheckboxHotkey("Unlimited Ammo", &unlimitedAmmo, "Enables unlimited ammo for all firearms and bows");
ImGui::CheckboxHotkey("No Spread", &noSpread, "Disables random bullet spread for all firearms and bows (doesn't completely remove spread for bows)");
ImGui::SameLine();
ImGui::CheckboxHotkey("No Recoil", &noRecoil, "Disables weapon recoil for all firearms");
ImGui::CheckboxHotkey("Instant Reload", &instantReload, "Makes reloading firearms and bows (almost) instant");
}
+7 -8
View File
@@ -156,9 +156,9 @@ namespace EGT::Menu {
auto dayNightCycle = EGSDK::GamePH::DayNightCycle::Get();
auto timeWeatherSystem = EGSDK::GamePH::TimeWeather::CSystem::Get();
auto iLevel = EGSDK::GamePH::LevelDI::Get();
ImGui::SeparatorText("Time##World");
ImGui::SeparatorTextSection("Time##World", false);
ImGui::BeginDisabled(!iLevel || !iLevel->IsLoaded() || !dayNightCycle || !timeWeatherSystem);
bool timeSlider = ImGui::SliderFloat("Time", &time, 0.01f, 24.0f, "%.2f", ImGuiSliderFlags_AlwaysClamp);
bool timeSlider = ImGui::SliderFloatStacked("Time", &time, 0.01f, 24.0f, "%.2f", ImGuiSliderFlags_AlwaysClamp);
EGSDK::GamePH::PlayerVariables::ManageVarByBool("AntizinDrainBlocked", true, false, timeSlider);
if (timeSlider) {
requestedTimeWeatherInterpolation = true;
@@ -167,24 +167,23 @@ namespace EGT::Menu {
}
ImGui::BeginDisabled(slowMotion.GetValue()); {
isModifyingGameSpeed = ImGui::SliderFloat("Game Speed", &gameSpeed, 0.0f, 2.0f, "%.2fx");
isModifyingGameSpeed = ImGui::SliderFloatStacked("Game Speed", &gameSpeed, 0.0f, 2.0f, "%.2fx");
if (isModifyingGameSpeed)
iLevel->TimerSetSpeedUp(gameSpeed);
ImGui::EndDisabled();
}
ImGui::CheckboxHotkey("Freeze Time", &freezeTime, "Freezes time");
ImGui::SameLine();
ImGui::CheckboxHotkey("Slow Motion", &slowMotion, "Slows the game down to the speed specified on the \"Slow Motion Speed\" slider");
ImGui::EndDisabled();
ImGui::SliderFloat("Slow Motion Speed", &slowMotionSpeed, 0.01f, 0.99f, "%.2fx", ImGuiSliderFlags_AlwaysClamp);
ImGui::SliderFloat("Slow Motion Transition Time", &slowMotionTransitionTime, 0.00f, 5.00f, "%.2fs", ImGuiSliderFlags_AlwaysClamp);
ImGui::SliderFloatStacked("Slow Motion Speed", &slowMotionSpeed, 0.01f, 0.99f, "%.2fx", ImGuiSliderFlags_AlwaysClamp);
ImGui::SliderFloatStacked("Slow Motion Transition Time", &slowMotionTransitionTime, 0.00f, 5.00f, "%.2fs", ImGuiSliderFlags_AlwaysClamp);
bool weatherDisabledFlag = !iLevel || !iLevel->IsLoaded() || !timeWeatherSystem;
ImGui::SeparatorText("Weather##World");
ImGui::SeparatorTextSection("Weather##World");
ImGui::BeginDisabled(weatherDisabledFlag);
if (ImGui::Combo("Weather", reinterpret_cast<int*>(&weather), weatherItems, IM_ARRAYSIZE(weatherItems))) {
if (ImGui::ComboStacked("Weather", reinterpret_cast<int*>(&weather), weatherItems, IM_ARRAYSIZE(weatherItems))) {
requestedTimeWeatherInterpolation = true;
timeWeatherSystem->SetForcedWeather(static_cast<EGSDK::GamePH::TimeWeather::EWeather>(weather - 1));
}