Implemented mock reddog window manager

Requires micross.ttf font in game root and ENABLE_IM_FONT_ATLAS_SNAPSHOT undefined, not currently in the font atlas.
This commit is contained in:
Hyper
2025-01-07 10:00:58 +00:00
parent 95bd71a23e
commit 2f68ee5df2
23 changed files with 996 additions and 92 deletions

View File

@@ -163,7 +163,14 @@ set(SWA_PATCHES_CXX_SOURCES
"patches/video_patches.cpp"
)
set(SWA_UI_CXX_SOURCES
set(SWA_UI_CXX_SOURCES
"ui/reddog/windows/counter_window.cpp"
"ui/reddog/windows/exports_window.cpp"
"ui/reddog/windows/view_window.cpp"
"ui/reddog/windows/window_list.cpp"
"ui/reddog/reddog_controls.cpp"
"ui/reddog/reddog_manager.cpp"
"ui/reddog/reddog_window.cpp"
"ui/achievement_menu.cpp"
"ui/achievement_overlay.cpp"
"ui/installer_wizard.cpp"
@@ -453,6 +460,22 @@ BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/co
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/common/kbm.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/common/kbm.dds" ARRAY_NAME "g_kbm" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/common/select_fade.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/common/select_fade.dds" ARRAY_NAME "g_select_fade" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/common/select_fill.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/common/select_fill.dds" ARRAY_NAME "g_select_fill" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/reddog/button_close_1.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/reddog/button_close_1.dds" ARRAY_NAME "g_button_close_1")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/reddog/button_close_2.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/reddog/button_close_2.dds" ARRAY_NAME "g_button_close_2")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/reddog/button_minimum_1.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/reddog/button_minimum_1.dds" ARRAY_NAME "g_button_minimum_1")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/reddog/button_minimum_2.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/reddog/button_minimum_2.dds" ARRAY_NAME "g_button_minimum_2")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/reddog/button_pin_1.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/reddog/button_pin_1.dds" ARRAY_NAME "g_button_pin_1")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/reddog/button_pin_2.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/reddog/button_pin_2.dds" ARRAY_NAME "g_button_pin_2")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/reddog/checkbox_1.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/reddog/checkbox_1.dds" ARRAY_NAME "g_checkbox_1")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/reddog/checkbox_2.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/reddog/checkbox_2.dds" ARRAY_NAME "g_checkbox_2")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/reddog/debug_icon.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/reddog/debug_icon.dds" ARRAY_NAME "g_debug_icon")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/reddog/common_icon.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/reddog/common_icon.dds" ARRAY_NAME "g_common_icon")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/reddog/mouse_cursor.bmp" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/reddog/mouse_cursor.bmp" ARRAY_NAME "g_mouse_cursor")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/reddog/mouse_cursor_h.bmp" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/reddog/mouse_cursor_h.bmp" ARRAY_NAME "g_mouse_cursor_h")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/reddog/mouse_cursor_slant_l.bmp" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/reddog/mouse_cursor_slant_l.bmp" ARRAY_NAME "g_mouse_cursor_slant_l")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/reddog/mouse_cursor_slant_r.bmp" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/reddog/mouse_cursor_slant_r.bmp" ARRAY_NAME "g_mouse_cursor_slant_r")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/reddog/mouse_cursor_v.bmp" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/reddog/mouse_cursor_v.bmp" ARRAY_NAME "g_mouse_cursor_v")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/reddog/title_bar.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/reddog/title_bar.dds" ARRAY_NAME "g_title_bar")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/installer/arrow_circle.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/installer/arrow_circle.dds" ARRAY_NAME "g_arrow_circle" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/installer/install_001.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/installer/install_001.dds" ARRAY_NAME "g_install_001" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/installer/install_002.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/installer/install_002.dds" ARRAY_NAME "g_install_002" COMPRESSION_TYPE "zstd")

View File

