Merge remote-tracking branch 'origin/main' into 26-04-04-config

This commit is contained in:
PJB3005
2026-04-05 00:12:17 +02:00
50 changed files with 1094 additions and 364 deletions
+83 -93
View File
@@ -74,19 +74,6 @@ constexpr static int PitchToSampleRate(u16 value) {
return static_cast<int>(static_cast<u64>(SampleRate) * value / 4096);
}
static void UpdateSampleRate(const JASDsp::TChannel& channel, ChannelAuxData& aux) {
auto sampleRate = PitchToSampleRate(channel.mPitch);
const SDL_AudioSpec spec = {
SDL_AUDIO_S16,
1,
sampleRate
};
SDL_SetAudioStreamFormat(aux.resampleStream, &spec, nullptr);
aux.prevPitch = channel.mPitch;
}
/**
* Reset state for a DSP channel between independent playbacks.
*/
@@ -98,8 +85,9 @@ static void ResetChannel(JASDsp::TChannel& channel, ChannelAuxData& aux) {
aux.hist0 = 0;
aux.hist1 = 0;
SDL_ClearAudioStream(aux.resampleStream);
UpdateSampleRate(channel, aux);
aux.decodeBufCount = 0;
aux.resamplePos = 0.0;
aux.resamplePrev = 0;
for (auto& volume : aux.prevVolume) {
volume = NAN;
@@ -196,15 +184,16 @@ static void ReadSampleData(
}
/**
* Read a single *contiguous* chunk of sample data from a channel,
* writes the samples to the channel's resampler stream.
* Read a single *contiguous* chunk of sample data from a channel into outBuf
*
* @returns Amount of samples actually read. Can be greater than the amount requested.
* @returns Amount of samples written to outBuf. May be less than desiredSamples
*/
static int ReadChannelSamplesChunk(
JASDsp::TChannel& channel,
ChannelAuxData& aux,
int desiredSamples) {
int desiredSamples,
s16* outBuf,
int outBufSize) {
assert(desiredSamples >= 0);
@@ -249,61 +238,49 @@ static int ReadChannelSamplesChunk(
channel.mSamplesLeft -= renderSamples;
channel.mSamplePosition += renderSamples;
SDL_PutAudioStreamData(
aux.resampleStream,
renderData + skipSamples,
static_cast<int>(renderSize - skipSamples * sizeof(u16)));
int outputCount = static_cast<int>(renderSamples - skipSamples);
// this should never be hit with the limits on pitch shift (i think) but just in case!!
outputCount = std::min(outputCount, outBufSize);
if (outputCount > 0) {
memcpy(outBuf, renderData + skipSamples, outputCount * sizeof(s16));
}
assert(curSamplePosition % channel.mSamplesPerBlock == 0 || channel.mSamplesLeft == 0);
return static_cast<int>(renderSamples - skipSamples);
return outputCount;
}
/**
* Reads new audio channels from a DSP channel and writes them to the resampler stream.
* Fill decodeBuf with at least `needed` samples, fewer may be written if the channel has no loop and its data ends
*/
static void SDLCALL ReadChannelSamples(
void *userdata,
SDL_AudioStream*,
int additional_amount,
int) {
if (additional_amount == 0) {
return;
}
const auto index = static_cast<u32>(reinterpret_cast<uintptr_t>(userdata));
auto& channel = JASDsp::CH_BUF[index];
auto& aux = ChannelAux[index];
if (channel.mSamplesLeft == 0 && !channel.mLoopFlag) {
// May get called when we're out of data to read.
// This is expected, as we need to drain the resampler channel before we mark the channel as finished.
return;
}
auto samplesRead = ReadChannelSamplesChunk(channel, aux, additional_amount);
additional_amount -= samplesRead;
if (channel.mSamplesLeft == 0) {
// Reached end of buffer.
if (!channel.mLoopFlag) {
return;
static void FillDecodeBuf(JASDsp::TChannel& channel, ChannelAuxData& aux, int needed) {
while (aux.decodeBufCount < needed) {
if (channel.mSamplesLeft == 0) {
if (!channel.mLoopFlag) {
// we aren't a looping channel and there's no samples left, we out of this fuckin loop
break;
} else {
// we are looping, handle loop logic
channel.mSamplesLeft = channel.mEndSample - channel.mLoopStartSample;
channel.mSamplePosition = channel.mLoopStartSample;
aux.hist1 = channel.mpPenult;
aux.hist0 = channel.mpLast;
}
}
channel.mSamplesLeft = channel.mEndSample - channel.mLoopStartSample;
channel.mSamplePosition = channel.mLoopStartSample;
int remainingDecodeSpace = ChannelAuxData::DECODE_BUF_SIZE - aux.decodeBufCount;
if (remainingDecodeSpace == 0) {
break;
}
aux.hist1 = channel.mpPenult;
aux.hist0 = channel.mpLast;
aux.decodeBufCount += ReadChannelSamplesChunk(
channel, aux, std::min(remainingDecodeSpace, needed - aux.decodeBufCount),
aux.decodeBuf + aux.decodeBufCount, remainingDecodeSpace
);
}
if (additional_amount >= 0) {
ReadChannelSamplesChunk(channel, aux, additional_amount);
}
channel.mAramStreamPosition = channel.mWaveAramAddress
+ ConvertSamplesToDataLength(channel, channel.mSamplePosition);
channel.mAramStreamPosition = channel.mWaveAramAddress + ConvertSamplesToDataLength(channel, channel.mSamplePosition);
}
/**
@@ -422,57 +399,70 @@ static void RenderOutputChannel(
prevVolume = targetVolume;
}
/**
* Fetch, decode, resample, output
*/
static void RenderChannel(
JASDsp::TChannel& channel,
ChannelAuxData& channelAux,
OutputSubframe& subframe) {
if (channel.mResetFlag) {
ResetChannel(channel, channelAux);
} else if (channelAux.prevPitch != channel.mPitch) {
UpdateSampleRate(channel, channelAux);
}
DspSubframe audioLoadBuffer = {};
// how many input samples we step per output sample, aka the resampling ratio
f32 step = (f32)PitchToSampleRate(channel.mPitch) / SampleRate;
int wantRead = sizeof(audioLoadBuffer);
auto read = SDL_GetAudioStreamData(
channelAux.resampleStream,
&audioLoadBuffer,
wantRead);
// how many input samples to resample to DSP_SUBFRAME_SIZE output samples
int needed = static_cast<int>(channelAux.resamplePos + DSP_SUBFRAME_SIZE * step) + 2;
if (read < wantRead) {
FillDecodeBuf(channel, channelAux, needed);
// source ran dry, channel is finished
if(channelAux.decodeBufCount < needed) {
channel.mIsFinished = true;
}
auto hasReadSamples = std::span(audioLoadBuffer).subspan(0, wantRead / sizeof(f32));
DspSubframe audioLoadBuffer = {};
f64 pos = channelAux.resamplePos;
s16 prev = channelAux.resamplePrev;
s16 next = channelAux.decodeBufCount > 0 ? channelAux.decodeBuf[0] : prev;
int srcIdx = 0;
// linear resampling and f32 conversion
for (int i = 0; i < DSP_SUBFRAME_SIZE; i++) {
audioLoadBuffer[i] = static_cast<f32>(prev + pos * (next - prev)) / 32768.0f;
pos += step;
while (pos >= 1.0) {
pos -= 1.0;
prev = next;
srcIdx++;
next = srcIdx < channelAux.decodeBufCount ? channelAux.decodeBuf[srcIdx] : prev;
}
}
// save resampler state for the next subframe, prevents popping on pitch change
channelAux.resamplePos = pos;
channelAux.resamplePrev = prev;
// move any remaining samples in the decode buf to the beginning
int remainingDecodeBuf = channelAux.decodeBufCount - srcIdx;
if (remainingDecodeBuf > 0) {
memmove(channelAux.decodeBuf, channelAux.decodeBuf + srcIdx, remainingDecodeBuf * sizeof(s16));
}
channelAux.decodeBufCount = std::max(0, remainingDecodeBuf);
auto hasReadSamples = std::span(audioLoadBuffer).subspan(0, DSP_SUBFRAME_SIZE);
static_assert(OutputSubframe::NUM_CHANNELS == 2, "Keep RenderChannel in sync!");
RenderOutputChannel(channel, channelAux, OutputChannel::LEFT, hasReadSamples, subframe);
RenderOutputChannel(channel, channelAux,OutputChannel::RIGHT, hasReadSamples, subframe);
RenderOutputChannel(channel, channelAux, OutputChannel::RIGHT, hasReadSamples, subframe);
}
void dusk::audio::DspInit() {
constexpr SDL_AudioSpec srcSpec = {
SDL_AUDIO_S16,
1,
SampleRate
};
constexpr SDL_AudioSpec dstSpec = {
SDL_AUDIO_F32,
1,
SampleRate
};
for (u32 i = 0; i < DSP_CHANNELS; i++) {
auto& aux = ChannelAux[i];
aux.resampleStream = SDL_CreateAudioStream(&srcSpec, &dstSpec);
SDL_SetAudioStreamGetCallback(
aux.resampleStream,
ReadChannelSamples,
reinterpret_cast<void*>(static_cast<uintptr_t>(i)));
}
}
void dusk::audio::ApplyVolume(
+11 -2
View File
@@ -26,8 +26,6 @@ namespace dusk::audio {
struct ChannelAuxData {
s16 hist1;
s16 hist0;
SDL_AudioStream* resampleStream;
u16 prevPitch;
// Used for debugging tools.
u32 resetCount;
@@ -43,6 +41,17 @@ namespace dusk::audio {
assert(channel < OutputChannel::OutputChannel_MAX);
return prevVolume[static_cast<int>(channel)];
}
// buffer for decoding before resampling, size is chosen based on how many input samples we would need to fetch for the highest possible pitch
// to fill one subframe of output samples after resampling
static constexpr int DECODE_BUF_SIZE = 2048;
s16 decodeBuf[DECODE_BUF_SIZE];
int decodeBufCount;
// basically stores our position between resamplePrev and decodeBuf[0] so we don't lose that fractional resampler position next subframe
f32 resamplePos;
// last consumed sample from decodeBuf
s16 resamplePrev;
};
extern ChannelAuxData ChannelAux[DSP_CHANNELS];
+4 -3
View File
@@ -50,9 +50,10 @@ static void DisplayDspChannel(int i) {
auto dolby = (channel.mAutoMixerPanDolby & 0xFF) / 127.5f;
auto fxMix = (channel.mAutoMixerFxMix >> 8) / 127.5f;
auto volume = VolumeFromU16(channel.mAutoMixerVolume);
auto pitch = channel.mPitch / 4096.0f;
ImGui::Text(
"Auto mixer active (pan: %f, dolby: %f, fx: %f, volume: %f)",
pan, dolby, fxMix, volume);
"Auto mixer active (pan: %f, dolby: %f, fx: %f, volume: %f, pitch %f)",
pan, dolby, fxMix, volume, pitch);
} else {
ImGui::Text(
"Bus connect: %04X(%.2f),%04X(%.2f),%04X(%.2f),%04X(%.2f),%04X(%.2f),%04X(%.2f)",
@@ -249,4 +250,4 @@ void dusk::ImGuiMenuTools::ShowAudioDebug() {
}
ImGui::End();
}
}
+2 -1
View File
@@ -26,7 +26,8 @@ namespace dusk {
}
ImGui::SetNextWindowBgAlpha(0.65f);
ImGui::SetNextWindowSizeConstraints(ImVec2(300, 0), ImVec2(FLT_MAX, FLT_MAX));
ImGui::SetNextWindowSizeConstraints(ImVec2(300.f * ImGuiScale(), 0),
ImVec2(FLT_MAX, FLT_MAX));
if (!ImGui::Begin("Camera Debug", nullptr, windowFlags)) {
ImGui::End();
+17 -1
View File
@@ -5,13 +5,29 @@
#include "imgui.h"
namespace dusk::config {
inline void ImguiCheckbox(const char* title, ConfigVar<bool>& var) {
inline void ImGuiCheckbox(const char* title, ConfigVar<bool>& var) {
bool copy = var.getValue();
if (ImGui::Checkbox(title, &copy)) {
var.setValue(copy);
Save();
}
}
static void ImGuiSliderFloat(const char* label, ConfigVar<float>& var, float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0) {
float val = var;
if (ImGui::SliderFloat(label, &val, v_min, v_max, format, flags)) {
var.setValue(val);
Save();
}
}
static void ImGuiSliderInt(const char* label, ConfigVar<int>& var, int v_min, int v_max, const char* format = "%d", ImGuiSliderFlags flags = 0) {
int val = var;
if (ImGui::SliderInt(label, &val, v_min, v_max, format, flags)) {
var.setValue(val);
Save();
}
}
}
#endif // DUSK_IMGUICONFIG_HPP
+89 -4
View File
@@ -1,3 +1,4 @@
#include <algorithm>
#include <array>
#include <numeric>
#include <string_view>
@@ -14,6 +15,7 @@
#include "JSystem/JUtility/JUTGamePad.h"
#if _WIN32
#define NOMINMAX
#include "Windows.h"
#endif
@@ -21,6 +23,8 @@ using namespace std::string_literals;
using namespace std::string_view_literals;
namespace dusk {
float ImGuiScale() { return ImGui::GetIO().DisplayFramebufferScale.x; }
void ImGuiStringViewText(std::string_view text) {
// begin()/end() do not work on MSVC
ImGui::TextUnformatted(text.data(), text.data() + text.size());
@@ -47,7 +51,7 @@ namespace dusk {
ImVec2 workSize = viewport->WorkSize;
ImVec2 windowPos;
ImVec2 windowPosPivot;
constexpr float padding = 10.0f;
const float padding = 10.0f * ImGuiScale();
windowPos.x = (corner & 1) != 0 ? (workPos.x + workSize.x - padding) : (workPos.x + padding);
windowPos.y = (corner & 2) != 0 ? (workPos.y + workSize.y - padding) : (workPos.y + padding);
windowPosPivot.x = (corner & 1) != 0 ? 1.0f : 0.0f;
@@ -172,25 +176,38 @@ namespace dusk {
ImGuiConsole::ImGuiConsole() {}
void ImGuiConsole::draw() {
void ImGuiConsole::PreDraw() {
if (!m_isLaunchInitialized) {
m_toasts.emplace_back("Press F1 to toggle menu"s, 5.f);
m_isLaunchInitialized = true;
}
if (CheckMenuViewToggle(ImGuiKey_F1, m_isHidden)) {
m_menuTools.afterDraw();
ShowToasts();
return;
}
// TODO: we need to be able to render the menu bar & any overlays separately
// The code currently ties them all together, so hiding the menu hides all windows
if (ImGui::BeginMainMenuBar()) {
m_menuGame.draw();
m_menuTools.draw();
m_menuEnhancements.draw();
ImGui::SetCursorPosX(ImGui::GetWindowWidth() - 80.0f);
ImGui::SetCursorPosX(ImGui::GetWindowWidth() - 80.0f * ImGuiScale());
ImGuiIO& io = ImGui::GetIO();
ImGuiStringViewText(fmt::format(FMT_STRING("FPS: {:.2f}\n"), io.Framerate));
ImGui::EndMainMenuBar();
}
ShowToasts();
}
void ImGuiConsole::PostDraw() {
m_menuTools.afterDraw();
ShowPipelineProgress();
}
bool ImGuiConsole::CheckMenuViewToggle(ImGuiKey key, bool& active) {
@@ -223,4 +240,72 @@ namespace dusk {
return "Null"sv;
}
}
void ImGuiConsole::ShowToasts() {
if (m_toasts.empty()) {
return;
}
auto& toast = m_toasts.front();
const float dt = ImGui::GetIO().DeltaTime;
toast.remain -= dt;
toast.current += dt;
const ImGuiViewport* viewport = ImGui::GetMainViewport();
const ImVec2 workPos = viewport->WorkPos;
const ImVec2 workSize = viewport->WorkSize;
constexpr float padding = 10.0f;
const ImVec2 windowPos{workPos.x + workSize.x / 2, workPos.y + workSize.y - padding};
ImGui::SetNextWindowPos(windowPos, ImGuiCond_Always, ImVec2{0.5f, 1.f});
const float alpha = std::min({toast.remain, toast.current, 1.f});
ImGui::SetNextWindowBgAlpha(alpha * 0.65f);
ImVec4 textColor = ImGui::GetStyleColorVec4(ImGuiCol_Text);
textColor.w *= alpha;
ImVec4 borderColor = ImGui::GetStyleColorVec4(ImGuiCol_Border);
borderColor.w *= alpha;
ImGui::PushStyleColor(ImGuiCol_Text, textColor);
ImGui::PushStyleColor(ImGuiCol_Border, borderColor);
if (ImGui::Begin("Toast", nullptr,
ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize |
ImGuiWindowFlags_NoSavedSettings |
ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav |
ImGuiWindowFlags_NoMove))
{
ImGuiStringViewText(toast.message);
}
ImGui::End();
ImGui::PopStyleColor(2);
if (toast.remain <= 0.f) {
m_toasts.pop_front();
}
}
void ImGuiConsole::ShowPipelineProgress() {
const auto* stats = aurora_get_stats();
const u32 queuedPipelines = stats->queuedPipelines;
if (queuedPipelines == 0) {
return;
}
const u32 createdPipelines = stats->createdPipelines;
const u32 totalPipelines = queuedPipelines + createdPipelines;
const auto* viewport = ImGui::GetMainViewport();
const auto padding = viewport->WorkPos.y + 10.f;
const auto halfWidth = viewport->GetWorkCenter().x;
ImGui::SetNextWindowPos(ImVec2{halfWidth, padding}, ImGuiCond_Always, ImVec2{0.5f, 0.f});
ImGui::SetNextWindowSize(ImVec2{halfWidth, 0.f}, ImGuiCond_Always);
ImGui::SetNextWindowBgAlpha(0.65f);
ImGui::Begin("Pipelines", nullptr,
ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing);
const auto percent = static_cast<float>(createdPipelines) / static_cast<float>(totalPipelines);
const auto progressStr = fmt::format("Processing pipelines: {} / {}", createdPipelines, totalPipelines);
const auto textSize = ImGui::CalcTextSize(progressStr.data(), progressStr.data() + progressStr.size());
ImGui::NewLine();
ImGui::SameLine(ImGui::GetWindowWidth() / 2.f - textSize.x + textSize.x / 2.f);
ImGuiStringViewText(progressStr);
ImGui::ProgressBar(percent);
ImGui::End();
}
}
+36 -23
View File
@@ -2,41 +2,54 @@
#define DUSK_IMGUI_HPP
#include <aurora/aurora.h>
#include <deque>
#include <string>
#include "imgui.h"
#include "ImGuiMenuEnhancements.hpp"
#include "ImGuiMenuGame.hpp"
#include "ImGuiMenuTools.hpp"
#include "ImGuiMenuEnhancements.hpp"
#include "imgui.h"
namespace dusk {
class ImGuiConsole {
public:
ImGuiConsole();
void draw();
class ImGuiConsole {
public:
ImGuiConsole();
void PreDraw();
void PostDraw();
ImGuiMenuTools::CollisionViewSettings& getCollisionViewSettings() { return m_menuTools.getCollisionViewSettings(); }
static bool CheckMenuViewToggle(ImGuiKey key, bool& active);
static bool CheckMenuViewToggle(ImGuiKey key, bool& active);
private:
struct Toast {
std::string message;
float remain;
float current = 0.f;
Toast(std::string message, float duration) noexcept : message(std::move(message)),
remain(duration) {}
};
private:
bool m_isHidden = false;
bool m_isHidden = true;
bool m_isLaunchInitialized = false;
std::deque<Toast> m_toasts;
ImGuiMenuGame m_menuGame;
ImGuiMenuTools m_menuTools;
ImGuiMenuEnhancements m_menuEnhancements;
ImGuiMenuGame m_menuGame;
ImGuiMenuTools m_menuTools;
ImGuiMenuEnhancements m_menuEnhancements;
};
void ShowToasts();
void ShowPipelineProgress();
};
extern ImGuiConsole g_imguiConsole;
extern ImGuiConsole g_imguiConsole;
std::string_view backend_name(AuroraBackend backend);
std::string BytesToString(size_t bytes);
void SetOverlayWindowLocation(int corner);
bool ShowCornerContextMenu(int& corner, int avoidCorner);
void ImGuiStringViewText(std::string_view text);
void ImGuiBeginGroupPanel(const char* name, const ImVec2& size);
void ImGuiEndGroupPanel();
}
std::string_view backend_name(AuroraBackend backend);
std::string BytesToString(size_t bytes);
void SetOverlayWindowLocation(int corner);
bool ShowCornerContextMenu(int& corner, int avoidCorner);
void ImGuiStringViewText(std::string_view text);
void ImGuiBeginGroupPanel(const char* name, const ImVec2& size);
void ImGuiEndGroupPanel();
float ImGuiScale();
} // namespace dusk
void DuskDebugPad();
+1 -3
View File
@@ -13,8 +13,6 @@ namespace dusk {
ImGui::TextUnformatted(text.c_str());
}
static inline float GetScale() { return ImGui::GetCurrentContext()->CurrentDpiScale; }
void ImGuiMenuGame::windowInputViewer() {
if (!m_showInputViewer) {
return;
@@ -35,7 +33,7 @@ namespace dusk {
ImGui::SetNextWindowBgAlpha(0.65f);
if (ImGui::Begin("Input Viewer", nullptr, windowFlags)) {
float scale = GetScale();
float scale = ImGuiScale();
if (!m_controllerName.empty()) {
TextCenter(m_controllerName);
ImGui::Separator();
+201
View File
@@ -0,0 +1,201 @@
#include "ImGuiEngine.hpp"
#include <SDL3/SDL_filesystem.h>
#include <SDL3/SDL_pixels.h>
#include <SDL3/SDL_surface.h>
#include <aurora/imgui.h>
#include <cmath>
#include <cstring>
#include <string>
#include "dusk/logging.h"
#ifdef IMGUI_ENABLE_FREETYPE
#include "misc/freetype/imgui_freetype.h"
#endif
namespace dusk {
namespace {
std::string GetAssetPath(const char* assetName) {
const char* basePath = SDL_GetBasePath();
if (basePath != nullptr && basePath[0] != '\0') {
return std::string(basePath) + "res/" + assetName;
}
return std::string("res/") + assetName;
}
bool AssetExists(const std::string& path) {
SDL_PathInfo pathInfo{};
return SDL_GetPathInfo(path.c_str(), &pathInfo) && pathInfo.type == SDL_PATHTYPE_FILE;
}
} // namespace
ImFont* ImGuiEngine::fontNormal;
ImFont* ImGuiEngine::fontLarge;
ImTextureID ImGuiEngine::duskIcon;
void ImGuiEngine_Initialize(float scale) {
ImGui::GetCurrentContext();
ImGuiIO& io = ImGui::GetIO();
io.Fonts->Clear();
const std::string fontPath = GetAssetPath("NotoMono-Regular.ttf");
const bool hasFontFile = AssetExists(fontPath);
ImFontConfig fontConfig{};
fontConfig.SizePixels = std::floor(15.f * scale);
snprintf(static_cast<char*>(fontConfig.Name), sizeof(fontConfig.Name),
"Noto Mono Regular, %dpx", static_cast<int>(fontConfig.SizePixels));
ImGuiEngine::fontNormal =
hasFontFile ?
io.Fonts->AddFontFromFileTTF(fontPath.c_str(), fontConfig.SizePixels, &fontConfig) :
nullptr;
if (ImGuiEngine::fontNormal == nullptr) {
if (hasFontFile) {
DuskLog.warn("Failed to load font '{}': {}", fontPath, SDL_GetError());
}
ImGuiEngine::fontNormal = io.Fonts->AddFontDefault(&fontConfig);
}
fontConfig.SizePixels = std::floor(26.f * scale);
#ifdef IMGUI_ENABLE_FREETYPE
fontConfig.FontBuilderFlags |= ImGuiFreeTypeBuilderFlags_Bold;
snprintf(static_cast<char*>(fontConfig.Name), sizeof(fontConfig.Name), "Noto Mono Bold, %dpx",
static_cast<int>(fontConfig.SizePixels));
#else
snprintf(static_cast<char*>(fontConfig.Name), sizeof(fontConfig.Name),
"Noto Mono Regular, %dpx", static_cast<int>(fontConfig.SizePixels));
#endif
ImGuiEngine::fontLarge =
hasFontFile ?
io.Fonts->AddFontFromFileTTF(fontPath.c_str(), fontConfig.SizePixels, &fontConfig) :
nullptr;
if (ImGuiEngine::fontLarge == nullptr) {
if (hasFontFile) {
DuskLog.warn("Failed to load font '{}': {}", fontPath, SDL_GetError());
}
ImGuiEngine::fontLarge = io.Fonts->AddFontDefault(&fontConfig);
}
auto& style = ImGui::GetStyle();
style = {}; // Reset sizes
style.WindowPadding = ImVec2(15, 15);
style.WindowRounding = 5.0f;
style.FrameBorderSize = 1.f;
style.FramePadding = ImVec2(5, 5);
style.FrameRounding = 4.0f;
style.ItemSpacing = ImVec2(12, 8);
style.ItemInnerSpacing = ImVec2(8, 6);
style.IndentSpacing = 25.0f;
style.ScrollbarSize = 15.0f;
style.ScrollbarRounding = 9.0f;
style.GrabMinSize = 5.0f;
style.GrabRounding = 3.0f;
style.PopupBorderSize = 1.f;
style.PopupRounding = 7.0;
style.TabBorderSize = 1.f;
style.TabRounding = 3.f;
auto* colors = style.Colors;
colors[ImGuiCol_Text] = ImVec4(0.95f, 0.96f, 0.98f, 1.00f);
colors[ImGuiCol_TextDisabled] = ImVec4(0.36f, 0.42f, 0.47f, 1.00f);
colors[ImGuiCol_WindowBg] = ImVec4(0.11f, 0.15f, 0.17f, 1.00f);
colors[ImGuiCol_ChildBg] = ImVec4(0.15f, 0.18f, 0.22f, 1.00f);
colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.08f, 0.08f, 0.94f);
colors[ImGuiCol_Border] = ImVec4(0.08f, 0.10f, 0.12f, 1.00f);
colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
colors[ImGuiCol_FrameBg] = ImVec4(0.20f, 0.25f, 0.29f, 1.00f);
colors[ImGuiCol_FrameBgHovered] = ImVec4(0.12f, 0.20f, 0.28f, 1.00f);
colors[ImGuiCol_FrameBgActive] = ImVec4(0.09f, 0.12f, 0.14f, 1.00f);
colors[ImGuiCol_TitleBg] = ImVec4(0.09f, 0.12f, 0.14f, 0.65f);
colors[ImGuiCol_TitleBgActive] = ImVec4(0.08f, 0.10f, 0.12f, 1.00f);
colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.00f, 0.00f, 0.00f, 0.51f);
colors[ImGuiCol_MenuBarBg] = ImVec4(0.15f, 0.18f, 0.22f, 1.00f);
colors[ImGuiCol_ScrollbarBg] = ImVec4(0.02f, 0.02f, 0.02f, 0.39f);
colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.20f, 0.25f, 0.29f, 1.00f);
colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.18f, 0.22f, 0.25f, 1.00f);
colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.09f, 0.21f, 0.31f, 1.00f);
colors[ImGuiCol_CheckMark] = ImVec4(0.28f, 0.56f, 1.00f, 1.00f);
colors[ImGuiCol_SliderGrab] = ImVec4(0.28f, 0.56f, 1.00f, 1.00f);
colors[ImGuiCol_SliderGrabActive] = ImVec4(0.37f, 0.61f, 1.00f, 1.00f);
colors[ImGuiCol_Button] = ImVec4(0.20f, 0.25f, 0.29f, 1.00f);
colors[ImGuiCol_ButtonHovered] = ImVec4(0.28f, 0.56f, 1.00f, 1.00f);
colors[ImGuiCol_ButtonActive] = ImVec4(0.06f, 0.53f, 0.98f, 1.00f);
colors[ImGuiCol_Header] = ImVec4(0.20f, 0.25f, 0.29f, 0.55f);
colors[ImGuiCol_HeaderHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.80f);
colors[ImGuiCol_HeaderActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
colors[ImGuiCol_Separator] = ImVec4(0.20f, 0.25f, 0.29f, 1.00f);
colors[ImGuiCol_SeparatorHovered] = ImVec4(0.10f, 0.40f, 0.75f, 0.78f);
colors[ImGuiCol_SeparatorActive] = ImVec4(0.10f, 0.40f, 0.75f, 1.00f);
colors[ImGuiCol_ResizeGrip] = ImVec4(0.26f, 0.59f, 0.98f, 0.25f);
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
colors[ImGuiCol_Tab] = ImVec4(0.11f, 0.15f, 0.17f, 1.00f);
colors[ImGuiCol_TabHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.80f);
colors[ImGuiCol_TabActive] = ImVec4(0.20f, 0.25f, 0.29f, 1.00f);
colors[ImGuiCol_TabUnfocused] = ImVec4(0.11f, 0.15f, 0.17f, 1.00f);
colors[ImGuiCol_TabUnfocusedActive] = ImVec4(0.11f, 0.15f, 0.17f, 1.00f);
colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f);
colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
colors[ImGuiCol_PlotHistogram] = ImVec4(0.06f, 0.53f, 0.98f, 1.00f);
colors[ImGuiCol_PlotHistogramHovered] = ImVec4(0.28f, 0.56f, 1.00f, 1.00f);
colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);
colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f);
colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f);
style.ScaleAllSizes(scale);
}
Icon GetIcon() {
const std::string iconPath = GetAssetPath("icon.png");
if (!AssetExists(iconPath)) {
return {};
}
SDL_Surface* loadedSurface = SDL_LoadPNG(iconPath.c_str());
if (loadedSurface == nullptr) {
DuskLog.warn("Failed to load icon '{}': {}", iconPath, SDL_GetError());
return {};
}
SDL_Surface* rgbaSurface = SDL_ConvertSurface(loadedSurface, SDL_PIXELFORMAT_RGBA32);
SDL_DestroySurface(loadedSurface);
if (rgbaSurface == nullptr) {
DuskLog.warn("Failed to convert icon '{}': {}", iconPath, SDL_GetError());
return {};
}
const auto iconWidth = static_cast<uint32_t>(rgbaSurface->w);
const auto iconHeight = static_cast<uint32_t>(rgbaSurface->h);
const size_t rowSize = static_cast<size_t>(iconWidth) * 4;
const size_t size = rowSize * static_cast<size_t>(iconHeight);
auto ptr = std::make_unique<uint8_t[]>(size);
for (uint32_t row = 0; row < iconHeight; ++row) {
const auto* src = static_cast<const uint8_t*>(rgbaSurface->pixels) +
static_cast<size_t>(row) * static_cast<size_t>(rgbaSurface->pitch);
auto* dst = ptr.get() + static_cast<size_t>(row) * rowSize;
std::memcpy(dst, src, rowSize);
}
SDL_DestroySurface(rgbaSurface);
return Icon{
std::move(ptr),
size,
iconWidth,
iconHeight,
};
}
void ImGuiEngine_AddTextures() {
auto icon = GetIcon();
if (icon.data == nullptr || icon.width == 0 || icon.height == 0) {
ImGuiEngine::duskIcon = 0;
return;
}
ImGuiEngine::duskIcon = aurora_imgui_add_texture(icon.width, icon.height, icon.data.get());
}
} // namespace dusk
+25
View File
@@ -0,0 +1,25 @@
#pragma once
#include <memory>
#include "imgui.h"
#include "misc/cpp/imgui_stdlib.h"
namespace dusk {
class ImGuiEngine {
public:
static ImFont* fontNormal;
static ImFont* fontLarge;
static ImTextureID duskIcon;
};
void ImGuiEngine_Initialize(float scale);
void ImGuiEngine_AddTextures();
struct Icon {
std::unique_ptr<uint8_t[]> data;
size_t size;
uint32_t width;
uint32_t height;
};
Icon GetIcon();
} // namespace dusk
+2 -1
View File
@@ -17,7 +17,8 @@ namespace dusk {
ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav;
ImGui::SetNextWindowBgAlpha(0.65f);
ImGui::SetNextWindowSizeConstraints(ImVec2(300, 0), ImVec2(FLT_MAX, FLT_MAX));
ImGui::SetNextWindowSizeConstraints(ImVec2(300.f * ImGuiScale(), 0),
ImVec2(FLT_MAX, FLT_MAX));
if (!ImGui::Begin("Map Loader", &m_showMapLoader, windowFlags)) {
ImGui::End();
+64 -17
View File
@@ -1,12 +1,8 @@
#include "fmt/format.h"
#include "imgui.h"
#include "aurora/gfx.h"
#include "ImGuiConsole.hpp"
#include "ImGuiMenuEnhancements.hpp"
#include "ImGuiConfig.hpp"
#include "dusk/settings.hpp"
#include <imgui_internal.h>
#include "dusk/settings.h"
namespace dusk {
ImGuiMenuEnhancements::ImGuiMenuEnhancements() {}
@@ -14,26 +10,81 @@ namespace dusk {
void ImGuiMenuEnhancements::draw() {
if (ImGui::BeginMenu("Enhancements")) {
if (ImGui::BeginMenu("Quality of Life")) {
config::ImguiCheckbox("Fast Iron Boots", settings::enhancements::FastIronBoots);
config::ImguiCheckbox("Invert Camera X Axis", settings::enhancements::InvertCameraXAxis);
config::ImguiCheckbox("Quick Transform (R+Y)", settings::enhancements::QuickTransform);
config::ImGuiCheckbox("Quick Transform (R+Y)", settings::game::enableQuickTransform);
config::ImGuiCheckbox("Bigger Wallets", settings::game::biggerWallets);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Wallet sizes are like in the HD version (500, 1000, 2000)");
}
config::ImGuiCheckbox("No Rupee Returns", settings::game::noReturnRupees);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Always collect Rupees even if your Wallet is too full");
}
config::ImGuiCheckbox("Disable Rupee Cutscenes", settings::game::disableRupeeCutscenes);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Rupees won't play cutscenes after you've collected them the first time");
}
config::ImGuiCheckbox("No Sword Recoil", settings::game::noSwordRecoil);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Link won't recoil when his sword hits walls");
}
config::ImGuiCheckbox("Faster Climbing", settings::game::fastClimbing);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Quicker climbing on ladders and vines like the HD version");
}
config::ImGuiCheckbox("Faster Tears of Light", settings::game::fastTears);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Tears of Light dropped by Shadow Insects pop out faster like the HD version");
}
config::ImGuiCheckbox("Hide TV Settings Screen", settings::game::hideTvSettingsScreen);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Hides the TV calibration screen shown when loading a save");
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Preferences")) {
config::ImGuiCheckbox("Mirror Mode", settings::game::enableMirrorMode);
config::ImGuiCheckbox("Invert Camera X Axis", settings::game::invertCameraXAxis);
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Graphics")) {
config::ImguiCheckbox("Native Bloom", settings::enhancements::EnableBloom);
config::ImguiCheckbox("Water Projection Offset", settings::enhancements::UseWaterProjectionOffset);
config::ImGuiCheckbox("Native Bloom", settings::game::enableBloom);
config::ImGuiCheckbox("Water Projection Offset", settings::game::useWaterProjectionOffset);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Adds GC-specific -0.01 transS offset\n"
"that causes ~6px ghost artifacts in water reflections");
}
config::ImguiCheckbox("Mirror Mode", settings::enhancements::MirrorMode);
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Restorations")) {
config::ImguiCheckbox("Restore Wii 1.0 Glitches", settings::enhancements::RestoreWiiGlitches);
if (ImGui::BeginMenu("Cheats")) {
config::ImGuiCheckbox("Fast Iron Boots", settings::game::enableFastIronBoots);
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Difficulty")) {
config::ImGuiSliderInt("Damage Multiplier", settings::game::damageMultiplier, 1, 8, "x%d");
config::ImGuiCheckbox("Instant Death", settings::game::instantDeath);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Any hit will instantly kill you");
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Technical")) {
config::ImGuiCheckbox("Restore Wii 1.0 Glitches", settings::game::restoreWiiGlitches);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Restores patched glitches from Wii USA 1.0, the first released version");
}
@@ -41,10 +92,6 @@ namespace dusk {
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Cheats")) {
ImGui::EndMenu();
}
ImGui::EndMenu();
}
}
+37 -31
View File
@@ -1,32 +1,36 @@
#include "fmt/format.h"
#include "imgui.h"
#include "aurora/gfx.h"
#include "ImGuiConsole.hpp"
#include "ImGuiMenuGame.hpp"
#include "ImGuiConfig.hpp"
#include <imgui_internal.h>
#include "JSystem/JUtility/JUTGamePad.h"
#include "d/actor/d_a_alink.h"
#include "dusk/audio/DuskAudioSystem.h"
#include "m_Do/m_Do_audio.h"
#include "dusk/hotkeys.h"
#include "dusk/settings.h"
#include "m_Do/m_Do_controller_pad.h"
namespace dusk {
static void ToggleFullscreen() {
settings::video::enableFullscreen.setValue(!settings::video::enableFullscreen);
VISetWindowFullscreen(settings::video::enableFullscreen);
}
ImGuiMenuGame::ImGuiMenuGame() {}
void ImGuiMenuGame::draw() {
if (ImGui::BeginMenu("Game")) {
if (ImGui::MenuItem("Reset", "Ctrl+R")) {
if (ImGui::MenuItem("Reset", hotkeys::DO_RESET)) {
JUTGamePad::C3ButtonReset::sResetSwitchPushing = true;
}
ImGui::Separator();
if (ImGui::BeginMenu("Graphics")) {
if (ImGui::MenuItem("Toggle Fullscreen", "F11")) {
m_fullscreen = !m_fullscreen;
VISetWindowFullscreen(m_fullscreen);
if (ImGui::MenuItem("Toggle Fullscreen", hotkeys::TOGGLE_FULLSCREEN)) {
ToggleFullscreen();
}
ImGui::EndMenu();
@@ -34,28 +38,28 @@ namespace dusk {
if (ImGui::BeginMenu("Audio")) {
ImGui::Text("Master Volume");
ImGui::SliderFloat("##m_masterVolume", &m_audioSettings.m_masterVolume, 0.0f, 1.0f, "");
config::ImGuiSliderFloat("##masterVolume", settings::audio::masterVolume, 0.0f, 1.0f, "");
/*
// TODO: implement additional settings
ImGui::Text("Main Music Volume");
ImGui::SliderFloat("##m_mainMusicVolume", &m_audioSettings.m_mainMusicVolume, 0.0f, 1.0f, "");
ImGui::SliderFloat("##mainMusicVolume", &getSettings().audio.mainMusicVolume, 0.0f, 1.0f, "");
ImGui::Text("Sub Music Volume");
ImGui::SliderFloat("##m_subMusicVolume", &m_audioSettings.m_subMusicVolume, 0.0f, 1.0f, "");
ImGui::SliderFloat("##subMusicVolume", &getSettings().audio.subMusicVolume, 0.0f, 1.0f, "");
ImGui::Text("Sound Effects Volume");
ImGui::SliderFloat("##m_soundEffectsVolume", &m_audioSettings.m_soundEffectsVolume, 0.0f, 1.0f, "");
ImGui::SliderFloat("##soundEffectsVolume", &getSettings().audio.soundEffectsVolume, 0.0f, 1.0f, "");
ImGui::Text("Fanfare Volume");
ImGui::SliderFloat("##m_fanfareVolume", &m_audioSettings.m_fanfareVolume, 0.0f, 1.0f, "");
ImGui::SliderFloat("##fanfareVolume", &getSettings().audio.fanfareVolume, 0.0f, 1.0f, "");
Z2AudioMgr* audioMgr = Z2AudioMgr::getInterface();
if (audioMgr != nullptr) {
}
*/
audio::SetMasterVolume(m_audioSettings.m_masterVolume);
audio::SetMasterVolume(settings::audio::masterVolume);
ImGui::EndMenu();
}
@@ -78,19 +82,19 @@ namespace dusk {
}
if (ImGui::IsKeyPressed(ImGuiKey_F11)) {
m_fullscreen = !m_fullscreen;
VISetWindowFullscreen(m_fullscreen);
ToggleFullscreen();
}
}
static void drawVirtualStick(const char* id, const ImVec2& stick) {
ImGui::SetCursorPos(ImVec2(ImGui::GetCursorPos().x + 5, ImGui::GetCursorPos().y));
float scale = ImGuiScale();
ImGui::SetCursorPos(ImVec2(ImGui::GetCursorPos().x + 5 * scale, ImGui::GetCursorPos().y));
ImGui::BeginChild(id, ImVec2(80, 80));
ImGui::BeginChild(id, ImVec2(80 * scale, 80 * scale));
ImDrawList* dl = ImGui::GetWindowDrawList();
ImVec2 p = ImGui::GetCursorScreenPos();
float radius = ImGui::GetCurrentContext()->CurrentDpiScale * 30.0f;
float radius = 30.0f * scale;
ImVec2 pos = ImVec2(p.x + radius, p.y + radius);
constexpr ImU32 stickGray = IM_COL32(150, 150, 150, 255);
@@ -98,7 +102,7 @@ namespace dusk {
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, red);
dl->AddCircleFilled(ImVec2(pos.x + stick.x * (radius), pos.y + -stick.y * (radius)), 3 * scale, red);
ImGui::EndChild();
}
@@ -139,12 +143,14 @@ namespace dusk {
}
}
float scale = ImGuiScale();
ImGuiWindowFlags windowFlags =
ImGuiWindowFlags_NoResize |
ImGuiWindowFlags_AlwaysAutoResize;
ImGui::SetNextWindowBgAlpha(0.65f);
ImGui::SetNextWindowSizeConstraints(ImVec2(850, 400), ImVec2(850, 400));
ImGui::SetNextWindowSizeConstraints(ImVec2(850 * scale, 400 * scale),
ImVec2(850 * scale, 400 * scale));
if (!ImGui::Begin("Controller Config", &m_showControllerConfig, windowFlags)) {
ImGui::End();
@@ -225,9 +231,9 @@ namespace dusk {
}
// buttons panel
constexpr float uiButtonSize = 40;
const float uiButtonSize = 40 * scale;
ImGuiBeginGroupPanel("Buttons", ImVec2(150, 20));
ImGuiBeginGroupPanel("Buttons", ImVec2(150 * scale, 20 * scale));
u32 buttonCount;
PADButtonMapping* btnMappingList = PADGetButtonMappings(m_controllerConfig.m_selectedPort, &buttonCount);
@@ -251,7 +257,7 @@ namespace dusk {
dispName = fmt::format("{0}##-{1}", PADGetNativeButtonName(btnMappingList[i].nativeButton), i);
}
bool pressed = ImGui::Button(dispName.c_str(),
ImVec2(100.0f, 20.0f));
ImVec2(100.0f * scale, 20.0f * scale));
if (pressed) {
m_controllerConfig.m_isReading = true;
@@ -268,7 +274,7 @@ namespace dusk {
uint32_t axisCount;
PADAxisMapping* axisMappingList = PADGetAxisMappings(m_controllerConfig.m_selectedPort, &axisCount);
ImGuiBeginGroupPanel("Triggers", ImVec2(150, 20));
ImGuiBeginGroupPanel("Triggers", ImVec2(150 * scale, 20 * scale));
PADAxis triggers[] = {PAD_AXIS_TRIGGER_L, PAD_AXIS_TRIGGER_R};
if (axisMappingList != nullptr) {
@@ -291,7 +297,7 @@ namespace dusk {
dispName = fmt::format("{0}##-{1}", PADGetNativeAxisName(axisMappingList[trigger].nativeAxis), trigger);
}
bool pressed = ImGui::Button(dispName.c_str(),
ImVec2(100.0f, 20.0f));
ImVec2(100.0f * scale, 20.0f * scale));
if (pressed) {
m_controllerConfig.m_isReading = true;
@@ -308,7 +314,7 @@ namespace dusk {
int port = m_controllerConfig.m_selectedPort;
// main stick panel
ImGuiBeginGroupPanel("Control Stick", ImVec2(150, 20));
ImGuiBeginGroupPanel("Control Stick", ImVec2(150 * scale, 20 * scale));
drawVirtualStick("##mainStick", ImVec2{ mDoCPd_c::getStickX(port), mDoCPd_c::getStickY(port) });
@@ -345,7 +351,7 @@ namespace dusk {
dispName = fmt::format("{0}##-{1}", PADGetNativeButtonName(axisMappingList[axis].nativeButton), axis);
}
}
bool pressed = ImGui::Button(dispName.c_str(), ImVec2(100.0f, 20.0f));
bool pressed = ImGui::Button(dispName.c_str(), ImVec2(100.0f * scale, 20.0f * scale));
if (pressed) {
m_controllerConfig.m_isReading = true;
@@ -372,7 +378,7 @@ namespace dusk {
ImGui::SameLine();
// sub stick panel
ImGuiBeginGroupPanel("C Stick", ImVec2(150, 20));
ImGuiBeginGroupPanel("C Stick", ImVec2(150 * scale, 20 * scale));
drawVirtualStick("##subStick", ImVec2{ mDoCPd_c::getSubStickX(port), mDoCPd_c::getSubStickY(port) });
@@ -409,7 +415,7 @@ namespace dusk {
dispName = fmt::format("{0}##-{1}", PADGetNativeButtonName(axisMappingList[axis].nativeButton), axis);
}
}
bool pressed = ImGui::Button(fmt::format("{0}##sub{1}", dispName, label).c_str(), ImVec2(100.0f, 20.0f));
bool pressed = ImGui::Button(fmt::format("{0}##sub{1}", dispName, label).c_str(), ImVec2(100.0f * scale, 20.0f * scale));
if (pressed) {
m_controllerConfig.m_isReading = true;
@@ -434,7 +440,7 @@ namespace dusk {
ImGui::SameLine();
// Triggers Panel
ImGuiBeginGroupPanel("Triggers", ImVec2(150, 20));
ImGuiBeginGroupPanel("Triggers", ImVec2(150 * scale, 20 * scale));
if (deadZones != nullptr) {
ImGui::Text("L Threshold");
@@ -460,7 +466,7 @@ namespace dusk {
ImGui::SameLine();
// Options panel
ImGuiBeginGroupPanel("Options", ImVec2(150, 20));
ImGuiBeginGroupPanel("Options", ImVec2(150 * scale, 20 * scale));
if (deadZones != nullptr) {
ImGui::Checkbox("Enable Dead Zones", &deadZones->useDeadzones);
-10
View File
@@ -17,14 +17,6 @@ namespace dusk {
void windowControllerConfig();
private:
struct {
float m_masterVolume = 1.0f;
float m_mainMusicVolume = 1.0f;
float m_subMusicVolume = 1.0f;
float m_soundEffectsVolume = 1.0f;
float m_fanfareVolume = 1.0f;
} m_audioSettings;
struct {
int m_selectedPort = 0;
bool m_isReading = false;
@@ -33,8 +25,6 @@ namespace dusk {
int m_pendingPort = -1;
} m_controllerConfig;
bool m_fullscreen = false;
bool m_showControllerConfig = false;
bool m_showInputViewer = false;
+19 -14
View File
@@ -2,6 +2,7 @@
#include "imgui.h"
#include "aurora/gfx.h"
#include "dusk/hotkeys.h"
#include "ImGuiConsole.hpp"
#include "ImGuiMenuTools.hpp"
@@ -23,28 +24,29 @@ namespace dusk {
ImGui::Separator();
auto& collisionView = getTransientSettings().collisionView;
if (ImGui::BeginMenu("Collision View")) {
ImGui::Checkbox("Enable Terrain view", &m_collisionViewSettings.m_enableTerrainView);
ImGui::Checkbox("Enable wireframe view", &m_collisionViewSettings.m_enableWireframe);
ImGui::SliderFloat("Opacity##terrain", &m_collisionViewSettings.m_terrainViewOpacity, 0.0f, 100.0f);
ImGui::SliderFloat("Draw Range", &m_collisionViewSettings.m_drawRange, 0.0f, 1000.0f);
ImGui::Checkbox("Enable Terrain view", &collisionView.enableTerrainView);
ImGui::Checkbox("Enable wireframe view", &collisionView.enableWireframe);
ImGui::SliderFloat("Opacity##terrain", &collisionView.terrainViewOpacity, 0.0f, 100.0f);
ImGui::SliderFloat("Draw Range", &collisionView.drawRange, 0.0f, 1000.0f);
ImGui::Separator();
ImGui::Checkbox("Enable Attack Collider view", &m_collisionViewSettings.m_enableAtView);
ImGui::Checkbox("Enable Target Collider view", &m_collisionViewSettings.m_enableTgView);
ImGui::Checkbox("Enable Push Collider view", &m_collisionViewSettings.m_enableCoView);
ImGui::SliderFloat("Opacity##colliders", &m_collisionViewSettings.m_colliderViewOpacity, 0.0f, 100.0f);
ImGui::Checkbox("Enable Attack Collider view", &collisionView.enableAtView);
ImGui::Checkbox("Enable Target Collider view", &collisionView.enableTgView);
ImGui::Checkbox("Enable Push Collider view", &collisionView.enableCoView);
ImGui::SliderFloat("Opacity##colliders", &collisionView.colliderViewOpacity, 0.0f, 100.0f);
ImGui::EndMenu();
}
ImGui::MenuItem("Process Management", "F2", &m_showProcessManagement);
ImGui::MenuItem("Debug Overlay", "F3", &m_showDebugOverlay);
ImGui::MenuItem("Heap Viewer", "F4", &m_showHeapOverlay);
ImGui::MenuItem("Stub Log", "F5", &m_showStubLog);
ImGui::MenuItem("Debug Camera", "F6", &m_showCameraOverlay);
ImGui::MenuItem("Process Management", hotkeys::SHOW_PROCESS_MANAGEMENT, &m_showProcessManagement);
ImGui::MenuItem("Debug Overlay", hotkeys::SHOW_DEBUG_OVERLAY, &m_showDebugOverlay);
ImGui::MenuItem("Heap Viewer", hotkeys::SHOW_HEAP_VIEWER, &m_showHeapOverlay);
ImGui::MenuItem("Stub Log", hotkeys::SHOW_STUB_LOG, &m_showStubLog);
ImGui::MenuItem("Debug Camera", hotkeys::SHOW_CAMERA_DEBUG, &m_showCameraOverlay);
ImGui::MenuItem("Map Loader", nullptr, &m_showMapLoader);
ImGui::MenuItem("Player Info", nullptr, &m_showPlayerInfo);
ImGui::MenuItem("Save Editor", nullptr, &m_showSaveEditor);
ImGui::MenuItem("Audio Debug", "F7", &m_showAudioDebug);
ImGui::MenuItem("Audio Debug", hotkeys::SHOW_AUDIO_DEBUG, &m_showAudioDebug);
ImGui::MenuItem("OSReport Force", nullptr, &OSReportReallyForceEnable);
ImGui::EndMenu();
}
@@ -131,6 +133,9 @@ namespace dusk {
BytesToString(stats->lastVertSize + stats->lastUniformSize +
stats->lastIndexSize + stats->lastStorageSize +
stats->lastTextureUploadSize)));
// TODO: persist to config
ShowCornerContextMenu(m_debugOverlayCorner, m_cameraOverlayCorner);
}
ImGui::End();
}
+1 -16
View File
@@ -10,17 +10,6 @@
namespace dusk {
class ImGuiMenuTools {
public:
struct CollisionViewSettings {
bool m_enableTerrainView = false;
bool m_enableWireframe = false;
bool m_enableAtView = false;
bool m_enableTgView = false;
bool m_enableCoView = false;
float m_terrainViewOpacity = 50.0f;
float m_colliderViewOpacity = 50.0f;
float m_drawRange = 100.0f;
};
ImGuiMenuTools();
void draw();
void afterDraw();
@@ -34,11 +23,9 @@ namespace dusk {
void ShowPlayerInfo();
void ShowAudioDebug();
CollisionViewSettings& getCollisionViewSettings() { return m_collisionViewSettings; }
private:
bool m_showDebugOverlay = false;
int m_debugOverlayCorner = 0; // top-left
int m_debugOverlayCorner = 2; // bottom-left
bool m_showCameraOverlay = false;
int m_cameraOverlayCorner = 3;
@@ -67,8 +54,6 @@ namespace dusk {
bool m_isDevelopmentMode = false;
bool m_showPlayerInfo = false;
CollisionViewSettings m_collisionViewSettings;
bool m_showSaveEditor = false;
ImGuiSaveEditor m_saveEditor;
};
+1 -1
View File
@@ -823,7 +823,7 @@ namespace dusk {
for (int e = 0; e < 255; e++) {
ImGui::Text("%03d ", e);
ImGui::SameLine();
for (int i = 8; i >= 0; i--) {
for (int i = 7; i >= 0; i--) {
bool flag = event.mEvent[e] & (1 << i);
if (ImGui::Checkbox(fmt::format("##event{0}{1}", e, i).c_str(), &flag)) {
if (flag)
+93 -24
View File
@@ -1,28 +1,97 @@
#include "dusk/settings.hpp"
#include "dusk/settings.h"
#include "dusk/config.hpp"
namespace dusk::settings::enhancements {
ConfigVar<bool> FastIronBoots("enhancements.fast_iron_boots", false);
ConfigVar<bool> InvertCameraXAxis("enhancements.invert_camera_x_axis", false);
ConfigVar<bool> QuickTransform("enhancements.quick_transform", false);
ConfigVar<bool> RestoreWiiGlitches("enhancements.restore_wii_glitches", false);
ConfigVar<bool> EnableBloom("enhancements.enable_bloom", true);
ConfigVar<bool> UseWaterProjectionOffset("enhancements.use_water_projection_offset", false);
ConfigVar<bool> MirrorMode("enhancements.mirror_mode", false);
void Register() {
Register(FastIronBoots);
Register(InvertCameraXAxis);
Register(QuickTransform);
Register(RestoreWiiGlitches);
Register(EnableBloom);
Register(UseWaterProjectionOffset);
Register(MirrorMode);
}
}
namespace dusk::settings {
void Register() {
enhancements::Register();
}
namespace video {
ConfigVar<bool> enableFullscreen("video.enableFullscreen", false);
}
namespace audio {
ConfigVar<float> masterVolume("audio.masterVolume", 1.0f);
ConfigVar<float> mainMusicVolume("audio.mainMusicVolume", 1.0f);
ConfigVar<float> subMusicVolume("audio.subMusicVolume", 1.0f);
ConfigVar<float> soundEffectsVolume("audio.soundEffectsVolume", 1.0f);
ConfigVar<float> fanfareVolume("audio.fanfareVolume", 1.0f);
}
namespace game {
// Quality of Life
ConfigVar<bool> enableQuickTransform("game.enableQuickTransform", false);
ConfigVar<bool> hideTvSettingsScreen("game.hideTvSettingsScreen", false);
ConfigVar<bool> biggerWallets("game.biggerWallets", false);
ConfigVar<bool> noReturnRupees("game.noReturnRupees", false);
ConfigVar<bool> disableRupeeCutscenes("game.disableRupeeCutscenes", false);
ConfigVar<bool> noSwordRecoil("game.noSwordRecoil", false);
ConfigVar<int> damageMultiplier("game.damageMultiplier", 1);
ConfigVar<bool> instantDeath("game.instantDeath", false);
ConfigVar<bool> fastClimbing("game.fastClimbing", false);
ConfigVar<bool> fastTears("game.fastTears", false);
// Preferences
ConfigVar<bool> enableMirrorMode("game.enableMirrorMode", false);
ConfigVar<bool> invertCameraXAxis("game.invertCameraXAxis", false);
// Graphics
ConfigVar<bool> enableBloom("game.enableBloom", true);
ConfigVar<bool> useWaterProjectionOffset("game.useWaterProjectionOffset", false);
// Cheats
ConfigVar<bool> enableFastIronBoots("game.enableFastIronBoots", false);
// Technical
ConfigVar<bool> restoreWiiGlitches("game.restoreWiiGlitches", false);
}
void Register() {
// Video
Register(video::enableFullscreen);
// Audio
Register(audio::masterVolume);
Register(audio::mainMusicVolume);
Register(audio::subMusicVolume);
Register(audio::soundEffectsVolume);
Register(audio::fanfareVolume);
// Game
Register(game::enableQuickTransform);
Register(game::hideTvSettingsScreen);
Register(game::biggerWallets);
Register(game::noReturnRupees);
Register(game::disableRupeeCutscenes);
Register(game::noSwordRecoil);
Register(game::damageMultiplier);
Register(game::instantDeath);
Register(game::fastClimbing);
Register(game::fastTears);
Register(game::enableMirrorMode);
Register(game::invertCameraXAxis);
Register(game::enableBloom);
Register(game::useWaterProjectionOffset);
Register(game::enableFastIronBoots);
Register(game::restoreWiiGlitches);
}
}
namespace dusk {
// Transient settings
static TransientSettings g_transientSettings = {
.collisionView = {
.enableTerrainView = false,
.enableWireframe = false,
.enableAtView = false,
.enableTgView = false,
.enableCoView = false,
.terrainViewOpacity = 50.0f,
.colliderViewOpacity = 50.0f,
.drawRange = 100.0f,
},
};
TransientSettings& getTransientSettings() {
return g_transientSettings;
}
}