mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-07-04 11:19:58 -04:00
Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1c1a849095 | |||
| 89d393e57a | |||
| 2f27687d80 | |||
| 167a50c01d | |||
| 313f03f5e5 | |||
| 6cfdc3d8a3 | |||
| 9c24a0bc4b | |||
| b99ad920c4 | |||
| 912b18eca1 | |||
| 9e651a51db | |||
| c8b6e997a7 | |||
| 928e187524 | |||
| cf12d19860 | |||
| e3a3ac56fb | |||
| d15ed81cd5 | |||
| ff054f6f47 | |||
| 667cf70fa0 | |||
| 73eb401c93 | |||
| b11f3add06 | |||
| 92f888a152 | |||
| 78ed5cc716 |
+2
-1
@@ -102,6 +102,7 @@ set(AURORA_ENABLE_DVD ON CACHE BOOL "Enable DVD API support" FORCE)
|
||||
set(AURORA_ENABLE_CARD ON CACHE BOOL "Enable CARD API support" FORCE)
|
||||
set(AURORA_ENABLE_RMLUI ON CACHE BOOL "Enable RmlUi UI support" FORCE)
|
||||
add_subdirectory(extern/aurora EXCLUDE_FROM_ALL)
|
||||
target_compile_definitions(aurora_mtx PRIVATE MTX_USE_PS=1)
|
||||
|
||||
add_subdirectory(libs/freeverb)
|
||||
|
||||
@@ -285,7 +286,7 @@ set(DUSK_COPYRIGHT "Copyright (C) Twilit Realm contributors")
|
||||
source_group("dolzel" FILES ${DOLZEL_FILES} ${Z2AUDIOLIB_FILES} ${REL_FILES})
|
||||
source_group("dusk" FILES ${DUSK_FILES})
|
||||
|
||||
set(GAME_COMPILE_DEFS TARGET_PC WIDESCREEN_SUPPORT=1 AVOID_UB=1 VERSION=0)
|
||||
set(GAME_COMPILE_DEFS TARGET_PC WIDESCREEN_SUPPORT=1 AVOID_UB=1 VERSION=0 MTX_USE_PS=1)
|
||||
|
||||
set(GAME_INCLUDE_DIRS
|
||||
include
|
||||
|
||||
Vendored
+1
-1
Submodule extern/aurora updated: 69fcfbffc2...18dc51234f
@@ -57,6 +57,8 @@ struct UserSettings {
|
||||
ConfigVar<bool> enableFullscreen;
|
||||
ConfigVar<bool> enableVsync;
|
||||
ConfigVar<bool> lockAspectRatio;
|
||||
ConfigVar<bool> enableFpsOverlay;
|
||||
ConfigVar<int> fpsOverlayCorner;
|
||||
} video;
|
||||
|
||||
struct {
|
||||
@@ -97,7 +99,7 @@ struct UserSettings {
|
||||
|
||||
// Preferences
|
||||
ConfigVar<bool> enableMirrorMode;
|
||||
ConfigVar<bool> disableMainHUD;
|
||||
ConfigVar<bool> minimalHUD;
|
||||
ConfigVar<bool> pauseOnFocusLost;
|
||||
ConfigVar<bool> enableLinkDollRotation;
|
||||
ConfigVar<bool> enableAchievementNotifications;
|
||||
@@ -132,6 +134,7 @@ struct UserSettings {
|
||||
ConfigVar<bool> invertCameraYAxis;
|
||||
ConfigVar<float> freeCameraSensitivity;
|
||||
ConfigVar<bool> debugFlyCam;
|
||||
ConfigVar<bool> debugFlyCamLockEvents;
|
||||
|
||||
// Cheats
|
||||
ConfigVar<bool> infiniteHearts;
|
||||
@@ -158,6 +161,7 @@ struct UserSettings {
|
||||
// Tools
|
||||
ConfigVar<bool> speedrunMode;
|
||||
ConfigVar<bool> liveSplitEnabled;
|
||||
ConfigVar<bool> recordingMode;
|
||||
} game;
|
||||
|
||||
struct {
|
||||
@@ -169,6 +173,7 @@ struct UserSettings {
|
||||
ConfigVar<bool> wasPresetChosen;
|
||||
ConfigVar<bool> enableCrashReporting;
|
||||
ConfigVar<int> cardFileType;
|
||||
ConfigVar<bool> enableAdvancedSettings;
|
||||
} backend;
|
||||
};
|
||||
|
||||
|
||||
+41
-2
@@ -20,18 +20,22 @@ body {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
fps,
|
||||
toast {
|
||||
position: absolute;
|
||||
border: 1dp #92875B;
|
||||
background-color: rgba(21, 22, 16, 80%);
|
||||
}
|
||||
|
||||
toast {
|
||||
top: 40dp;
|
||||
right: 40dp;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
border-radius: 14dp;
|
||||
overflow: hidden;
|
||||
border: 1dp #92875B;
|
||||
backdrop-filter: blur(5dp);
|
||||
box-shadow: 0 0 15dp 3dp;
|
||||
background-color: rgba(21, 22, 16, 80%);
|
||||
filter: opacity(0);
|
||||
transform: scale(0.9);
|
||||
transform-origin: center;
|
||||
@@ -186,6 +190,41 @@ icon.warning {
|
||||
decorator: text("" center center);
|
||||
}
|
||||
|
||||
fps {
|
||||
display: none;
|
||||
z-index: 99;
|
||||
font-size: 18dp;
|
||||
font-weight: bold;
|
||||
padding: 9dp 12dp;
|
||||
border-radius: 7dp;
|
||||
pointer-events: none;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
fps[open] {
|
||||
display: block;
|
||||
}
|
||||
|
||||
fps[corner=tl] {
|
||||
top: 12dp;
|
||||
left: 12dp;
|
||||
}
|
||||
|
||||
fps[corner=tr] {
|
||||
top: 12dp;
|
||||
right: 12dp;
|
||||
}
|
||||
|
||||
fps[corner=bl] {
|
||||
bottom: 12dp;
|
||||
left: 12dp;
|
||||
}
|
||||
|
||||
fps[corner=br] {
|
||||
bottom: 12dp;
|
||||
right: 12dp;
|
||||
}
|
||||
|
||||
logo {
|
||||
position: absolute;
|
||||
width: 100dp;
|
||||
|
||||
@@ -322,3 +322,84 @@ body.animate-in .intro-item {
|
||||
.delay-5 {
|
||||
transition: opacity transform 0.3s 0.6s cubic-in-out;
|
||||
}
|
||||
|
||||
/* Mobile layout */
|
||||
@media (max-height: 640dp) {
|
||||
.gradient {
|
||||
decorator: horizontal-gradient(#00000000 #000000FF);
|
||||
}
|
||||
|
||||
body.mirrored .gradient {
|
||||
decorator: horizontal-gradient(#000000FF #00000000);
|
||||
}
|
||||
|
||||
menu {
|
||||
left: 20dp;
|
||||
right: 20dp;
|
||||
width: auto;
|
||||
min-width: 0;
|
||||
max-width: none;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16dp;
|
||||
}
|
||||
|
||||
body.mirrored menu {
|
||||
left: 20dp;
|
||||
right: 20dp;
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
hero {
|
||||
flex: 1 1 0;
|
||||
min-width: 0;
|
||||
max-width: 48%;
|
||||
|
||||
}
|
||||
|
||||
body.mirrored hero {
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
hero img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#menu-list {
|
||||
flex: 1 1 0;
|
||||
min-width: 0;
|
||||
max-width: 52%;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
#menu-list button {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#menu-list button:hover,
|
||||
#menu-list button:focus-visible {
|
||||
decorator: horizontal-gradient(#FEE68500 #FEE685FF);
|
||||
}
|
||||
|
||||
body.mirrored #menu-list {
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
body.mirrored #menu-list button {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
body.mirrored #menu-list button:hover,
|
||||
body.mirrored #menu-list button:focus-visible {
|
||||
decorator: horizontal-gradient(#FEE685FF #FEE68500);
|
||||
}
|
||||
|
||||
.eyebrow,
|
||||
disc-info,
|
||||
version-info {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
+13
-4
@@ -287,6 +287,10 @@ icon.celebration {
|
||||
decorator: text("" center center);
|
||||
}
|
||||
|
||||
icon.question-mark {
|
||||
decorator: text("" center center);
|
||||
}
|
||||
|
||||
.achievement-row {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
@@ -343,7 +347,7 @@ icon.celebration {
|
||||
color: rgba(224, 219, 200, 45%);
|
||||
}
|
||||
|
||||
progressbar {
|
||||
progress {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 6dp;
|
||||
@@ -352,12 +356,12 @@ progressbar {
|
||||
margin: 6dp 0 2dp 0;
|
||||
}
|
||||
|
||||
progressbar.progress-done fill {
|
||||
progress.progress-done fill {
|
||||
background-color: #44aa22;
|
||||
border-radius: 3dp;
|
||||
}
|
||||
|
||||
progressbar.progress-ongoing fill {
|
||||
progress.progress-ongoing fill {
|
||||
background-color: #2255bb;
|
||||
border-radius: 3dp;
|
||||
}
|
||||
@@ -447,6 +451,11 @@ window.modal.danger .modal-header icon {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.modal-body span.tip {
|
||||
font-size: 14dp;
|
||||
color: #92875B;
|
||||
}
|
||||
|
||||
.verification-progress {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -460,7 +469,7 @@ window.modal.danger .modal-header icon {
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
progressbar.verification-progress-bar {
|
||||
progress.verification-progress-bar {
|
||||
height: 8dp;
|
||||
margin: 2dp 0 0 0;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,10 @@
|
||||
#include "SSystem/SComponent/c_counter.h"
|
||||
#include <cstring>
|
||||
|
||||
#if TARGET_PC
|
||||
#include "dusk/settings.h"
|
||||
#endif
|
||||
|
||||
#define DRAW_TYPE_YELLOW 0
|
||||
#define DRAW_TYPE_RED 1
|
||||
|
||||
@@ -1422,6 +1426,11 @@ int dAttention_c::Run() {
|
||||
}
|
||||
|
||||
void dAttention_c::Draw() {
|
||||
#if TARGET_PC
|
||||
if (dusk::getSettings().game.recordingMode) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (mAttParam.CheckFlag(dAttParam_c::EFlag_ARROW_OFF)) {
|
||||
draw[0].field_0x173 = 3;
|
||||
draw[1].field_0x173 = 3;
|
||||
|
||||
+63
-11
@@ -31,6 +31,7 @@
|
||||
#if TARGET_PC
|
||||
#include "dusk/frame_interpolation.h"
|
||||
#include "dusk/logging.h"
|
||||
#include "imgui.h"
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
@@ -7483,6 +7484,8 @@ static constexpr f32 FLYCAM_SPEED = 0.5f;
|
||||
static constexpr f32 FLYCAM_FAST_SPEED = 4.0f;
|
||||
static constexpr f32 FLYCAM_ROTATION_SPEED = 0.002f;
|
||||
static constexpr f32 FLYCAM_TRIGGER_DEADZONE = 20.0f;
|
||||
static constexpr s16 FLYCAM_ROLL_SPEED = 256;
|
||||
static ImVec2 sFlyCamLastMousePos = {-1.f, -1.f};
|
||||
|
||||
#if TARGET_PC
|
||||
bool dCamera_c::executeDebugFlyCam() {
|
||||
@@ -7490,6 +7493,7 @@ bool dCamera_c::executeDebugFlyCam() {
|
||||
if (mDebugFlyCam.initialized) {
|
||||
deactivateDebugFlyCam();
|
||||
}
|
||||
sFlyCamLastMousePos = {-1.f, -1.f};
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -7519,16 +7523,63 @@ bool dCamera_c::executeDebugFlyCam() {
|
||||
mDebugFlyCam.initialized = true;
|
||||
}
|
||||
|
||||
event->mEventStatus = 1;
|
||||
dComIfGp_getEventManager().setCameraPlay(1);
|
||||
if (dusk::getSettings().game.debugFlyCamLockEvents) {
|
||||
event->mEventStatus = 1;
|
||||
dComIfGp_getEventManager().setCameraPlay(1);
|
||||
} else {
|
||||
if (event->mEventStatus != 0) {
|
||||
event->mEventStatus = 0;
|
||||
}
|
||||
dComIfGp_getEventManager().setCameraPlay(0);
|
||||
}
|
||||
|
||||
interface_of_controller_pad& pad = mDoCPd_c::getCpadInfo(0);
|
||||
f32 stickY = pad.mMainStickPosY * 72.0f;
|
||||
f32 stickX = pad.mMainStickPosX * 72.0f;
|
||||
f32 cStickY = pad.mCStickPosY * 59.0f;
|
||||
f32 cStickX = pad.mCStickPosX * 59.0f;
|
||||
f32 trigL = pad.mTriggerLeft * 150.0f;
|
||||
f32 trigR = pad.mTriggerRight * 150.0f;
|
||||
f32 stickY = 0.f;
|
||||
f32 stickX = 0.f;
|
||||
f32 cStickY = 0.f;
|
||||
f32 cStickX = 0.f;
|
||||
f32 trigL = 0.f;
|
||||
f32 trigR = 0.f;
|
||||
f32 rollInput = 0.f;
|
||||
bool fast = false;
|
||||
|
||||
if (dusk::getSettings().game.debugFlyCamLockEvents) {
|
||||
interface_of_controller_pad& pad = mDoCPd_c::getCpadInfo(0);
|
||||
stickY = pad.mMainStickPosY * 72.0f;
|
||||
stickX = pad.mMainStickPosX * 72.0f;
|
||||
cStickY = pad.mCStickPosY * 59.0f;
|
||||
cStickX = pad.mCStickPosX * 59.0f;
|
||||
trigL = pad.mTriggerLeft * 150.0f;
|
||||
trigR = pad.mTriggerRight * 150.0f;
|
||||
fast = mDoCPd_c::getHoldZ(PAD_1);
|
||||
if (mDoCPd_c::getHoldY(PAD_1)) rollInput -= 1.f;
|
||||
if (mDoCPd_c::getHoldX(PAD_1)) rollInput += 1.f;
|
||||
}
|
||||
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if (!io.WantCaptureKeyboard) {
|
||||
f32 kbX = 0.0f, kbY = 0.0f;
|
||||
if (ImGui::IsKeyDown(ImGuiKey_W) || ImGui::IsKeyDown(ImGuiKey_UpArrow)) kbY += 1.f;
|
||||
if (ImGui::IsKeyDown(ImGuiKey_S) || ImGui::IsKeyDown(ImGuiKey_DownArrow)) kbY -= 1.f;
|
||||
if (ImGui::IsKeyDown(ImGuiKey_D) || ImGui::IsKeyDown(ImGuiKey_RightArrow)) kbX += 1.f;
|
||||
if (ImGui::IsKeyDown(ImGuiKey_A) || ImGui::IsKeyDown(ImGuiKey_LeftArrow)) kbX -= 1.f;
|
||||
f32 len = sqrtf(kbX * kbX + kbY * kbY);
|
||||
if (len > 1.f) { kbX /= len; kbY /= len; }
|
||||
stickX += kbX * 72.0f;
|
||||
stickY += kbY * 72.0f;
|
||||
if (ImGui::IsKeyDown(ImGuiKey_Space)) trigR += 150.0f;
|
||||
if (ImGui::IsKeyDown(ImGuiKey_LeftCtrl)) trigL += 150.0f;
|
||||
if (ImGui::IsKeyDown(ImGuiKey_LeftShift)) fast = true;
|
||||
if (ImGui::IsKeyDown(ImGuiKey_Q)) rollInput -= 1.0f;
|
||||
if (ImGui::IsKeyDown(ImGuiKey_E)) rollInput += 1.0f;
|
||||
}
|
||||
bool mouseValid = !io.WantCaptureMouse && io.MousePos.x >= 0.0f && io.MousePos.y >= 0.0f;
|
||||
if (mouseValid && sFlyCamLastMousePos.x >= 0.0f) {
|
||||
cStickX -= (io.MousePos.x - sFlyCamLastMousePos.x) * 2.0f;
|
||||
cStickY -= (io.MousePos.y - sFlyCamLastMousePos.y) * 2.0f;
|
||||
}
|
||||
sFlyCamLastMousePos = mouseValid ? io.MousePos : ImVec2{-1.0f, -1.0f};
|
||||
}
|
||||
|
||||
f32 verticalDisp = 0.0f;
|
||||
if (trigR >= FLYCAM_TRIGGER_DEADZONE) {
|
||||
@@ -7542,7 +7593,7 @@ bool dCamera_c::executeDebugFlyCam() {
|
||||
f32 moveDx = stickY * cosf(mDebugFlyCam.yaw) * cosf(mDebugFlyCam.pitch) - stickX * sinf(mDebugFlyCam.yaw);
|
||||
f32 moveDz = stickY * sinf(mDebugFlyCam.yaw) * cosf(mDebugFlyCam.pitch) + stickX * cosf(mDebugFlyCam.yaw);
|
||||
|
||||
f32 speed = mDoCPd_c::getHoldZ(PAD_1) ? FLYCAM_FAST_SPEED : FLYCAM_SPEED;
|
||||
f32 speed = fast ? FLYCAM_FAST_SPEED : FLYCAM_SPEED;
|
||||
|
||||
mEye.x += speed * moveDx;
|
||||
mEye.y += speed * moveDy;
|
||||
@@ -7553,6 +7604,7 @@ bool dCamera_c::executeDebugFlyCam() {
|
||||
mCenter.z = mEye.z + sinf(mDebugFlyCam.yaw) * cosf(mDebugFlyCam.pitch) * FLYCAM_TARGET_DIST;
|
||||
mCenter.y = mEye.y + sinf(mDebugFlyCam.pitch) * FLYCAM_TARGET_DIST;
|
||||
|
||||
mBank = mBank + static_cast<s16>(rollInput * FLYCAM_ROLL_SPEED * (fast ? FLYCAM_FAST_SPEED / FLYCAM_SPEED : 1.f));
|
||||
Reset(mCenter, mEye);
|
||||
|
||||
f32 yawInput = dusk::getSettings().game.invertCameraXAxis ? cStickX : -cStickX;
|
||||
@@ -7570,7 +7622,7 @@ void dCamera_c::deactivateDebugFlyCam() {
|
||||
Reset(mDebugFlyCam.savedCenter, mDebugFlyCam.savedEye, mDebugFlyCam.savedFovy, mDebugFlyCam.savedBank.Val());
|
||||
|
||||
dEvt_control_c* event = dComIfGp_getEvent();
|
||||
if (event != nullptr) {
|
||||
if (event != nullptr && event->mEventStatus != 0) {
|
||||
event->mEventStatus = 0;
|
||||
}
|
||||
dComIfGp_getEventManager().setCameraPlay(0);
|
||||
|
||||
+6
-3
@@ -24,9 +24,10 @@
|
||||
#include "d/actor/d_a_horse.h"
|
||||
#include <cstring>
|
||||
|
||||
#if TARGET_PC
|
||||
#include "dusk/memory.h"
|
||||
|
||||
#include "dusk/memory.h"
|
||||
#include "dusk/settings.h"
|
||||
#endif
|
||||
|
||||
int dMeter2_c::_create() {
|
||||
stage_stag_info_class* stag_info = dComIfGp_getStageStagInfo();
|
||||
@@ -317,7 +318,9 @@ int dMeter2_c::_execute() {
|
||||
|
||||
int dMeter2_c::_draw() {
|
||||
#if TARGET_PC
|
||||
if (dusk::getSettings().game.disableMainHUD) {
|
||||
if (dusk::getSettings().game.recordingMode || dusk::getSettings().game.minimalHUD ||
|
||||
dusk::getSettings().game.debugFlyCam)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
#include "d/d_com_inf_game.h"
|
||||
#include "d/d_pane_class.h"
|
||||
|
||||
#if TARGET_PC
|
||||
#include "dusk/settings.h"
|
||||
#endif
|
||||
|
||||
dMsgScrnArrow_c::dMsgScrnArrow_c() {
|
||||
mpScreen = JKR_NEW J2DScreen();
|
||||
JUT_ASSERT(0, mpScreen != NULL);
|
||||
@@ -65,6 +69,11 @@ dMsgScrnArrow_c::~dMsgScrnArrow_c() {
|
||||
}
|
||||
|
||||
void dMsgScrnArrow_c::draw() {
|
||||
#if TARGET_PC
|
||||
if (dusk::getSettings().game.recordingMode) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
J2DGrafContext* graf_ctx = dComIfGp_getCurrentGrafPort();
|
||||
mpScreen->draw(0.0f, 0.0f, graf_ctx);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
#include "d/d_pane_class.h"
|
||||
#include <cstring>
|
||||
|
||||
#if TARGET_PC
|
||||
#include "dusk/settings.h"
|
||||
#endif
|
||||
|
||||
dMsgScrnBase_c::dMsgScrnBase_c() {
|
||||
init();
|
||||
}
|
||||
@@ -57,12 +61,22 @@ void dMsgScrnBase_c::init() {
|
||||
}
|
||||
|
||||
void dMsgScrnBase_c::multiDraw() {
|
||||
#if TARGET_PC
|
||||
if (dusk::getSettings().game.recordingMode) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (field_0x48 != NULL) {
|
||||
dComIfGd_set2DOpa(field_0x48);
|
||||
}
|
||||
}
|
||||
|
||||
void dMsgScrnBase_c::draw() {
|
||||
#if TARGET_PC
|
||||
if (dusk::getSettings().game.recordingMode) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
J2DGrafContext* ctx = dComIfGp_getCurrentGrafPort();
|
||||
|
||||
ctx->setup2D();
|
||||
@@ -72,10 +86,20 @@ void dMsgScrnBase_c::draw() {
|
||||
}
|
||||
|
||||
void dMsgScrnBase_c::drawSelf() {
|
||||
#if TARGET_PC
|
||||
if (dusk::getSettings().game.recordingMode) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
drawOutFont(0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
void dMsgScrnBase_c::drawOutFont(f32 param_0, f32 param_1, f32 param_2) {
|
||||
#if TARGET_PC
|
||||
if (dusk::getSettings().game.recordingMode) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
mpOutFont->draw(NULL, param_0, param_1, param_2);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
#include "d/d_msg_object.h"
|
||||
#include "d/d_pane_class.h"
|
||||
|
||||
#if TARGET_PC
|
||||
#include "dusk/settings.h"
|
||||
#endif
|
||||
|
||||
dMsgScrnBoss_c::dMsgScrnBoss_c() {
|
||||
static u64 t_tag[7] = {
|
||||
MULTI_CHAR('sfontb0'), MULTI_CHAR('sfontb1'), MULTI_CHAR('sfontb2'), MULTI_CHAR('sfontl0'), MULTI_CHAR('sfontl1'), MULTI_CHAR('sfontl2'), MULTI_CHAR('sfont00'),
|
||||
@@ -91,6 +95,11 @@ void dMsgScrnBoss_c::exec() {
|
||||
}
|
||||
|
||||
void dMsgScrnBoss_c::drawSelf() {
|
||||
#if TARGET_PC
|
||||
if (dusk::getSettings().game.recordingMode) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
J2DGrafContext* ctx = dComIfGp_getCurrentGrafPort();
|
||||
ctx->setup2D();
|
||||
drawOutFont(0.0f, 0.0f, 1.0f);
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
#include "d/d_msg_out_font.h"
|
||||
#include "d/d_pane_class.h"
|
||||
|
||||
#if TARGET_PC
|
||||
#include "dusk/settings.h"
|
||||
#endif
|
||||
|
||||
dMsgScrnKanban_c::dMsgScrnKanban_c(JKRExpHeap* param_0) {
|
||||
if (param_0 != NULL) {
|
||||
field_0xd4 = param_0;
|
||||
@@ -176,6 +180,11 @@ void dMsgScrnKanban_c::exec() {
|
||||
}
|
||||
|
||||
void dMsgScrnKanban_c::draw() {
|
||||
#if TARGET_PC
|
||||
if (dusk::getSettings().game.recordingMode) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
J2DGrafContext* grafContext = dComIfGp_getCurrentGrafPort();
|
||||
grafContext->setup2D();
|
||||
mpScreen->draw(0.0f, 0.0f, grafContext);
|
||||
|
||||
@@ -12,6 +12,10 @@
|
||||
#include "d/d_msg_object.h"
|
||||
#include "d/d_pane_class.h"
|
||||
|
||||
#if TARGET_PC
|
||||
#include "dusk/settings.h"
|
||||
#endif
|
||||
|
||||
dMsgScrnPlace_c::dMsgScrnPlace_c() {
|
||||
static u64 t_tag[7] = {
|
||||
MULTI_CHAR('sfontb0'), MULTI_CHAR('sfontb1'), MULTI_CHAR('sfontb2'), MULTI_CHAR('sfontl0'), MULTI_CHAR('sfontl1'), MULTI_CHAR('sfontl2'), MULTI_CHAR('sfont00'),
|
||||
@@ -127,6 +131,11 @@ void dMsgScrnPlace_c::exec() {
|
||||
}
|
||||
|
||||
void dMsgScrnPlace_c::drawSelf() {
|
||||
#if TARGET_PC
|
||||
if (dusk::getSettings().game.recordingMode) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
J2DGrafContext* grafContext = dComIfGp_getCurrentGrafPort();
|
||||
grafContext->setup2D();
|
||||
drawOutFont(0.0f, 0.0f, 1.0f);
|
||||
|
||||
@@ -20,6 +20,10 @@
|
||||
#include "JSystem/J2DGraph/J2DScreen.h"
|
||||
#include <cstring>
|
||||
|
||||
#if TARGET_PC
|
||||
#include "dusk/settings.h"
|
||||
#endif
|
||||
|
||||
dMsgScrnTalk_c::dMsgScrnTalk_c(u8 param_1, u8 param_2, JKRExpHeap* param_3) {
|
||||
if (param_3 != NULL) {
|
||||
field_0xe4 = param_3;
|
||||
@@ -303,6 +307,11 @@ void dMsgScrnTalk_c::exec() {
|
||||
}
|
||||
|
||||
void dMsgScrnTalk_c::drawSelf() {
|
||||
#if TARGET_PC
|
||||
if (dusk::getSettings().game.recordingMode) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
J2DGrafContext* grafContext[1];
|
||||
grafContext[0] = dComIfGp_getCurrentGrafPort();
|
||||
grafContext[0]->setup2D();
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
#include "d/d_msg_out_font.h"
|
||||
#include "d/d_pane_class.h"
|
||||
|
||||
#if TARGET_PC
|
||||
#include "dusk/settings.h"
|
||||
#endif
|
||||
|
||||
dMsgScrnTree_c::dMsgScrnTree_c(JUTFont* param_0, JKRExpHeap* param_1) {
|
||||
if (param_1 != NULL) {
|
||||
field_0xd8 = param_1;
|
||||
@@ -187,6 +191,11 @@ void dMsgScrnTree_c::exec() {
|
||||
}
|
||||
|
||||
void dMsgScrnTree_c::draw() {
|
||||
#if TARGET_PC
|
||||
if (dusk::getSettings().game.recordingMode) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
J2DGrafContext* grafContext = dComIfGp_getCurrentGrafPort();
|
||||
grafContext->setup2D();
|
||||
mpScreen->draw(0.0f, 0.0f, grafContext);
|
||||
|
||||
+31
-8
@@ -21,16 +21,39 @@ static bool checkEnabled() {
|
||||
return !__OSReport_disable || dusk::OSReportReallyForceEnable;
|
||||
}
|
||||
|
||||
#ifndef va_copy
|
||||
#define va_copy(d, s) ((d) = (s))
|
||||
#endif
|
||||
|
||||
static std::string FormatToString(const char* msg, va_list list) {
|
||||
int ret = vsnprintf(nullptr, 0, msg, list);
|
||||
if (ret <= 0) {
|
||||
return {};
|
||||
size_t size = (strlen(msg) * 2) + 50;
|
||||
std::string str;
|
||||
va_list ap;
|
||||
int attempts = 0;
|
||||
while (true) {
|
||||
str.resize(size);
|
||||
va_copy(ap, list);
|
||||
int n = vsnprintf(str.data(), size, msg, ap);
|
||||
va_end(ap);
|
||||
if (n > -1 && n < size) {
|
||||
str.resize(n);
|
||||
break;
|
||||
}
|
||||
|
||||
++attempts;
|
||||
if (attempts >= 3) {
|
||||
if (n == -1) {
|
||||
str.clear();
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (n > -1) {
|
||||
size = n + 1;
|
||||
} else {
|
||||
size *= 2;
|
||||
}
|
||||
}
|
||||
++ret;
|
||||
std::unique_ptr<char[]> buf(new char[ret]);
|
||||
vsnprintf(buf.get(), ret, msg, list);
|
||||
buf[ret - 1] = '\0';
|
||||
return {buf.get()};
|
||||
return str;
|
||||
}
|
||||
|
||||
void OSReport(const char* fmt, ...) {
|
||||
|
||||
@@ -282,7 +282,9 @@ static void ShowAllJAISeqs() {
|
||||
}
|
||||
|
||||
void dusk::ImGuiMenuTools::ShowAudioDebug() {
|
||||
if (!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F10, m_showAudioDebug)) {
|
||||
if (!getSettings().backend.enableAdvancedSettings ||
|
||||
!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F10, m_showAudioDebug))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -328,7 +330,9 @@ void dusk::ImGuiMenuTools::ShowAudioDebug() {
|
||||
}
|
||||
|
||||
void dusk::ImGuiMenuTools::ShowSaveEditor() {
|
||||
if (!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F6, m_showSaveEditor)) {
|
||||
if (!getSettings().backend.enableAdvancedSettings ||
|
||||
!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F6, m_showSaveEditor))
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_saveEditor.draw(m_showSaveEditor);
|
||||
|
||||
@@ -10,7 +10,9 @@
|
||||
|
||||
namespace dusk {
|
||||
void ImGuiMenuTools::ShowCameraOverlay() {
|
||||
if (!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F9, m_showCameraOverlay)) {
|
||||
if (!getSettings().backend.enableAdvancedSettings ||
|
||||
!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F9, m_showCameraOverlay))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -61,16 +63,32 @@ namespace dusk {
|
||||
ImGui::SetTooltip("Cannot enable while paused or during an active event.");
|
||||
} else {
|
||||
ImGui::SetTooltip("Detach camera and fly freely.\n"
|
||||
"Left stick: move, C-stick: look\n"
|
||||
"L/R triggers: up/down, Z: fast");
|
||||
"WASD/Arrows/Left stick: move, Mouse/C-stick: look\n"
|
||||
"Ctrl/L: down, Space/R: up, Shift/Z: fast\n"
|
||||
"Q Key/Y: roll left, R Key/X: roll right");
|
||||
}
|
||||
}
|
||||
if (eventRunning) {
|
||||
ImGui::EndDisabled();
|
||||
}
|
||||
|
||||
if (!getSettings().game.debugFlyCam) {
|
||||
ImGui::BeginDisabled();
|
||||
}
|
||||
config::ImGuiCheckbox("Lock Events", getSettings().game.debugFlyCamLockEvents);
|
||||
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
|
||||
if (!getSettings().game.debugFlyCam) {
|
||||
ImGui::SetTooltip("Enable Fly Mode first.");
|
||||
} else {
|
||||
ImGui::SetTooltip("Freeze game events while flying.");
|
||||
}
|
||||
}
|
||||
if (!getSettings().game.debugFlyCam) {
|
||||
ImGui::EndDisabled();
|
||||
}
|
||||
|
||||
ShowCornerContextMenu(m_cameraOverlayCorner, 0);
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -261,12 +261,19 @@ namespace dusk {
|
||||
}
|
||||
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_F11)) {
|
||||
ImGuiMenuGame::ToggleFullscreen();
|
||||
getSettings().video.enableFullscreen.setValue(!getSettings().video.enableFullscreen);
|
||||
VISetWindowFullscreen(getSettings().video.enableFullscreen);
|
||||
config::Save();
|
||||
}
|
||||
|
||||
if (ImGui::GetIO().KeyShift && ImGui::IsKeyPressed(ImGuiKey_F1)) {
|
||||
m_isHidden = !m_isHidden;
|
||||
if (getSettings().backend.enableAdvancedSettings) {
|
||||
m_isHidden = !m_isHidden;
|
||||
} else {
|
||||
m_isHidden = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool showMenu = !m_isHidden;
|
||||
|
||||
// The menu bar renders with ImGuiCol_WindowBg behind it. We just want ImGuiCol_MenuBarBg,
|
||||
@@ -276,16 +283,6 @@ namespace dusk {
|
||||
m_menuGame.draw();
|
||||
m_menuTools.draw();
|
||||
|
||||
const auto fpsLabel =
|
||||
fmt::format(FMT_STRING("FPS: {:.2f}\n"), ImGui::GetIO().Framerate);
|
||||
const auto fpsSize =
|
||||
ImGui::CalcTextSize(fpsLabel.data(), fpsLabel.data() + fpsLabel.size());
|
||||
ImGui::SetCursorPosX(
|
||||
ImMax(ImGui::GetCursorPosX(), ImGui::GetWindowWidth() -
|
||||
ImGui::GetStyle().DisplaySafeAreaPadding.x -
|
||||
fpsSize.x - ImGui::GetStyle().ItemSpacing.x));
|
||||
ImGuiStringViewText(fpsLabel);
|
||||
|
||||
ImGui::EndMainMenuBar();
|
||||
}
|
||||
ImGui::PopStyleColor();
|
||||
@@ -360,8 +357,7 @@ namespace dusk {
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
m_menuGame.windowControllerConfig();
|
||||
m_menuGame.windowInputViewer();
|
||||
m_menuTools.ShowInputViewer();
|
||||
m_menuGame.drawSpeedrunTimerOverlay();
|
||||
|
||||
if (getSettings().game.liveSplitEnabled) {
|
||||
|
||||
@@ -3,12 +3,11 @@
|
||||
#include "imgui.h"
|
||||
#include <imgui_internal.h>
|
||||
#include "ImGuiConsole.hpp"
|
||||
#include "ImGuiMenuGame.hpp"
|
||||
|
||||
#include <dolphin/pad.h>
|
||||
|
||||
namespace dusk {
|
||||
void ImGuiMenuGame::windowInputViewer() {
|
||||
void ImGuiMenuTools::ShowInputViewer() {
|
||||
if (!m_showInputViewer) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,9 @@ namespace dusk {
|
||||
void ShowHeapDetailed(JKRHeap* heap, OpenHeapData& data, bool& open);
|
||||
|
||||
void ImGuiMenuTools::ShowHeapOverlay() {
|
||||
if (!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F4, m_showHeapOverlay)) {
|
||||
if (!getSettings().backend.enableAdvancedSettings ||
|
||||
!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F4, m_showHeapOverlay))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,9 @@
|
||||
|
||||
namespace dusk {
|
||||
void ImGuiMenuTools::ShowMapLoader() {
|
||||
if (!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F7, m_showMapLoader)) {
|
||||
if (!getSettings().backend.enableAdvancedSettings ||
|
||||
!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F7, m_showMapLoader))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,573 +1,16 @@
|
||||
#include "fmt/format.h"
|
||||
#include "imgui.h"
|
||||
|
||||
#include "ImGuiEngine.hpp"
|
||||
#include "ImGuiConsole.hpp"
|
||||
#include "ImGuiConfig.hpp"
|
||||
|
||||
#include "dusk/main.h"
|
||||
#include "dusk/hotkeys.h"
|
||||
#include "m_Do/m_Do_main.h"
|
||||
|
||||
#include <SDL3/SDL_gamepad.h>
|
||||
|
||||
namespace dusk {
|
||||
void ImGuiMenuGame::ToggleFullscreen() {
|
||||
getSettings().video.enableFullscreen.setValue(!getSettings().video.enableFullscreen);
|
||||
VISetWindowFullscreen(getSettings().video.enableFullscreen);
|
||||
config::Save();
|
||||
}
|
||||
|
||||
ImGuiMenuGame::ImGuiMenuGame() {}
|
||||
|
||||
void ImGuiMenuGame::draw() {
|
||||
if (ImGui::BeginMenu("Settings")) {
|
||||
// TODO: Remove this once Controller Config exists in RmlUi
|
||||
if (ImGui::Button("Configure Controller")){
|
||||
m_showControllerConfig = !m_showControllerConfig;
|
||||
}
|
||||
|
||||
ImGui::Checkbox("Show Input Viewer", &m_showInputViewer);
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
}
|
||||
|
||||
static void drawVirtualStick(const char* id, const ImVec2& stick) {
|
||||
float scale = ImGuiScale();
|
||||
ImGui::SetCursorPos(ImVec2(ImGui::GetCursorPos().x + 45 * scale, ImGui::GetCursorPos().y + 10));
|
||||
|
||||
ImGui::BeginChild(id, ImVec2(80 * scale, 80 * scale), 0, ImGuiWindowFlags_NoBackground);
|
||||
ImDrawList* dl = ImGui::GetWindowDrawList();
|
||||
ImVec2 p = ImGui::GetCursorScreenPos();
|
||||
|
||||
float radius = 30.0f * scale;
|
||||
ImVec2 pos = ImVec2(p.x + radius, p.y + radius);
|
||||
|
||||
constexpr ImU32 stickGray = IM_COL32(150, 150, 150, 255);
|
||||
constexpr ImU32 white = IM_COL32(255, 255, 255, 255);
|
||||
constexpr ImU32 red = IM_COL32(230, 0, 0, 255);
|
||||
|
||||
dl->AddCircleFilled(pos, radius, stickGray, 8);
|
||||
dl->AddCircleFilled(ImVec2(pos.x + stick.x * (radius), pos.y + -stick.y * (radius)), 3 * scale, red);
|
||||
ImGui::EndChild();
|
||||
}
|
||||
|
||||
struct SpecificButtonName {
|
||||
SDL_GamepadType Type;
|
||||
const char* Name;
|
||||
};
|
||||
|
||||
struct ButtonNames {
|
||||
SDL_GamepadButton Button;
|
||||
std::vector<SpecificButtonName> Names;
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
static const std::vector<ButtonNames> GamepadButtonNames = {
|
||||
{ SDL_GAMEPAD_BUTTON_LEFT_STICK, {
|
||||
{SDL_GAMEPAD_TYPE_PS3, "L3"},
|
||||
{SDL_GAMEPAD_TYPE_PS4, "L3"},
|
||||
{SDL_GAMEPAD_TYPE_PS5, "L3"},
|
||||
{SDL_GAMEPAD_TYPE_XBOX360, "Left Stick"},
|
||||
{SDL_GAMEPAD_TYPE_XBOXONE, "Left Stick"},
|
||||
{SDL_GAMEPAD_TYPE_GAMECUBE, "Control Stick"},
|
||||
}},
|
||||
{ SDL_GAMEPAD_BUTTON_RIGHT_STICK, {
|
||||
{SDL_GAMEPAD_TYPE_PS3, "R3"},
|
||||
{SDL_GAMEPAD_TYPE_PS4, "R3"},
|
||||
{SDL_GAMEPAD_TYPE_PS5, "R3"},
|
||||
{SDL_GAMEPAD_TYPE_XBOX360, "Right Stick"},
|
||||
{SDL_GAMEPAD_TYPE_XBOXONE, "Right Stick"},
|
||||
{SDL_GAMEPAD_TYPE_GAMECUBE, "C Stick"},
|
||||
}},
|
||||
{ SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, {
|
||||
{SDL_GAMEPAD_TYPE_PS3, "L1"},
|
||||
{SDL_GAMEPAD_TYPE_PS4, "L1"},
|
||||
{SDL_GAMEPAD_TYPE_PS5, "L1"},
|
||||
{SDL_GAMEPAD_TYPE_XBOX360, "LB"},
|
||||
{SDL_GAMEPAD_TYPE_XBOXONE, "LB"},
|
||||
}},
|
||||
{ SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, {
|
||||
{SDL_GAMEPAD_TYPE_PS3, "R1"},
|
||||
{SDL_GAMEPAD_TYPE_PS4, "R1"},
|
||||
{SDL_GAMEPAD_TYPE_PS5, "R1"},
|
||||
{SDL_GAMEPAD_TYPE_XBOX360, "RB"},
|
||||
{SDL_GAMEPAD_TYPE_XBOXONE, "RB"},
|
||||
{SDL_GAMEPAD_TYPE_GAMECUBE, "Z"},
|
||||
}},
|
||||
{ SDL_GAMEPAD_BUTTON_BACK, {
|
||||
{SDL_GAMEPAD_TYPE_PS3, "Select"},
|
||||
{SDL_GAMEPAD_TYPE_PS4, "Share"},
|
||||
{SDL_GAMEPAD_TYPE_PS5, "Create"},
|
||||
{SDL_GAMEPAD_TYPE_XBOX360, "Back"},
|
||||
{SDL_GAMEPAD_TYPE_XBOXONE, "View"},
|
||||
}},
|
||||
{ SDL_GAMEPAD_BUTTON_START, {
|
||||
{SDL_GAMEPAD_TYPE_PS3, "Start"},
|
||||
{SDL_GAMEPAD_TYPE_PS4, "Options"},
|
||||
{SDL_GAMEPAD_TYPE_PS5, "Options"},
|
||||
{SDL_GAMEPAD_TYPE_XBOX360, "Start"},
|
||||
{SDL_GAMEPAD_TYPE_XBOXONE, "Menu"},
|
||||
{SDL_GAMEPAD_TYPE_GAMECUBE, "Start/Pause"},
|
||||
}},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
static const char* GetNameForGamepadButton(SDL_Gamepad* gamepad, u32 buttonUntyped) {
|
||||
if (buttonUntyped == PAD_NATIVE_BUTTON_INVALID) {
|
||||
return "Not bound";
|
||||
}
|
||||
|
||||
auto button = static_cast<SDL_GamepadButton>(buttonUntyped);
|
||||
auto label = SDL_GetGamepadButtonLabel(gamepad, button);
|
||||
|
||||
switch (label) {
|
||||
case SDL_GAMEPAD_BUTTON_LABEL_A:
|
||||
return "A";
|
||||
case SDL_GAMEPAD_BUTTON_LABEL_B:
|
||||
return "B";
|
||||
case SDL_GAMEPAD_BUTTON_LABEL_X:
|
||||
return "X";
|
||||
case SDL_GAMEPAD_BUTTON_LABEL_Y:
|
||||
return "Y";
|
||||
case SDL_GAMEPAD_BUTTON_LABEL_CROSS:
|
||||
return "Cross";
|
||||
case SDL_GAMEPAD_BUTTON_LABEL_CIRCLE:
|
||||
return "Circle";
|
||||
case SDL_GAMEPAD_BUTTON_LABEL_TRIANGLE:
|
||||
return "Triangle";
|
||||
case SDL_GAMEPAD_BUTTON_LABEL_SQUARE:
|
||||
return "Square";
|
||||
default:; // Fall through
|
||||
}
|
||||
|
||||
auto padType = SDL_GetGamepadType(gamepad);
|
||||
for (const auto& buttonNames : GamepadButtonNames) {
|
||||
if (buttonNames.Button != button) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const auto& name : buttonNames.Names) {
|
||||
if (name.Type == padType) {
|
||||
return name.Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (button) {
|
||||
case SDL_GAMEPAD_BUTTON_DPAD_LEFT:
|
||||
return "D-pad left";
|
||||
case SDL_GAMEPAD_BUTTON_DPAD_RIGHT:
|
||||
return "D-pad right";
|
||||
case SDL_GAMEPAD_BUTTON_DPAD_UP:
|
||||
return "D-pad up";
|
||||
case SDL_GAMEPAD_BUTTON_DPAD_DOWN:
|
||||
return "D-pad down";
|
||||
default:
|
||||
return PADGetNativeButtonName(buttonUntyped);
|
||||
}
|
||||
}
|
||||
|
||||
void ImGuiMenuGame::windowControllerConfig() {
|
||||
if (!m_showControllerConfig) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if pending for a button mapping, check to set new input
|
||||
if (m_controllerConfig.m_pendingButtonMapping != nullptr) {
|
||||
s32 nativeButton = PADGetNativeButtonPressed(m_controllerConfig.m_pendingPort);
|
||||
if (nativeButton != -1) {
|
||||
m_controllerConfig.m_pendingButtonMapping->nativeButton = nativeButton;
|
||||
m_controllerConfig.m_pendingButtonMapping = nullptr;
|
||||
m_controllerConfig.m_pendingPort = -1;
|
||||
PADBlockInput(false);
|
||||
PADSerializeMappings();
|
||||
}
|
||||
}
|
||||
|
||||
// if pending for an axis mapping, check to set new input
|
||||
if (m_controllerConfig.m_pendingAxisMapping != nullptr) {
|
||||
auto nativeAxis = PADGetNativeAxisPulled(m_controllerConfig.m_pendingPort);
|
||||
if (nativeAxis.nativeAxis != -1) {
|
||||
m_controllerConfig.m_pendingAxisMapping->nativeAxis = nativeAxis;
|
||||
m_controllerConfig.m_pendingAxisMapping->nativeButton = -1;
|
||||
m_controllerConfig.m_pendingAxisMapping = nullptr;
|
||||
m_controllerConfig.m_pendingPort = -1;
|
||||
PADBlockInput(false);
|
||||
PADSerializeMappings();
|
||||
} else {
|
||||
auto nativeButton = PADGetNativeButtonPressed(m_controllerConfig.m_pendingPort);
|
||||
if (nativeButton != -1) {
|
||||
m_controllerConfig.m_pendingAxisMapping->nativeAxis = {-1, AXIS_SIGN_POSITIVE};
|
||||
m_controllerConfig.m_pendingAxisMapping->nativeButton = nativeButton;
|
||||
m_controllerConfig.m_pendingAxisMapping = nullptr;
|
||||
m_controllerConfig.m_pendingPort = -1;
|
||||
PADBlockInput(false);
|
||||
PADSerializeMappings();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float scale = ImGuiScale();
|
||||
ImGuiWindowFlags windowFlags =
|
||||
ImGuiWindowFlags_NoResize |
|
||||
ImGuiWindowFlags_AlwaysAutoResize;
|
||||
|
||||
// ImGui::SetNextWindowBgAlpha(0.65f);
|
||||
|
||||
if (!ImGui::Begin("Controller Config", &m_showControllerConfig, windowFlags)) {
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
|
||||
// port tabs
|
||||
ImGui::BeginTabBar("##ControllerTabs");
|
||||
for (int i = PAD_1; i <= PAD_4; i++) {
|
||||
if (ImGui::BeginTabItem(fmt::format("Port {}", i + 1).c_str())) {
|
||||
m_controllerConfig.m_selectedPort = i;
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
}
|
||||
ImGui::EndTabBar();
|
||||
|
||||
// if tab is changed while waiting for input, cancel pending
|
||||
if ((m_controllerConfig.m_pendingButtonMapping != nullptr ||
|
||||
m_controllerConfig.m_pendingAxisMapping != nullptr) &&
|
||||
m_controllerConfig.m_pendingPort != m_controllerConfig.m_selectedPort)
|
||||
{
|
||||
m_controllerConfig.m_pendingButtonMapping = nullptr;
|
||||
m_controllerConfig.m_pendingAxisMapping = nullptr;
|
||||
m_controllerConfig.m_pendingPort = -1;
|
||||
PADBlockInput(false);
|
||||
}
|
||||
|
||||
// get a list of all available controller's names
|
||||
std::vector<std::string> controllerList;
|
||||
controllerList.push_back("None");
|
||||
for (int i = 0; i < PADCount(); i++) {
|
||||
// attach index to name for unique name
|
||||
controllerList.push_back(fmt::format("{}-{}", PADGetNameForControllerIndex(i), i));
|
||||
}
|
||||
|
||||
// get current controller name
|
||||
const char* tmpName = PADGetName(m_controllerConfig.m_selectedPort);
|
||||
std::string currentName = "None";
|
||||
if (tmpName != nullptr) {
|
||||
currentName = fmt::format("{}-{}", tmpName, PADGetIndexForPort(m_controllerConfig.m_selectedPort));
|
||||
}
|
||||
|
||||
// controller selection combo box
|
||||
bool changedController = false;
|
||||
int changedControllerIndex = 0;
|
||||
ImGui::SetNextItemWidth(400.0f * scale);
|
||||
if (ImGui::BeginCombo("##ControllerDeviceList", currentName.c_str())) {
|
||||
for (int i = 0; const auto& name : controllerList) {
|
||||
if (ImGui::Selectable(name.c_str(), currentName == name)) {
|
||||
changedControllerIndex = i;
|
||||
changedController = true;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
// handle controller change
|
||||
if (changedController) {
|
||||
if (changedControllerIndex > 0) {
|
||||
PADSetPortForIndex(changedControllerIndex - 1, m_controllerConfig.m_selectedPort);
|
||||
}
|
||||
else if (changedControllerIndex == 0) {
|
||||
// if "None" selected
|
||||
PADClearPort(m_controllerConfig.m_selectedPort);
|
||||
}
|
||||
PADSerializeMappings();
|
||||
}
|
||||
|
||||
// restore defaults button
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Default")) {
|
||||
PADRestoreDefaultMapping(m_controllerConfig.m_selectedPort);
|
||||
PADSerializeMappings();
|
||||
}
|
||||
|
||||
// buttons panel
|
||||
const float uiButtonSize = 40 * scale;
|
||||
ImVec2 btnSize(110.0f * scale, 30.0f * scale);
|
||||
|
||||
ImGuiBeginGroupPanel("Buttons", ImVec2(150 * scale, 20 * scale));
|
||||
|
||||
SDL_Gamepad* gamepad = PADGetSDLGamepadForIndex(PADGetIndexForPort(m_controllerConfig.m_selectedPort));
|
||||
u32 buttonCount;
|
||||
PADButtonMapping* btnMappingList = PADGetButtonMappings(m_controllerConfig.m_selectedPort, &buttonCount);
|
||||
if (btnMappingList != nullptr) {
|
||||
for (int i = 0; i < buttonCount; i++) {
|
||||
const char* btnName = PADGetButtonName(btnMappingList[i].padButton);
|
||||
ImVec2 len = ImGui::CalcTextSize(btnName);
|
||||
ImVec2 pos = ImGui::GetCursorPos();
|
||||
|
||||
ImGui::SetCursorPosY(pos.y + len.y / 4);
|
||||
ImGui::SetCursorPosX(pos.x + abs(len.x - uiButtonSize));
|
||||
ImGui::Text("%s", btnName);
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::SetCursorPosY(pos.y);
|
||||
|
||||
std::string dispName;
|
||||
if (m_controllerConfig.m_isReading && m_controllerConfig.m_pendingButtonMapping == &btnMappingList[i]) {
|
||||
dispName = fmt::format("Press a Key...##{}", btnName);
|
||||
} else {
|
||||
const char* nativeName = GetNameForGamepadButton(gamepad, btnMappingList[i].nativeButton);
|
||||
if (nativeName == nullptr) {
|
||||
nativeName = "[unbound]";
|
||||
}
|
||||
dispName = fmt::format("{0}##-{1}", nativeName, i);
|
||||
}
|
||||
bool pressed = ImGui::Button(dispName.c_str(),
|
||||
btnSize);
|
||||
|
||||
if (pressed) {
|
||||
m_controllerConfig.m_isReading = true;
|
||||
m_controllerConfig.m_pendingPort = m_controllerConfig.m_selectedPort;
|
||||
m_controllerConfig.m_pendingButtonMapping = &btnMappingList[i];
|
||||
PADBlockInput(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGuiEndGroupPanel();
|
||||
ImGui::SameLine();
|
||||
|
||||
uint32_t axisCount;
|
||||
PADAxisMapping* axisMappingList = PADGetAxisMappings(m_controllerConfig.m_selectedPort, &axisCount);
|
||||
|
||||
ImGuiBeginGroupPanel("Analog Triggers", ImVec2(150 * scale, 20 * scale));
|
||||
|
||||
PADAxis triggers[] = {PAD_AXIS_TRIGGER_L, PAD_AXIS_TRIGGER_R};
|
||||
if (axisMappingList != nullptr) {
|
||||
for (PADAxis trigger : triggers) {
|
||||
const char* axisName = PADGetAxisName(axisMappingList[trigger].padAxis);
|
||||
ImVec2 len = ImGui::CalcTextSize(axisName);
|
||||
ImVec2 pos = ImGui::GetCursorPos();
|
||||
|
||||
ImGui::SetCursorPosY(pos.y + len.y / 4);
|
||||
ImGui::SetCursorPosX(pos.x + abs(len.x - uiButtonSize));
|
||||
ImGui::Text("%s", axisName);
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::SetCursorPosY(pos.y);
|
||||
|
||||
std::string dispName;
|
||||
if (m_controllerConfig.m_isReading && m_controllerConfig.m_pendingAxisMapping == &axisMappingList[trigger]) {
|
||||
dispName = fmt::format("Press a Key...##{}", axisName);
|
||||
} else {
|
||||
dispName = fmt::format("{0}##-{1}", PADGetNativeAxisName(axisMappingList[trigger].nativeAxis), trigger);
|
||||
}
|
||||
bool pressed = ImGui::Button(dispName.c_str(),
|
||||
btnSize);
|
||||
|
||||
if (pressed) {
|
||||
m_controllerConfig.m_isReading = true;
|
||||
m_controllerConfig.m_pendingPort = m_controllerConfig.m_selectedPort;
|
||||
m_controllerConfig.m_pendingAxisMapping = &axisMappingList[trigger];
|
||||
PADBlockInput(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int port = m_controllerConfig.m_selectedPort;
|
||||
PADDeadZones* deadZones = PADGetDeadZones(port);
|
||||
|
||||
if (deadZones != nullptr) {
|
||||
ImGui::Text("L Threshold");
|
||||
ImGui::SameLine();
|
||||
{
|
||||
float tmp = static_cast<float>(deadZones->leftTriggerActivationZone * 100.f) / 32767.f;
|
||||
if (ImGui::DragFloat("##LThreshold", &tmp, 0.5f, 0.f, 100.f, "%.3f%%")) {
|
||||
deadZones->leftTriggerActivationZone = static_cast<u16>((tmp / 100.f) * 32767);
|
||||
PADSerializeMappings();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (deadZones != nullptr) {
|
||||
ImGui::Text("R Threshold");
|
||||
ImGui::SameLine();
|
||||
{
|
||||
float tmp = static_cast<float>(deadZones->rightTriggerActivationZone * 100.f) / 32767.f;
|
||||
if (ImGui::DragFloat("##RThreshold", &tmp, 0.5f, 0.f, 100.f, "%.3f%%")) {
|
||||
deadZones->rightTriggerActivationZone = static_cast<u16>((tmp / 100.f) * 32767);
|
||||
PADSerializeMappings();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGuiEndGroupPanel();
|
||||
ImGui::SameLine();
|
||||
|
||||
// main stick panel
|
||||
ImGuiBeginGroupPanel("Control Stick", ImVec2(150 * scale, 20 * scale));
|
||||
|
||||
drawVirtualStick("##mainStick", ImVec2{ mDoCPd_c::getStickX(port), mDoCPd_c::getStickY(port) });
|
||||
|
||||
if (axisMappingList != nullptr) {
|
||||
const PADAxis lStickAxes[] = {PAD_AXIS_LEFT_Y_POS, PAD_AXIS_LEFT_Y_NEG, PAD_AXIS_LEFT_X_NEG, PAD_AXIS_LEFT_X_POS};
|
||||
for (auto axis : lStickAxes) {
|
||||
const char* label = PADGetAxisDirectionLabel(axis);
|
||||
ImVec2 len = ImGui::CalcTextSize(label);
|
||||
ImVec2 pos = ImGui::GetCursorPos();
|
||||
|
||||
ImGui::SetCursorPosY(pos.y + len.y / 4);
|
||||
ImGui::SetCursorPosX(pos.x + abs(len.x - uiButtonSize));
|
||||
ImGui::Text("%s", label);
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::SetCursorPosY(pos.y);
|
||||
|
||||
std::string dispName;
|
||||
if (m_controllerConfig.m_isReading && m_controllerConfig.m_pendingAxisMapping == &axisMappingList[axis]) {
|
||||
dispName = fmt::format("Press a Key...##{}", label);
|
||||
} else {
|
||||
if (axisMappingList[axis].nativeAxis.nativeAxis != -1) {
|
||||
const char* signStr;
|
||||
if (axis == PAD_AXIS_TRIGGER_L || axis == PAD_AXIS_TRIGGER_R) {
|
||||
signStr = "";
|
||||
} else if (axisMappingList[axis].nativeAxis.sign == AXIS_SIGN_POSITIVE) {
|
||||
signStr = "+";
|
||||
} else {
|
||||
signStr = "-";
|
||||
}
|
||||
dispName = fmt::format("{0}{1}##-{2}", PADGetNativeAxisName(axisMappingList[axis].nativeAxis), signStr, axis);
|
||||
} else {
|
||||
assert(axisMappingList[axis].nativeButton != -1);
|
||||
dispName = fmt::format("{0}##-{1}", PADGetNativeButtonName(axisMappingList[axis].nativeButton), axis);
|
||||
}
|
||||
}
|
||||
bool pressed = ImGui::Button(dispName.c_str(), btnSize);
|
||||
|
||||
if (pressed) {
|
||||
m_controllerConfig.m_isReading = true;
|
||||
m_controllerConfig.m_pendingPort = m_controllerConfig.m_selectedPort;
|
||||
m_controllerConfig.m_pendingAxisMapping = &axisMappingList[axis];
|
||||
PADBlockInput(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (deadZones != nullptr) {
|
||||
ImGui::Text("Dead Zone");
|
||||
{
|
||||
float tmp = static_cast<float>(deadZones->stickDeadZone * 100.f) / 32767.f;
|
||||
if (ImGui::DragFloat("##mainDeadZone", &tmp, 0.5f, 0.f, 100.f, "%.3f%%")) {
|
||||
deadZones->stickDeadZone = static_cast<u16>((tmp / 100.f) * 32767);
|
||||
PADSerializeMappings();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGuiEndGroupPanel();
|
||||
ImGui::SameLine();
|
||||
|
||||
// sub stick panel
|
||||
ImGuiBeginGroupPanel("C Stick", ImVec2(150 * scale, 20 * scale));
|
||||
|
||||
drawVirtualStick("##subStick", ImVec2{ mDoCPd_c::getSubStickX(port), mDoCPd_c::getSubStickY(port) });
|
||||
|
||||
if (axisMappingList != nullptr) {
|
||||
const PADAxis rStickAxes[] = {PAD_AXIS_RIGHT_Y_POS, PAD_AXIS_RIGHT_Y_NEG, PAD_AXIS_RIGHT_X_NEG, PAD_AXIS_RIGHT_X_POS};
|
||||
for (auto axis : rStickAxes) {
|
||||
const char* label = PADGetAxisDirectionLabel(axisMappingList[axis].padAxis);
|
||||
ImVec2 len = ImGui::CalcTextSize(label);
|
||||
ImVec2 pos = ImGui::GetCursorPos();
|
||||
|
||||
ImGui::SetCursorPosY(pos.y + len.y / 4);
|
||||
ImGui::SetCursorPosX(pos.x + abs(len.x - uiButtonSize));
|
||||
ImGui::Text("%s", label);
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::SetCursorPosY(pos.y);
|
||||
|
||||
std::string dispName;
|
||||
if (m_controllerConfig.m_isReading && m_controllerConfig.m_pendingAxisMapping == &axisMappingList[axis]) {
|
||||
dispName = fmt::format("Press a Key...##sub{}", label);
|
||||
} else {
|
||||
if (axisMappingList[axis].nativeAxis.nativeAxis != -1) {
|
||||
const char* signStr;
|
||||
if (axis == PAD_AXIS_TRIGGER_L || axis == PAD_AXIS_TRIGGER_R) {
|
||||
signStr = "";
|
||||
} else if (axisMappingList[axis].nativeAxis.sign == AXIS_SIGN_POSITIVE) {
|
||||
signStr = "+";
|
||||
} else {
|
||||
signStr = "-";
|
||||
}
|
||||
dispName = fmt::format("{0}{1}##-{2}", PADGetNativeAxisName(axisMappingList[axis].nativeAxis), signStr, axis);
|
||||
} else {
|
||||
assert(axisMappingList[axis].nativeButton != -1);
|
||||
dispName = fmt::format("{0}##-{1}", PADGetNativeButtonName(axisMappingList[axis].nativeButton), axis);
|
||||
}
|
||||
}
|
||||
bool pressed = ImGui::Button(fmt::format("{0}##sub{1}", dispName, label).c_str(), btnSize);
|
||||
|
||||
if (pressed) {
|
||||
m_controllerConfig.m_isReading = true;
|
||||
m_controllerConfig.m_pendingPort = m_controllerConfig.m_selectedPort;
|
||||
m_controllerConfig.m_pendingAxisMapping = &axisMappingList[axis];
|
||||
PADBlockInput(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (deadZones != nullptr) {
|
||||
ImGui::Text("Dead Zone");
|
||||
{
|
||||
float tmp = static_cast<float>(deadZones->substickDeadZone * 100.f) / 32767.f;
|
||||
if (ImGui::DragFloat("##subDeadZone", &tmp, 0.5f, 0.f, 100.f, "%.3f%%")) {
|
||||
deadZones->substickDeadZone = static_cast<u16>((tmp / 100.f) * 32767);
|
||||
PADSerializeMappings();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGuiEndGroupPanel();
|
||||
ImGui::SameLine();
|
||||
|
||||
// Options panel
|
||||
ImGuiBeginGroupPanel("Options", ImVec2(150 * scale, -1));
|
||||
|
||||
if (deadZones != nullptr) {
|
||||
if (ImGui::Checkbox("Enable Dead Zones", &deadZones->useDeadzones)) {
|
||||
PADSerializeMappings();
|
||||
}
|
||||
if (ImGui::Checkbox("Emulate Triggers", &deadZones->emulateTriggers)) {
|
||||
PADSerializeMappings();
|
||||
}
|
||||
}
|
||||
|
||||
if (PADSupportsRumbleIntensity(m_controllerConfig.m_selectedPort)) {
|
||||
ImGuiBeginGroupPanel("Rumble Intensity", ImVec2(150 * scale, -1));
|
||||
u16 low;
|
||||
u16 high;
|
||||
(void)PADGetRumbleIntensity(m_controllerConfig.m_selectedPort, &low, &high);
|
||||
float fLow = (static_cast<float>(low) / 32767.f) * 100.f;
|
||||
bool changed = ImGui::SliderFloat("Low", &fLow, 0.f, 100.f, "%.0f%%");
|
||||
float fHigh = (static_cast<float>(high) / 32767.f) * 100.f;
|
||||
changed |= ImGui::SliderFloat("High", &fHigh, 0.f, 100.f, "%.0f%%");
|
||||
if (changed) {
|
||||
PADSetRumbleIntensity(m_controllerConfig.m_selectedPort,
|
||||
static_cast<u16>((fLow / 100) * 32767),
|
||||
static_cast<u16>((fHigh / 100) * 32767));
|
||||
PADSerializeMappings();
|
||||
}
|
||||
if (ImGui::Button(fmt::format("{0}...##rumbleTest", m_controllerConfig.m_isRumbling ? "Stop": "Test").c_str(), {-1, 0})) {
|
||||
PADControlMotor(m_controllerConfig.m_selectedPort, !m_controllerConfig.m_isRumbling ? PAD_MOTOR_RUMBLE : PAD_MOTOR_STOP_HARD);
|
||||
m_controllerConfig.m_isRumbling ^= 1;
|
||||
}
|
||||
ImGuiEndGroupPanel();
|
||||
}
|
||||
ImGuiEndGroupPanel();
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
void ImGuiMenuGame::draw() {}
|
||||
|
||||
static std::string GetFormattedTime(OSTime ticks) {
|
||||
OSCalendarTime time;
|
||||
|
||||
@@ -46,31 +46,11 @@ namespace dusk {
|
||||
ImGuiMenuGame();
|
||||
void draw();
|
||||
|
||||
void windowInputViewer();
|
||||
void windowControllerConfig();
|
||||
void drawSpeedrunTimerOverlay();
|
||||
|
||||
static void ToggleFullscreen();
|
||||
|
||||
static void resetForSpeedrunMode();
|
||||
|
||||
private:
|
||||
struct {
|
||||
int m_selectedPort = 0;
|
||||
bool m_isReading = false;
|
||||
PADButtonMapping* m_pendingButtonMapping = nullptr;
|
||||
PADAxisMapping* m_pendingAxisMapping = nullptr;
|
||||
int m_pendingPort = -1;
|
||||
bool m_isRumbling = false;
|
||||
} m_controllerConfig;
|
||||
|
||||
bool m_showControllerConfig = false;
|
||||
|
||||
bool m_showInputViewer = false;
|
||||
bool m_showInputViewerGyro = false;
|
||||
int m_inputOverlayCorner = 3;
|
||||
std::string m_controllerName;
|
||||
|
||||
bool m_showTimerWindow = false;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -48,6 +48,8 @@ namespace dusk {
|
||||
ImGui::EndDisabled();
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::Checkbox("Show Input Viewer", &m_showInputViewer);
|
||||
|
||||
#if DUSK_CAN_OPEN_DATA_FOLDER
|
||||
ImGui::Separator();
|
||||
@@ -119,7 +121,9 @@ namespace dusk {
|
||||
}
|
||||
|
||||
void ImGuiMenuTools::ShowDebugOverlay() {
|
||||
if (!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F3, m_showDebugOverlay)) {
|
||||
if (!getSettings().backend.enableAdvancedSettings ||
|
||||
!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F3, m_showDebugOverlay))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -183,7 +187,9 @@ namespace dusk {
|
||||
}
|
||||
|
||||
void ImGuiMenuTools::ShowPlayerInfo() {
|
||||
if (!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F5, m_showPlayerInfo)) {
|
||||
if (!getSettings().backend.enableAdvancedSettings ||
|
||||
!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F5, m_showPlayerInfo))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ namespace dusk {
|
||||
void ShowAudioDebug();
|
||||
void ShowSaveEditor();
|
||||
void ShowStateShare();
|
||||
void ShowInputViewer();
|
||||
|
||||
private:
|
||||
bool m_showDebugOverlay = false;
|
||||
@@ -66,6 +67,11 @@ namespace dusk {
|
||||
|
||||
bool m_showStateShare = false;
|
||||
ImGuiStateShare m_stateShare;
|
||||
|
||||
bool m_showInputViewer = false;
|
||||
bool m_showInputViewerGyro = false;
|
||||
int m_inputOverlayCorner = 3;
|
||||
std::string m_controllerName;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -126,7 +126,9 @@ namespace dusk {
|
||||
}
|
||||
|
||||
void ImGuiMenuTools::ShowProcessManager() {
|
||||
if (!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F2, m_showProcessManagement)) {
|
||||
if (!getSettings().backend.enableAdvancedSettings ||
|
||||
!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F2, m_showProcessManagement))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -417,7 +417,9 @@ void ImGuiStateShare::draw(bool& open) {
|
||||
}
|
||||
|
||||
void ImGuiMenuTools::ShowStateShare() {
|
||||
if (!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F8, m_showStateShare)) {
|
||||
if (!getSettings().backend.enableAdvancedSettings ||
|
||||
!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F8, m_showStateShare))
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_stateShare.draw(m_showStateShare);
|
||||
|
||||
+23
-13
@@ -8,6 +8,8 @@ UserSettings g_userSettings = {
|
||||
.enableFullscreen {"video.enableFullscreen", false},
|
||||
.enableVsync {"video.enableVsync", true},
|
||||
.lockAspectRatio {"video.lockAspectRatio", false},
|
||||
.enableFpsOverlay {"game.enableFpsOverlay", false},
|
||||
.fpsOverlayCorner {"game.fpsOverlayCorner", 0},
|
||||
},
|
||||
|
||||
.audio = {
|
||||
@@ -45,9 +47,9 @@ UserSettings g_userSettings = {
|
||||
|
||||
// Preferences
|
||||
.enableMirrorMode {"game.enableMirrorMode", false},
|
||||
.disableMainHUD {"game.disableMainHUD", false},
|
||||
.minimalHUD {"game.minimalHUD", false},
|
||||
.pauseOnFocusLost {"game.pauseOnFocusLost", false},
|
||||
.enableLinkDollRotation = {"game.enableLinkDollRotation", false},
|
||||
.enableLinkDollRotation {"game.enableLinkDollRotation", false},
|
||||
.enableAchievementNotifications {"game.enableAchievementNotifications", true},
|
||||
|
||||
// Graphics
|
||||
@@ -79,18 +81,19 @@ UserSettings g_userSettings = {
|
||||
.invertCameraYAxis {"game.invertCameraYAxis", false},
|
||||
.freeCameraSensitivity {"game.freeCameraSensitivity", 1.0f},
|
||||
.debugFlyCam {"game.debugFlyCam", false},
|
||||
.debugFlyCamLockEvents {"game.debugFlyCamLockEvents", true},
|
||||
|
||||
// Cheats
|
||||
.infiniteHearts {"game.infiniteHearts", false},
|
||||
.infiniteArrows{"game.infiniteArrows", false},
|
||||
.infiniteBombs{"game.infiniteBombs", false},
|
||||
.infiniteOil{"game.infiniteOil", false},
|
||||
.infiniteOxygen{"game.infiniteOxygen", false},
|
||||
.infiniteRupees{"game.infiniteRupees", false},
|
||||
.infiniteArrows {"game.infiniteArrows", false},
|
||||
.infiniteBombs {"game.infiniteBombs", false},
|
||||
.infiniteOil {"game.infiniteOil", false},
|
||||
.infiniteOxygen {"game.infiniteOxygen", false},
|
||||
.infiniteRupees {"game.infiniteRupees", false},
|
||||
.enableIndefiniteItemDrops {"game.enableIndefiniteItemDrops", false},
|
||||
.moonJump{"game.moonJump", false},
|
||||
.superClawshot{"game.superClawshot", false},
|
||||
.alwaysGreatspin{"game.alwaysGreatspin", false},
|
||||
.moonJump {"game.moonJump", false},
|
||||
.superClawshot {"game.superClawshot", false},
|
||||
.alwaysGreatspin {"game.alwaysGreatspin", false},
|
||||
.enableFastIronBoots {"game.enableFastIronBoots", false},
|
||||
.canTransformAnywhere {"game.canTransformAnywhere", false},
|
||||
.fastSpinner {"game.fastSpinner", false},
|
||||
@@ -104,7 +107,8 @@ UserSettings g_userSettings = {
|
||||
|
||||
// Tools
|
||||
.speedrunMode {"game.speedrunMode", false},
|
||||
.liveSplitEnabled {"game.liveSplitEnabled", false}
|
||||
.liveSplitEnabled {"game.liveSplitEnabled", false},
|
||||
.recordingMode {"game.recordingMode", false}
|
||||
},
|
||||
|
||||
.backend = {
|
||||
@@ -115,7 +119,8 @@ UserSettings g_userSettings = {
|
||||
.showPipelineCompilation {"backend.showPipelineCompilation", false},
|
||||
.wasPresetChosen {"backend.wasPresetChosen", false},
|
||||
.enableCrashReporting {"backend.enableCrashReporting", true},
|
||||
.cardFileType {"backend.cardFileType", static_cast<int>(CARD_GCIFOLDER)}
|
||||
.cardFileType {"backend.cardFileType", static_cast<int>(CARD_GCIFOLDER)},
|
||||
.enableAdvancedSettings {"backend.enableAdvancedSettings", false},
|
||||
}
|
||||
};
|
||||
|
||||
@@ -128,6 +133,8 @@ void registerSettings() {
|
||||
Register(g_userSettings.video.enableFullscreen);
|
||||
Register(g_userSettings.video.enableVsync);
|
||||
Register(g_userSettings.video.lockAspectRatio);
|
||||
Register(g_userSettings.video.enableFpsOverlay);
|
||||
Register(g_userSettings.video.fpsOverlayCorner);
|
||||
|
||||
// Audio
|
||||
Register(g_userSettings.audio.masterVolume);
|
||||
@@ -161,7 +168,7 @@ void registerSettings() {
|
||||
Register(g_userSettings.game.invertCameraXAxis);
|
||||
Register(g_userSettings.game.invertCameraYAxis);
|
||||
Register(g_userSettings.game.freeCameraSensitivity);
|
||||
Register(g_userSettings.game.disableMainHUD);
|
||||
Register(g_userSettings.game.minimalHUD);
|
||||
Register(g_userSettings.game.pauseOnFocusLost);
|
||||
Register(g_userSettings.game.bloomMode);
|
||||
Register(g_userSettings.game.bloomMultiplier);
|
||||
@@ -182,6 +189,7 @@ void registerSettings() {
|
||||
Register(g_userSettings.game.enableTurboKeybind);
|
||||
Register(g_userSettings.game.speedrunMode);
|
||||
Register(g_userSettings.game.liveSplitEnabled);
|
||||
Register(g_userSettings.game.recordingMode);
|
||||
Register(g_userSettings.game.fastSpinner);
|
||||
Register(g_userSettings.game.infiniteHearts);
|
||||
Register(g_userSettings.game.infiniteArrows);
|
||||
@@ -205,6 +213,7 @@ void registerSettings() {
|
||||
Register(g_userSettings.game.gyroInvertYaw);
|
||||
Register(g_userSettings.game.freeCamera);
|
||||
Register(g_userSettings.game.debugFlyCam);
|
||||
Register(g_userSettings.game.debugFlyCamLockEvents);
|
||||
|
||||
Register(g_userSettings.backend.isoPath);
|
||||
Register(g_userSettings.backend.isoVerification);
|
||||
@@ -214,6 +223,7 @@ void registerSettings() {
|
||||
Register(g_userSettings.backend.wasPresetChosen);
|
||||
Register(g_userSettings.backend.enableCrashReporting);
|
||||
Register(g_userSettings.backend.cardFileType);
|
||||
Register(g_userSettings.backend.enableAdvancedSettings);
|
||||
}
|
||||
|
||||
// Transient settings
|
||||
|
||||
@@ -41,7 +41,7 @@ Rml::String build_achievement_info_rml(const Achievement& a) {
|
||||
if (a.isCounter) {
|
||||
float fraction = a.goal > 0 ? float(a.progress) / float(a.goal) : 1.0f;
|
||||
s += fmt::format(
|
||||
R"(<progressbar value="{:.3f}" class="{}"/>)"
|
||||
R"(<progress value="{:.3f}" class="{}"/>)"
|
||||
R"(<span class="achievement-progress">{} / {}</span>)",
|
||||
fraction,
|
||||
a.unlocked ? "progress-done" : "progress-ongoing",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include "bool_button.hpp"
|
||||
#include "button.hpp"
|
||||
#include "pane.hpp"
|
||||
#include "select_button.hpp"
|
||||
#include "number_button.hpp"
|
||||
|
||||
#include <SDL3/SDL_gamepad.h>
|
||||
#include <SDL3/SDL_keyboard.h>
|
||||
@@ -279,6 +279,18 @@ s32 keyboard_key_pressed() {
|
||||
return PAD_KEY_INVALID;
|
||||
}
|
||||
|
||||
u16 percent_to_raw(int percent) {
|
||||
return static_cast<u16>((static_cast<float>(percent) / 100.f) * 32767.f);
|
||||
}
|
||||
|
||||
int deadzone_raw_to_percent(u16 raw) {
|
||||
return static_cast<int>((static_cast<float>(raw) * 100.f) / 32767.f + 0.5f);
|
||||
}
|
||||
|
||||
int rumble_raw_to_percent(u16 raw) {
|
||||
return static_cast<int>((static_cast<float>(raw) / 32767.f) * 100.f + 0.5f);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ControllerConfigWindow::ControllerConfigWindow() {
|
||||
@@ -308,6 +320,7 @@ ControllerConfigWindow::ControllerConfigWindow() {
|
||||
}
|
||||
|
||||
void ControllerConfigWindow::hide(bool close) {
|
||||
stop_rumble_test();
|
||||
cancel_pending_binding();
|
||||
Window::hide(close);
|
||||
}
|
||||
@@ -318,16 +331,18 @@ void ControllerConfigWindow::update() {
|
||||
}
|
||||
|
||||
void ControllerConfigWindow::build_port_tab(Rml::Element* content, int port) {
|
||||
stop_rumble_test();
|
||||
auto& leftPane = add_child<Pane>(content, Pane::Type::Controlled);
|
||||
auto& rightPane = add_child<Pane>(content, Pane::Type::Uncontrolled);
|
||||
mRightPane = &rightPane;
|
||||
mActivePort = port;
|
||||
|
||||
auto addPageButton = [this, &leftPane, &rightPane, port](
|
||||
Page page, Rml::String key, auto getValue) {
|
||||
Page page, Rml::String key, auto getValue, auto isDisabled) {
|
||||
leftPane.register_control(leftPane.add_select_button({
|
||||
.key = std::move(key),
|
||||
.getValue = std::move(getValue),
|
||||
.isDisabled = std::move(isDisabled),
|
||||
}),
|
||||
rightPane, [this, port, page](Pane& pane) {
|
||||
mPage = page;
|
||||
@@ -335,10 +350,11 @@ void ControllerConfigWindow::build_port_tab(Rml::Element* content, int port) {
|
||||
});
|
||||
};
|
||||
|
||||
addPageButton(Page::Controller, "Controller", [port] { return current_controller_name(port); });
|
||||
addPageButton(Page::Buttons, "Buttons", [] { return Rml::String(">"); });
|
||||
addPageButton(Page::Triggers, "Triggers", [] { return Rml::String(">"); });
|
||||
addPageButton(Page::Sticks, "Sticks", [] { return Rml::String(">"); });
|
||||
addPageButton(Page::Controller, "Controller", [port] { return current_controller_name(port); }, [] { return false; });
|
||||
addPageButton(Page::Buttons, "Buttons", [] { return Rml::String(">"); }, [] { return false; });
|
||||
addPageButton(Page::Triggers, "Triggers", [] { return Rml::String(">"); }, [] { return false; });
|
||||
addPageButton(Page::Sticks, "Sticks", [] { return Rml::String(">"); }, [] { return false; });
|
||||
addPageButton(Page::Rumble, "Rumble", [] { return Rml::String(">"); }, [port] { return !PADSupportsRumbleIntensity(static_cast<u32>(port)); });
|
||||
|
||||
leftPane.add_section("Options");
|
||||
leftPane.register_control(leftPane.add_child<BoolButton>(BoolButton::Props{
|
||||
@@ -684,6 +700,38 @@ void ControllerConfigWindow::render_page(Pane& pane, int port, Page page) {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (PADDeadZones* deadZones = PADGetDeadZones(port)) {
|
||||
pane.add_section("Emulated Trigger Thresholds");
|
||||
pane.add_child<NumberButton>(NumberButton::Props{
|
||||
.key = "L Threshold",
|
||||
.getValue = [deadZones] { return deadzone_raw_to_percent(deadZones->leftTriggerActivationZone); },
|
||||
.setValue =
|
||||
[deadZones](int value) {
|
||||
deadZones->leftTriggerActivationZone = percent_to_raw(value);
|
||||
PADSerializeMappings();
|
||||
},
|
||||
.isDisabled = [deadZones] { return !deadZones->emulateTriggers; },
|
||||
.min = 0,
|
||||
.max = 100,
|
||||
.step = 1,
|
||||
.suffix = "%",
|
||||
});
|
||||
pane.add_child<NumberButton>(NumberButton::Props{
|
||||
.key = "R Threshold",
|
||||
.getValue = [deadZones] { return deadzone_raw_to_percent(deadZones->rightTriggerActivationZone); },
|
||||
.setValue =
|
||||
[deadZones](int value) {
|
||||
deadZones->rightTriggerActivationZone = percent_to_raw(value);
|
||||
PADSerializeMappings();
|
||||
},
|
||||
.isDisabled = [deadZones] { return !deadZones->emulateTriggers; },
|
||||
.min = 0,
|
||||
.max = 100,
|
||||
.step = 1,
|
||||
.suffix = "%",
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Page::Sticks: {
|
||||
@@ -769,12 +817,121 @@ void ControllerConfigWindow::render_page(Pane& pane, int port, Page page) {
|
||||
addAxis(PAD_AXIS_LEFT_Y_NEG);
|
||||
addAxis(PAD_AXIS_LEFT_X_NEG);
|
||||
addAxis(PAD_AXIS_LEFT_X_POS);
|
||||
if (PADDeadZones* deadZones = PADGetDeadZones(port)) {
|
||||
pane.add_child<NumberButton>(NumberButton::Props{
|
||||
.key = "Deadzone",
|
||||
.getValue = [deadZones] { return deadzone_raw_to_percent(deadZones->stickDeadZone); },
|
||||
.setValue =
|
||||
[deadZones](int value) {
|
||||
deadZones->stickDeadZone = percent_to_raw(value);
|
||||
PADSerializeMappings();
|
||||
},
|
||||
.isDisabled = [deadZones] { return !deadZones->useDeadzones; },
|
||||
.min = 0,
|
||||
.max = 100,
|
||||
.step = 1,
|
||||
.suffix = "%",
|
||||
});
|
||||
}
|
||||
|
||||
pane.add_section("C Stick");
|
||||
addAxis(PAD_AXIS_RIGHT_Y_POS);
|
||||
addAxis(PAD_AXIS_RIGHT_Y_NEG);
|
||||
addAxis(PAD_AXIS_RIGHT_X_NEG);
|
||||
addAxis(PAD_AXIS_RIGHT_X_POS);
|
||||
if (PADDeadZones* deadZones = PADGetDeadZones(port)) {
|
||||
pane.add_child<NumberButton>(NumberButton::Props{
|
||||
.key = "Deadzone",
|
||||
.getValue = [deadZones] { return deadzone_raw_to_percent(deadZones->substickDeadZone); },
|
||||
.setValue =
|
||||
[deadZones](int value) {
|
||||
deadZones->substickDeadZone = percent_to_raw(value);
|
||||
PADSerializeMappings();
|
||||
},
|
||||
.isDisabled = [deadZones] { return !deadZones->useDeadzones; },
|
||||
.min = 0,
|
||||
.max = 100,
|
||||
.step = 1,
|
||||
.suffix = "%",
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case Page::Rumble: {
|
||||
auto& rumbleTest = pane.add_select_button({
|
||||
.key = "Test Rumble",
|
||||
.getValue =
|
||||
[this, port] {
|
||||
return (mRumbleTestActive && mRumbleTestPort == port) ? Rml::String("Stop")
|
||||
: Rml::String("Start");
|
||||
},
|
||||
});
|
||||
rumbleTest.on_pressed([this, port] {
|
||||
if (!PADSupportsRumbleIntensity(static_cast<u32>(port))) {
|
||||
return;
|
||||
}
|
||||
mDoAud_seStartMenu(kSoundItemChange);
|
||||
if (mRumbleTestActive && mRumbleTestPort == port) {
|
||||
PADControlMotor(port, PAD_MOTOR_STOP_HARD);
|
||||
mRumbleTestActive = false;
|
||||
mRumbleTestPort = -1;
|
||||
} else {
|
||||
if (mRumbleTestActive) {
|
||||
PADControlMotor(mRumbleTestPort, PAD_MOTOR_STOP_HARD);
|
||||
}
|
||||
PADControlMotor(port, PAD_MOTOR_RUMBLE);
|
||||
mRumbleTestActive = true;
|
||||
mRumbleTestPort = port;
|
||||
}
|
||||
});
|
||||
pane.add_child<NumberButton>(NumberButton::Props{
|
||||
.key = "Low Rumble Frequency",
|
||||
.getValue =
|
||||
[port] {
|
||||
u16 low = 0;
|
||||
u16 high = 0;
|
||||
PADGetRumbleIntensity(static_cast<u32>(port), &low, &high);
|
||||
return rumble_raw_to_percent(low);
|
||||
},
|
||||
.setValue =
|
||||
[port](int value) {
|
||||
u16 low = 0;
|
||||
u16 high = 0;
|
||||
PADGetRumbleIntensity(static_cast<u32>(port), &low, &high);
|
||||
PADSetRumbleIntensity(static_cast<u32>(port), percent_to_raw(value), high);
|
||||
PADSerializeMappings();
|
||||
},
|
||||
.isDisabled = [this] { return mRumbleTestActive; },
|
||||
.min = 0,
|
||||
.max = 100,
|
||||
.step = 1,
|
||||
.suffix = "%",
|
||||
});
|
||||
pane.add_child<NumberButton>(NumberButton::Props{
|
||||
.key = "High Rumble Frequency",
|
||||
.getValue =
|
||||
[port] {
|
||||
u16 low = 0;
|
||||
u16 high = 0;
|
||||
PADGetRumbleIntensity(static_cast<u32>(port), &low, &high);
|
||||
return rumble_raw_to_percent(high);
|
||||
},
|
||||
.setValue =
|
||||
[port](int value) {
|
||||
u16 low = 0;
|
||||
u16 high = 0;
|
||||
PADGetRumbleIntensity(static_cast<u32>(port), &low, &high);
|
||||
PADSetRumbleIntensity(static_cast<u32>(port), low, percent_to_raw(value));
|
||||
PADSerializeMappings();
|
||||
},
|
||||
.isDisabled = [this] { return mRumbleTestActive; },
|
||||
.min = 0,
|
||||
.max = 100,
|
||||
.step = 1,
|
||||
.suffix = "%",
|
||||
});
|
||||
pane.add_text("Configure your desired rumble intensities, then run a test to check how they feel.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -938,4 +1095,15 @@ Rml::String ControllerConfigWindow::pending_key_label() const {
|
||||
return mPendingBindingArmed ? "Press a key or mouse button..." : "Waiting...";
|
||||
}
|
||||
|
||||
void ControllerConfigWindow::stop_rumble_test() {
|
||||
if (!mRumbleTestActive) {
|
||||
return;
|
||||
}
|
||||
if (mRumbleTestPort >= PAD_CHAN0 && mRumbleTestPort < PAD_CHANMAX) {
|
||||
PADControlMotor(mRumbleTestPort, PAD_MOTOR_STOP_HARD);
|
||||
}
|
||||
mRumbleTestActive = false;
|
||||
mRumbleTestPort = -1;
|
||||
}
|
||||
|
||||
} // namespace dusk::ui
|
||||
|
||||
@@ -19,6 +19,7 @@ private:
|
||||
Buttons,
|
||||
Triggers,
|
||||
Sticks,
|
||||
Rumble,
|
||||
};
|
||||
|
||||
void build_port_tab(Rml::Element* content, int port);
|
||||
@@ -34,6 +35,7 @@ private:
|
||||
void cancel_pending_binding();
|
||||
void finish_pending_key_binding();
|
||||
Rml::String pending_key_label() const;
|
||||
void stop_rumble_test();
|
||||
|
||||
Page mPage = Page::Controller;
|
||||
Pane* mRightPane = nullptr;
|
||||
@@ -46,6 +48,8 @@ private:
|
||||
PADAxisMapping* mPendingAxisMapping = nullptr;
|
||||
int mPendingKeyButton = -1;
|
||||
int mPendingKeyAxis = -1;
|
||||
bool mRumbleTestActive = false;
|
||||
int mRumbleTestPort = -1;
|
||||
};
|
||||
|
||||
} // namespace dusk::ui
|
||||
|
||||
@@ -91,18 +91,23 @@ Rml::Element* create_stepped_carousel_arrow(
|
||||
return parent->AppendChild(std::move(button));
|
||||
}
|
||||
|
||||
void update_carousel_arrow_color(Rml::Element* arrow, bool dim) {
|
||||
const Rml::Colourb& color = Rml::Colourb(255, 255, 255, dim ? 128 : 255);
|
||||
arrow->SetProperty(Rml::PropertyId::Color, Rml::Property(color, Rml::Unit::COLOUR));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
SteppedCarousel::SteppedCarousel(Rml::Element* parent, Props props)
|
||||
: Component(create_stepped_carousel_root(parent)), mProps(std::move(props)) {
|
||||
Rml::Element* prevElem = create_stepped_carousel_arrow(mRoot, "prev", "");
|
||||
mPrevElem = create_stepped_carousel_arrow(mRoot, "prev", "");
|
||||
mValueElem = append(mRoot, "div");
|
||||
mValueElem->SetClass("stepped-carousel-value", true);
|
||||
Rml::Element* nextElem = create_stepped_carousel_arrow(mRoot, "next", "");
|
||||
mNextElem = create_stepped_carousel_arrow(mRoot, "next", "");
|
||||
|
||||
listen(prevElem, Rml::EventId::Click,
|
||||
listen(mPrevElem, Rml::EventId::Click,
|
||||
[this](Rml::Event&) { handle_nav_command(NavCommand::Left); });
|
||||
listen(nextElem, Rml::EventId::Click,
|
||||
listen(mNextElem, Rml::EventId::Click,
|
||||
[this](Rml::Event&) { handle_nav_command(NavCommand::Right); });
|
||||
listen(mRoot, Rml::EventId::Keydown, [this](Rml::Event& event) {
|
||||
const auto cmd = map_nav_event(event);
|
||||
@@ -126,6 +131,9 @@ void SteppedCarousel::update() {
|
||||
} else {
|
||||
mValueElem->SetInnerRML(std::to_string(value));
|
||||
}
|
||||
|
||||
update_carousel_arrow_color(mPrevElem, value == mProps.min);
|
||||
update_carousel_arrow_color(mNextElem, value == mProps.max);
|
||||
}
|
||||
|
||||
bool SteppedCarousel::handle_nav_command(NavCommand cmd) {
|
||||
@@ -280,4 +288,4 @@ void GraphicsTuner::reset_default() {
|
||||
set_value(mOption, mDefaultValue);
|
||||
}
|
||||
|
||||
} // namespace dusk::ui
|
||||
} // namespace dusk::ui
|
||||
|
||||
@@ -34,6 +34,8 @@ private:
|
||||
void apply(int value);
|
||||
|
||||
Props mProps;
|
||||
Rml::Element* mPrevElem = nullptr;
|
||||
Rml::Element* mNextElem = nullptr;
|
||||
Rml::Element* mValueElem = nullptr;
|
||||
};
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "f_pc/f_pc_manager.h"
|
||||
#include "f_pc/f_pc_name.h"
|
||||
#include "imgui.h"
|
||||
#include "modal.hpp"
|
||||
#include "settings.hpp"
|
||||
#include "ui.hpp"
|
||||
#include "window.hpp"
|
||||
@@ -50,17 +51,68 @@ MenuBar::MenuBar() : Document(kDocumentSource), mRoot(mDocument->GetElementById(
|
||||
// mTabBar->add_tab("Warp", [] {
|
||||
// // TODO
|
||||
// });
|
||||
mTabBar->add_tab("Editor", [this] { push(std::make_unique<EditorWindow>()); });
|
||||
|
||||
if (getSettings().backend.enableAdvancedSettings) {
|
||||
mTabBar->add_tab("Editor", [this] { push(std::make_unique<EditorWindow>()); });
|
||||
}
|
||||
|
||||
mTabBar->add_tab("Achievements", [this] { push(std::make_unique<AchievementsWindow>()); });
|
||||
mTabBar->add_tab("Reset", [this] {
|
||||
mTabBar->set_active_tab(-1);
|
||||
if (fpcM_SearchByName(fpcNm_LOGO_SCENE_e)) {
|
||||
return;
|
||||
}
|
||||
JUTGamePad::C3ButtonReset::sResetSwitchPushing = true;
|
||||
hide(false);
|
||||
const auto dismiss = [](Modal& modal) { modal.pop(); };
|
||||
push(std::make_unique<Modal>(Modal::Props{
|
||||
.title = "Reset Game",
|
||||
.bodyRml = "Unsaved progress will be lost.<br/>"
|
||||
"<span class=\"tip\">Tip: You can also reset by holding Start+X+B</span>",
|
||||
.actions =
|
||||
{
|
||||
ModalAction{
|
||||
.label = "Cancel",
|
||||
.onPressed = dismiss,
|
||||
},
|
||||
ModalAction{
|
||||
.label = "Reset",
|
||||
.onPressed =
|
||||
[this, dismiss](Modal& modal) {
|
||||
if (fpcM_SearchByName(fpcNm_LOGO_SCENE_e)) {
|
||||
dismiss(modal);
|
||||
return;
|
||||
}
|
||||
JUTGamePad::C3ButtonReset::sResetSwitchPushing = true;
|
||||
dismiss(modal);
|
||||
hide(false);
|
||||
},
|
||||
},
|
||||
},
|
||||
.onDismiss = dismiss,
|
||||
.icon = "question-mark",
|
||||
}));
|
||||
});
|
||||
mTabBar->add_tab("Quit", [this] {
|
||||
mTabBar->set_active_tab(-1);
|
||||
const auto dismiss = [](Modal& modal) { modal.pop(); };
|
||||
push(std::make_unique<Modal>(Modal::Props{
|
||||
.title = "Quit Dusk",
|
||||
.bodyRml = "Unsaved progress will be lost.",
|
||||
.actions =
|
||||
{
|
||||
ModalAction{
|
||||
.label = "Cancel",
|
||||
.onPressed = dismiss,
|
||||
},
|
||||
ModalAction{
|
||||
.label = "Quit",
|
||||
.onPressed =
|
||||
[dismiss](Modal& modal) {
|
||||
dismiss(modal);
|
||||
IsRunning = false;
|
||||
},
|
||||
},
|
||||
},
|
||||
.onDismiss = dismiss,
|
||||
.icon = "question-mark",
|
||||
}));
|
||||
});
|
||||
mTabBar->add_tab("Quit", [] { IsRunning = false; });
|
||||
|
||||
// Hide document after transition completion
|
||||
listen(mRoot, Rml::EventId::Transitionend, [this](Rml::Event& event) {
|
||||
|
||||
@@ -14,12 +14,9 @@ Modal::Modal(Props props) : WindowSmall("modal", "modal-dialog"), mProps(std::mo
|
||||
title->SetClass("modal-title", true);
|
||||
title->SetInnerRML(mProps.title);
|
||||
|
||||
if (mProps.isWarning) {
|
||||
if (!mProps.icon.empty()) {
|
||||
auto* icon = append(header, "icon");
|
||||
icon->SetClass("warning", true);
|
||||
} else if (mProps.isError) {
|
||||
auto* icon = append(header, "icon");
|
||||
icon->SetClass("error", true);
|
||||
icon->SetClass(mProps.icon, true);
|
||||
}
|
||||
|
||||
auto* body = append(mDialog, "div");
|
||||
|
||||
@@ -19,8 +19,7 @@ public:
|
||||
std::vector<ModalAction> actions;
|
||||
std::function<void(Modal&)> onDismiss;
|
||||
Rml::String variant;
|
||||
bool isWarning = false;
|
||||
bool isError = false;
|
||||
Rml::String icon = "";
|
||||
};
|
||||
|
||||
explicit Modal(Props props);
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#include "string_button.hpp"
|
||||
|
||||
#include <climits>
|
||||
|
||||
namespace dusk::ui {
|
||||
|
||||
class NumberButton : public BaseStringButton {
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "window.hpp"
|
||||
|
||||
#include <SDL3/SDL_gamepad.h>
|
||||
#include <SDL3/SDL_timer.h>
|
||||
#include <algorithm>
|
||||
#include <dolphin/pad.h>
|
||||
|
||||
@@ -19,6 +20,7 @@ const Rml::String kDocumentSource = R"RML(
|
||||
<link type="text/rcss" href="res/rml/overlay.rcss" />
|
||||
</head>
|
||||
<body>
|
||||
<fps id="fps" />
|
||||
</body>
|
||||
</rml>
|
||||
)RML";
|
||||
@@ -31,6 +33,8 @@ constexpr std::array<std::pair<const char*, const char*>, 3> kAutoSaveLayers{{
|
||||
|
||||
constexpr auto kMenuNotificationDuration = std::chrono::milliseconds(2500);
|
||||
|
||||
constexpr std::array<const char*, 4> kFpsCorners = { "tl", "tr", "bl", "br" };
|
||||
|
||||
Rml::Element* create_toast(Rml::Element* parent, const Toast& toast) {
|
||||
if (toast.type == "autosave") {
|
||||
auto* logo = append(parent, "logo");
|
||||
@@ -153,7 +157,46 @@ void remove_element(Rml::Element*& elem) noexcept {
|
||||
|
||||
} // namespace
|
||||
|
||||
// https://vplesko.com/posts/how_to_implement_an_fps_counter.html
|
||||
void Overlay::advance_fps_counter(float& outFps, Uint64 perfFreq) {
|
||||
if (perfFreq == 0) {
|
||||
outFps = 0.f;
|
||||
return;
|
||||
}
|
||||
|
||||
const Uint64 curr = SDL_GetPerformanceCounter();
|
||||
if (!mFpsHavePrevCounter) {
|
||||
mFpsPrevCounter = curr;
|
||||
mFpsHavePrevCounter = true;
|
||||
outFps = 0.f;
|
||||
return;
|
||||
}
|
||||
|
||||
const Uint64 processingTicks = curr - mFpsPrevCounter;
|
||||
mFpsPrevCounter = curr;
|
||||
|
||||
mFpsFrameEvents.push_back({curr, processingTicks});
|
||||
mFpsSumTicks += processingTicks;
|
||||
|
||||
while (!mFpsFrameEvents.empty() && mFpsFrameEvents.front().endCounter + perfFreq < curr) {
|
||||
mFpsSumTicks -= mFpsFrameEvents.front().processingTicks;
|
||||
mFpsFrameEvents.pop_front();
|
||||
}
|
||||
|
||||
const auto n = mFpsFrameEvents.size();
|
||||
if (n == 0 || mFpsSumTicks == 0) {
|
||||
outFps = 0.f;
|
||||
return;
|
||||
}
|
||||
|
||||
const double avgSeconds =
|
||||
static_cast<double>(mFpsSumTicks) / static_cast<double>(n) / static_cast<double>(perfFreq);
|
||||
outFps = static_cast<float>(1.0 / avgSeconds);
|
||||
}
|
||||
|
||||
Overlay::Overlay() : Document(kDocumentSource) {
|
||||
mFpsCounter = mDocument->GetElementById("fps");
|
||||
|
||||
listen(mDocument, Rml::EventId::Focus, [](Rml::Event&) { Log.warn("Overlay received focus"); });
|
||||
listen(mDocument, Rml::EventId::Transitionend, [this](Rml::Event& event) {
|
||||
if (event.GetTargetElement() == mCurrentToast) {
|
||||
@@ -187,6 +230,33 @@ void Overlay::update() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mFpsCounter != nullptr) {
|
||||
if (getSettings().video.enableFpsOverlay.getValue()) {
|
||||
const int idx = getSettings().video.fpsOverlayCorner.getValue();
|
||||
mFpsCounter->SetAttribute("open", "");
|
||||
mFpsCounter->SetAttribute("corner", kFpsCorners[idx]);
|
||||
|
||||
const Uint64 perfFreq = SDL_GetPerformanceFrequency();
|
||||
float fps = 0.f;
|
||||
advance_fps_counter(fps, perfFreq);
|
||||
|
||||
const Uint64 now = SDL_GetPerformanceCounter();
|
||||
// Limit updates to twice per second
|
||||
const bool refreshLabel = perfFreq == 0 || mFpsLastUpdate == 0 ||
|
||||
static_cast<double>(now - mFpsLastUpdate) >= 0.5 * static_cast<double>(perfFreq);
|
||||
if (refreshLabel) {
|
||||
mFpsLastUpdate = now;
|
||||
mFpsCounter->SetInnerRML(escape(fmt::format("{:.0f} FPS", fps)));
|
||||
}
|
||||
} else {
|
||||
mFpsCounter->RemoveAttribute("open");
|
||||
mFpsFrameEvents.clear();
|
||||
mFpsSumTicks = 0;
|
||||
mFpsHavePrevCounter = false;
|
||||
mFpsLastUpdate = 0;
|
||||
}
|
||||
}
|
||||
|
||||
const bool showControllerWarning = PADGetIndexForPort(PAD_CHAN0) < 0 &&
|
||||
PADGetKeyButtonBindings(PAD_CHAN0, nullptr) == nullptr &&
|
||||
dynamic_cast<Window*>(top_document()) == nullptr &&
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "document.hpp"
|
||||
|
||||
#include <chrono>
|
||||
#include <deque>
|
||||
|
||||
namespace dusk::ui {
|
||||
|
||||
@@ -16,11 +17,25 @@ public:
|
||||
protected:
|
||||
bool handle_nav_command(Rml::Event& event, NavCommand cmd) override;
|
||||
|
||||
Rml::Element* mFpsCounter = nullptr;
|
||||
Rml::Element* mCurrentToast = nullptr;
|
||||
Rml::Element* mControllerWarning = nullptr;
|
||||
Rml::Element* mMenuNotification = nullptr;
|
||||
clock::time_point mCurrentToastStartTime;
|
||||
clock::time_point mMenuNotificationStartTime;
|
||||
|
||||
struct FpsFrameEvent {
|
||||
Uint64 endCounter;
|
||||
Uint64 processingTicks;
|
||||
};
|
||||
|
||||
std::deque<FpsFrameEvent> mFpsFrameEvents;
|
||||
Uint64 mFpsSumTicks = 0;
|
||||
bool mFpsHavePrevCounter = false;
|
||||
Uint64 mFpsPrevCounter = 0;
|
||||
Uint64 mFpsLastUpdate = 0;
|
||||
|
||||
void advance_fps_counter(float& outFps, Uint64 perfFreq);
|
||||
};
|
||||
|
||||
} // namespace dusk::ui
|
||||
|
||||
+10
-1
@@ -126,11 +126,20 @@ Component& Pane::register_control(
|
||||
}
|
||||
});
|
||||
component.listen(component.root(), Rml::EventId::Focus,
|
||||
[&component, &nextPane, callback = std::move(callback)](Rml::Event&) {
|
||||
[this, &component, &nextPane, callback = std::move(callback)](Rml::Event&) {
|
||||
if (component.disabled()) {
|
||||
return;
|
||||
}
|
||||
nextPane.clear();
|
||||
|
||||
// If an item is already selected, deselect
|
||||
for (const auto& child : mChildren) {
|
||||
if (child->selected()) {
|
||||
set_selected_item(-1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
callback(nextPane);
|
||||
}
|
||||
|
||||
@@ -278,7 +278,7 @@ public:
|
||||
mFileName = append(content, "div");
|
||||
mFileName->SetClass("verification-file", true);
|
||||
|
||||
mProgress = append(content, "progressbar");
|
||||
mProgress = append(content, "progress");
|
||||
mProgress->SetClass("progress-ongoing", true);
|
||||
mProgress->SetClass("verification-progress-bar", true);
|
||||
mProgress->SetAttribute("value", 0.f);
|
||||
@@ -507,7 +507,7 @@ void try_push_verification_modal(Document& host) {
|
||||
},
|
||||
.onDismiss = dismiss,
|
||||
.variant = "danger",
|
||||
.isWarning = true,
|
||||
.icon = "warning",
|
||||
}));
|
||||
return;
|
||||
}
|
||||
@@ -523,7 +523,7 @@ void try_push_verification_modal(Document& host) {
|
||||
},
|
||||
},
|
||||
.onDismiss = dismiss,
|
||||
.isError = true,
|
||||
.icon = "error",
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -610,9 +610,6 @@ Prelaunch::Prelaunch() : Document(kDocumentSource), mRoot(mDocument->GetElementB
|
||||
}
|
||||
|
||||
IsGameLaunched = true;
|
||||
if (!getSettings().backend.wasPresetChosen) {
|
||||
push_document(std::make_unique<dusk::ui::PresetWindow>());
|
||||
}
|
||||
hide(true);
|
||||
});
|
||||
apply_intro_animation(mMenuButtons.back()->root(), "delay-1");
|
||||
@@ -624,7 +621,7 @@ Prelaunch::Prelaunch() : Document(kDocumentSource), mRoot(mDocument->GetElementB
|
||||
});
|
||||
apply_intro_animation(mMenuButtons.back()->root(), "delay-2");
|
||||
|
||||
mMenuButtons.push_back(std::make_unique<Button>(menuList, "Quit To Desktop"));
|
||||
mMenuButtons.push_back(std::make_unique<Button>(menuList, "Quit"));
|
||||
mMenuButtons.back()->on_pressed([] { IsRunning = false; });
|
||||
apply_intro_animation(mMenuButtons.back()->root(), "delay-3");
|
||||
}
|
||||
@@ -718,9 +715,6 @@ void Prelaunch::update() {
|
||||
activeDiscLoaded && state.configuredDiscPath != state.activeDiscPath;
|
||||
mDocument->SetClass("disc-ready", IsGameLaunched);
|
||||
if (canLaunchConfiguredDisc) {
|
||||
if (getSettings().backend.skipPreLaunchUI) {
|
||||
hide(true);
|
||||
}
|
||||
IsGameLaunched = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ void applyPresetDusk() {
|
||||
s.game.internalResolutionScale.setValue(0);
|
||||
s.game.shadowResolutionMultiplier.setValue(4);
|
||||
s.game.enableGyroAim.setValue(true);
|
||||
s.game.autoSave.setValue(true);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
+97
-18
@@ -10,6 +10,7 @@
|
||||
#include "dusk/livesplit.h"
|
||||
#include "graphics_tuner.hpp"
|
||||
#include "m_Do/m_Do_main.h"
|
||||
#include "menu_bar.hpp"
|
||||
#include "number_button.hpp"
|
||||
#include "pane.hpp"
|
||||
#include "prelaunch.hpp"
|
||||
@@ -33,6 +34,13 @@ constexpr std::array kCardFileTypes = {
|
||||
"GCI Folder",
|
||||
};
|
||||
|
||||
constexpr std::array kFpsOverlayCornerNames = {
|
||||
"Top Left",
|
||||
"Top Right",
|
||||
"Bottom Left",
|
||||
"Bottom Right",
|
||||
};
|
||||
|
||||
bool try_parse_backend(std::string_view backend, AuroraBackend& outBackend) {
|
||||
if (backend == "auto") {
|
||||
outBackend = BACKEND_AUTO;
|
||||
@@ -332,9 +340,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
||||
.getValue =
|
||||
[] {
|
||||
const auto& state = prelaunch_state();
|
||||
if (!state.configuredDiscCanLaunch ||
|
||||
!state.configuredDiscInfo.isPal)
|
||||
{
|
||||
if (!state.configuredDiscCanLaunch || !state.configuredDiscInfo.isPal) {
|
||||
return kLanguageNames[0];
|
||||
}
|
||||
const u8 idx = static_cast<u8>(getSettings().game.language.getValue());
|
||||
@@ -430,7 +436,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
||||
});
|
||||
}
|
||||
|
||||
add_tab("Graphics", [this](Rml::Element* content) {
|
||||
add_tab("Video", [this](Rml::Element* content) {
|
||||
auto& leftPane = add_child<Pane>(content, Pane::Type::Controlled);
|
||||
auto& rightPane = add_child<Pane>(content, Pane::Type::Uncontrolled);
|
||||
|
||||
@@ -472,6 +478,57 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
||||
.key = "Pause on Focus Lost",
|
||||
.isDisabled = [] { return IsMobile; },
|
||||
});
|
||||
leftPane.register_control(
|
||||
leftPane.add_select_button({
|
||||
.key = "Show FPS Counter",
|
||||
.getValue =
|
||||
[] {
|
||||
if (!getSettings().video.enableFpsOverlay.getValue()) {
|
||||
return Rml::String{"Off"};
|
||||
}
|
||||
const int idx = getSettings().video.fpsOverlayCorner.getValue();
|
||||
return Rml::String{kFpsOverlayCornerNames[idx]};
|
||||
},
|
||||
.isModified =
|
||||
[] {
|
||||
const auto& enable = getSettings().video.enableFpsOverlay;
|
||||
const auto& corner = getSettings().video.fpsOverlayCorner;
|
||||
return enable.getValue() != enable.getDefaultValue() ||
|
||||
(enable.getValue() && corner.getValue() != corner.getDefaultValue());
|
||||
},
|
||||
}),
|
||||
rightPane, [](Pane& pane) {
|
||||
pane.add_button(
|
||||
{
|
||||
.text = "Off",
|
||||
.isSelected =
|
||||
[] { return !getSettings().video.enableFpsOverlay.getValue(); },
|
||||
})
|
||||
.on_pressed([] {
|
||||
mDoAud_seStartMenu(kSoundItemChange);
|
||||
getSettings().video.enableFpsOverlay.setValue(false);
|
||||
config::Save();
|
||||
});
|
||||
for (int i = 0; i < static_cast<int>(kFpsOverlayCornerNames.size()); ++i) {
|
||||
pane.add_button(
|
||||
{
|
||||
.text = kFpsOverlayCornerNames[i],
|
||||
.isSelected =
|
||||
[i] {
|
||||
return getSettings().video.enableFpsOverlay.getValue() &&
|
||||
getSettings().video.fpsOverlayCorner.getValue() == i;
|
||||
},
|
||||
})
|
||||
.on_pressed([i] {
|
||||
mDoAud_seStartMenu(kSoundItemChange);
|
||||
getSettings().video.enableFpsOverlay.setValue(true);
|
||||
getSettings().video.fpsOverlayCorner.setValue(i);
|
||||
config::Save();
|
||||
});
|
||||
}
|
||||
pane.add_rml(
|
||||
"<br/>Display the current framerate in a corner of the screen while playing.");
|
||||
});
|
||||
|
||||
leftPane.add_section("Resolution");
|
||||
graphics_tuner_control(*this, leftPane, rightPane,
|
||||
@@ -687,8 +744,8 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
||||
leftPane.add_section("General");
|
||||
addOption("Mirror Mode", getSettings().game.enableMirrorMode,
|
||||
"Mirrors the world horizontally, matching the Wii version of the game.");
|
||||
addOption("Disable Main HUD", getSettings().game.disableMainHUD,
|
||||
"Disables the main HUD of the game.<br/>Useful for recording or a more immersive "
|
||||
addOption("Minimal HUD", getSettings().game.minimalHUD,
|
||||
"Disables the elements of the main HUD of the game.<br/>Useful for a more immersive "
|
||||
"experience.");
|
||||
addOption("Restore Wii 1.0 Glitches", getSettings().game.restoreWiiGlitches,
|
||||
"Restores patched glitches from Wii USA 1.0, the first released version.");
|
||||
@@ -736,11 +793,8 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
||||
config_bool_select(leftPane, rightPane, getSettings().game.autoSave,
|
||||
{
|
||||
.key = "Autosave",
|
||||
.icon = "warning",
|
||||
.helpText =
|
||||
"Autosaves the game when going to a new area, opening a dungeon door, "
|
||||
"or getting a new item.<br/><br/><icon class=\"warning\"/> Experimental "
|
||||
"feature: Use at your own risk.",
|
||||
.helpText = "Autosaves the game when going to a new area, opening a dungeon door, "
|
||||
"or getting a new item.",
|
||||
});
|
||||
addOption("Instant Saves", getSettings().game.instantSaves,
|
||||
"Skips the delay when writing to the Memory Card.");
|
||||
@@ -828,11 +882,11 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
||||
"Lets the magic armor work without consuming rupees.");
|
||||
});
|
||||
|
||||
// TODO: Reorganize all of this?
|
||||
add_tab("Interface", [this](Rml::Element* content) {
|
||||
auto& leftPane = add_child<Pane>(content, Pane::Type::Controlled);
|
||||
auto& rightPane = add_child<Pane>(content, Pane::Type::Uncontrolled);
|
||||
|
||||
leftPane.add_section("Dusk");
|
||||
config_bool_select(leftPane, rightPane, getSettings().game.enableAchievementNotifications,
|
||||
{
|
||||
.key = "Achievement Notifications",
|
||||
@@ -853,19 +907,44 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
||||
config_bool_select(leftPane, rightPane, getSettings().backend.skipPreLaunchUI,
|
||||
{
|
||||
.key = "Skip Dusk Main Menu",
|
||||
.helpText = "When starting Dusk, skips the main menu and boots straight into the "
|
||||
.helpText = "When starting Dusk, skip the main menu and boot straight into the "
|
||||
"game if a disc image is available.",
|
||||
});
|
||||
config_bool_select(leftPane, rightPane, getSettings().game.hideTvSettingsScreen,
|
||||
{
|
||||
.key = "Skip TV Settings Screen",
|
||||
.helpText = "Skips the TV calibration screen shown when loading a save.",
|
||||
});
|
||||
config_bool_select(leftPane, rightPane, getSettings().backend.showPipelineCompilation,
|
||||
{
|
||||
.key = "Show Pipeline Compilation",
|
||||
.helpText = "Show an overlay when shaders are being compiled for your hardware.",
|
||||
});
|
||||
config_bool_select(leftPane, rightPane, getSettings().backend.enableAdvancedSettings,
|
||||
{
|
||||
.key = "Enable Advanced Settings",
|
||||
.icon = "warning",
|
||||
.helpText = "Show advanced settings and debugging tools with "
|
||||
"Shift+F1.<br/><br/><icon class=\"warning\"/> WARNING: Debugging tools "
|
||||
"can easily break your game. Do not use on a regular save!",
|
||||
.onChange =
|
||||
[](bool) {
|
||||
for (auto& doc : get_document_stack()) {
|
||||
if (dynamic_cast<MenuBar*>(doc.get())) {
|
||||
doc = std::make_unique<MenuBar>();
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
leftPane.add_section("Game");
|
||||
config_bool_select(leftPane, rightPane, getSettings().game.hideTvSettingsScreen,
|
||||
{
|
||||
.key = "Skip TV Settings Screen",
|
||||
.helpText = "Skips the TV calibration screen shown when loading a save.",
|
||||
});
|
||||
config_bool_select(leftPane, rightPane, getSettings().game.recordingMode,
|
||||
{
|
||||
.key = "Recording Mode",
|
||||
.helpText = "Disables the game HUD and all background music.<br/><br/>Useful for "
|
||||
"recording footage.",
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+11
-1
@@ -212,6 +212,15 @@ bool TabBar::handle_nav_command(Rml::Event& event, NavCommand cmd) {
|
||||
if (activeTab != -1) {
|
||||
currentComponent = activeTab;
|
||||
}
|
||||
} else {
|
||||
int activeTab = tab_containing(event.GetTargetElement());
|
||||
if (activeTab != -1) {
|
||||
currentComponent = activeTab;
|
||||
} else if (mLastFocusedTabIndex >= 0 &&
|
||||
mLastFocusedTabIndex < static_cast<int>(mTabs.size()))
|
||||
{
|
||||
currentComponent = mLastFocusedTabIndex;
|
||||
}
|
||||
}
|
||||
int direction = isNext ? 1 : -1;
|
||||
if (currentComponent == -1) {
|
||||
@@ -221,8 +230,9 @@ bool TabBar::handle_nav_command(Rml::Event& event, NavCommand cmd) {
|
||||
return false;
|
||||
}
|
||||
currentComponent = -1;
|
||||
} else if (cmd == NavCommand::Next) {
|
||||
currentComponent = -1;
|
||||
} else {
|
||||
// Next/Previous require a currently selected tab to navigate from
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -363,6 +363,10 @@ void push_toast(Toast toast) noexcept {
|
||||
sToasts.push_back(std::move(toast));
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<Document> >& get_document_stack() noexcept {
|
||||
return sDocumentStack;
|
||||
}
|
||||
|
||||
std::deque<Toast>& get_toasts() noexcept {
|
||||
return sToasts;
|
||||
}
|
||||
|
||||
@@ -82,6 +82,8 @@ Rml::Element* append(Rml::Element* parent, const Rml::String& tag) noexcept;
|
||||
NavCommand map_nav_event(const Rml::Event& event) noexcept;
|
||||
Insets safe_area_insets(Rml::Context* context) noexcept;
|
||||
|
||||
std::vector<std::unique_ptr<Document> >& get_document_stack() noexcept;
|
||||
|
||||
void push_toast(Toast toast) noexcept;
|
||||
std::deque<Toast>& get_toasts() noexcept;
|
||||
void show_menu_notification() noexcept;
|
||||
|
||||
@@ -743,6 +743,10 @@ static void duskExecute() {
|
||||
handleGamepadColor();
|
||||
updateAutoSave();
|
||||
|
||||
if (dusk::getSettings().game.recordingMode) {
|
||||
Z2GetSeqMgr()->bgmAllMute(0, 0);
|
||||
}
|
||||
|
||||
if (mDoCPd_c::getHoldR(PAD_1) && mDoCPd_c::getTrigX(PAD_1)) {
|
||||
if (const auto link = g_dComIfG_gameInfo.play.getPlayer(0)) {
|
||||
dynamic_cast<daAlink_c*>(link)->handleWolfHowl();
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
#include "dusk/gx_helper.h"
|
||||
#include "dusk/imgui/ImGuiConsole.hpp"
|
||||
#include "dusk/logging.h"
|
||||
#include "dusk/settings.h"
|
||||
#endif
|
||||
|
||||
class mDoGph_HIO_c : public JORReflexible {
|
||||
@@ -1172,6 +1173,11 @@ static void drawDepth2(view_class* param_0, view_port_class* param_1, int param_
|
||||
}
|
||||
|
||||
static void trimming(view_class* param_0, view_port_class* param_1) {
|
||||
#if TARGET_PC
|
||||
if (dusk::getSettings().game.recordingMode) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
ZoneScoped;
|
||||
UNUSED(param_0);
|
||||
|
||||
|
||||
@@ -708,7 +708,7 @@ int game_main(int argc, char* argv[]) {
|
||||
dComIfG_ct();
|
||||
|
||||
// Development Mode
|
||||
mDoMain::developmentMode = 1; // Force Dev Mode for Debugging
|
||||
// mDoMain::developmentMode = 1; // Force Dev Mode for Debugging
|
||||
mDoDvdThd::SyncWidthSound = false;
|
||||
|
||||
OSReport("Starting main01 (Game Loop)...\n");
|
||||
|
||||
Reference in New Issue
Block a user