@@ -17,6 +17,7 @@
#include <res/font/im_font_atlas.dds.h>
#include <shader/shader_cache.h>
#include <SWA.h>
#include <ui/reddog/reddog_manager.h>
#include <ui/achievement_menu.h>
#include <ui/achievement_overlay.h>
#include <ui/button_guide.h>
@@ -1186,9 +1187,16 @@ static void CreateImGuiBackend()
AchievementMenu::Init();
AchievementOverlay::Init();
ButtonGuide::Init();
InstallerWizard::Init();
MessageWindow::Init();
OptionsMenu::Init();
InstallerWizard::Init();
#if !_DEBUG
if (Config::Debug)
#endif
{
Reddog::Manager::Init();
}
ImGui_ImplSDL2_InitForOther(GameWindow::s_pWindow);
@@ -1943,82 +1951,58 @@ static double g_applicationValues[PROFILER_VALUE_COUNT];
static Profiler g_presentProfiler;
static Profiler g_renderDirectorProfiler;
static bool g_profilerVisible;
static bool g_profilerWasToggled;
static void DrawProfiler()
void Video::DrawCounter()
{
bool toggleProfiler = SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_F1] != 0;
g_applicationValues[g_profilerValueIndex] = App::s_deltaTime * 1000.0;
if (!g_profilerWasToggled && toggleProfiler)
g_profilerVisible = !g_profilerVisible;
const double applicationAvg = std::accumulate(g_applicationValues, g_applicationValues + PROFILER_VALUE_COUNT, 0.0) / PROFILER_VALUE_COUNT;
double presentAvg = g_presentProfiler.UpdateAndReturnAverage();
double renderDirectorAvg = g_renderDirectorProfiler.UpdateAndReturnAverage();
g_profilerWasToggled = toggleProfiler;
if (!g_profilerVisible)
return;
ImFont* font = ImFontAtlasSnapshot::GetFont("FOT-SeuratPro-M.otf");
float defaultScale = font->Scale;
font->Scale = ImGui::GetDefaultFont()->FontSize / font->FontSize;
ImGui::PushFont(font);
if (ImGui::Begin("Profiler", &g_profilerVisible))
if (ImPlot::BeginPlot("Frame Time"))
{
g_applicationValues[g_profilerValueIndex] = App::s_deltaTime * 1000.0;
const double applicationAvg = std::accumulate(g_applicationValues, g_applicationValues + PROFILER_VALUE_COUNT, 0.0) / PROFILER_VALUE_COUNT;
double presentAvg = g_presentProfiler.UpdateAndReturnAverage();
double renderDirectorAvg = g_renderDirectorProfiler.UpdateAndReturnAverage();
if (ImPlot::BeginPlot("Frame Time"))
{
ImPlot::SetupAxisLimits(ImAxis_Y1, 0.0, 20.0);
ImPlot::SetupAxis(ImAxis_Y1, "ms", ImPlotAxisFlags_None);
ImPlot::PlotLine<double>("Application", g_applicationValues, PROFILER_VALUE_COUNT, 1.0, 0.0, ImPlotLineFlags_None, g_profilerValueIndex);
ImPlot::PlotLine<double>("Present", g_presentProfiler.values, PROFILER_VALUE_COUNT, 1.0, 0.0, ImPlotLineFlags_None, g_profilerValueIndex);
ImPlot::PlotLine<double>("Render Director", g_renderDirectorProfiler.values, PROFILER_VALUE_COUNT, 1.0, 0.0, ImPlotLineFlags_None, g_profilerValueIndex);
ImPlot::EndPlot();
}
g_profilerValueIndex = (g_profilerValueIndex + 1) % PROFILER_VALUE_COUNT;
ImGui::Text("Current Application: %g ms (%g FPS)", App::s_deltaTime * 1000.0, 1.0 / App::s_deltaTime);
ImGui::Text("Current Present: %g ms (%g FPS)", g_presentProfiler.value.load(), 1000.0 / g_presentProfiler.value.load());
ImGui::Text("Current Render Director: %g ms (%g FPS)", g_renderDirectorProfiler.value.load(), 1000.0 / g_renderDirectorProfiler.value.load());
ImGui::NewLine();
ImGui::Text("Average Application: %g ms (%g FPS)", applicationAvg, 1000.0 / applicationAvg);
ImGui::Text("Average Present: %g ms (%g FPS)", presentAvg, 1000.0 / presentAvg);
ImGui::Text("Average Render Director: %g ms (%g FPS)", renderDirectorAvg, 1000.0 / renderDirectorAvg);
ImGui::NewLine();
O1HeapDiagnostics diagnostics, physicalDiagnostics;
{
std::lock_guard lock(g_userHeap.mutex);
diagnostics = o1heapGetDiagnostics(g_userHeap.heap);
}
{
std::lock_guard lock(g_userHeap.physicalMutex);
physicalDiagnostics = o1heapGetDiagnostics(g_userHeap.physicalHeap);
}
ImGui::Text("Heap Allocated: %d MB", int32_t(diagnostics.allocated / (1024 * 1024)));
ImGui::Text("Physical Heap Allocated: %d MB", int32_t(physicalDiagnostics.allocated / (1024 * 1024)));
ImGui::NewLine();
ImGui::Text("Present Wait: %s", g_capabilities.presentWait ? "Supported" : "Unsupported");
ImGui::Text("Triangle Fan: %s", g_capabilities.triangleFan ? "Supported" : "Unsupported");
ImGui::NewLine();
const char* sdlVideoDriver = SDL_GetCurrentVideoDriver();
if (sdlVideoDriver != nullptr)
ImGui::Text("SDL Video Driver: %s", sdlVideoDriver);
ImPlot::SetupAxisLimits(ImAxis_Y1, 0.0, 20.0);
ImPlot::SetupAxis(ImAxis_Y1, "ms", ImPlotAxisFlags_None);
ImPlot::PlotLine<double>("Application", g_applicationValues, PROFILER_VALUE_COUNT, 1.0, 0.0, ImPlotLineFlags_None, g_profilerValueIndex);
ImPlot::PlotLine<double>("Present", g_presentProfiler.values, PROFILER_VALUE_COUNT, 1.0, 0.0, ImPlotLineFlags_None, g_profilerValueIndex);
ImPlot::PlotLine<double>("Render Director", g_renderDirectorProfiler.values, PROFILER_VALUE_COUNT, 1.0, 0.0, ImPlotLineFlags_None, g_profilerValueIndex);
ImPlot::EndPlot();
}
ImGui::End();
ImGui::PopFont();
font->Scale = defaultScale;
g_profilerValueIndex = (g_profilerValueIndex + 1) % PROFILER_VALUE_COUNT;
ImGui::Text("Current Application: %g ms (%g FPS)", App::s_deltaTime * 1000.0, 1.0 / App::s_deltaTime);
ImGui::Text("Current Present: %g ms (%g FPS)", g_presentProfiler.value.load(), 1000.0 / g_presentProfiler.value.load());
ImGui::Text("Current Render Director: %g ms (%g FPS)", g_renderDirectorProfiler.value.load(), 1000.0 / g_renderDirectorProfiler.value.load());
ImGui::NewLine();
ImGui::Text("Average Application: %g ms (%g FPS)", applicationAvg, 1000.0 / applicationAvg);
ImGui::Text("Average Present: %g ms (%g FPS)", presentAvg, 1000.0 / presentAvg);
ImGui::Text("Average Render Director: %g ms (%g FPS)", renderDirectorAvg, 1000.0 / renderDirectorAvg);
ImGui::NewLine();
O1HeapDiagnostics diagnostics, physicalDiagnostics;
{
std::lock_guard lock(g_userHeap.mutex);
diagnostics = o1heapGetDiagnostics(g_userHeap.heap);
}
{
std::lock_guard lock(g_userHeap.physicalMutex);
physicalDiagnostics = o1heapGetDiagnostics(g_userHeap.physicalHeap);
}
ImGui::Text("Heap Allocated: %d MB", int32_t(diagnostics.allocated / (1024 * 1024)));
ImGui::Text("Physical Heap Allocated: %d MB", int32_t(physicalDiagnostics.allocated / (1024 * 1024)));
ImGui::NewLine();
auto capabilities = g_device->getCapabilities();
ImGui::Text("Present Wait: %s", capabilities.presentWait ? "Supported" : "Unsupported");
ImGui::Text("Triangle Fan: %s", capabilities.triangleFan ? "Supported" : "Unsupported");
ImGui::NewLine();
const char* sdlVideoDriver = SDL_GetCurrentVideoDriver();
if (sdlVideoDriver != nullptr)
ImGui::Text("SDL Video Driver: %s", sdlVideoDriver);
}
static void DrawImGui()
@@ -2052,7 +2036,12 @@ static void DrawImGui()
ButtonGuide::Draw();
Fader::Draw();
DrawProfiler();
#if !_DEBUG
if (Config::Debug)
#endif
{
Reddog::Manager::Draw();
}
ImGui::Render();

View File

@@ -20,6 +20,7 @@ struct Video
static void Present();
static void StartPipelinePrecompilation();
static void WaitForGPU();
static void DrawCounter();
};
struct GuestSamplerState

View File

@@ -12,6 +12,11 @@
#pragma comment(lib, "dwmapi.lib")
#endif
#include <res/images/reddog/mouse_cursor.bmp.h>
#include <res/images/reddog/mouse_cursor_h.bmp.h>
#include <res/images/reddog/mouse_cursor_slant_l.bmp.h>
#include <res/images/reddog/mouse_cursor_slant_r.bmp.h>
#include <res/images/reddog/mouse_cursor_v.bmp.h>
#include <res/images/game_icon.bmp.h>
#include <res/images/game_icon_night.bmp.h>
@@ -105,7 +110,7 @@ int Window_OnSDLEvent(void*, SDL_Event* event)
GameWindow::s_isFocused = true;
if (GameWindow::IsFullscreen())
SDL_ShowCursor(GameWindow::s_isFullscreenCursorVisible ? SDL_ENABLE : SDL_DISABLE);
SDL_ShowCursor(GameWindow::s_isCursorVisible ? SDL_ENABLE : SDL_DISABLE);
break;
}
@@ -146,7 +151,7 @@ int Window_OnSDLEvent(void*, SDL_Event* event)
if (event->type == SDL_CONTROLLERBUTTONDOWN || event->type == SDL_CONTROLLERBUTTONUP || event->type == SDL_CONTROLLERAXISMOTION)
{
// Hide mouse cursor when controller input is detected.
SDL_ShowCursor(SDL_DISABLE);
SDL_ShowCursor(GameWindow::s_isCursorVisible ? SDL_ENABLE : SDL_DISABLE);
}
else if (event->type == SDL_MOUSEMOTION)
{
@@ -264,23 +269,23 @@ void GameWindow::Update()
s_isChangingDisplay = false;
}
SDL_Surface* GameWindow::GetIconSurface(void* pIconBmp, size_t iconSize)
SDL_Surface* GameWindow::CreateSurface(void* pBitmapData, size_t bitmapSize)
{
auto rw = SDL_RWFromMem(pIconBmp, iconSize);
auto rw = SDL_RWFromMem(pBitmapData, bitmapSize);
auto surface = SDL_LoadBMP_RW(rw, 1);
if (!surface)
LOGF_ERROR("Failed to load icon: {}", SDL_GetError());
LOGF_ERROR("Failed to create surface: {}", SDL_GetError());
return surface;
}
void GameWindow::SetIcon(void* pIconBmp, size_t iconSize)
{
if (auto icon = GetIconSurface(pIconBmp, iconSize))
if (auto surface = CreateSurface(pIconBmp, iconSize))
{
SDL_SetWindowIcon(s_pWindow, icon);
SDL_FreeSurface(icon);
SDL_SetWindowIcon(s_pWindow, surface);
SDL_FreeSurface(surface);
}
}
@@ -296,6 +301,69 @@ void GameWindow::SetIcon(bool isNight)
}
}
void GameWindow::SetCursor(ECursorType cursorType)
{
if (s_currentCursor == cursorType)
return;
s_currentCursor = cursorType;
uint8_t* pBitmapData;
size_t bitmapSize;
int x, y;
switch (cursorType)
{
case ECursorType::DebugDefault:
pBitmapData = g_mouse_cursor;
bitmapSize = sizeof(g_mouse_cursor);
x = 0;
y = 0;
break;
case ECursorType::DebugHorizontal:
pBitmapData = g_mouse_cursor_h;
bitmapSize = sizeof(g_mouse_cursor_h);
x = 15;
y = 15;
break;
case ECursorType::DebugVertical:
pBitmapData = g_mouse_cursor_v;
bitmapSize = sizeof(g_mouse_cursor_v);
x = 15;
y = 15;
break;
case ECursorType::DebugLeftDiagonal:
pBitmapData = g_mouse_cursor_slant_l;
bitmapSize = sizeof(g_mouse_cursor_slant_l);
x = 16;
y = 15;
break;
case ECursorType::DebugRightDiagonal:
pBitmapData = g_mouse_cursor_slant_r;
bitmapSize = sizeof(g_mouse_cursor_slant_r);
x = 16;
y = 15;
break;
default:
SDL_SetCursor(SDL_GetDefaultCursor());
return;
}
if (auto surface = CreateSurface(pBitmapData, bitmapSize))
{
if (auto cursor = SDL_CreateColorCursor(surface, x, y))
{
SDL_SetCursor(cursor);
SDL_FreeSurface(surface);
}
}
}
const char* GameWindow::GetTitle()
{
return Config::Language == ELanguage::Japanese
@@ -338,7 +406,7 @@ bool GameWindow::SetFullscreen(bool isEnabled)
if (isEnabled)
{
SDL_SetWindowFullscreen(s_pWindow, SDL_WINDOW_FULLSCREEN_DESKTOP);
SDL_ShowCursor(s_isFullscreenCursorVisible ? SDL_ENABLE : SDL_DISABLE);
SDL_ShowCursor(s_isCursorVisible ? SDL_ENABLE : SDL_DISABLE);
}
else
{
@@ -352,13 +420,13 @@ bool GameWindow::SetFullscreen(bool isEnabled)
return isEnabled;
}
void GameWindow::SetFullscreenCursorVisibility(bool isVisible)
void GameWindow::SetCursorVisibility(bool isVisible)
{
s_isFullscreenCursorVisible = isVisible;
s_isCursorVisible = isVisible;
if (IsFullscreen())
{
SDL_ShowCursor(s_isFullscreenCursorVisible ? SDL_ENABLE : SDL_DISABLE);
SDL_ShowCursor(s_isCursorVisible ? SDL_ENABLE : SDL_DISABLE);
}
else
{

View File

@@ -9,6 +9,16 @@
#define MIN_WIDTH 640
#define MIN_HEIGHT 480
enum class ECursorType
{
Default,
DebugDefault,
DebugHorizontal,
DebugVertical,
DebugLeftDiagonal,
DebugRightDiagonal
};
class GameWindow
{
public:
@@ -22,18 +32,21 @@ public:
static inline bool s_isFocused;
static inline bool s_isIconNight;
static inline bool s_isFullscreenCursorVisible;
static inline bool s_isCursorVisible;
static inline bool s_isChangingDisplay;
static SDL_Surface* GetIconSurface(void* pIconBmp, size_t iconSize);
static inline ECursorType s_currentCursor;
static SDL_Surface* CreateSurface(void* pBitmapData, size_t bitmapSize);
static void SetIcon(void* pIconBmp, size_t iconSize);
static void SetIcon(bool isNight = false);
static void SetCursor(ECursorType cursorType = ECursorType::Default);
static const char* GetTitle();
static void SetTitle(const char* title = nullptr);
static void SetTitleBarColour();
static bool IsFullscreen();
static bool SetFullscreen(bool isEnabled);
static void SetFullscreenCursorVisibility(bool isVisible);
static void SetCursorVisibility(bool isVisible);
static bool IsMaximised();
static EWindowState SetMaximised(bool isEnabled);
static SDL_Rect GetDimensions();

View File

@@ -1557,7 +1557,7 @@ bool InstallerWizard::Run(std::filesystem::path installPath, bool skipGame)
g_currentPage = g_firstPage;
}
GameWindow::SetFullscreenCursorVisibility(true);
GameWindow::SetCursorVisibility(true);
s_isVisible = true;
while (s_isVisible)
@@ -1569,7 +1569,7 @@ bool InstallerWizard::Run(std::filesystem::path installPath, bool skipGame)
Video::Present();
}
GameWindow::SetFullscreenCursorVisibility(false);
GameWindow::SetCursorVisibility(false);
NFD_Quit();
InstallerWizard::Shutdown();

View File

@@ -0,0 +1,59 @@
#include "reddog_controls.h"
#include <gpu/video.h>
#include <res/images/reddog/checkbox_1.dds.h>
#include <res/images/reddog/checkbox_2.dds.h>
constexpr float CHECKBOX_SIZE = 16.0f;
static std::unique_ptr<GuestTexture> g_upCheckbox1;
static std::unique_ptr<GuestTexture> g_upCheckbox2;
void Reddog::InitControlsResources()
{
g_upCheckbox1 = LoadTexture(g_checkbox_1, sizeof(g_checkbox_1));
g_upCheckbox2 = LoadTexture(g_checkbox_2, sizeof(g_checkbox_2));
}
bool Reddog::Checkbox(const char* label, bool* v)
{
ImGuiWindow* window = ImGui::GetCurrentWindow();
if (window->SkipItems)
return false;
auto& ctx = *GImGui;
auto& style = ctx.Style;
auto id = window->GetID(label);
auto labelSize = ImGui::CalcTextSize(label, nullptr, true);
auto pos = window->DC.CursorPos;
ImVec2 size = { CHECKBOX_SIZE, CHECKBOX_SIZE };
ImRect checkBoundingBox(pos, ImVec2(pos.x + size.x, pos.y + size.y));
ImRect totalBoundingBox(pos, ImVec2(pos.x + size.x + (labelSize.x > 0.0f ? style.ItemInnerSpacing.x + labelSize.x : 0.0f), pos.y + size.y));
ImGui::ItemSize(totalBoundingBox, style.FramePadding.y);
if (!ImGui::ItemAdd(totalBoundingBox, id))
return false;
bool isHovered, isHeld;
bool isPressed = ImGui::ButtonBehavior(checkBoundingBox, id, &isHovered, &isHeld);
if (isPressed)
{
*v = !*v;
ImGui::MarkItemEdited(id);
}
auto texture = *v
? g_upCheckbox2.get()
: g_upCheckbox1.get();
window->DrawList->AddImage(texture, checkBoundingBox.Min, checkBoundingBox.Max);
if (labelSize.x > 0.0f)
ImGui::RenderText({ checkBoundingBox.Max.x + style.ItemInnerSpacing.x, checkBoundingBox.Min.y + style.FramePadding.y }, label);
return isPressed;
}

View File

@@ -0,0 +1,7 @@
#pragma once
namespace Reddog
{
void InitControlsResources();
bool Checkbox(const char* label, bool* v);
}

View File

@@ -0,0 +1,146 @@
#include "reddog_manager.h"
#include <gpu/video.h>
#include <ui/reddog/windows/window_list.h>
#include <ui/reddog/reddog_controls.h>
#include <ui/game_window.h>
#include <ui/imgui_utils.h>
#include <res/images/reddog/debug_icon.dds.h>
static std::unique_ptr<GuestTexture> g_upDebugIcon;
static ImVec2 g_debugIconPosOrig;
static ImVec2 g_debugIconPos = { 0, 0 };
static bool g_isDebugIconClicked = false;
static bool g_isDraggingDebugIcon = false;
static bool g_isReddogToggled = false;
static bool g_isWindowListVisible = false;
void Reddog::Manager::Init()
{
g_upDebugIcon = LoadTexture(g_debug_icon, sizeof(g_debug_icon));
Reddog::InitControlsResources();
Reddog::InitWindowResources();
}
void Reddog::Manager::Draw()
{
bool isReddogToggled = SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_F1] != 0;
if (!g_isReddogToggled && isReddogToggled)
{
s_isVisible = !s_isVisible;
if (!s_isVisible)
{
g_debugIconPos = { 0, 0 };
GameWindow::SetCursor(ECursorType::Default);
GameWindow::SetCursorVisibility(false);
}
}
g_isReddogToggled = isReddogToggled;
if (!s_isVisible)
return;
if (GameWindow::s_currentCursor == ECursorType::Default)
{
GameWindow::SetCursor(ECursorType::DebugDefault);
GameWindow::SetCursorVisibility(true);
}
auto drawList = ImGui::GetForegroundDrawList();
auto& res = ImGui::GetIO().DisplaySize;
auto debugIconSize = Scale(32);
ImVec2 debugIconMin = g_debugIconPos;
ImVec2 debugIconMax = { g_debugIconPos.x + debugIconSize, g_debugIconPos.y + debugIconSize };
drawList->AddImage(g_upDebugIcon.get(), debugIconMin, debugIconMax);
if (ImGui::IsMouseHoveringRect(debugIconMin, debugIconMax, false) && ImGui::IsMouseClicked(0))
{
g_debugIconPosOrig = g_debugIconPos;
g_isDraggingDebugIcon = true;
}
g_isDebugIconClicked = false;
if (g_isDraggingDebugIcon && ImGui::IsMouseDown(0))
{
auto& delta = ImGui::GetIO().MouseDelta;
g_debugIconPos.x += delta.x;
g_debugIconPos.y += delta.y;
}
else
{
if (g_isDraggingDebugIcon &&
g_debugIconPos.x == g_debugIconPosOrig.x &&
g_debugIconPos.y == g_debugIconPosOrig.y)
{
g_isDebugIconClicked = true;
g_isWindowListVisible = !g_isWindowListVisible;
}
g_isDraggingDebugIcon = false;
}
if (auto pWindowList = GetWindow<WindowList>(WINDOW_LIST_NAME))
{
if (!g_isDebugIconClicked && !pWindowList->IsFocused)
pWindowList->IsVisible = g_isWindowListVisible = false;
pWindowList->IsVisible = g_isWindowListVisible;
if (pWindowList->ImWindow)
{
if (debugIconMin.x > res.x / 2)
{
pWindowList->ImWindow->Pos.x = debugIconMax.x - pWindowList->ImWindow->Size.x;
}
else
{
pWindowList->ImWindow->Pos.x = debugIconMin.x;
}
if (debugIconMin.y > res.y / 2)
{
pWindowList->ImWindow->Pos.y = debugIconMin.y - pWindowList->ImWindow->Size.y;
}
else
{
pWindowList->ImWindow->Pos.y = debugIconMin.y + debugIconSize;
}
}
}
for (auto& pWindow : Reddog::GetWindows())
{
auto pTrueWindow = (Reddog::Window*)pWindow;
if (!pTrueWindow->IsVisible)
continue;
pWindow->Draw();
}
}
Reddog::Window* Reddog::Manager::GetWindow(const char* pName)
{
for (auto pWindow : Reddog::GetWindows())
{
if (strcmp(pWindow->GetName(), pName) == 0)
return (Reddog::Window*)pWindow;
}
return nullptr;
}
template<typename T>
T* Reddog::Manager::GetWindow(const char* pName)
{
return (T*)Reddog::Manager::GetWindow(pName);
}

View File

@@ -0,0 +1,20 @@
#pragma once
#include <ui/reddog/reddog_window.h>
namespace Reddog
{
class Manager
{
public:
static inline bool s_isVisible = false;
static void Init();
static void Draw();
static Window* GetWindow(const char* pName);
template<typename T>
static T* GetWindow(const char* pName);
};
}

View File

@@ -0,0 +1,364 @@
#include "reddog_window.h"
#include <gpu/imgui/imgui_snapshot.h>
#include <gpu/video.h>
#include <ui/reddog/reddog_manager.h>
#include <ui/game_window.h>
#include <ui/imgui_utils.h>
#include <res/images/debug_menu/button_close_1.dds.h>
#include <res/images/debug_menu/button_close_2.dds.h>
#include <res/images/debug_menu/button_minimum_1.dds.h>
#include <res/images/debug_menu/button_minimum_2.dds.h>
#include <res/images/debug_menu/button_pin_1.dds.h>
#include <res/images/debug_menu/button_pin_2.dds.h>
#include <res/images/debug_menu/common_icon.dds.h>
#include <res/images/debug_menu/title_bar.dds.h>
constexpr float MIN_WINDOW_SIZE = 21.0f;
static std::unique_ptr<GuestTexture> g_upButtonClose1;
static std::unique_ptr<GuestTexture> g_upButtonClose2;
static std::unique_ptr<GuestTexture> g_upButtonMinimum1;
static std::unique_ptr<GuestTexture> g_upButtonMinimum2;
static std::unique_ptr<GuestTexture> g_upButtonPin1;
static std::unique_ptr<GuestTexture> g_upButtonPin2;
static std::unique_ptr<GuestTexture> g_upCommonIcon;
static std::unique_ptr<GuestTexture> g_upTitleBar;
static std::unique_ptr<GuestTexture> g_upWindowFrame;
ImFont* g_font;
float g_defaultFontScale;
ImGuiStyle g_defaultStyle;
static std::vector<Reddog::IWindow*>& Reddog::GetWindows()
{
static std::vector<Reddog::IWindow*> g_windows;
return g_windows;
}
void Reddog::InitWindowResources()
{
g_font = ImFontAtlasSnapshot::GetFont("micross.ttf");
g_defaultFontScale = g_font->Scale;
auto& style = ImGui::GetStyle();
g_defaultStyle = style;
g_upButtonClose1 = LoadTexture(g_button_close_1, sizeof(g_button_close_1));
g_upButtonClose2 = LoadTexture(g_button_close_2, sizeof(g_button_close_2));
g_upButtonMinimum1 = LoadTexture(g_button_minimum_1, sizeof(g_button_minimum_1));
g_upButtonMinimum2 = LoadTexture(g_button_minimum_2, sizeof(g_button_minimum_2));
g_upButtonPin1 = LoadTexture(g_button_pin_1, sizeof(g_button_pin_1));
g_upButtonPin2 = LoadTexture(g_button_pin_2, sizeof(g_button_pin_2));
g_upCommonIcon = LoadTexture(g_common_icon, sizeof(g_common_icon));
g_upTitleBar = LoadTexture(g_title_bar, sizeof(g_title_bar));
}
void Reddog::Window::BeginStyle()
{
g_font->Scale = ImGui::GetDefaultFont()->FontSize / g_font->FontSize;
ImGui::PushFont(g_font);
UpdateStyle();
}
void Reddog::Window::UpdateStyle()
{
auto& style = ImGui::GetStyle();
style.WindowMinSize = { 0, MIN_WINDOW_SIZE };
auto colBg = IsFocused
? ImU32ToImVec4(ActiveColour)
: ImU32ToImVec4(InactiveColour);
auto colBlack = ImVec4(0, 0, 0, 1);
auto colTrans = ImVec4(0, 0, 0, 0);
auto colWhite = ImVec4(1, 1, 1, 1);
style.Colors[ImGuiCol_Border] = colTrans;
style.Colors[ImGuiCol_Button] = colTrans;
style.Colors[ImGuiCol_ButtonActive] = ImVec4(0.8f, 0.788f, 0.741f, 1);
style.Colors[ImGuiCol_ButtonHovered] = ImVec4(0.722f, 0.714f, 0.667f, 1);
style.Colors[ImGuiCol_CheckMark] = colBlack;
style.Colors[ImGuiCol_ChildBg] = colBg;
style.Colors[ImGuiCol_FrameBg] = colBg;
style.Colors[ImGuiCol_PopupBg] = colBg;
style.Colors[ImGuiCol_ResizeGrip] = colTrans;
style.Colors[ImGuiCol_ResizeGripActive] = colTrans;
style.Colors[ImGuiCol_ResizeGripHovered] = colTrans;
style.Colors[ImGuiCol_ScrollbarBg] = ImVec4(0.6f, 0.6f, 0.6f, 1);
style.Colors[ImGuiCol_ScrollbarGrab] = ImVec4(1, 0.6f, 0, 1);
style.Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(1, 0.6f, 0, 1);
style.Colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(1, 0.6f, 0, 1);
style.Colors[ImGuiCol_SeparatorActive] = colTrans;
style.Colors[ImGuiCol_SeparatorHovered] = colTrans;
style.Colors[ImGuiCol_SliderGrab] = colWhite;
style.Colors[ImGuiCol_Tab] = ImVec4(0.467f, 0.467f, 0.467f, 1);
style.Colors[ImGuiCol_TabActive] = ImVec4(0.6f, 0.6f, 0.6f, 1);
style.Colors[ImGuiCol_TabHovered] = ImVec4(0.667f, 0.667f, 0.667f, 1);
style.Colors[ImGuiCol_Text] = colBlack;
style.Colors[ImGuiCol_WindowBg] = colBg;
}
void Reddog::Window::EndStyle()
{
ImGui::PopFont();
g_font->Scale = g_defaultFontScale;
ImGui::GetStyle() = g_defaultStyle;
}
void Reddog::Window::CreateWindowGrips()
{
if (!ImWindow || !IsFocused)
return;
auto& io = ImGui::GetIO();
auto windowPos = ImWindow->Pos;
auto windowSize = ImWindow->Size;
constexpr float resizeMargin = 5.0f;
ImRect grips[6] =
{
// Corners
ImRect(windowPos.x, windowPos.y + windowSize.y - resizeMargin, windowPos.x + resizeMargin, windowPos.y + windowSize.y), // Bottom left
ImRect(windowPos.x + windowSize.x - resizeMargin, windowPos.y + windowSize.y - resizeMargin, windowPos.x + windowSize.x, windowPos.y + windowSize.y), // Bottom right
// Edges
ImRect(windowPos.x + resizeMargin, windowPos.y, windowPos.x + windowSize.x - resizeMargin, windowPos.y + resizeMargin), // Top
ImRect(windowPos.x + resizeMargin, windowPos.y + windowSize.y - resizeMargin, windowPos.x + windowSize.x - resizeMargin, windowPos.y + windowSize.y), // Bottom
ImRect(windowPos.x, windowPos.y + resizeMargin, windowPos.x + resizeMargin, windowPos.y + windowSize.y - resizeMargin), // Left
ImRect(windowPos.x + windowSize.x - resizeMargin, windowPos.y + resizeMargin, windowPos.x + windowSize.x, windowPos.y + windowSize.y - resizeMargin) // Right
};
auto hoveredGrip = -1;
for (int i = 0; i < IM_ARRAYSIZE(grips); i++)
{
auto& grip = grips[i];
if (ImGui::IsMouseHoveringRect(grip.Min, grip.Max))
hoveredGrip = i;
}
if (hoveredGrip < 0)
{
GameWindow::SetCursor(ECursorType::DebugDefault);
}
else
{
if (hoveredGrip == 0)
{
GameWindow::SetCursor(ECursorType::DebugRightDiagonal);
}
else if (hoveredGrip == 1)
{
GameWindow::SetCursor(ECursorType::DebugLeftDiagonal);
}
else if (hoveredGrip == 2 || hoveredGrip == 3)
{
GameWindow::SetCursor(ECursorType::DebugVertical);
}
else
{
GameWindow::SetCursor(ECursorType::DebugHorizontal);
}
}
}
void Reddog::Window::DrawFrame()
{
if (!ImWindow)
return;
if ((Flags & eWindowFlags_NoResize) == 0)
CreateWindowGrips();
UpdateStyle();
auto drawList = ImGui::GetWindowDrawList();
auto windowPos = ImWindow->Pos;
auto windowSize = ImWindow->Size;
auto isFocused = ImGui::IsWindowFocused();
auto hasTitleBar = (Flags & eWindowFlags_NoTitleBar) == 0;
float titleBarHeight = hasTitleBar ? 20.0f : 0.0f;
ImVec2 windowMin = { windowPos.x, windowPos.y + titleBarHeight };
ImVec2 windowMax = { windowPos.x + windowSize.x, windowPos.y + windowSize.y };
drawList->AddRectFilled(windowMin, windowMax, isFocused ? ActiveColour : InactiveColour);
drawList->AddLine(windowMin, { windowMax.x, windowMin.y }, IM_COL32(170, 170, 170, 255)); // Outer top line.
drawList->AddLine({ windowMin.x + 1, windowMin.y + 1 }, { windowMin.x + 1, windowMax.y }, IM_COL32(153, 153, 153, 255)); // Outer left line.
drawList->AddLine({ windowMin.x, windowMax.y - 2 }, { windowMax.x, windowMax.y - 2 }, IM_COL32(51, 51, 51, 255)); // Outer bottom line.
drawList->AddLine({ windowMax.x - 2, windowMin.y + 1 }, { windowMax.x - 2, windowMax.y }, IM_COL32(85, 85, 85, 255)); // Outer right line.
drawList->AddLine({ windowMin.x + 2, windowMin.y + 1 }, { windowMax.x - 2, windowMin.y + 1 }, IM_COL32(51, 51, 51, 255)); // Inner top line.
drawList->AddLine({ windowMin.x + 2, windowMin.y + 2 }, { windowMin.x + 2, windowMax.y - 2 }, IM_COL32(85, 85, 85, 255)); // Inner left line.
drawList->AddLine({ windowMin.x + 3, windowMax.y - 3 }, { windowMax.x - 2, windowMax.y - 3 }, IM_COL32(170, 170, 170, 255)); // Inner bottom line.
drawList->AddLine({ windowMax.x - 3, windowMin.y + 2 }, { windowMax.x - 3, windowMax.y - 3 }, IM_COL32(153, 153, 153, 255)); // Inner right line.
// Close window if unfocused whilst unpinned (yes it works like this in SU preview).
if (!IsPinned && !isFocused && m_pIsVisible)
*m_pIsVisible = !*m_pIsVisible;
if (hasTitleBar)
{
auto height = titleBarHeight;
auto left = PIXELS_TO_UV_COORDS(32, 32, 0, 0, 3, 32);
auto centre = PIXELS_TO_UV_COORDS(32, 32, 3, 0, 26, 32);
auto right = PIXELS_TO_UV_COORDS(32, 32, 29, 0, 3, 32);
auto col = isFocused
? IM_COL32(245, 245, 245, 255)
: IM_COL32(246, 226, 202, 255);
drawList->AddImage(g_upTitleBar.get(), { windowPos.x, windowPos.y }, { windowPos.x + 3, windowPos.y + height }, GET_UV_COORDS(left), col);
drawList->AddImage(g_upTitleBar.get(), { windowPos.x + 3, windowPos.y }, { windowPos.x + windowSize.x - 3, windowPos.y + height }, GET_UV_COORDS(centre), col);
drawList->AddImage(g_upTitleBar.get(), { windowPos.x + windowSize.x - 3, windowPos.y }, { windowPos.x + windowSize.x, windowPos.y + height }, GET_UV_COORDS(right), col);
auto cmnSize = 16.0f;
ImVec2 cmnIconMin = { windowPos.x + 9, windowPos.y + 2 };
ImVec2 cmnIconMax = { cmnIconMin.x + cmnSize, cmnIconMin.y + cmnSize };
drawList->AddImage(g_upCommonIcon.get(), cmnIconMin, cmnIconMax, { 0, 0 }, { 1, 1 }, IM_COL32(255, 255, 255, 255));
drawList->AddText({ cmnIconMax.x + 5, windowPos.y + 4 }, IM_COL32(255, 255, 255, 255), Name);
ImVec2 closeButtonMin = { windowPos.x + windowSize.x - cmnSize - 4, windowPos.y + 3 };
ImVec2 closeButtonMax = { closeButtonMin.x + cmnSize, closeButtonMin.y + cmnSize };
ImGui::SetCursorScreenPos(closeButtonMin);
ImGui::InvisibleButton("##CloseButton", { cmnSize, cmnSize });
bool isCloseButtonActive = ImGui::IsItemActive();
if (isCloseButtonActive)
{
drawList->AddImage(g_upButtonClose2.get(), closeButtonMin, closeButtonMax);
m_isCloseButtonPressed = true;
}
else
{
drawList->AddImage(g_upButtonClose1.get(), closeButtonMin, closeButtonMax);
if (m_isCloseButtonPressed && m_pIsVisible)
{
*m_pIsVisible = !*m_pIsVisible;
m_isCloseButtonPressed = false;
}
}
ImVec2 minimumButtonMin = { closeButtonMin.x - cmnSize - 4, windowPos.y + 3 };
ImVec2 minimumButtonMax = { minimumButtonMin.x + cmnSize, minimumButtonMin.y + cmnSize };
ImGui::SetCursorScreenPos(minimumButtonMin);
ImGui::InvisibleButton("##MinimumButton", { cmnSize, cmnSize });
bool isMinimumButtonActive = ImGui::IsItemActive();
if (isMinimumButtonActive)
{
drawList->AddImage(g_upButtonMinimum2.get(), minimumButtonMin, minimumButtonMax);
m_isMinimumButtonPressed = true;
}
else
{
drawList->AddImage(g_upButtonMinimum1.get(), minimumButtonMin, minimumButtonMax);
if (m_isMinimumButtonPressed)
{
IsMinimum = !IsMinimum;
if (IsMinimum)
{
m_preMinimumWindowSize = windowSize;
ImGui::SetWindowSize(ImWindow, { windowSize.x, MIN_WINDOW_SIZE });
}
else
{
ImGui::SetWindowSize(ImWindow, { windowSize.x, m_preMinimumWindowSize.y });
}
m_isMinimumButtonPressed = false;
}
}
ImVec2 pinButtonMin = { minimumButtonMin.x - cmnSize - 4, windowPos.y + 3 };
ImVec2 pinButtonMax = { pinButtonMin.x + cmnSize, pinButtonMin.y + cmnSize };
ImGui::SetCursorScreenPos(pinButtonMin);
ImGui::InvisibleButton("##PinButton", { cmnSize, cmnSize });
bool isPinButtonActive = ImGui::IsItemActive();
if (isPinButtonActive)
{
drawList->AddImage(g_upButtonPin2.get(), pinButtonMin, pinButtonMax);
m_isPinButtonPressed = true;
}
else
{
drawList->AddImage(g_upButtonPin1.get(), pinButtonMin, pinButtonMax);
if (m_isPinButtonPressed)
{
IsPinned = !IsPinned;
m_isPinButtonPressed = false;
}
}
}
}
void Reddog::Window::SetVisible(bool isVisible)
{
IsVisible = m_isSetVisible = isVisible;
}
bool Reddog::Window::Begin(bool* pIsVisible)
{
if (pIsVisible)
{
m_pIsVisible = pIsVisible;
}
else
{
m_pIsVisible = &IsVisible;
}
BeginStyle();
ImGui::SetNextWindowSizeConstraints({ m_minWidth, m_minHeight }, { m_maxWidth, m_maxHeight });
auto flags = REDDOG_IMGUI_FLAGS;
if ((Flags & eWindowFlags_NoResize) != 0)
flags |= ImGuiWindowFlags_NoResize;
bool result = ImGui::Begin(Name, m_pIsVisible, flags);
if (result && *m_pIsVisible)
{
ImWindow = ImGui::GetCurrentWindow();
IsFocused = ImGui::IsWindowFocused();
if (m_isSetVisible)
{
ImGui::SetWindowFocus();
m_isSetVisible = false;
}
DrawFrame();
return true;
}
return false;
}
void Reddog::Window::End()
{
ImGui::End();
EndStyle();
}

View File

@@ -0,0 +1,87 @@
#pragma once
#define REDDOG_IMGUI_FLAGS ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoBackground
namespace Reddog
{
enum EWindowFlags : uint32_t
{
eWindowFlags_None = 0,
eWindowFlags_NoTitleBar = 1 << 0,
eWindowFlags_NoResize = 1 << 1,
eWindowFlags_NoListEntry = 1 << 2
};
class IWindow
{
public:
virtual ~IWindow() = default;
virtual const char* GetName() = 0;
virtual void Draw() = 0;
};
extern std::vector<IWindow*>& GetWindows();
class Window : public IWindow
{
private:
bool* m_pIsVisible{ nullptr };
bool m_isSetVisible{};
bool m_isCloseButtonPressed{};
bool m_isMinimumButtonPressed{};
bool m_isPinButtonPressed{};
ImVec2 m_preMinimumWindowSize{};
void BeginStyle();
void UpdateStyle();
void EndStyle();
void CreateWindowGrips();
void DrawFrame();
protected:
float m_minWidth{ 175.0f };
float m_minHeight{};
float m_maxWidth{ FLT_MAX };
float m_maxHeight{ FLT_MAX };
public:
const char* Name{ "(null)" };
EWindowFlags Flags{ eWindowFlags_None };
bool IsFocused{ true };
bool IsMinimum{};
bool IsPinned{ true };
bool IsVisible{};
ImGuiWindow* ImWindow{ nullptr };
ImU32 ActiveColour{ IM_COL32(232, 231, 255, 255) };
ImU32 InactiveColour{ IM_COL32(193, 192, 181, 255) };
Window()
{
GetWindows().push_back(this);
}
Window(const char* pName, EWindowFlags flags = eWindowFlags_None) : Name(pName), Flags(flags)
{
GetWindows().push_back(this);
}
const char* GetName() override
{
return Name;
}
void Draw() override
{
Begin();
End();
}
void SetVisible(bool isVisible = true);
bool Begin(bool* pIsVisible = nullptr);
void End();
};
void InitWindowResources();
}

View File

@@ -0,0 +1,13 @@
#include "counter_window.h"
#include <gpu/video.h>
static CounterWindow g_window;
void CounterWindow::Draw()
{
if (Begin())
{
Video::DrawCounter();
}
End();
}

View File

@@ -0,0 +1,17 @@
#pragma once
#include <ui/reddog/reddog_window.h>
class CounterWindow : public Reddog::Window
{
public:
CounterWindow() : Window()
{
Name = "Counter";
m_minWidth = 215;
m_minHeight = 328;
}
void Draw() override;
};

View File

@@ -0,0 +1,19 @@
#include "exports_window.h"
#include <ui/reddog/reddog_controls.h>
#include <user/config.h>
static ExportsWindow g_window{ "Exports" };
void ExportsWindow::Draw()
{
if (Begin())
{
ImGui::TextColored({ 1, 0, 0, 1 }, "For testing purposes only, use Hedge Mod Manager to toggle these.");
Reddog::Checkbox("Allow Cancelling Unleash", &Config::AllowCancellingUnleash.Value);
Reddog::Checkbox("Fix Unleash Out of Control Drain", &Config::FixUnleashOutOfControlDrain.Value);
Reddog::Checkbox("Homing Attack on Boost", &Config::HomingAttackOnBoost.Value);
Reddog::Checkbox("Save Score at Checkpoints", &Config::SaveScoreAtCheckpoints.Value);
Reddog::Checkbox("Skip Intro Logos", &Config::SkipIntroLogos.Value);
}
End();
}

View File

@@ -0,0 +1,11 @@
#pragma once
#include <ui/reddog/reddog_window.h>
class ExportsWindow : public Reddog::Window
{
public:
using Reddog::Window::Window;
void Draw() override;
};

View File

@@ -0,0 +1,14 @@
#include "view_window.h"
#include <kernel/memory.h>
#include <ui/reddog/reddog_controls.h>
static ViewWindow g_window{ "View" };
void ViewWindow::Draw()
{
if (Begin())
{
Reddog::Checkbox("Render HUD", (bool*)g_memory.Translate(0x8328BB26));
}
End();
}

View File

@@ -0,0 +1,11 @@
#pragma once
#include <ui/reddog/reddog_window.h>
class ViewWindow : public Reddog::Window
{
public:
using Reddog::Window::Window;
void Draw() override;
};

View File

@@ -0,0 +1,21 @@
#include "window_list.h"
static WindowList g_window;
void WindowList::Draw()
{
if (Begin())
{
for (auto& pWindow : Reddog::GetWindows())
{
auto pTrueWindow = (Reddog::Window*)pWindow;
if ((pTrueWindow->Flags & Reddog::eWindowFlags_NoListEntry) != 0)
continue;
if (ImGui::Button(pTrueWindow->Name, { 190, 26 }))
pTrueWindow->SetVisible();
}
}
End();
}

View File

@@ -0,0 +1,20 @@
#pragma once
#include <ui/reddog/reddog_window.h>
#define WINDOW_LIST_NAME "##WindowList"
class WindowList : public Reddog::Window
{
public:
WindowList() : Window()
{
Name = WINDOW_LIST_NAME;
Flags = (Reddog::EWindowFlags)(Reddog::eWindowFlags_NoTitleBar | Reddog::eWindowFlags_NoResize | Reddog::eWindowFlags_NoListEntry);
ActiveColour = InactiveColour = IM_COL32_WHITE;
m_minWidth = m_minHeight = 0;
}
void Draw() override;
};

View File

@@ -596,6 +596,7 @@ public:
CONFIG_DEFINE_LOCALISED("System", bool, ControlTutorial, true);
CONFIG_DEFINE_LOCALISED("System", bool, AchievementNotifications, true);
CONFIG_DEFINE_ENUM_LOCALISED("System", ETimeOfDayTransition, TimeOfDayTransition, ETimeOfDayTransition::Xbox);
CONFIG_DEFINE("System", bool, Debug, false);
CONFIG_DEFINE_LOCALISED("Input", bool, InvertCameraX, false);
CONFIG_DEFINE_LOCALISED("Input", bool, InvertCameraY, false);