diff --git a/README.md b/README.md
index f02185ca..3d7c2561 100644
--- a/README.md
+++ b/README.md
@@ -5,6 +5,7 @@
+
diff --git a/src/ARCodeFile.cpp b/src/ARCodeFile.cpp
index 602a2e7b..2b37e859 100644
--- a/src/ARCodeFile.cpp
+++ b/src/ARCodeFile.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/ARCodeFile.h b/src/ARCodeFile.h
index 11e71efe..2cdf1f05 100644
--- a/src/ARCodeFile.h
+++ b/src/ARCodeFile.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/AREngine.cpp b/src/AREngine.cpp
index c7d49fe6..879c620c 100644
--- a/src/AREngine.cpp
+++ b/src/AREngine.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/AREngine.h b/src/AREngine.h
index 21044676..cdffac07 100644
--- a/src/AREngine.h
+++ b/src/AREngine.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/ARM.cpp b/src/ARM.cpp
index 644a58a2..3ecae2c8 100644
--- a/src/ARM.cpp
+++ b/src/ARM.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/ARM.h b/src/ARM.h
index cb47f287..8efb8fa6 100644
--- a/src/ARM.h
+++ b/src/ARM.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/ARMInterpreter.cpp b/src/ARMInterpreter.cpp
index 5621876a..93b347b5 100644
--- a/src/ARMInterpreter.cpp
+++ b/src/ARMInterpreter.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/ARMInterpreter.h b/src/ARMInterpreter.h
index cff4821a..1066ac69 100644
--- a/src/ARMInterpreter.h
+++ b/src/ARMInterpreter.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/ARMInterpreter_ALU.cpp b/src/ARMInterpreter_ALU.cpp
index 51b219d7..3e94d2af 100644
--- a/src/ARMInterpreter_ALU.cpp
+++ b/src/ARMInterpreter_ALU.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/ARMInterpreter_ALU.h b/src/ARMInterpreter_ALU.h
index 6998b637..58d8165c 100644
--- a/src/ARMInterpreter_ALU.h
+++ b/src/ARMInterpreter_ALU.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/ARMInterpreter_Branch.cpp b/src/ARMInterpreter_Branch.cpp
index 45f0440d..284dfa75 100644
--- a/src/ARMInterpreter_Branch.cpp
+++ b/src/ARMInterpreter_Branch.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/ARMInterpreter_Branch.h b/src/ARMInterpreter_Branch.h
index 51a561c1..e3d16776 100644
--- a/src/ARMInterpreter_Branch.h
+++ b/src/ARMInterpreter_Branch.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/ARMInterpreter_LoadStore.cpp b/src/ARMInterpreter_LoadStore.cpp
index d874fb9a..4a640bc5 100644
--- a/src/ARMInterpreter_LoadStore.cpp
+++ b/src/ARMInterpreter_LoadStore.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/ARMInterpreter_LoadStore.h b/src/ARMInterpreter_LoadStore.h
index 32d6e4d2..62828194 100644
--- a/src/ARMInterpreter_LoadStore.h
+++ b/src/ARMInterpreter_LoadStore.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/ARMJIT.cpp b/src/ARMJIT.cpp
index c3fcba26..1ebcce8e 100644
--- a/src/ARMJIT.cpp
+++ b/src/ARMJIT.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/ARMJIT.h b/src/ARMJIT.h
index 7619f234..a228a4dd 100644
--- a/src/ARMJIT.h
+++ b/src/ARMJIT.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/ARMJIT_A64/ARMJIT_ALU.cpp b/src/ARMJIT_A64/ARMJIT_ALU.cpp
index b25bcaa3..cb777500 100644
--- a/src/ARMJIT_A64/ARMJIT_ALU.cpp
+++ b/src/ARMJIT_A64/ARMJIT_ALU.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team, RSDuck
+ Copyright 2016-2024 melonDS team, RSDuck
This file is part of melonDS.
diff --git a/src/ARMJIT_A64/ARMJIT_Branch.cpp b/src/ARMJIT_A64/ARMJIT_Branch.cpp
index 92717e91..f9c2e0c5 100644
--- a/src/ARMJIT_A64/ARMJIT_Branch.cpp
+++ b/src/ARMJIT_A64/ARMJIT_Branch.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team, RSDuck
+ Copyright 2016-2024 melonDS team, RSDuck
This file is part of melonDS.
diff --git a/src/ARMJIT_A64/ARMJIT_Compiler.cpp b/src/ARMJIT_A64/ARMJIT_Compiler.cpp
index 7981ed67..f05de448 100644
--- a/src/ARMJIT_A64/ARMJIT_Compiler.cpp
+++ b/src/ARMJIT_A64/ARMJIT_Compiler.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team, RSDuck
+ Copyright 2016-2024 melonDS team, RSDuck
This file is part of melonDS.
diff --git a/src/ARMJIT_A64/ARMJIT_Compiler.h b/src/ARMJIT_A64/ARMJIT_Compiler.h
index 2b0048a9..a7b567f6 100644
--- a/src/ARMJIT_A64/ARMJIT_Compiler.h
+++ b/src/ARMJIT_A64/ARMJIT_Compiler.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team, RSDuck
+ Copyright 2016-2024 melonDS team, RSDuck
This file is part of melonDS.
diff --git a/src/ARMJIT_A64/ARMJIT_Linkage.S b/src/ARMJIT_A64/ARMJIT_Linkage.S
index b73905bd..9c360ec0 100644
--- a/src/ARMJIT_A64/ARMJIT_Linkage.S
+++ b/src/ARMJIT_A64/ARMJIT_Linkage.S
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team, RSDuck
+ Copyright 2016-2024 melonDS team, RSDuck
This file is part of melonDS.
diff --git a/src/ARMJIT_A64/ARMJIT_LoadStore.cpp b/src/ARMJIT_A64/ARMJIT_LoadStore.cpp
index e108b7b4..6d2c4276 100644
--- a/src/ARMJIT_A64/ARMJIT_LoadStore.cpp
+++ b/src/ARMJIT_A64/ARMJIT_LoadStore.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team, RSDuck
+ Copyright 2016-2024 melonDS team, RSDuck
This file is part of melonDS.
diff --git a/src/ARMJIT_Compiler.h b/src/ARMJIT_Compiler.h
index ff4f8ff7..46cce5b0 100644
--- a/src/ARMJIT_Compiler.h
+++ b/src/ARMJIT_Compiler.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team, RSDuck
+ Copyright 2016-2024 melonDS team, RSDuck
This file is part of melonDS.
diff --git a/src/ARMJIT_Internal.h b/src/ARMJIT_Internal.h
index 8429bade..5b393903 100644
--- a/src/ARMJIT_Internal.h
+++ b/src/ARMJIT_Internal.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team, RSDuck
+ Copyright 2016-2024 melonDS team, RSDuck
This file is part of melonDS.
diff --git a/src/ARMJIT_Memory.cpp b/src/ARMJIT_Memory.cpp
index c8969aee..51e022d1 100644
--- a/src/ARMJIT_Memory.cpp
+++ b/src/ARMJIT_Memory.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/ARMJIT_Memory.h b/src/ARMJIT_Memory.h
index d36f6032..88e647d5 100644
--- a/src/ARMJIT_Memory.h
+++ b/src/ARMJIT_Memory.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/ARMJIT_RegisterCache.h b/src/ARMJIT_RegisterCache.h
index e5f28dd6..d2680731 100644
--- a/src/ARMJIT_RegisterCache.h
+++ b/src/ARMJIT_RegisterCache.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team, RSDuck
+ Copyright 2016-2024 melonDS team, RSDuck
This file is part of melonDS.
diff --git a/src/ARMJIT_x64/ARMJIT_ALU.cpp b/src/ARMJIT_x64/ARMJIT_ALU.cpp
index 69449ff9..8f7a1b22 100644
--- a/src/ARMJIT_x64/ARMJIT_ALU.cpp
+++ b/src/ARMJIT_x64/ARMJIT_ALU.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/ARMJIT_x64/ARMJIT_Branch.cpp b/src/ARMJIT_x64/ARMJIT_Branch.cpp
index f7a01f48..c32e2b73 100644
--- a/src/ARMJIT_x64/ARMJIT_Branch.cpp
+++ b/src/ARMJIT_x64/ARMJIT_Branch.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/ARMJIT_x64/ARMJIT_Compiler.cpp b/src/ARMJIT_x64/ARMJIT_Compiler.cpp
index b18837f3..ba6c0fb4 100644
--- a/src/ARMJIT_x64/ARMJIT_Compiler.cpp
+++ b/src/ARMJIT_x64/ARMJIT_Compiler.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/ARMJIT_x64/ARMJIT_Compiler.h b/src/ARMJIT_x64/ARMJIT_Compiler.h
index 941d8924..3965e882 100644
--- a/src/ARMJIT_x64/ARMJIT_Compiler.h
+++ b/src/ARMJIT_x64/ARMJIT_Compiler.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/ARMJIT_x64/ARMJIT_GenOffsets.cpp b/src/ARMJIT_x64/ARMJIT_GenOffsets.cpp
index e2a74eee..e4812c0a 100644
--- a/src/ARMJIT_x64/ARMJIT_GenOffsets.cpp
+++ b/src/ARMJIT_x64/ARMJIT_GenOffsets.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team, RSDuck
+ Copyright 2016-2024 melonDS team, RSDuck
This file is part of melonDS.
diff --git a/src/ARMJIT_x64/ARMJIT_Linkage.S b/src/ARMJIT_x64/ARMJIT_Linkage.S
index 023f6e7b..18596003 100644
--- a/src/ARMJIT_x64/ARMJIT_Linkage.S
+++ b/src/ARMJIT_x64/ARMJIT_Linkage.S
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/ARMJIT_x64/ARMJIT_LoadStore.cpp b/src/ARMJIT_x64/ARMJIT_LoadStore.cpp
index 8520bebc..219c7271 100644
--- a/src/ARMJIT_x64/ARMJIT_LoadStore.cpp
+++ b/src/ARMJIT_x64/ARMJIT_LoadStore.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/ARMJIT_x64/ARMJIT_Offsets.h b/src/ARMJIT_x64/ARMJIT_Offsets.h
index 9d2a9522..738fc4ea 100644
--- a/src/ARMJIT_x64/ARMJIT_Offsets.h
+++ b/src/ARMJIT_x64/ARMJIT_Offsets.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team, RSDuck
+ Copyright 2016-2024 melonDS team, RSDuck
This file is part of melonDS.
diff --git a/src/ARM_InstrInfo.cpp b/src/ARM_InstrInfo.cpp
index d53c88f0..58838307 100644
--- a/src/ARM_InstrInfo.cpp
+++ b/src/ARM_InstrInfo.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/ARM_InstrInfo.h b/src/ARM_InstrInfo.h
index 13f66b09..fe4095b4 100644
--- a/src/ARM_InstrInfo.h
+++ b/src/ARM_InstrInfo.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/ARM_InstrTable.h b/src/ARM_InstrTable.h
index 7cdad66d..8213c2e0 100644
--- a/src/ARM_InstrTable.h
+++ b/src/ARM_InstrTable.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/Args.h b/src/Args.h
index 0b20bbf0..2c405e29 100644
--- a/src/Args.h
+++ b/src/Args.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 50cd7708..3e177835 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -133,6 +133,7 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/version.h.in" "${CMAKE_CURRENT_BINAR
target_sources(core PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/version.h")
target_include_directories(core PUBLIC "${CMAKE_CURRENT_BINARY_DIR}")
+set(BUILD_SHARED_LIBS OFF)
add_subdirectory(teakra EXCLUDE_FROM_ALL)
# Workaround for building teakra with -O0 on Windows either failing or hanging forever
target_compile_options(teakra PRIVATE "$<$:-Og>")
@@ -140,7 +141,9 @@ target_link_libraries(core PRIVATE teakra)
if (NOT MSVC)
# MSVC has its own compiler flag syntax; if we ever support it,
- # be sure to silence any equivalent warnings there.
+ # be sure to add equivalent flags here.
+
+ target_compile_options(core PUBLIC -fwrapv)
target_compile_options(core PRIVATE "$<$:-Wno-invalid-offsetof>")
# These warnings are excessive, and are only triggered in the ARMJIT code
diff --git a/src/CP15.cpp b/src/CP15.cpp
index 06e01e83..d5898ac8 100644
--- a/src/CP15.cpp
+++ b/src/CP15.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/CRC32.cpp b/src/CRC32.cpp
index 0756c034..82fe467f 100644
--- a/src/CRC32.cpp
+++ b/src/CRC32.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/CRC32.h b/src/CRC32.h
index 11879057..90fb8057 100644
--- a/src/CRC32.h
+++ b/src/CRC32.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/DMA.cpp b/src/DMA.cpp
index 0fc6cf05..80cd592c 100644
--- a/src/DMA.cpp
+++ b/src/DMA.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/DMA.h b/src/DMA.h
index e0e3be15..354f4495 100644
--- a/src/DMA.h
+++ b/src/DMA.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/DMA_Timings.cpp b/src/DMA_Timings.cpp
index 912e4e2e..a51fedfb 100644
--- a/src/DMA_Timings.cpp
+++ b/src/DMA_Timings.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/DMA_Timings.h b/src/DMA_Timings.h
index 63dc4676..38206235 100644
--- a/src/DMA_Timings.h
+++ b/src/DMA_Timings.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/DSi.cpp b/src/DSi.cpp
index 5b98957c..0a0bd36d 100644
--- a/src/DSi.cpp
+++ b/src/DSi.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
@@ -70,8 +70,28 @@ const u32 NDMAModes[] =
0xFF, // wifi / GBA cart slot (TODO)
};
-DSi::DSi(DSiArgs&& args) noexcept :
- NDS(std::move(args), 1),
+/*DSi::DSi() noexcept :
+ DSi(
+ DSiArgs {
+ NDSArgs {
+ nullptr,
+ nullptr,
+ bios_arm9_bin,
+ bios_arm7_bin,
+ Firmware(0),
+ },
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ false
+ }
+ )
+{
+}*/
+
+DSi::DSi(DSiArgs&& args, void* userdata) noexcept :
+ NDS(std::move(args), 1, userdata),
NDMAs {
DSi_NDMA(0, 0, *this),
DSi_NDMA(0, 1, *this),
diff --git a/src/DSi.h b/src/DSi.h
index 755e1f50..7b7a94a2 100644
--- a/src/DSi.h
+++ b/src/DSi.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
@@ -131,7 +131,8 @@ public:
void ARM7IOWrite32(u32 addr, u32 val) override;
public:
- DSi(DSiArgs&& args) noexcept;
+ DSi(DSiArgs&& args, void* userdata = nullptr) noexcept;
+ //DSi() noexcept;
~DSi() noexcept override;
DSi(const DSi&) = delete;
DSi& operator=(const DSi&) = delete;
diff --git a/src/DSi_AES.cpp b/src/DSi_AES.cpp
index 379dea13..36fe2892 100644
--- a/src/DSi_AES.cpp
+++ b/src/DSi_AES.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/DSi_AES.h b/src/DSi_AES.h
index d83c870e..badeb192 100644
--- a/src/DSi_AES.h
+++ b/src/DSi_AES.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/DSi_Camera.cpp b/src/DSi_Camera.cpp
index a1cdbe0a..b1d60d04 100644
--- a/src/DSi_Camera.cpp
+++ b/src/DSi_Camera.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
@@ -410,7 +410,7 @@ void DSi_Camera::DoSavestate(Savestate* file)
void DSi_Camera::Reset()
{
- Platform::Camera_Stop(Num);
+ Platform::Camera_Stop(Num, DSi.UserData);
DataPos = 0;
RegAddr = 0;
@@ -435,7 +435,7 @@ void DSi_Camera::Reset()
void DSi_Camera::Stop()
{
- Platform::Camera_Stop(Num);
+ Platform::Camera_Stop(Num, DSi.UserData);
}
bool DSi_Camera::IsActivated() const
@@ -474,7 +474,7 @@ void DSi_Camera::StartTransfer()
FrameFormat = 0;
}
- Platform::Camera_CaptureFrame(Num, FrameBuffer, 640, 480, true);
+ Platform::Camera_CaptureFrame(Num, FrameBuffer, 640, 480, true, DSi.UserData);
}
bool DSi_Camera::TransferDone() const
@@ -655,8 +655,8 @@ void DSi_Camera::I2C_WriteReg(u16 addr, u16 val)
StandbyCnt = val;
//printf("CAM%d STBCNT=%04X (%04X)\n", Num, StandbyCnt, val);
bool isactive = IsActivated();
- if (isactive && !wasactive) Platform::Camera_Start(Num);
- else if (wasactive && !isactive) Platform::Camera_Stop(Num);
+ if (isactive && !wasactive) Platform::Camera_Start(Num, DSi.UserData);
+ else if (wasactive && !isactive) Platform::Camera_Stop(Num, DSi.UserData);
}
return;
case 0x001A:
@@ -665,8 +665,8 @@ void DSi_Camera::I2C_WriteReg(u16 addr, u16 val)
MiscCnt = val & 0x0B7B;
//printf("CAM%d MISCCNT=%04X (%04X)\n", Num, MiscCnt, val);
bool isactive = IsActivated();
- if (isactive && !wasactive) Platform::Camera_Start(Num);
- else if (wasactive && !isactive) Platform::Camera_Stop(Num);
+ if (isactive && !wasactive) Platform::Camera_Start(Num, DSi.UserData);
+ else if (wasactive && !isactive) Platform::Camera_Stop(Num, DSi.UserData);
}
return;
diff --git a/src/DSi_Camera.h b/src/DSi_Camera.h
index 363cea43..604e06ac 100644
--- a/src/DSi_Camera.h
+++ b/src/DSi_Camera.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/DSi_I2C.cpp b/src/DSi_I2C.cpp
index 28f98dc8..f28562e9 100644
--- a/src/DSi_I2C.cpp
+++ b/src/DSi_I2C.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/DSi_I2C.h b/src/DSi_I2C.h
index 5dfeebd0..a05c7aed 100644
--- a/src/DSi_I2C.h
+++ b/src/DSi_I2C.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/DSi_NAND.cpp b/src/DSi_NAND.cpp
index 8da02540..a6b6c566 100644
--- a/src/DSi_NAND.cpp
+++ b/src/DSi_NAND.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/DSi_NAND.h b/src/DSi_NAND.h
index 104845d5..7af434d9 100644
--- a/src/DSi_NAND.h
+++ b/src/DSi_NAND.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/DSi_NDMA.cpp b/src/DSi_NDMA.cpp
index 7c77c9ad..452ac6e6 100644
--- a/src/DSi_NDMA.cpp
+++ b/src/DSi_NDMA.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/DSi_NDMA.h b/src/DSi_NDMA.h
index fb34dbdf..9f8e6706 100644
--- a/src/DSi_NDMA.h
+++ b/src/DSi_NDMA.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/DSi_NWifi.cpp b/src/DSi_NWifi.cpp
index a6177dec..792bf12d 100644
--- a/src/DSi_NWifi.cpp
+++ b/src/DSi_NWifi.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
@@ -1334,7 +1334,7 @@ void DSi_NWifi::WMI_SendPacket(u16 len)
}
printf("\n");*/
- Platform::LAN_SendPacket(LANBuffer, lan_len);
+ Platform::Net_SendPacket(LANBuffer, lan_len, DSi.UserData);
}
void DSi_NWifi::SendWMIEvent(u8 ep, u16 id, u8* data, u32 len)
@@ -1442,20 +1442,26 @@ void DSi_NWifi::CheckRX()
if (!Mailbox[8].CanFit(2048))
return;
- int rxlen = Platform::LAN_RecvPacket(LANBuffer);
- if (rxlen > 0)
+ int rxlen = Platform::Net_RecvPacket(LANBuffer, DSi.UserData);
+ while (rxlen > 0)
{
//printf("WMI packet recv %04X %04X %04X\n", *(u16*)&LANBuffer[0], *(u16*)&LANBuffer[2], *(u16*)&LANBuffer[4]);
// check destination MAC
if (*(u32*)&LANBuffer[0] != 0xFFFFFFFF || *(u16*)&LANBuffer[4] != 0xFFFF)
{
if (memcmp(&LANBuffer[0], &EEPROM[0x00A], 6))
- return;
+ {
+ rxlen = Platform::Net_RecvPacket(LANBuffer, DSi.UserData);
+ continue;
+ }
}
// check source MAC, in case we get a packet we just sent out
if (!memcmp(&LANBuffer[6], &EEPROM[0x00A], 6))
- return;
+ {
+ rxlen = Platform::Net_RecvPacket(LANBuffer, DSi.UserData);
+ continue;
+ }
// packet is good
diff --git a/src/DSi_NWifi.h b/src/DSi_NWifi.h
index 39e9459c..84ac8a49 100644
--- a/src/DSi_NWifi.h
+++ b/src/DSi_NWifi.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/DSi_SD.cpp b/src/DSi_SD.cpp
index 72fe3756..c600bc76 100644
--- a/src/DSi_SD.cpp
+++ b/src/DSi_SD.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/DSi_SD.h b/src/DSi_SD.h
index 29620dc5..5d376600 100644
--- a/src/DSi_SD.h
+++ b/src/DSi_SD.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/DSi_SPI_TSC.cpp b/src/DSi_SPI_TSC.cpp
index d515db9f..dbb60c10 100644
--- a/src/DSi_SPI_TSC.cpp
+++ b/src/DSi_SPI_TSC.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/DSi_SPI_TSC.h b/src/DSi_SPI_TSC.h
index d1a71063..f20f7ac1 100644
--- a/src/DSi_SPI_TSC.h
+++ b/src/DSi_SPI_TSC.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/DSi_TMD.h b/src/DSi_TMD.h
index f07b3d1c..5ea91a6f 100644
--- a/src/DSi_TMD.h
+++ b/src/DSi_TMD.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/FATIO.cpp b/src/FATIO.cpp
index 233014e4..aea33ee6 100644
--- a/src/FATIO.cpp
+++ b/src/FATIO.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/FATIO.h b/src/FATIO.h
index 6d8aa499..f8184885 100644
--- a/src/FATIO.h
+++ b/src/FATIO.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/FATStorage.cpp b/src/FATStorage.cpp
index f735d4b8..200c99d5 100644
--- a/src/FATStorage.cpp
+++ b/src/FATStorage.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/FATStorage.h b/src/FATStorage.h
index 00628461..030b765b 100644
--- a/src/FATStorage.h
+++ b/src/FATStorage.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/FIFO.h b/src/FIFO.h
index 026c2c7f..5fc04832 100644
--- a/src/FIFO.h
+++ b/src/FIFO.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
@@ -24,6 +24,7 @@
namespace melonDS
{
+
template
class FIFO
{
@@ -191,5 +192,121 @@ private:
u32 ReadPos, WritePos;
};
+template
+class RingBuffer
+{
+public:
+ void Clear()
+ {
+ NumOccupied = 0;
+ ReadPos = 0;
+ WritePos = 0;
+ memset(Buffer, 0, Size);
+ }
+
+
+ void DoSavestate(Savestate* file)
+ {
+ file->Var32(&NumOccupied);
+ file->Var32(&ReadPos);
+ file->Var32(&WritePos);
+
+ file->VarArray(Buffer, Size);
+ }
+
+
+ bool Write(const void* data, u32 len)
+ {
+ if (!CanFit(len)) return false;
+
+ if ((WritePos + len) >= Size)
+ {
+ u32 part1 = Size - WritePos;
+ memcpy(&Buffer[WritePos], data, part1);
+ if (len > part1)
+ memcpy(Buffer, &((u8*)data)[part1], len - part1);
+ WritePos = len - part1;
+ }
+ else
+ {
+ memcpy(&Buffer[WritePos], data, len);
+ WritePos += len;
+ }
+
+ NumOccupied += len;
+
+ return true;
+ }
+
+ bool Read(void* data, u32 len)
+ {
+ if (NumOccupied < len) return false;
+
+ u32 readpos = ReadPos;
+ if ((readpos + len) >= Size)
+ {
+ u32 part1 = Size - readpos;
+ memcpy(data, &Buffer[readpos], part1);
+ if (len > part1)
+ memcpy(&((u8*)data)[part1], Buffer, len - part1);
+ ReadPos = len - part1;
+ }
+ else
+ {
+ memcpy(data, &Buffer[readpos], len);
+ ReadPos += len;
+ }
+
+ NumOccupied -= len;
+ return true;
+ }
+
+ bool Peek(void* data, u32 offset, u32 len)
+ {
+ if (NumOccupied < len) return false;
+
+ u32 readpos = ReadPos + offset;
+ if (readpos >= Size) readpos -= Size;
+
+ if ((readpos + len) >= Size)
+ {
+ u32 part1 = Size - readpos;
+ memcpy(data, &Buffer[readpos], part1);
+ if (len > part1)
+ memcpy(&((u8*)data)[part1], Buffer, len - part1);
+ }
+ else
+ {
+ memcpy(data, &Buffer[readpos], len);
+ }
+
+ return true;
+ }
+
+ bool Skip(u32 len)
+ {
+ if (NumOccupied < len) return false;
+
+ ReadPos += len;
+ if (ReadPos >= Size)
+ ReadPos -= Size;
+
+ NumOccupied -= len;
+ return true;
+ }
+
+ u32 Level() const { return NumOccupied; }
+ bool IsEmpty() const { return NumOccupied == 0; }
+ bool IsFull() const { return NumOccupied >= Size; }
+
+ bool CanFit(u32 num) const { return ((NumOccupied + num) <= Size); }
+
+private:
+ u8 Buffer[Size] = {0};
+ u32 NumOccupied = 0;
+ u32 ReadPos = 0, WritePos = 0;
+};
+
}
+
#endif
diff --git a/src/GBACart.cpp b/src/GBACart.cpp
index 1be50e75..40e90436 100644
--- a/src/GBACart.cpp
+++ b/src/GBACart.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
@@ -95,17 +95,18 @@ u32 CartCommon::GetSaveMemoryLength() const
return 0;
}
-CartGame::CartGame(const u8* rom, u32 len, const u8* sram, u32 sramlen, GBACart::CartType type) :
- CartGame(CopyToUnique(rom, len), len, CopyToUnique(sram, sramlen), sramlen, type)
+CartGame::CartGame(const u8* rom, u32 len, const u8* sram, u32 sramlen, void* userdata, GBACart::CartType type) :
+ CartGame(CopyToUnique(rom, len), len, CopyToUnique(sram, sramlen), sramlen, userdata, type)
{
}
-CartGame::CartGame(std::unique_ptr&& rom, u32 len, std::unique_ptr&& sram, u32 sramlen, GBACart::CartType type) :
+CartGame::CartGame(std::unique_ptr&& rom, u32 len, std::unique_ptr&& sram, u32 sramlen, void* userdata, GBACart::CartType type) :
CartCommon(type),
ROM(std::move(rom)),
ROMLength(len),
SRAM(std::move(sram)),
- SRAMLength(sramlen)
+ SRAMLength(sramlen),
+ UserData(userdata)
{
if (SRAM && SRAMLength)
{
@@ -170,7 +171,7 @@ void CartGame::DoSavestate(Savestate* file)
file->Var8((u8*)&SRAMType);
if ((!file->Saving) && SRAM)
- Platform::WriteGBASave(SRAM.get(), SRAMLength, 0, SRAMLength);
+ Platform::WriteGBASave(SRAM.get(), SRAMLength, 0, SRAMLength, UserData);
}
void CartGame::SetupSave(u32 type)
@@ -223,7 +224,7 @@ void CartGame::SetSaveMemory(const u8* savedata, u32 savelen)
u32 len = std::min(savelen, SRAMLength);
memcpy(SRAM.get(), savedata, len);
- Platform::WriteGBASave(savedata, len, 0, len);
+ Platform::WriteGBASave(savedata, len, 0, len, UserData);
}
u16 CartGame::ROMRead(u32 addr) const
@@ -464,7 +465,7 @@ void CartGame::SRAMWrite_FLASH(u32 addr, u8 val)
u32 start_addr = addr + 0x10000 * SRAMFlashState.bank;
memset((u8*)&SRAM[start_addr], 0xFF, 0x1000);
- Platform::WriteGBASave(SRAM.get(), SRAMLength, start_addr, 0x1000);
+ Platform::WriteGBASave(SRAM.get(), SRAMLength, start_addr, 0x1000, UserData);
}
SRAMFlashState.state = 0;
SRAMFlashState.cmd = 0;
@@ -523,18 +524,18 @@ void CartGame::SRAMWrite_SRAM(u32 addr, u8 val)
*(u8*)&SRAM[addr] = val;
// TODO: optimize this!!
- Platform::WriteGBASave(SRAM.get(), SRAMLength, addr, 1);
+ Platform::WriteGBASave(SRAM.get(), SRAMLength, addr, 1, UserData);
}
}
-CartGameSolarSensor::CartGameSolarSensor(const u8* rom, u32 len, const u8* sram, u32 sramlen) :
- CartGameSolarSensor(CopyToUnique(rom, len), len, CopyToUnique(sram, sramlen), sramlen)
+CartGameSolarSensor::CartGameSolarSensor(const u8* rom, u32 len, const u8* sram, u32 sramlen, void* userdata) :
+ CartGameSolarSensor(CopyToUnique(rom, len), len, CopyToUnique(sram, sramlen), sramlen, userdata)
{
}
-CartGameSolarSensor::CartGameSolarSensor(std::unique_ptr&& rom, u32 len, std::unique_ptr&& sram, u32 sramlen) :
- CartGame(std::move(rom), len, std::move(sram), sramlen, CartType::GameSolarSensor)
+CartGameSolarSensor::CartGameSolarSensor(std::unique_ptr&& rom, u32 len, std::unique_ptr&& sram, u32 sramlen, void* userdata) :
+ CartGame(std::move(rom), len, std::move(sram), sramlen, userdata, CartType::GameSolarSensor)
{
}
@@ -680,7 +681,7 @@ void CartRAMExpansion::ROMWrite(u32 addr, u16 val)
}
}
-GBACartSlot::GBACartSlot(std::unique_ptr&& cart) noexcept : Cart(std::move(cart))
+GBACartSlot::GBACartSlot(melonDS::NDS& nds, std::unique_ptr&& cart) noexcept : NDS(nds), Cart(std::move(cart))
{
}
@@ -723,24 +724,24 @@ void GBACartSlot::DoSavestate(Savestate* file) noexcept
if (Cart) Cart->DoSavestate(file);
}
-std::unique_ptr ParseROM(std::unique_ptr&& romdata, u32 romlen)
+std::unique_ptr ParseROM(std::unique_ptr&& romdata, u32 romlen, void* userdata)
{
- return ParseROM(std::move(romdata), romlen, nullptr, 0);
+ return ParseROM(std::move(romdata), romlen, nullptr, 0, userdata);
}
-std::unique_ptr ParseROM(const u8* romdata, u32 romlen, const u8* sramdata, u32 sramlen)
+std::unique_ptr ParseROM(const u8* romdata, u32 romlen, const u8* sramdata, u32 sramlen, void* userdata)
{
auto [romcopy, romcopylen] = PadToPowerOf2(romdata, romlen);
- return ParseROM(std::move(romcopy), romcopylen, CopyToUnique(sramdata, sramlen), sramlen);
+ return ParseROM(std::move(romcopy), romcopylen, CopyToUnique(sramdata, sramlen), sramlen, userdata);
}
-std::unique_ptr ParseROM(const u8* romdata, u32 romlen)
+std::unique_ptr ParseROM(const u8* romdata, u32 romlen, void* userdata)
{
- return ParseROM(romdata, romlen, nullptr, 0);
+ return ParseROM(romdata, romlen, nullptr, 0, userdata);
}
-std::unique_ptr ParseROM(std::unique_ptr&& romdata, u32 romlen, std::unique_ptr&& sramdata, u32 sramlen)
+std::unique_ptr ParseROM(std::unique_ptr&& romdata, u32 romlen, std::unique_ptr&& sramdata, u32 sramlen, void* userdata)
{
if (romdata == nullptr)
{
@@ -773,9 +774,9 @@ std::unique_ptr ParseROM(std::unique_ptr&& romdata, u32 romlen
std::unique_ptr cart;
if (solarsensor)
- cart = std::make_unique(std::move(cartrom), cartromsize, std::move(sramdata), sramlen);
+ cart = std::make_unique(std::move(cartrom), cartromsize, std::move(sramdata), sramlen, userdata);
else
- cart = std::make_unique(std::move(cartrom), cartromsize, std::move(sramdata), sramlen);
+ cart = std::make_unique(std::move(cartrom), cartromsize, std::move(sramdata), sramlen, userdata);
cart->Reset();
diff --git a/src/GBACart.h b/src/GBACart.h
index 493bf6b8..4eb0faad 100644
--- a/src/GBACart.h
+++ b/src/GBACart.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
@@ -72,8 +72,8 @@ private:
class CartGame : public CartCommon
{
public:
- CartGame(const u8* rom, u32 len, const u8* sram, u32 sramlen, GBACart::CartType type = GBACart::CartType::Game);
- CartGame(std::unique_ptr&& rom, u32 len, std::unique_ptr&& sram, u32 sramlen, GBACart::CartType type = GBACart::CartType::Game);
+ CartGame(const u8* rom, u32 len, const u8* sram, u32 sramlen, void* userdata, GBACart::CartType type = GBACart::CartType::Game);
+ CartGame(std::unique_ptr&& rom, u32 len, std::unique_ptr&& sram, u32 sramlen, void* userdata, GBACart::CartType type = GBACart::CartType::Game);
~CartGame() override;
u32 Checksum() const override;
@@ -104,6 +104,8 @@ protected:
u8 SRAMRead_SRAM(u32 addr);
void SRAMWrite_SRAM(u32 addr, u8 val);
+ void* UserData;
+
std::unique_ptr ROM;
u32 ROMLength;
@@ -147,8 +149,8 @@ private:
class CartGameSolarSensor : public CartGame
{
public:
- CartGameSolarSensor(const u8* rom, u32 len, const u8* sram, u32 sramlen);
- CartGameSolarSensor(std::unique_ptr&& rom, u32 len, std::unique_ptr&& sram, u32 sramlen);
+ CartGameSolarSensor(const u8* rom, u32 len, const u8* sram, u32 sramlen, void* userdata);
+ CartGameSolarSensor(std::unique_ptr&& rom, u32 len, std::unique_ptr&& sram, u32 sramlen, void* userdata);
void Reset() override;
@@ -197,7 +199,7 @@ enum
class GBACartSlot
{
public:
- GBACartSlot(std::unique_ptr&& cart = nullptr) noexcept;
+ GBACartSlot(melonDS::NDS& nds, std::unique_ptr&& cart = nullptr) noexcept;
~GBACartSlot() noexcept = default;
void Reset() noexcept;
void DoSavestate(Savestate* file) noexcept;
@@ -258,6 +260,7 @@ public:
/// if a cart is loaded and supports SRAM, otherwise zero.
[[nodiscard]] u32 GetSaveMemoryLength() const noexcept { return Cart ? Cart->GetSaveMemoryLength() : 0; }
private:
+ melonDS::NDS& NDS;
std::unique_ptr Cart = nullptr;
u16 OpenBusDecay = 0;
};
@@ -270,9 +273,9 @@ private:
/// @param romlen The length of the ROM data in bytes.
/// @returns A \c GBACart::CartCommon object representing the parsed ROM,
/// or \c nullptr if the ROM data couldn't be parsed.
-std::unique_ptr ParseROM(const u8* romdata, u32 romlen);
-std::unique_ptr ParseROM(std::unique_ptr&& romdata, u32 romlen);
-std::unique_ptr ParseROM(const u8* romdata, u32 romlen, const u8* sramdata, u32 sramlen);
+std::unique_ptr ParseROM(const u8* romdata, u32 romlen, void* userdata = nullptr);
+std::unique_ptr ParseROM(std::unique_ptr&& romdata, u32 romlen, void* userdata = nullptr);
+std::unique_ptr ParseROM(const u8* romdata, u32 romlen, const u8* sramdata, u32 sramlen, void* userdata = nullptr);
/// @param romdata The ROM data to parse. Will be moved-from.
/// @param romlen Length of romdata in bytes.
@@ -282,7 +285,7 @@ std::unique_ptr ParseROM(const u8* romdata, u32 romlen, const u8* sr
/// May be zero, in which case the cart will have no save data.
/// @return Unique pointer to the parsed GBA cart,
/// or \c nullptr if there was an error.
-std::unique_ptr ParseROM(std::unique_ptr&& romdata, u32 romlen, std::unique_ptr&& sramdata, u32 sramlen);
+std::unique_ptr ParseROM(std::unique_ptr&& romdata, u32 romlen, std::unique_ptr&& sramdata, u32 sramlen, void* userdata = nullptr);
}
diff --git a/src/GPU.cpp b/src/GPU.cpp
index 07a6654e..f24d8ab5 100644
--- a/src/GPU.cpp
+++ b/src/GPU.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/GPU.h b/src/GPU.h
index 780d5e01..26e9d5df 100644
--- a/src/GPU.h
+++ b/src/GPU.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/GPU2D.cpp b/src/GPU2D.cpp
index be6a5987..4ad0853a 100644
--- a/src/GPU2D.cpp
+++ b/src/GPU2D.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/GPU2D.h b/src/GPU2D.h
index e87167cb..f56167a1 100644
--- a/src/GPU2D.h
+++ b/src/GPU2D.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/GPU2D_Soft.cpp b/src/GPU2D_Soft.cpp
index 26f9a875..cf168f82 100644
--- a/src/GPU2D_Soft.cpp
+++ b/src/GPU2D_Soft.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
@@ -254,7 +254,11 @@ void SoftRenderer::DrawScanline(u32 line, Unit* unit)
if (GPU.GPU3D.IsRendererAccelerated())
{
- dst[256*3] = masterBrightness | (CurUnit->DispCnt & 0x30000);
+ u32 xpos = GPU.GPU3D.GetRenderXPos();
+
+ dst[256*3] = masterBrightness |
+ (CurUnit->DispCnt & 0x30000) |
+ (xpos << 24) | ((xpos & 0x100) << 15);
return;
}
diff --git a/src/GPU2D_Soft.h b/src/GPU2D_Soft.h
index befb67f6..d9942f61 100644
--- a/src/GPU2D_Soft.h
+++ b/src/GPU2D_Soft.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/GPU3D.cpp b/src/GPU3D.cpp
index 44561dfa..8da5527a 100644
--- a/src/GPU3D.cpp
+++ b/src/GPU3D.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/GPU3D.h b/src/GPU3D.h
index f5446f34..15b31096 100644
--- a/src/GPU3D.h
+++ b/src/GPU3D.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/GPU3D_Compute.cpp b/src/GPU3D_Compute.cpp
index da255950..346a6a53 100644
--- a/src/GPU3D_Compute.cpp
+++ b/src/GPU3D_Compute.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/GPU3D_Compute.h b/src/GPU3D_Compute.h
index 7544c09e..f3f184de 100644
--- a/src/GPU3D_Compute.h
+++ b/src/GPU3D_Compute.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/GPU3D_Compute_shaders.h b/src/GPU3D_Compute_shaders.h
index 572f9ad6..26fb7bde 100644
--- a/src/GPU3D_Compute_shaders.h
+++ b/src/GPU3D_Compute_shaders.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/GPU3D_OpenGL.cpp b/src/GPU3D_OpenGL.cpp
index 9088f078..3f85db8c 100644
--- a/src/GPU3D_OpenGL.cpp
+++ b/src/GPU3D_OpenGL.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
@@ -233,6 +233,7 @@ std::unique_ptr GLRenderer::New() noexcept
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(IndexBuffer), nullptr, GL_DYNAMIC_DRAW);
glGenFramebuffers(1, &result->MainFramebuffer);
+ glGenFramebuffers(1, &result->DownscaleFramebuffer);
// color buffers
glGenTextures(1, &result->ColorBufferTex);
diff --git a/src/GPU3D_OpenGL.h b/src/GPU3D_OpenGL.h
index dcab6e87..d69af324 100644
--- a/src/GPU3D_OpenGL.h
+++ b/src/GPU3D_OpenGL.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/GPU3D_OpenGL_shaders.h b/src/GPU3D_OpenGL_shaders.h
index 13492b7f..03bd43f9 100644
--- a/src/GPU3D_OpenGL_shaders.h
+++ b/src/GPU3D_OpenGL_shaders.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/GPU3D_Soft.cpp b/src/GPU3D_Soft.cpp
index a8da14cd..e2526069 100644
--- a/src/GPU3D_Soft.cpp
+++ b/src/GPU3D_Soft.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/GPU3D_Soft.h b/src/GPU3D_Soft.h
index 45b2c539..55a698b0 100644
--- a/src/GPU3D_Soft.h
+++ b/src/GPU3D_Soft.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/GPU_OpenGL.cpp b/src/GPU_OpenGL.cpp
index 6084405b..a58dbedb 100644
--- a/src/GPU_OpenGL.cpp
+++ b/src/GPU_OpenGL.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
@@ -51,7 +51,6 @@ std::optional GLCompositor::New() noexcept
GLCompositor::GLCompositor(GLuint compShader) noexcept : CompShader(compShader)
{
CompScaleLoc = glGetUniformLocation(CompShader, "u3DScale");
- Comp3DXPosLoc = glGetUniformLocation(CompShader, "u3DXPos");
glUseProgram(CompShader);
GLuint screenTextureUniform = glGetUniformLocation(CompShader, "ScreenTex");
@@ -140,7 +139,6 @@ GLCompositor::GLCompositor(GLCompositor&& other) noexcept :
ScreenH(other.ScreenH),
ScreenW(other.ScreenW),
CompScaleLoc(other.CompScaleLoc),
- Comp3DXPosLoc(other.Comp3DXPosLoc),
CompVertices(other.CompVertices),
CompShader(other.CompShader),
CompVertexBufferID(other.CompVertexBufferID),
@@ -165,7 +163,6 @@ GLCompositor& GLCompositor::operator=(GLCompositor&& other) noexcept
ScreenH = other.ScreenH;
ScreenW = other.ScreenW;
CompScaleLoc = other.CompScaleLoc;
- Comp3DXPosLoc = other.Comp3DXPosLoc;
CompVertices = other.CompVertices;
// Clean up these resources before overwriting them
@@ -258,9 +255,6 @@ void GLCompositor::RenderFrame(const GPU& gpu, Renderer3D& renderer) noexcept
glUseProgram(CompShader);
glUniform1ui(CompScaleLoc, Scale);
- // TODO: support setting this midframe, if ever needed
- glUniform1i(Comp3DXPosLoc, ((int)gpu.GPU3D.GetRenderXPos() << 23) >> 23);
-
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, CompScreenInputTex);
diff --git a/src/GPU_OpenGL.h b/src/GPU_OpenGL.h
index e9f4b173..2e482861 100644
--- a/src/GPU_OpenGL.h
+++ b/src/GPU_OpenGL.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
@@ -52,7 +52,6 @@ private:
GLuint CompShader {};
GLuint CompScaleLoc = 0;
- GLuint Comp3DXPosLoc = 0;
GLuint CompVertexBufferID = 0;
GLuint CompVertexArrayID = 0;
diff --git a/src/GPU_OpenGL_shaders.h b/src/GPU_OpenGL_shaders.h
index a8c5b951..3c463ab8 100644
--- a/src/GPU_OpenGL_shaders.h
+++ b/src/GPU_OpenGL_shaders.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
@@ -43,7 +43,6 @@ void main()
const char* kCompositorFS_Nearest = R"(#version 140
uniform uint u3DScale;
-uniform int u3DXPos;
uniform usampler2D ScreenTex;
uniform sampler2D _3DTex;
@@ -56,11 +55,13 @@ void main()
{
ivec4 pixel = ivec4(texelFetch(ScreenTex, ivec2(fTexcoord), 0));
- float _3dxpos = float(u3DXPos);
-
ivec4 mbright = ivec4(texelFetch(ScreenTex, ivec2(256*3, int(fTexcoord.y)), 0));
int dispmode = mbright.b & 0x3;
+ // mbright.a == HOFS bit0..7
+ // mbright.b bit7 == HOFS bit8 (sign)
+ float _3dxpos = float(mbright.a - ((mbright.b & 0x80) * 2));
+
if (dispmode == 1)
{
ivec4 val1 = pixel;
diff --git a/src/JitBlock.h b/src/JitBlock.h
index 9b31d6d7..2dc516fd 100644
--- a/src/JitBlock.h
+++ b/src/JitBlock.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/MemConstants.h b/src/MemConstants.h
index e9aa6b2b..3e10cbce 100644
--- a/src/MemConstants.h
+++ b/src/MemConstants.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/MemRegion.h b/src/MemRegion.h
index 11b3d1da..0a8212c7 100644
--- a/src/MemRegion.h
+++ b/src/MemRegion.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/NDS.cpp b/src/NDS.cpp
index 94a24029..7ef6602c 100644
--- a/src/NDS.cpp
+++ b/src/NDS.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
@@ -89,8 +89,9 @@ NDS::NDS() noexcept :
{
}
-NDS::NDS(NDSArgs&& args, int type) noexcept :
+NDS::NDS(NDSArgs&& args, int type, void* userdata) noexcept :
ConsoleType(type),
+ UserData(userdata),
ARM7BIOS(*args.ARM7BIOS),
ARM9BIOS(*args.ARM9BIOS),
ARM7BIOSNative(CRC32(ARM7BIOS.data(), ARM7BIOS.size()) == ARM7BIOSCRC32),
@@ -102,7 +103,7 @@ NDS::NDS(NDSArgs&& args, int type) noexcept :
RTC(*this),
Wifi(*this),
NDSCartSlot(*this, std::move(args.NDSROM)),
- GBACartSlot(type == 1 ? nullptr : std::move(args.GBAROM)),
+ GBACartSlot(*this, type == 1 ? nullptr : std::move(args.GBAROM)),
AREngine(*this),
ARM9(*this, args.GDB, args.JIT.has_value()),
ARM7(*this, args.GDB, args.JIT.has_value()),
@@ -574,7 +575,7 @@ void NDS::Stop(Platform::StopReason reason)
Log(level, "Stopping emulated console (Reason: %s)\n", StopReasonName(reason));
Running = false;
- Platform::SignalStop(reason);
+ Platform::SignalStop(reason, UserData);
GPU.Stop();
SPU.Stop();
}
@@ -1540,7 +1541,7 @@ void NDS::NocashPrint(u32 ncpu, u32 addr)
}
output[ptr] = '\0';
- Log(LogLevel::Debug, "%s", output);
+ Log(LogLevel::Debug, "%s\n", output);
}
void NDS::MonitorARM9Jump(u32 addr)
diff --git a/src/NDS.h b/src/NDS.h
index f9df2d69..c965cde0 100644
--- a/src/NDS.h
+++ b/src/NDS.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
@@ -229,6 +229,8 @@ private:
#endif
public: // TODO: Encapsulate the rest of these members
+ void* UserData;
+
int ConsoleType;
int CurCPU;
@@ -522,7 +524,7 @@ private:
template
u32 RunFrame();
public:
- NDS(NDSArgs&& args) noexcept : NDS(std::move(args), 0) {}
+ NDS(NDSArgs&& args, void* userdata = nullptr) noexcept : NDS(std::move(args), 0, userdata) {}
NDS() noexcept;
virtual ~NDS() noexcept;
NDS(const NDS&) = delete;
@@ -532,7 +534,7 @@ public:
// The frontend should set and unset this manually after creating and destroying the NDS object.
[[deprecated("Temporary workaround until JIT code generation is revised to accommodate multiple NDS objects.")]] static NDS* Current;
protected:
- explicit NDS(NDSArgs&& args, int type) noexcept;
+ explicit NDS(NDSArgs&& args, int type, void* userdata) noexcept;
virtual void DoSavestateExtra(Savestate* file) {}
};
diff --git a/src/NDSCart.cpp b/src/NDSCart.cpp
index a64d8a27..b0eef56a 100644
--- a/src/NDSCart.cpp
+++ b/src/NDSCart.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
@@ -173,17 +173,18 @@ void NDSCartSlot::Key2_Encrypt(const u8* data, u32 len) noexcept
}
-CartCommon::CartCommon(const u8* rom, u32 len, u32 chipid, bool badDSiDump, ROMListEntry romparams, melonDS::NDSCart::CartType type) :
- CartCommon(CopyToUnique(rom, len), len, chipid, badDSiDump, romparams, type)
+CartCommon::CartCommon(const u8* rom, u32 len, u32 chipid, bool badDSiDump, ROMListEntry romparams, melonDS::NDSCart::CartType type, void* userdata) :
+ CartCommon(CopyToUnique(rom, len), len, chipid, badDSiDump, romparams, type, userdata)
{
}
-CartCommon::CartCommon(std::unique_ptr&& rom, u32 len, u32 chipid, bool badDSiDump, ROMListEntry romparams, melonDS::NDSCart::CartType type) :
+CartCommon::CartCommon(std::unique_ptr&& rom, u32 len, u32 chipid, bool badDSiDump, ROMListEntry romparams, melonDS::NDSCart::CartType type, void* userdata) :
ROM(std::move(rom)),
ROMLength(len),
ChipID(chipid),
ROMParams(romparams),
- CartType(type)
+ CartType(type),
+ UserData(userdata)
{
memcpy(&Header, ROM.get(), sizeof(Header));
IsDSi = Header.IsDSi() && !badDSiDump;
@@ -375,13 +376,13 @@ const NDSBanner* CartCommon::Banner() const
return nullptr;
}
-CartRetail::CartRetail(const u8* rom, u32 len, u32 chipid, bool badDSiDump, ROMListEntry romparams, std::unique_ptr&& sram, u32 sramlen, melonDS::NDSCart::CartType type) :
- CartRetail(CopyToUnique(rom, len), len, chipid, badDSiDump, romparams, std::move(sram), sramlen, type)
+CartRetail::CartRetail(const u8* rom, u32 len, u32 chipid, bool badDSiDump, ROMListEntry romparams, std::unique_ptr&& sram, u32 sramlen, void* userdata, melonDS::NDSCart::CartType type) :
+ CartRetail(CopyToUnique(rom, len), len, chipid, badDSiDump, romparams, std::move(sram), sramlen, userdata, type)
{
}
-CartRetail::CartRetail(std::unique_ptr&& rom, u32 len, u32 chipid, bool badDSiDump, ROMListEntry romparams, std::unique_ptr&& sram, u32 sramlen, melonDS::NDSCart::CartType type) :
- CartCommon(std::move(rom), len, chipid, badDSiDump, romparams, type)
+CartRetail::CartRetail(std::unique_ptr&& rom, u32 len, u32 chipid, bool badDSiDump, ROMListEntry romparams, std::unique_ptr&& sram, u32 sramlen, void* userdata, melonDS::NDSCart::CartType type) :
+ CartCommon(std::move(rom), len, chipid, badDSiDump, romparams, type, userdata)
{
u32 savememtype = ROMParams.SaveMemType <= 10 ? ROMParams.SaveMemType : 0;
constexpr int sramlengths[] =
@@ -469,7 +470,7 @@ void CartRetail::DoSavestate(Savestate* file)
file->Var8(&SRAMStatus);
if ((!file->Saving) && SRAM)
- Platform::WriteNDSSave(SRAM.get(), SRAMLength, 0, SRAMLength);
+ Platform::WriteNDSSave(SRAM.get(), SRAMLength, 0, SRAMLength, UserData);
}
void CartRetail::SetSaveMemory(const u8* savedata, u32 savelen)
@@ -478,7 +479,7 @@ void CartRetail::SetSaveMemory(const u8* savedata, u32 savelen)
u32 len = std::min(savelen, SRAMLength);
memcpy(SRAM.get(), savedata, len);
- Platform::WriteNDSSave(savedata, len, 0, len);
+ Platform::WriteNDSSave(savedata, len, 0, len, UserData);
}
int CartRetail::ROMCommandStart(NDS& nds, NDSCart::NDSCartSlot& cartslot, const u8* cmd, u8* data, u32 len)
@@ -594,7 +595,8 @@ u8 CartRetail::SRAMWrite_EEPROMTiny(u8 val, u32 pos, bool last)
{
SRAMStatus &= ~(1<<1);
Platform::WriteNDSSave(SRAM.get(), SRAMLength,
- (SRAMFirstAddr + ((SRAMCmd==0x0A)?0x100:0)) & 0x1FF, SRAMAddr-SRAMFirstAddr);
+ (SRAMFirstAddr + ((SRAMCmd==0x0A)?0x100:0)) & 0x1FF, SRAMAddr-SRAMFirstAddr,
+ UserData);
}
return 0;
@@ -658,7 +660,8 @@ u8 CartRetail::SRAMWrite_EEPROM(u8 val, u32 pos, bool last)
{
SRAMStatus &= ~(1<<1);
Platform::WriteNDSSave(SRAM.get(), SRAMLength,
- SRAMFirstAddr & (SRAMLength-1), SRAMAddr-SRAMFirstAddr);
+ SRAMFirstAddr & (SRAMLength-1), SRAMAddr-SRAMFirstAddr,
+ UserData);
}
return 0;
@@ -715,7 +718,8 @@ u8 CartRetail::SRAMWrite_FLASH(u8 val, u32 pos, bool last)
{
SRAMStatus &= ~(1<<1);
Platform::WriteNDSSave(SRAM.get(), SRAMLength,
- SRAMFirstAddr & (SRAMLength-1), SRAMAddr-SRAMFirstAddr);
+ SRAMFirstAddr & (SRAMLength-1), SRAMAddr-SRAMFirstAddr,
+ UserData);
}
return 0;
@@ -752,7 +756,8 @@ u8 CartRetail::SRAMWrite_FLASH(u8 val, u32 pos, bool last)
{
SRAMStatus &= ~(1<<1);
Platform::WriteNDSSave(SRAM.get(), SRAMLength,
- SRAMFirstAddr & (SRAMLength-1), SRAMAddr-SRAMFirstAddr);
+ SRAMFirstAddr & (SRAMLength-1), SRAMAddr-SRAMFirstAddr,
+ UserData);
}
return 0;
@@ -798,7 +803,8 @@ u8 CartRetail::SRAMWrite_FLASH(u8 val, u32 pos, bool last)
{
SRAMStatus &= ~(1<<1);
Platform::WriteNDSSave(SRAM.get(), SRAMLength,
- SRAMFirstAddr & (SRAMLength-1), SRAMAddr-SRAMFirstAddr);
+ SRAMFirstAddr & (SRAMLength-1), SRAMAddr-SRAMFirstAddr,
+ UserData);
}
return 0;
@@ -821,7 +827,8 @@ u8 CartRetail::SRAMWrite_FLASH(u8 val, u32 pos, bool last)
{
SRAMStatus &= ~(1<<1);
Platform::WriteNDSSave(SRAM.get(), SRAMLength,
- SRAMFirstAddr & (SRAMLength-1), SRAMAddr-SRAMFirstAddr);
+ SRAMFirstAddr & (SRAMLength-1), SRAMAddr-SRAMFirstAddr,
+ UserData);
}
return 0;
@@ -832,13 +839,13 @@ u8 CartRetail::SRAMWrite_FLASH(u8 val, u32 pos, bool last)
}
}
-CartRetailNAND::CartRetailNAND(const u8* rom, u32 len, u32 chipid, ROMListEntry romparams, std::unique_ptr&& sram, u32 sramlen) :
- CartRetailNAND(CopyToUnique(rom, len), len, chipid, romparams, std::move(sram), sramlen)
+CartRetailNAND::CartRetailNAND(const u8* rom, u32 len, u32 chipid, ROMListEntry romparams, std::unique_ptr&& sram, u32 sramlen, void* userdata) :
+ CartRetailNAND(CopyToUnique(rom, len), len, chipid, romparams, std::move(sram), sramlen, userdata)
{
}
-CartRetailNAND::CartRetailNAND(std::unique_ptr&& rom, u32 len, u32 chipid, ROMListEntry romparams, std::unique_ptr&& sram, u32 sramlen) :
- CartRetail(std::move(rom), len, chipid, false, romparams, std::move(sram), sramlen, CartType::RetailNAND)
+CartRetailNAND::CartRetailNAND(std::unique_ptr&& rom, u32 len, u32 chipid, ROMListEntry romparams, std::unique_ptr&& sram, u32 sramlen, void* userdata) :
+ CartRetail(std::move(rom), len, chipid, false, romparams, std::move(sram), sramlen, userdata, CartType::RetailNAND)
{
BuildSRAMID();
}
@@ -908,7 +915,7 @@ int CartRetailNAND::ROMCommandStart(NDS& nds, NDSCart::NDSCartSlot& cartslot, co
if (SRAMLength && SRAMAddr < (SRAMBase+SRAMLength-0x20000))
{
memcpy(&SRAM[SRAMAddr - SRAMBase], SRAMWriteBuffer, 0x800);
- Platform::WriteNDSSave(SRAM.get(), SRAMLength, SRAMAddr - SRAMBase, 0x800);
+ Platform::WriteNDSSave(SRAM.get(), SRAMLength, SRAMAddr - SRAMBase, 0x800, UserData);
}
SRAMAddr = 0;
@@ -1064,8 +1071,8 @@ void CartRetailNAND::BuildSRAMID()
}
-CartRetailIR::CartRetailIR(const u8* rom, u32 len, u32 chipid, u32 irversion, bool badDSiDump, ROMListEntry romparams, std::unique_ptr&& sram, u32 sramlen) :
- CartRetailIR(CopyToUnique(rom, len), len, chipid, irversion, badDSiDump, romparams, std::move(sram), sramlen)
+CartRetailIR::CartRetailIR(const u8* rom, u32 len, u32 chipid, u32 irversion, bool badDSiDump, ROMListEntry romparams, std::unique_ptr&& sram, u32 sramlen, void* userdata) :
+ CartRetailIR(CopyToUnique(rom, len), len, chipid, irversion, badDSiDump, romparams, std::move(sram), sramlen, userdata)
{
}
@@ -1077,9 +1084,10 @@ CartRetailIR::CartRetailIR(
bool badDSiDump,
ROMListEntry romparams,
std::unique_ptr&& sram,
- u32 sramlen
+ u32 sramlen,
+ void* userdata
) :
- CartRetail(std::move(rom), len, chipid, badDSiDump, romparams, std::move(sram), sramlen, CartType::RetailIR),
+ CartRetail(std::move(rom), len, chipid, badDSiDump, romparams, std::move(sram), sramlen, userdata, CartType::RetailIR),
IRVersion(irversion)
{
}
@@ -1122,13 +1130,13 @@ u8 CartRetailIR::SPIWrite(u8 val, u32 pos, bool last)
return 0;
}
-CartRetailBT::CartRetailBT(const u8* rom, u32 len, u32 chipid, ROMListEntry romparams, std::unique_ptr&& sram, u32 sramlen) :
- CartRetailBT(CopyToUnique(rom, len), len, chipid, romparams, std::move(sram), sramlen)
+CartRetailBT::CartRetailBT(const u8* rom, u32 len, u32 chipid, ROMListEntry romparams, std::unique_ptr&& sram, u32 sramlen, void* userdata) :
+ CartRetailBT(CopyToUnique(rom, len), len, chipid, romparams, std::move(sram), sramlen, userdata)
{
}
-CartRetailBT::CartRetailBT(std::unique_ptr&& rom, u32 len, u32 chipid, ROMListEntry romparams, std::unique_ptr&& sram, u32 sramlen) :
- CartRetail(std::move(rom), len, chipid, false, romparams, std::move(sram), sramlen, CartType::RetailBT)
+CartRetailBT::CartRetailBT(std::unique_ptr&& rom, u32 len, u32 chipid, ROMListEntry romparams, std::unique_ptr&& sram, u32 sramlen, void* userdata) :
+ CartRetail(std::move(rom), len, chipid, false, romparams, std::move(sram), sramlen, userdata, CartType::RetailBT)
{
Log(LogLevel::Info,"POKETYPE CART\n");
}
@@ -1150,12 +1158,12 @@ u8 CartRetailBT::SPIWrite(u8 val, u32 pos, bool last)
}
-CartSD::CartSD(const u8* rom, u32 len, u32 chipid, ROMListEntry romparams, std::optional&& sdcard) :
- CartSD(CopyToUnique(rom, len), len, chipid, romparams, std::move(sdcard))
+CartSD::CartSD(const u8* rom, u32 len, u32 chipid, ROMListEntry romparams, void* userdata, std::optional&& sdcard) :
+ CartSD(CopyToUnique(rom, len), len, chipid, romparams, userdata, std::move(sdcard))
{}
-CartSD::CartSD(std::unique_ptr&& rom, u32 len, u32 chipid, ROMListEntry romparams, std::optional&& sdcard) :
- CartCommon(std::move(rom), len, chipid, false, romparams, CartType::Homebrew),
+CartSD::CartSD(std::unique_ptr&& rom, u32 len, u32 chipid, ROMListEntry romparams, void* userdata, std::optional&& sdcard) :
+ CartCommon(std::move(rom), len, chipid, false, romparams, CartType::Homebrew, userdata),
SD(std::move(sdcard))
{
sdcard = std::nullopt;
@@ -1306,12 +1314,12 @@ void CartSD::ReadROM_B7(u32 addr, u32 len, u8* data, u32 offset) const
memcpy(data+offset, ROM.get()+addr, len);
}
-CartHomebrew::CartHomebrew(const u8* rom, u32 len, u32 chipid, ROMListEntry romparams, std::optional&& sdcard) :
- CartSD(rom, len, chipid, romparams, std::move(sdcard))
+CartHomebrew::CartHomebrew(const u8* rom, u32 len, u32 chipid, ROMListEntry romparams, void* userdata, std::optional&& sdcard) :
+ CartSD(rom, len, chipid, romparams, userdata, std::move(sdcard))
{}
-CartHomebrew::CartHomebrew(std::unique_ptr&& rom, u32 len, u32 chipid, ROMListEntry romparams, std::optional&& sdcard) :
- CartSD(std::move(rom), len, chipid, romparams, std::move(sdcard))
+CartHomebrew::CartHomebrew(std::unique_ptr&& rom, u32 len, u32 chipid, ROMListEntry romparams, void* userdata, std::optional&& sdcard) :
+ CartSD(std::move(rom), len, chipid, romparams, userdata, std::move(sdcard))
{}
CartHomebrew::~CartHomebrew() = default;
@@ -1565,12 +1573,12 @@ void NDSCartSlot::DecryptSecureArea(u8* out) noexcept
}
}
-std::unique_ptr ParseROM(const u8* romdata, u32 romlen, std::optional&& args)
+std::unique_ptr ParseROM(const u8* romdata, u32 romlen, void* userdata, std::optional&& args)
{
- return ParseROM(CopyToUnique(romdata, romlen), romlen, std::move(args));
+ return ParseROM(CopyToUnique(romdata, romlen), romlen, userdata, std::move(args));
}
-std::unique_ptr ParseROM(std::unique_ptr&& romdata, u32 romlen, std::optional&& args)
+std::unique_ptr ParseROM(std::unique_ptr&& romdata, u32 romlen, void* userdata, std::optional&& args)
{
if (romdata == nullptr)
{
@@ -1659,21 +1667,21 @@ std::unique_ptr ParseROM(std::unique_ptr&& romdata, u32 romlen
if (homebrew)
{
std::optional sdcard = args && args->SDCard ? std::make_optional(std::move(*args->SDCard)) : std::nullopt;
- cart = std::make_unique(std::move(cartrom), cartromsize, cartid, romparams, std::move(sdcard));
+ cart = std::make_unique(std::move(cartrom), cartromsize, cartid, romparams, userdata, std::move(sdcard));
}
else if (gametitle[0] == 0 && !strncmp("SD/TF-NDS", gametitle + 1, 9) && gamecode == 0x414D5341)
{
std::optional sdcard = args && args->SDCard ? std::make_optional(std::move(*args->SDCard)) : std::nullopt;
- cart = std::make_unique(std::move(cartrom), cartromsize, cartid, romparams, CartR4TypeR4, CartR4LanguageEnglish, std::move(sdcard));
+ cart = std::make_unique(std::move(cartrom), cartromsize, cartid, romparams, CartR4TypeR4, CartR4LanguageEnglish, userdata, std::move(sdcard));
}
else if (cartid & 0x08000000)
- cart = std::make_unique(std::move(cartrom), cartromsize, cartid, romparams, std::move(sram), sramlen);
+ cart = std::make_unique(std::move(cartrom), cartromsize, cartid, romparams, std::move(sram), sramlen, userdata);
else if (irversion != 0)
- cart = std::make_unique(std::move(cartrom), cartromsize, cartid, irversion, badDSiDump, romparams, std::move(sram), sramlen);
+ cart = std::make_unique(std::move(cartrom), cartromsize, cartid, irversion, badDSiDump, romparams, std::move(sram), sramlen, userdata);
else if ((gamecode & 0xFFFFFF) == 0x505A55) // UZPx
- cart = std::make_unique(std::move(cartrom), cartromsize, cartid, romparams, std::move(sram), sramlen);
+ cart = std::make_unique(std::move(cartrom), cartromsize, cartid, romparams, std::move(sram), sramlen, userdata);
else
- cart = std::make_unique(std::move(cartrom), cartromsize, cartid, badDSiDump, romparams, std::move(sram), sramlen);
+ cart = std::make_unique(std::move(cartrom), cartromsize, cartid, badDSiDump, romparams, std::move(sram), sramlen, userdata);
args = std::nullopt;
return cart;
diff --git a/src/NDSCart.h b/src/NDSCart.h
index 2f6a3be5..3c4bb4f5 100644
--- a/src/NDSCart.h
+++ b/src/NDSCart.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
@@ -76,8 +76,8 @@ struct NDSCartArgs
class CartCommon
{
public:
- CartCommon(const u8* rom, u32 len, u32 chipid, bool badDSiDump, ROMListEntry romparams, CartType type);
- CartCommon(std::unique_ptr&& rom, u32 len, u32 chipid, bool badDSiDump, ROMListEntry romparams, CartType type);
+ CartCommon(const u8* rom, u32 len, u32 chipid, bool badDSiDump, ROMListEntry romparams, CartType type, void* userdata);
+ CartCommon(std::unique_ptr&& rom, u32 len, u32 chipid, bool badDSiDump, ROMListEntry romparams, CartType type, void* userdata);
virtual ~CartCommon();
[[nodiscard]] u32 Type() const { return CartType; };
@@ -111,6 +111,8 @@ public:
protected:
void ReadROM(u32 addr, u32 len, u8* data, u32 offset) const;
+ void* UserData;
+
std::unique_ptr ROM = nullptr;
u32 ROMLength = 0;
u32 ChipID = 0;
@@ -139,6 +141,7 @@ public:
ROMListEntry romparams,
std::unique_ptr&& sram,
u32 sramlen,
+ void* userdata,
melonDS::NDSCart::CartType type = CartType::Retail
);
CartRetail(
@@ -148,6 +151,7 @@ public:
ROMListEntry romparams,
std::unique_ptr&& sram,
u32 sramlen,
+ void* userdata,
melonDS::NDSCart::CartType type = CartType::Retail
);
~CartRetail() override;
@@ -187,8 +191,8 @@ protected:
class CartRetailNAND : public CartRetail
{
public:
- CartRetailNAND(const u8* rom, u32 len, u32 chipid, ROMListEntry romparams, std::unique_ptr&& sram, u32 sramlen);
- CartRetailNAND(std::unique_ptr&& rom, u32 len, u32 chipid, ROMListEntry romparams, std::unique_ptr&& sram, u32 sramlen);
+ CartRetailNAND(const u8* rom, u32 len, u32 chipid, ROMListEntry romparams, std::unique_ptr&& sram, u32 sramlen, void* userdata);
+ CartRetailNAND(std::unique_ptr&& rom, u32 len, u32 chipid, ROMListEntry romparams, std::unique_ptr&& sram, u32 sramlen, void* userdata);
~CartRetailNAND() override;
void Reset() override;
@@ -216,8 +220,8 @@ private:
class CartRetailIR : public CartRetail
{
public:
- CartRetailIR(const u8* rom, u32 len, u32 chipid, u32 irversion, bool badDSiDump, ROMListEntry romparams, std::unique_ptr&& sram, u32 sramlen);
- CartRetailIR(std::unique_ptr&& rom, u32 len, u32 chipid, u32 irversion, bool badDSiDump, ROMListEntry romparams, std::unique_ptr&& sram, u32 sramlen);
+ CartRetailIR(const u8* rom, u32 len, u32 chipid, u32 irversion, bool badDSiDump, ROMListEntry romparams, std::unique_ptr&& sram, u32 sramlen, void* userdata);
+ CartRetailIR(std::unique_ptr&& rom, u32 len, u32 chipid, u32 irversion, bool badDSiDump, ROMListEntry romparams, std::unique_ptr&& sram, u32 sramlen, void* userdata);
~CartRetailIR() override;
void Reset() override;
@@ -235,8 +239,8 @@ private:
class CartRetailBT : public CartRetail
{
public:
- CartRetailBT(const u8* rom, u32 len, u32 chipid, ROMListEntry romparams, std::unique_ptr&& sram, u32 sramlen);
- CartRetailBT(std::unique_ptr&& rom, u32 len, u32 chipid, ROMListEntry romparams, std::unique_ptr&& sram, u32 sramlen);
+ CartRetailBT(const u8* rom, u32 len, u32 chipid, ROMListEntry romparams, std::unique_ptr&& sram, u32 sramlen, void* userdata);
+ CartRetailBT(std::unique_ptr&& rom, u32 len, u32 chipid, ROMListEntry romparams, std::unique_ptr&& sram, u32 sramlen, void* userdata);
~CartRetailBT() override;
u8 SPIWrite(u8 val, u32 pos, bool last) override;
@@ -246,8 +250,8 @@ public:
class CartSD : public CartCommon
{
public:
- CartSD(const u8* rom, u32 len, u32 chipid, ROMListEntry romparams, std::optional&& sdcard = std::nullopt);
- CartSD(std::unique_ptr&& rom, u32 len, u32 chipid, ROMListEntry romparams, std::optional&& sdcard = std::nullopt);
+ CartSD(const u8* rom, u32 len, u32 chipid, ROMListEntry romparams, void* userdata, std::optional&& sdcard = std::nullopt);
+ CartSD(std::unique_ptr&& rom, u32 len, u32 chipid, ROMListEntry romparams, void* userdata, std::optional&& sdcard = std::nullopt);
~CartSD() override;
[[nodiscard]] const std::optional& GetSDCard() const noexcept { return SD; }
@@ -288,8 +292,8 @@ protected:
class CartHomebrew : public CartSD
{
public:
- CartHomebrew(const u8* rom, u32 len, u32 chipid, ROMListEntry romparams, std::optional&& sdcard = std::nullopt);
- CartHomebrew(std::unique_ptr&& rom, u32 len, u32 chipid, ROMListEntry romparams, std::optional&& sdcard = std::nullopt);
+ CartHomebrew(const u8* rom, u32 len, u32 chipid, ROMListEntry romparams, void* userdata, std::optional&& sdcard = std::nullopt);
+ CartHomebrew(std::unique_ptr&& rom, u32 len, u32 chipid, ROMListEntry romparams, void* userdata, std::optional&& sdcard = std::nullopt);
~CartHomebrew() override;
void Reset() override;
@@ -322,7 +326,7 @@ enum CartR4Language
class CartR4 : public CartSD
{
public:
- CartR4(std::unique_ptr&& rom, u32 len, u32 chipid, ROMListEntry romparams, CartR4Type ctype, CartR4Language clanguage,
+ CartR4(std::unique_ptr&& rom, u32 len, u32 chipid, ROMListEntry romparams, CartR4Type ctype, CartR4Language clanguage, void* userdata,
std::optional&& sdcard = std::nullopt);
~CartR4() override;
@@ -461,8 +465,8 @@ private:
/// If not given, the cart will not have an SD card.
/// @returns A \c NDSCart::CartCommon object representing the parsed ROM,
/// or \c nullptr if the ROM data couldn't be parsed.
-std::unique_ptr ParseROM(const u8* romdata, u32 romlen, std::optional&& args = std::nullopt);
-std::unique_ptr ParseROM(std::unique_ptr&& romdata, u32 romlen, std::optional&& args = std::nullopt);
+std::unique_ptr ParseROM(const u8* romdata, u32 romlen, void* userdata = nullptr, std::optional&& args = std::nullopt);
+std::unique_ptr ParseROM(std::unique_ptr&& romdata, u32 romlen, void* userdata = nullptr, std::optional&& args = std::nullopt);
}
#endif
diff --git a/src/NDSCartR4.cpp b/src/NDSCartR4.cpp
index 8497f556..46fbeb6a 100644
--- a/src/NDSCartR4.cpp
+++ b/src/NDSCartR4.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
@@ -67,9 +67,9 @@ static void DecryptR4Sector(u8* dest, u8* src, u16 key1)
}
}
-CartR4::CartR4(std::unique_ptr&& rom, u32 len, u32 chipid, ROMListEntry romparams, CartR4Type ctype, CartR4Language clanguage,
+CartR4::CartR4(std::unique_ptr&& rom, u32 len, u32 chipid, ROMListEntry romparams, CartR4Type ctype, CartR4Language clanguage, void* userdata,
std::optional&& sdcard)
- : CartSD(std::move(rom), len, chipid, romparams, std::move(sdcard))
+ : CartSD(std::move(rom), len, chipid, romparams, userdata, std::move(sdcard))
{
InitStatus = 0;
R4CartType = ctype;
diff --git a/src/NDS_Header.h b/src/NDS_Header.h
index 77a5baca..80d5ced6 100644
--- a/src/NDS_Header.h
+++ b/src/NDS_Header.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team, WaluigiWare64
+ Copyright 2016-2024 melonDS team, WaluigiWare64
This file is part of melonDS.
diff --git a/src/NonStupidBitfield.h b/src/NonStupidBitfield.h
index a3cc4b2e..7332394b 100644
--- a/src/NonStupidBitfield.h
+++ b/src/NonStupidBitfield.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2022 melonDS team, RSDuck
+ Copyright 2016-2024 melonDS team, RSDuck
This file is part of melonDS.
diff --git a/src/OpenGLSupport.cpp b/src/OpenGLSupport.cpp
index a7d000ce..f728386f 100644
--- a/src/OpenGLSupport.cpp
+++ b/src/OpenGLSupport.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/OpenGLSupport.h b/src/OpenGLSupport.h
index f8c44300..b426597d 100644
--- a/src/OpenGLSupport.h
+++ b/src/OpenGLSupport.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/Platform.h b/src/Platform.h
index 425c712c..ddc31dfd 100644
--- a/src/Platform.h
+++ b/src/Platform.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
@@ -31,14 +31,6 @@ class Firmware;
namespace Platform
{
-void Init(int argc, char** argv);
-
-/**
- * Frees all resources that were allocated in \c Init
- * or by any other \c Platform function.
- */
-void DeInit();
-
enum StopReason {
/**
* The emulator stopped for some unspecified reason.
@@ -77,20 +69,8 @@ enum StopReason {
* Frontends should not call this directly;
* use \c NDS::Stop instead.
*/
-void SignalStop(StopReason reason);
+void SignalStop(StopReason reason, void* userdata);
-/**
- * @returns The ID of the running melonDS instance if running in local multiplayer mode,
- * or 0 if not.
- */
-int InstanceID();
-
-/**
- * @returns A suffix that should be appended to all instance-specific paths
- * if running in local multiplayer mode,
- * or the empty string if not.
- */
-std::string InstanceFileSuffix();
/**
* Denotes how a file will be opened and accessed.
@@ -188,6 +168,9 @@ enum class FileSeekOrigin
*/
struct FileHandle;
+// retrieves the path to a local file, without opening the file
+std::string GetLocalFilePath(const std::string& filename);
+
// Simple fopen() wrapper that supports UTF8.
// Can be optionally restricted to only opening a file that already exists.
FileHandle* OpenFile(const std::string& path, FileMode mode);
@@ -288,41 +271,37 @@ void Sleep(u64 usecs);
// functions called when the NDS or GBA save files need to be written back to storage
// savedata and savelen are always the entire save memory buffer and its full length
// writeoffset and writelen indicate which part of the memory was altered
-void WriteNDSSave(const u8* savedata, u32 savelen, u32 writeoffset, u32 writelen);
-void WriteGBASave(const u8* savedata, u32 savelen, u32 writeoffset, u32 writelen);
+void WriteNDSSave(const u8* savedata, u32 savelen, u32 writeoffset, u32 writelen, void* userdata);
+void WriteGBASave(const u8* savedata, u32 savelen, u32 writeoffset, u32 writelen, void* userdata);
/// Called when the firmware needs to be written back to storage,
/// after one of the supported write commands finishes execution.
/// @param firmware The firmware that was just written.
/// @param writeoffset The offset of the first byte that was written to firmware.
/// @param writelen The number of bytes that were written to firmware.
-void WriteFirmware(const Firmware& firmware, u32 writeoffset, u32 writelen);
+void WriteFirmware(const Firmware& firmware, u32 writeoffset, u32 writelen, void* userdata);
// called when the RTC date/time is changed and the frontend might need to take it into account
-void WriteDateTime(int year, int month, int day, int hour, int minute, int second);
+void WriteDateTime(int year, int month, int day, int hour, int minute, int second, void* userdata);
// local multiplayer comm interface
// packet type: DS-style TX header (12 bytes) + original 802.11 frame
-bool MP_Init();
-void MP_DeInit();
-void MP_Begin();
-void MP_End();
-int MP_SendPacket(u8* data, int len, u64 timestamp);
-int MP_RecvPacket(u8* data, u64* timestamp);
-int MP_SendCmd(u8* data, int len, u64 timestamp);
-int MP_SendReply(u8* data, int len, u64 timestamp, u16 aid);
-int MP_SendAck(u8* data, int len, u64 timestamp);
-int MP_RecvHostPacket(u8* data, u64* timestamp);
-u16 MP_RecvReplies(u8* data, u64 timestamp, u16 aidmask);
+void MP_Begin(void* userdata);
+void MP_End(void* userdata);
+int MP_SendPacket(u8* data, int len, u64 timestamp, void* userdata);
+int MP_RecvPacket(u8* data, u64* timestamp, void* userdata);
+int MP_SendCmd(u8* data, int len, u64 timestamp, void* userdata);
+int MP_SendReply(u8* data, int len, u64 timestamp, u16 aid, void* userdata);
+int MP_SendAck(u8* data, int len, u64 timestamp, void* userdata);
+int MP_RecvHostPacket(u8* data, u64* timestamp, void* userdata);
+u16 MP_RecvReplies(u8* data, u64 timestamp, u16 aidmask, void* userdata);
-// LAN comm interface
+// network comm interface
// packet type: Ethernet (802.3)
-bool LAN_Init();
-void LAN_DeInit();
-int LAN_SendPacket(u8* data, int len);
-int LAN_RecvPacket(u8* data);
+int Net_SendPacket(u8* data, int len, void* userdata);
+int Net_RecvPacket(u8* data, void* userdata);
// interface for camera emulation
@@ -330,9 +309,9 @@ int LAN_RecvPacket(u8* data);
// 0 = DSi outer camera
// 1 = DSi inner camera
// other values reserved for future camera addon emulation
-void Camera_Start(int num);
-void Camera_Stop(int num);
-void Camera_CaptureFrame(int num, u32* frame, int width, int height, bool yuv);
+void Camera_Start(int num, void* userdata);
+void Camera_Stop(int num, void* userdata);
+void Camera_CaptureFrame(int num, u32* frame, int width, int height, bool yuv, void* userdata);
struct DynamicLibrary;
diff --git a/src/ROMList.cpp b/src/ROMList.cpp
index 3ff771f8..e4ce7d2a 100644
--- a/src/ROMList.cpp
+++ b/src/ROMList.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/ROMList.h b/src/ROMList.h
index 82ee0ccf..e27ee728 100644
--- a/src/ROMList.h
+++ b/src/ROMList.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/RTC.cpp b/src/RTC.cpp
index d8219df1..fe262644 100644
--- a/src/RTC.cpp
+++ b/src/RTC.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
@@ -602,7 +602,7 @@ void RTC::SaveDateTime()
{
int y, m, d, h, i, s;
GetDateTime(y, m, d, h, i, s);
- Platform::WriteDateTime(y, m, d, h, i, s);
+ Platform::WriteDateTime(y, m, d, h, i, s, NDS.UserData);
}
void RTC::CmdRead()
diff --git a/src/RTC.h b/src/RTC.h
index 1477e0eb..7c3671ce 100644
--- a/src/RTC.h
+++ b/src/RTC.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/SPI.cpp b/src/SPI.cpp
index 2aa915c6..6ab94c3a 100644
--- a/src/SPI.cpp
+++ b/src/SPI.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
@@ -260,7 +260,7 @@ void FirmwareMem::Release()
// Request that the start of the Wi-fi/userdata settings region
// through the end of the firmware blob be flushed to disk
- Platform::WriteFirmware(FirmwareData, wifioffset, FirmwareData.Length() - wifioffset);
+ Platform::WriteFirmware(FirmwareData, wifioffset, FirmwareData.Length() - wifioffset, NDS.UserData);
}
SPIDevice::Release();
diff --git a/src/SPI.h b/src/SPI.h
index 7ed889a4..350708ef 100644
--- a/src/SPI.h
+++ b/src/SPI.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/SPI_Firmware.cpp b/src/SPI_Firmware.cpp
index 89c8fa61..c7a0f9d9 100644
--- a/src/SPI_Firmware.cpp
+++ b/src/SPI_Firmware.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/SPI_Firmware.h b/src/SPI_Firmware.h
index c8ca25c3..a5d40eeb 100644
--- a/src/SPI_Firmware.h
+++ b/src/SPI_Firmware.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/SPU.cpp b/src/SPU.cpp
index 69c0b9de..eb30c0a9 100644
--- a/src/SPU.cpp
+++ b/src/SPU.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/SPU.h b/src/SPU.h
index 6e3d1aae..19253891 100644
--- a/src/SPU.h
+++ b/src/SPU.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/Savestate.cpp b/src/Savestate.cpp
index 6d6a9a47..c51459d9 100644
--- a/src/Savestate.cpp
+++ b/src/Savestate.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/Savestate.h b/src/Savestate.h
index 2e1400a0..dce62844 100644
--- a/src/Savestate.h
+++ b/src/Savestate.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/TinyVector.h b/src/TinyVector.h
index 5a30ff65..66da63ec 100644
--- a/src/TinyVector.h
+++ b/src/TinyVector.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team, RSDuck
+ Copyright 2016-2024 melonDS team, RSDuck
This file is part of melonDS.
diff --git a/src/Utils.cpp b/src/Utils.cpp
index 698cf9bd..bb5848c1 100644
--- a/src/Utils.cpp
+++ b/src/Utils.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/Utils.h b/src/Utils.h
index 63be217b..eae9193a 100644
--- a/src/Utils.h
+++ b/src/Utils.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/Wifi.cpp b/src/Wifi.cpp
index d8f440b4..b097da1e 100644
--- a/src/Wifi.cpp
+++ b/src/Wifi.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
@@ -93,25 +93,11 @@ Wifi::Wifi(melonDS::NDS& nds) : NDS(nds)
{
NDS.RegisterEventFunc(Event_Wifi, 0, MemberEventFunc(Wifi, USTimer));
- //MPInited = false;
- //LANInited = false;
-
- Platform::MP_Init();
- MPInited = true;
-
- Platform::LAN_Init();
- LANInited = true;
-
- WifiAP = new class WifiAP(this);
+ WifiAP = new class WifiAP(this, NDS.UserData);
}
Wifi::~Wifi()
{
- if (MPInited)
- Platform::MP_DeInit();
- if (LANInited)
- Platform::LAN_DeInit();
-
delete WifiAP; WifiAP = nullptr;
NDS.UnregisterEventFunc(Event_Wifi, 0);
@@ -368,7 +354,7 @@ void Wifi::UpdatePowerOn()
ScheduleTimer(true);
- Platform::MP_Begin();
+ Platform::MP_Begin(NDS.UserData);
}
else
{
@@ -376,7 +362,7 @@ void Wifi::UpdatePowerOn()
NDS.CancelEvent(Event_Wifi);
- Platform::MP_End();
+ Platform::MP_End(NDS.UserData);
}
}
@@ -664,23 +650,23 @@ void Wifi::TXSendFrame(const TXSlot* slot, int num)
case 0:
case 2:
case 3:
- Platform::MP_SendPacket(TXBuffer, 12+len, USTimestamp);
+ Platform::MP_SendPacket(TXBuffer, 12+len, USTimestamp, NDS.UserData);
if (!IsMP) WifiAP->SendPacket(TXBuffer, 12+len);
break;
case 1:
*(u16*)&TXBuffer[12 + 24+2] = MPClientMask;
- Platform::MP_SendCmd(TXBuffer, 12+len, USTimestamp);
+ Platform::MP_SendCmd(TXBuffer, 12+len, USTimestamp, NDS.UserData);
break;
case 5:
IncrementTXCount(slot);
- Platform::MP_SendReply(TXBuffer, 12+len, USTimestamp, IOPORT(W_AIDLow));
+ Platform::MP_SendReply(TXBuffer, 12+len, USTimestamp, IOPORT(W_AIDLow), NDS.UserData);
break;
case 4:
*(u64*)&TXBuffer[0xC + 24] = USCounter;
- Platform::MP_SendPacket(TXBuffer, 12+len, USTimestamp);
+ Platform::MP_SendPacket(TXBuffer, 12+len, USTimestamp, NDS.UserData);
break;
}
}
@@ -836,7 +822,7 @@ void Wifi::SendMPDefaultReply()
*(u16*)&reply[0xC + 0x16] = IOPORT(W_TXSeqNo) << 4;
*(u32*)&reply[0xC + 0x18] = 0;
- int txlen = Platform::MP_SendReply(reply, 12+28, USTimestamp, IOPORT(W_AIDLow));
+ int txlen = Platform::MP_SendReply(reply, 12+28, USTimestamp, IOPORT(W_AIDLow), NDS.UserData);
WIFI_LOG("wifi: sent %d/40 bytes of MP default reply\n", txlen);
}
@@ -946,7 +932,7 @@ void Wifi::SendMPAck(u16 cmdcount, u16 clientfail)
*(u32*)&ack[0] = PreambleLen(TXSlots[1].Rate);
}
- int txlen = Platform::MP_SendAck(ack, 12+32, USTimestamp);
+ int txlen = Platform::MP_SendAck(ack, 12+32, USTimestamp, NDS.UserData);
WIFI_LOG("wifi: sent %d/44 bytes of MP ack, %d %d\n", txlen, ComStatus, RXTime);
}
@@ -1069,7 +1055,7 @@ bool Wifi::ProcessTX(TXSlot* slot, int num)
u16 res = 0;
if (MPClientMask)
- res = Platform::MP_RecvReplies(MPClientReplies, USTimestamp, MPClientMask);
+ res = Platform::MP_RecvReplies(MPClientReplies, USTimestamp, MPClientMask, NDS.UserData);
MPClientFail &= ~res;
// TODO: 112 likely includes the ack preamble, which needs adjusted
@@ -1508,7 +1494,7 @@ void Wifi::FinishRX()
// in the case this client wasn't ready to send a reply
// TODO: also send this if we have RX disabled
- Platform::MP_SendReply(nullptr, 0, USTimestamp, 0);
+ Platform::MP_SendReply(nullptr, 0, USTimestamp, 0, NDS.UserData);
}
}
else if ((rxflags & 0x800F) == 0x8001)
@@ -1592,13 +1578,13 @@ bool Wifi::CheckRX(int type) // 0=regular 1=MP replies 2=MP host frames
if (type == 0)
{
- rxlen = Platform::MP_RecvPacket(RXBuffer, ×tamp);
+ rxlen = Platform::MP_RecvPacket(RXBuffer, ×tamp, NDS.UserData);
if ((rxlen <= 0) && (!IsMP))
rxlen = WifiAP->RecvPacket(RXBuffer);
}
else
{
- rxlen = Platform::MP_RecvHostPacket(RXBuffer, ×tamp);
+ rxlen = Platform::MP_RecvHostPacket(RXBuffer, ×tamp, NDS.UserData);
if (rxlen < 0)
{
// host is gone
diff --git a/src/Wifi.h b/src/Wifi.h
index 2e0465a6..14eddd65 100644
--- a/src/Wifi.h
+++ b/src/Wifi.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
@@ -241,9 +241,6 @@ private:
u16 MPLastSeqno;
- bool MPInited;
- bool LANInited;
-
int USUntilPowerOn;
// MULTIPLAYER SYNC APPARATUS
diff --git a/src/WifiAP.cpp b/src/WifiAP.cpp
index 855dc244..0a239f7d 100644
--- a/src/WifiAP.cpp
+++ b/src/WifiAP.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
@@ -71,7 +71,7 @@ bool MACEqual(const u8* a, const u8* b);
bool MACIsBroadcast(const u8* a);
-WifiAP::WifiAP(Wifi* client) : Client(client)
+WifiAP::WifiAP(Wifi* client, void* userdata) : Client(client), UserData(userdata)
{
}
@@ -301,7 +301,7 @@ int WifiAP::SendPacket(const u8* data, int len)
*(u16*)&LANBuffer[12] = *(u16*)&data[30]; // type
memcpy(&LANBuffer[14], &data[32], lan_len - 14);
- Platform::LAN_SendPacket(LANBuffer, lan_len);
+ Platform::Net_SendPacket(LANBuffer, lan_len, UserData);
}
}
return len;
@@ -368,14 +368,23 @@ int WifiAP::RecvPacket(u8* data)
if (ClientStatus < 2) return 0;
- int rxlen = Platform::LAN_RecvPacket(LANBuffer);
- if (rxlen > 0)
+ int rxlen = Platform::Net_RecvPacket(LANBuffer, UserData);
+ while (rxlen > 0)
{
// check destination MAC
if (!MACIsBroadcast(&LANBuffer[0]))
{
if (!MACEqual(&LANBuffer[0], Client->GetMAC()))
- return 0;
+ {
+ rxlen = Platform::Net_RecvPacket(LANBuffer, UserData);
+ continue;
+ }
+ }
+
+ if (MACEqual(&LANBuffer[6], Client->GetMAC()))
+ {
+ rxlen = Platform::Net_RecvPacket(LANBuffer, UserData);
+ continue;
}
// packet is good
diff --git a/src/WifiAP.h b/src/WifiAP.h
index a9e80c3b..8f0ef608 100644
--- a/src/WifiAP.h
+++ b/src/WifiAP.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
@@ -28,7 +28,7 @@ class Wifi;
class WifiAP
{
public:
- WifiAP(Wifi* client);
+ WifiAP(Wifi* client, void* userdata);
~WifiAP();
void Reset();
@@ -44,6 +44,7 @@ public:
private:
Wifi* Client;
+ void* UserData;
u64 USCounter;
diff --git a/src/fatfs/ff.h b/src/fatfs/ff.h
index 1662d836..88ff1f71 100644
--- a/src/fatfs/ff.h
+++ b/src/fatfs/ff.h
@@ -40,8 +40,8 @@ extern "C" {
#include
typedef unsigned __int64 QWORD;
#include
-#define isnan(v) _isnan(v)
-#define isinf(v) (!_finite(v))
+//#define isnan(v) _isnan(v)
+//#define isinf(v) (!_finite(v))
#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__cplusplus) /* C99 or later */
#define FF_INTDEF 2
diff --git a/src/frontend/FrontendUtil.h b/src/frontend/FrontendUtil.h
deleted file mode 100644
index 6f09d4b7..00000000
--- a/src/frontend/FrontendUtil.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- Copyright 2016-2023 melonDS team
-
- This file is part of melonDS.
-
- melonDS is free software: you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free
- Software Foundation, either version 3 of the License, or (at your option)
- any later version.
-
- melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with melonDS. If not, see http://www.gnu.org/licenses/.
-*/
-
-#ifndef FRONTENDUTIL_H
-#define FRONTENDUTIL_H
-
-#include "types.h"
-
-#include
-#include
-
-namespace melonDS
-{
-class NDS;
-}
-namespace Frontend
-{
-using namespace melonDS;
-
-enum ScreenLayout
-{
- screenLayout_Natural, // top screen above bottom screen always
- screenLayout_Horizontal,
- screenLayout_Vertical,
- screenLayout_Hybrid,
- screenLayout_MAX,
-};
-
-enum ScreenRotation
-{
- screenRot_0Deg,
- screenRot_90Deg,
- screenRot_180Deg,
- screenRot_270Deg,
- screenRot_MAX,
-};
-
-enum ScreenSizing
-{
- screenSizing_Even, // both screens get same size
- screenSizing_EmphTop, // make top screen as big as possible, fit bottom screen in remaining space
- screenSizing_EmphBot,
- screenSizing_Auto, // not applied in SetupScreenLayout
- screenSizing_TopOnly,
- screenSizing_BotOnly,
- screenSizing_MAX,
-};
-
-// setup the display layout based on the provided display size and parameters
-// * screenWidth/screenHeight: size of the host display
-// * screenLayout: how the DS screens are laid out
-// * rotation: angle at which the DS screens are presented
-// * sizing: how the display size is shared between the two screens
-// * screenGap: size of the gap between the two screens in pixels
-// * integerScale: force screens to be scaled up at integer scaling factors
-// * screenSwap: whether to swap the position of both screens
-// * topAspect/botAspect: ratio by which to scale the top and bottom screen respectively
-void SetupScreenLayout(int screenWidth, int screenHeight,
- ScreenLayout screenLayout,
- ScreenRotation rotation,
- ScreenSizing sizing,
- int screenGap,
- bool integerScale,
- bool swapScreens,
- float topAspect, float botAspect);
-
-const int MaxScreenTransforms = 3;
-
-// get a 2x3 transform matrix for each screen and whether it's a top or bottom screen
-// note: the transform assumes an origin point at the top left of the display,
-// X going right and Y going down
-// for each screen the source coordinates should be (0,0) and (256,192)
-// 'out' should point to an array of 6*MaxScreenTransforms floats
-// 'kind' should point to an array of MaxScreenTransforms ints
-// (0 = indicates top screen, 1 = bottom screen)
-// returns the amount of screens
-int GetScreenTransforms(float* out, int* kind);
-
-// de-transform the provided host display coordinates to get coordinates
-// on the bottom screen
-bool GetTouchCoords(int& x, int& y, bool clamp);
-
-
-// initialize the audio utility
-void Init_Audio(int outputfreq);
-
-// get how many samples to read from the core audio output
-// based on how many are needed by the frontend (outlen in samples)
-int AudioOut_GetNumSamples(int outlen);
-
-// resample audio from the core audio output to match the frontend's
-// output frequency, and apply specified volume
-// note: this assumes the output buffer is interleaved stereo
-void AudioOut_Resample(s16* inbuf, int inlen, s16* outbuf, int outlen, int volume);
-
-// feed silence to the microphone input
-void Mic_FeedSilence(NDS& nds);
-
-// feed random noise to the microphone input
-void Mic_FeedNoise(NDS& nds);
-
-// feed an external buffer to the microphone input
-// buffer should be mono
-void Mic_FeedExternalBuffer(NDS& nds);
-void Mic_SetExternalBuffer(s16* buffer, u32 len);
-
-}
-
-#endif // FRONTENDUTIL_H
diff --git a/src/frontend/Util_Video.cpp b/src/frontend/ScreenLayout.cpp
similarity index 93%
rename from src/frontend/Util_Video.cpp
rename to src/frontend/ScreenLayout.cpp
index e772be9a..bb9a60cb 100644
--- a/src/frontend/Util_Video.cpp
+++ b/src/frontend/ScreenLayout.cpp
@@ -1,553 +1,548 @@
-/*
- Copyright 2016-2023 melonDS team
-
- This file is part of melonDS.
-
- melonDS is free software: you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free
- Software Foundation, either version 3 of the License, or (at your option)
- any later version.
-
- melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with melonDS. If not, see http://www.gnu.org/licenses/.
-*/
-
-#include
-#include
-#include
-#include
-#include
-
-#include "FrontendUtil.h"
-
-
-namespace Frontend
-{
-
-float TopScreenMtx[6];
-float BotScreenMtx[6];
-float HybScreenMtx[6];
-float TouchMtx[6];
-float HybTouchMtx[6];
-bool TopEnable;
-bool BotEnable;
-bool HybEnable;
-int HybScreen;
-int HybPrevTouchScreen; // 0:unknown, 1:buttom screen, 2:hybrid screen
-
-void M23_Identity(float* m)
-{
- m[0] = 1; m[1] = 0;
- m[2] = 0; m[3] = 1;
- m[4] = 0; m[5] = 0;
-}
-
-void M23_Scale(float* m, float s)
-{
- m[0] *= s; m[1] *= s;
- m[2] *= s; m[3] *= s;
- m[4] *= s; m[5] *= s;
-}
-
-void M23_Scale(float* m, float x, float y)
-{
- m[0] *= x; m[1] *= y;
- m[2] *= x; m[3] *= y;
- m[4] *= x; m[5] *= y;
-}
-
-void M23_RotateFast(float* m, int angle)
-{
- if (angle == 0) return;
-
- float temp[4]; memcpy(temp, m, sizeof(float)*4);
-
- switch (angle)
- {
- case 1: // 90
- m[0] = temp[2];
- m[1] = temp[3];
- m[2] = -temp[0];
- m[3] = -temp[1];
- break;
-
- case 2: // 180
- m[0] = -temp[0];
- m[1] = -temp[1];
- m[2] = -temp[2];
- m[3] = -temp[3];
- break;
-
- case 3: // 270
- m[0] = -temp[2];
- m[1] = -temp[3];
- m[2] = temp[0];
- m[3] = temp[1];
- break;
- }
-}
-
-void M23_Translate(float* m, float tx, float ty)
-{
- m[4] += tx;
- m[5] += ty;
-}
-
-void M23_Multiply(float* m, float* _a, float* _b)
-{
- float a[6]; memcpy(a, _a, 6*sizeof(float));
- float b[6]; memcpy(b, _b, 6*sizeof(float));
-
- m[0] = (a[0] * b[0]) + (a[2] * b[1]);
- m[1] = (a[1] * b[0]) + (a[3] * b[1]);
-
- m[2] = (a[0] * b[2]) + (a[2] * b[3]);
- m[3] = (a[1] * b[2]) + (a[3] * b[3]);
-
- m[4] = (a[0] * b[4]) + (a[2] * b[5]) + a[4];
- m[5] = (a[1] * b[4]) + (a[3] * b[5]) + a[5];
-}
-
-void M23_Transform(float* m, float& x, float& y)
-{
- float vx = x;
- float vy = y;
-
- x = (vx * m[0]) + (vy * m[2]) + m[4];
- y = (vx * m[1]) + (vy * m[3]) + m[5];
-}
-
-
-void SetupScreenLayout(int screenWidth, int screenHeight,
- ScreenLayout screenLayout,
- ScreenRotation rotation,
- ScreenSizing sizing,
- int screenGap,
- bool integerScale,
- bool swapScreens,
- float topAspect, float botAspect)
-{
- HybEnable = screenLayout == 3;
- if (HybEnable)
- {
- screenLayout = screenLayout_Natural;
- sizing = screenSizing_Even;
- HybScreen = swapScreens ? 1 : 0;
- swapScreens = false;
- topAspect = botAspect = 1;
- HybPrevTouchScreen = 0;
- }
-
- float refpoints[6][2] =
- {
- {0, 0}, {256, 192},
- {0, 0}, {256, 192},
- {0, 0}, {256, 192}
- };
-
- int layout = screenLayout == screenLayout_Natural
- ? rotation % 2
- : screenLayout - 1;
-
- float botScale = 1;
- float hybScale = 1;
- float botTrans[4] = {0};
- float hybTrans[2] = {0};
-
- M23_Identity(TopScreenMtx);
- M23_Identity(BotScreenMtx);
- M23_Identity(HybScreenMtx);
-
- M23_Translate(TopScreenMtx, -256/2, -192/2);
- M23_Translate(BotScreenMtx, -256/2, -192/2);
-
- M23_Scale(TopScreenMtx, topAspect, 1);
- M23_Scale(BotScreenMtx, botAspect, 1);
-
- // rotation
- {
- float rotmtx[6];
- M23_Identity(rotmtx);
-
- M23_RotateFast(rotmtx, rotation);
- M23_Multiply(TopScreenMtx, rotmtx, TopScreenMtx);
- M23_Multiply(BotScreenMtx, rotmtx, BotScreenMtx);
- M23_Multiply(HybScreenMtx, rotmtx, HybScreenMtx);
-
- M23_Transform(TopScreenMtx, refpoints[0][0], refpoints[0][1]);
- M23_Transform(TopScreenMtx, refpoints[1][0], refpoints[1][1]);
- M23_Transform(BotScreenMtx, refpoints[2][0], refpoints[2][1]);
- M23_Transform(BotScreenMtx, refpoints[3][0], refpoints[3][1]);
- }
-
- int posRefPointOffset = 0;
- int posRefPointCount = HybEnable ? 6 : 4;
-
- if (sizing == screenSizing_TopOnly || sizing == screenSizing_BotOnly)
- {
- float* mtx = sizing == screenSizing_TopOnly ? TopScreenMtx : BotScreenMtx;
- int primOffset = sizing == screenSizing_TopOnly ? 0 : 2;
- int secOffset = sizing == screenSizing_BotOnly ? 2 : 0;
-
- float hSize = fabsf(refpoints[primOffset][0] - refpoints[primOffset+1][0]);
- float vSize = fabsf(refpoints[primOffset][1] - refpoints[primOffset+1][1]);
-
- float scale = std::min(screenWidth / hSize, screenHeight / vSize);
- if (integerScale)
- scale = floorf(scale);
-
- TopEnable = sizing == screenSizing_TopOnly;
- BotEnable = sizing == screenSizing_BotOnly;
- botScale = scale;
-
- M23_Scale(mtx, scale);
- refpoints[primOffset][0] *= scale;
- refpoints[primOffset][1] *= scale;
- refpoints[primOffset+1][0] *= scale;
- refpoints[primOffset+1][1] *= scale;
-
- posRefPointOffset = primOffset;
- posRefPointCount = 2;
- }
- else
- {
- TopEnable = BotEnable = true;
-
- // move screens apart
- {
- int idx = layout == 0 ? 1 : 0;
-
- bool moveV = rotation % 2 == layout;
-
- float offsetBot = (moveV ? 192.0 : 256.0 * botAspect) / 2.0 + screenGap / 2.0;
- float offsetTop = -((moveV ? 192.0 : 256.0 * topAspect) / 2.0 + screenGap / 2.0);
-
- if ((rotation == 1 || rotation == 2) ^ swapScreens)
- {
- offsetTop *= -1;
- offsetBot *= -1;
- }
-
- M23_Translate(TopScreenMtx, (idx==0)?offsetTop:0, (idx==1)?offsetTop:0);
- M23_Translate(BotScreenMtx, (idx==0)?offsetBot:0, (idx==1)?offsetBot:0);
-
- refpoints[0][idx] += offsetTop;
- refpoints[1][idx] += offsetTop;
- refpoints[2][idx] += offsetBot;
- refpoints[3][idx] += offsetBot;
-
- botTrans[idx] = offsetBot;
- }
-
- // scale
- {
- if (sizing == screenSizing_Even)
- {
- float minX = refpoints[0][0], maxX = minX;
- float minY = refpoints[0][1], maxY = minY;
-
- for (int i = 1; i < 4; i++)
- {
- minX = std::min(minX, refpoints[i][0]);
- minY = std::min(minY, refpoints[i][1]);
- maxX = std::max(maxX, refpoints[i][0]);
- maxY = std::max(maxY, refpoints[i][1]);
- }
-
- float hSize = maxX - minX;
- float vSize = maxY - minY;
-
- if (HybEnable)
- {
- hybScale = layout == 0
- ? (4 * vSize) / (3 * hSize)
- : (4 * hSize) / (3 * vSize);
- if (layout == 0)
- hSize += (vSize * 4) / 3;
- else
- vSize += (hSize * 4) / 3;
- }
-
- // scale evenly
- float scale = std::min(screenWidth / hSize, screenHeight / vSize);
-
- if (integerScale)
- scale = floor(scale);
-
- hybScale *= scale;
-
- M23_Scale(TopScreenMtx, scale);
- M23_Scale(BotScreenMtx, scale);
- M23_Scale(HybScreenMtx, hybScale);
-
- for (int i = 0; i < 4; i++)
- {
- refpoints[i][0] *= scale;
- refpoints[i][1] *= scale;
- }
-
- botScale = scale;
-
- // move screens aside
- if (HybEnable)
- {
- float hybWidth = layout == 0
- ? (scale * vSize * 4) / 3
- : (scale * hSize * 4) / 3;
-
- if (rotation > screenRot_90Deg)
- hybWidth *= -1;
-
- M23_Translate(TopScreenMtx, (layout==0)?hybWidth:0, (layout==1)?hybWidth:0);
- M23_Translate(BotScreenMtx, (layout==0)?hybWidth:0, (layout==1)?hybWidth:0);
- refpoints[0][layout] += hybWidth;
- refpoints[1][layout] += hybWidth;
- refpoints[2][layout] += hybWidth;
- refpoints[3][layout] += hybWidth;
-
- botTrans[2+layout] += hybWidth;
-
- hybTrans[0] = scale * (rotation == screenRot_0Deg || rotation == screenRot_270Deg ? minX : maxX);
- hybTrans[1] = scale * (rotation == screenRot_0Deg || rotation == screenRot_90Deg ? minY : maxY);
- M23_Translate(HybScreenMtx, hybTrans[0], hybTrans[1]);
-
- M23_Transform(HybScreenMtx, refpoints[4][0], refpoints[4][1]);
- M23_Transform(HybScreenMtx, refpoints[5][0], refpoints[5][1]);
- }
- }
- else
- {
- int primOffset = (sizing == screenSizing_EmphTop) ? 0 : 2;
- int secOffset = (sizing == screenSizing_EmphTop) ? 2 : 0;
- float* primMtx = (sizing == screenSizing_EmphTop) ? TopScreenMtx : BotScreenMtx;
- float* secMtx = (sizing == screenSizing_EmphTop) ? BotScreenMtx : TopScreenMtx;
-
- float primMinX = refpoints[primOffset][0], primMaxX = primMinX;
- float primMinY = refpoints[primOffset][1], primMaxY = primMinY;
- float secMinX = refpoints[secOffset][0], secMaxX = secMinX;
- float secMinY = refpoints[secOffset][1], secMaxY = secMinY;
-
- primMinX = std::min(primMinX, refpoints[primOffset+1][0]);
- primMinY = std::min(primMinY, refpoints[primOffset+1][1]);
- primMaxX = std::max(primMaxX, refpoints[primOffset+1][0]);
- primMaxY = std::max(primMaxY, refpoints[primOffset+1][1]);
-
- secMinX = std::min(secMinX, refpoints[secOffset+1][0]);
- secMinY = std::min(secMinY, refpoints[secOffset+1][1]);
- secMaxX = std::max(secMaxX, refpoints[secOffset+1][0]);
- secMaxY = std::max(secMaxY, refpoints[secOffset+1][1]);
-
- float primHSize = layout == 1 ? std::max(primMaxX, -primMinX) : primMaxX - primMinX;
- float primVSize = layout == 0 ? std::max(primMaxY, -primMinY) : primMaxY - primMinY;
-
- float secHSize = layout == 1 ? std::max(secMaxX, -secMinX) : secMaxX - secMinX;
- float secVSize = layout == 0 ? std::max(secMaxY, -secMinY) : secMaxY - secMinY;
-
- float primScale = std::min(screenWidth / primHSize, screenHeight / primVSize);
- float secScale = 1.f;
-
- if (integerScale)
- primScale = floorf(primScale);
-
- if (layout == 0)
- {
- if (screenHeight - primVSize * primScale < secVSize)
- primScale = std::min(screenWidth / primHSize, (screenHeight - secVSize) / primVSize);
- else
- secScale = std::min((screenHeight - primVSize * primScale) / secVSize, screenWidth / secHSize);
- }
- else
- {
- if (screenWidth - primHSize * primScale < secHSize)
- primScale = std::min((screenWidth - secHSize) / primHSize, screenHeight / primVSize);
- else
- secScale = std::min((screenWidth - primHSize * primScale) / secHSize, screenHeight / secVSize);
- }
-
- if (integerScale)
- {
- primScale = floorf(primScale);
- secScale = floorf(secScale);
- }
-
- M23_Scale(primMtx, primScale);
- M23_Scale(secMtx, secScale);
-
- refpoints[primOffset+0][0] *= primScale;
- refpoints[primOffset+0][1] *= primScale;
- refpoints[primOffset+1][0] *= primScale;
- refpoints[primOffset+1][1] *= primScale;
- refpoints[secOffset+0][0] *= secScale;
- refpoints[secOffset+0][1] *= secScale;
- refpoints[secOffset+1][0] *= secScale;
- refpoints[secOffset+1][1] *= secScale;
-
- botScale = (sizing == screenSizing_EmphTop) ? secScale : primScale;
- }
- }
- }
-
- // position
- {
- float minX = refpoints[posRefPointOffset][0], maxX = minX;
- float minY = refpoints[posRefPointOffset][1], maxY = minY;
-
- for (int i = posRefPointOffset + 1; i < posRefPointOffset + posRefPointCount; i++)
- {
- minX = std::min(minX, refpoints[i][0]);
- minY = std::min(minY, refpoints[i][1]);
- maxX = std::max(maxX, refpoints[i][0]);
- maxY = std::max(maxY, refpoints[i][1]);
- }
-
- float width = maxX - minX;
- float height = maxY - minY;
-
- float tx = (screenWidth/2) - (width/2) - minX;
- float ty = (screenHeight/2) - (height/2) - minY;
-
- M23_Translate(TopScreenMtx, tx, ty);
- M23_Translate(BotScreenMtx, tx, ty);
- M23_Translate(HybScreenMtx, tx, ty);
-
- botTrans[2] += tx; botTrans[3] += ty;
- hybTrans[0] += tx; hybTrans[1] += ty;
- }
-
- // prepare a 'reverse' matrix for the touchscreen
- // this matrix undoes the transforms applied to the bottom screen
- // and can be used to calculate touchscreen coords from host screen coords
- if (BotEnable)
- {
- M23_Identity(TouchMtx);
-
- M23_Translate(TouchMtx, -botTrans[2], -botTrans[3]);
- M23_Scale(TouchMtx, 1.f / botScale);
- M23_Translate(TouchMtx, -botTrans[0], -botTrans[1]);
-
- float rotmtx[6];
- M23_Identity(rotmtx);
- M23_RotateFast(rotmtx, (4-rotation) & 3);
- M23_Multiply(TouchMtx, rotmtx, TouchMtx);
-
- M23_Scale(TouchMtx, 1.f/botAspect, 1);
- M23_Translate(TouchMtx, 256/2, 192/2);
-
- if (HybEnable && HybScreen == 1)
- {
- M23_Identity(HybTouchMtx);
-
- M23_Translate(HybTouchMtx, -hybTrans[0], -hybTrans[1]);
- M23_Scale(HybTouchMtx, 1.f/hybScale);
- M23_Multiply(HybTouchMtx, rotmtx, HybTouchMtx);
- }
- }
-}
-
-int GetScreenTransforms(float* out, int* kind)
-{
- int num = 0;
- if (TopEnable)
- {
- memcpy(out + 6*num, TopScreenMtx, sizeof(TopScreenMtx));
- kind[num++] = 0;
- }
- if (BotEnable)
- {
- memcpy(out + 6*num, BotScreenMtx, sizeof(BotScreenMtx));
- kind[num++] = 1;
- }
- if (HybEnable)
- {
- memcpy(out + 6*num, HybScreenMtx, sizeof(HybScreenMtx));
- kind[num++] = HybScreen;
- }
- return num;
-}
-
-bool GetTouchCoords(int& x, int& y, bool clamp)
-{
- if (HybEnable && HybScreen == 1)
- {
- float vx = x;
- float vy = y;
- float hvx = x;
- float hvy = y;
-
- M23_Transform(TouchMtx, vx, vy);
- M23_Transform(HybTouchMtx, hvx, hvy);
-
- if (clamp)
- {
- if (HybPrevTouchScreen == 1)
- {
- x = std::clamp((int)vx, 0, 255);
- y = std::clamp((int)vy, 0, 191);
-
- return true;
- }
- if (HybPrevTouchScreen == 2)
- {
- x = std::clamp((int)hvx, 0, 255);
- y = std::clamp((int)hvy, 0, 191);
-
- return true;
- }
- }
- else
- {
- if (vx >= 0 && vx < 256 && vy >= 0 && vy < 192)
- {
- HybPrevTouchScreen = 1;
-
- x = (int)vx;
- y = (int)vy;
-
- return true;
- }
- if (hvx >= 0 && hvx < 256 && hvy >= 0 && hvy < 192)
- {
- HybPrevTouchScreen = 2;
-
- x = (int)hvx;
- y = (int)hvy;
-
- return true;
- }
- }
- }
- else if (BotEnable)
- {
- float vx = x;
- float vy = y;
-
- M23_Transform(TouchMtx, vx, vy);
-
- if (clamp)
- {
- x = std::clamp((int)vx, 0, 255);
- y = std::clamp((int)vy, 0, 191);
-
- return true;
- }
- else
- {
- if (vx >= 0 && vx < 256 && vy >= 0 && vy < 192)
- {
- x = (int)vx;
- y = (int)vy;
-
- return true;
- }
- }
- }
-
- return false;
-}
-
-}
-
+/*
+ Copyright 2016-2024 melonDS team
+
+ This file is part of melonDS.
+
+ melonDS is free software: you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation, either version 3 of the License, or (at your option)
+ any later version.
+
+ melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with melonDS. If not, see http://www.gnu.org/licenses/.
+*/
+
+#include
+#include
+#include
+
+#include "ScreenLayout.h"
+
+
+void M23_Identity(float* m)
+{
+ m[0] = 1; m[1] = 0;
+ m[2] = 0; m[3] = 1;
+ m[4] = 0; m[5] = 0;
+}
+
+void M23_Scale(float* m, float s)
+{
+ m[0] *= s; m[1] *= s;
+ m[2] *= s; m[3] *= s;
+ m[4] *= s; m[5] *= s;
+}
+
+void M23_Scale(float* m, float x, float y)
+{
+ m[0] *= x; m[1] *= y;
+ m[2] *= x; m[3] *= y;
+ m[4] *= x; m[5] *= y;
+}
+
+void M23_RotateFast(float* m, int angle)
+{
+ if (angle == 0) return;
+
+ float temp[4]; memcpy(temp, m, sizeof(float)*4);
+
+ switch (angle)
+ {
+ case 1: // 90
+ m[0] = temp[2];
+ m[1] = temp[3];
+ m[2] = -temp[0];
+ m[3] = -temp[1];
+ break;
+
+ case 2: // 180
+ m[0] = -temp[0];
+ m[1] = -temp[1];
+ m[2] = -temp[2];
+ m[3] = -temp[3];
+ break;
+
+ case 3: // 270
+ m[0] = -temp[2];
+ m[1] = -temp[3];
+ m[2] = temp[0];
+ m[3] = temp[1];
+ break;
+ }
+}
+
+void M23_Translate(float* m, float tx, float ty)
+{
+ m[4] += tx;
+ m[5] += ty;
+}
+
+void M23_Multiply(float* m, float* _a, float* _b)
+{
+ float a[6]; memcpy(a, _a, 6*sizeof(float));
+ float b[6]; memcpy(b, _b, 6*sizeof(float));
+
+ m[0] = (a[0] * b[0]) + (a[2] * b[1]);
+ m[1] = (a[1] * b[0]) + (a[3] * b[1]);
+
+ m[2] = (a[0] * b[2]) + (a[2] * b[3]);
+ m[3] = (a[1] * b[2]) + (a[3] * b[3]);
+
+ m[4] = (a[0] * b[4]) + (a[2] * b[5]) + a[4];
+ m[5] = (a[1] * b[4]) + (a[3] * b[5]) + a[5];
+}
+
+void M23_Transform(float* m, float& x, float& y)
+{
+ float vx = x;
+ float vy = y;
+
+ x = (vx * m[0]) + (vy * m[2]) + m[4];
+ y = (vx * m[1]) + (vy * m[3]) + m[5];
+}
+
+
+ScreenLayout::ScreenLayout()
+{
+ M23_Identity(TopScreenMtx);
+ M23_Identity(BotScreenMtx);
+ M23_Identity(HybScreenMtx);
+ M23_Identity(TouchMtx);
+ M23_Identity(HybTouchMtx);
+ TopEnable = true;
+ BotEnable = true;
+ HybEnable = false;
+ HybScreen = 0;
+ HybPrevTouchScreen = 0;
+}
+
+void ScreenLayout::Setup(int screenWidth, int screenHeight,
+ ScreenLayoutType screenLayout,
+ ScreenRotation rotation,
+ ScreenSizing sizing,
+ int screenGap,
+ bool integerScale,
+ bool swapScreens,
+ float topAspect, float botAspect)
+{
+ HybEnable = screenLayout == 3;
+ if (HybEnable)
+ {
+ screenLayout = screenLayout_Natural;
+ sizing = screenSizing_Even;
+ HybScreen = swapScreens ? 1 : 0;
+ swapScreens = false;
+ topAspect = botAspect = 1;
+ HybPrevTouchScreen = 0;
+ }
+
+ float refpoints[6][2] =
+ {
+ {0, 0}, {256, 192},
+ {0, 0}, {256, 192},
+ {0, 0}, {256, 192}
+ };
+
+ int layout = screenLayout == screenLayout_Natural
+ ? rotation % 2
+ : screenLayout - 1;
+
+ float botScale = 1;
+ float hybScale = 1;
+ float botTrans[4] = {0};
+ float hybTrans[2] = {0};
+
+ M23_Identity(TopScreenMtx);
+ M23_Identity(BotScreenMtx);
+ M23_Identity(HybScreenMtx);
+
+ M23_Translate(TopScreenMtx, -256/2, -192/2);
+ M23_Translate(BotScreenMtx, -256/2, -192/2);
+
+ M23_Scale(TopScreenMtx, topAspect, 1);
+ M23_Scale(BotScreenMtx, botAspect, 1);
+
+ // rotation
+ {
+ float rotmtx[6];
+ M23_Identity(rotmtx);
+
+ M23_RotateFast(rotmtx, rotation);
+ M23_Multiply(TopScreenMtx, rotmtx, TopScreenMtx);
+ M23_Multiply(BotScreenMtx, rotmtx, BotScreenMtx);
+ M23_Multiply(HybScreenMtx, rotmtx, HybScreenMtx);
+
+ M23_Transform(TopScreenMtx, refpoints[0][0], refpoints[0][1]);
+ M23_Transform(TopScreenMtx, refpoints[1][0], refpoints[1][1]);
+ M23_Transform(BotScreenMtx, refpoints[2][0], refpoints[2][1]);
+ M23_Transform(BotScreenMtx, refpoints[3][0], refpoints[3][1]);
+ }
+
+ int posRefPointOffset = 0;
+ int posRefPointCount = HybEnable ? 6 : 4;
+
+ if (sizing == screenSizing_TopOnly || sizing == screenSizing_BotOnly)
+ {
+ float* mtx = sizing == screenSizing_TopOnly ? TopScreenMtx : BotScreenMtx;
+ int primOffset = sizing == screenSizing_TopOnly ? 0 : 2;
+ int secOffset = sizing == screenSizing_BotOnly ? 2 : 0;
+
+ float hSize = fabsf(refpoints[primOffset][0] - refpoints[primOffset+1][0]);
+ float vSize = fabsf(refpoints[primOffset][1] - refpoints[primOffset+1][1]);
+
+ float scale = std::min(screenWidth / hSize, screenHeight / vSize);
+ if (integerScale)
+ scale = floorf(scale);
+
+ TopEnable = sizing == screenSizing_TopOnly;
+ BotEnable = sizing == screenSizing_BotOnly;
+ botScale = scale;
+
+ M23_Scale(mtx, scale);
+ refpoints[primOffset][0] *= scale;
+ refpoints[primOffset][1] *= scale;
+ refpoints[primOffset+1][0] *= scale;
+ refpoints[primOffset+1][1] *= scale;
+
+ posRefPointOffset = primOffset;
+ posRefPointCount = 2;
+ }
+ else
+ {
+ TopEnable = BotEnable = true;
+
+ // move screens apart
+ {
+ int idx = layout == 0 ? 1 : 0;
+
+ bool moveV = rotation % 2 == layout;
+
+ float offsetBot = (moveV ? 192.0 : 256.0 * botAspect) / 2.0 + screenGap / 2.0;
+ float offsetTop = -((moveV ? 192.0 : 256.0 * topAspect) / 2.0 + screenGap / 2.0);
+
+ if ((rotation == 1 || rotation == 2) ^ swapScreens)
+ {
+ offsetTop *= -1;
+ offsetBot *= -1;
+ }
+
+ M23_Translate(TopScreenMtx, (idx==0)?offsetTop:0, (idx==1)?offsetTop:0);
+ M23_Translate(BotScreenMtx, (idx==0)?offsetBot:0, (idx==1)?offsetBot:0);
+
+ refpoints[0][idx] += offsetTop;
+ refpoints[1][idx] += offsetTop;
+ refpoints[2][idx] += offsetBot;
+ refpoints[3][idx] += offsetBot;
+
+ botTrans[idx] = offsetBot;
+ }
+
+ // scale
+ {
+ if (sizing == screenSizing_Even)
+ {
+ float minX = refpoints[0][0], maxX = minX;
+ float minY = refpoints[0][1], maxY = minY;
+
+ for (int i = 1; i < 4; i++)
+ {
+ minX = std::min(minX, refpoints[i][0]);
+ minY = std::min(minY, refpoints[i][1]);
+ maxX = std::max(maxX, refpoints[i][0]);
+ maxY = std::max(maxY, refpoints[i][1]);
+ }
+
+ float hSize = maxX - minX;
+ float vSize = maxY - minY;
+
+ if (HybEnable)
+ {
+ hybScale = layout == 0
+ ? (4 * vSize) / (3 * hSize)
+ : (4 * hSize) / (3 * vSize);
+ if (layout == 0)
+ hSize += (vSize * 4) / 3;
+ else
+ vSize += (hSize * 4) / 3;
+ }
+
+ // scale evenly
+ float scale = std::min(screenWidth / hSize, screenHeight / vSize);
+
+ if (integerScale)
+ scale = floor(scale);
+
+ hybScale *= scale;
+
+ M23_Scale(TopScreenMtx, scale);
+ M23_Scale(BotScreenMtx, scale);
+ M23_Scale(HybScreenMtx, hybScale);
+
+ for (int i = 0; i < 4; i++)
+ {
+ refpoints[i][0] *= scale;
+ refpoints[i][1] *= scale;
+ }
+
+ botScale = scale;
+
+ // move screens aside
+ if (HybEnable)
+ {
+ float hybWidth = layout == 0
+ ? (scale * vSize * 4) / 3
+ : (scale * hSize * 4) / 3;
+
+ if (rotation > screenRot_90Deg)
+ hybWidth *= -1;
+
+ M23_Translate(TopScreenMtx, (layout==0)?hybWidth:0, (layout==1)?hybWidth:0);
+ M23_Translate(BotScreenMtx, (layout==0)?hybWidth:0, (layout==1)?hybWidth:0);
+ refpoints[0][layout] += hybWidth;
+ refpoints[1][layout] += hybWidth;
+ refpoints[2][layout] += hybWidth;
+ refpoints[3][layout] += hybWidth;
+
+ botTrans[2+layout] += hybWidth;
+
+ hybTrans[0] = scale * (rotation == screenRot_0Deg || rotation == screenRot_270Deg ? minX : maxX);
+ hybTrans[1] = scale * (rotation == screenRot_0Deg || rotation == screenRot_90Deg ? minY : maxY);
+ M23_Translate(HybScreenMtx, hybTrans[0], hybTrans[1]);
+
+ M23_Transform(HybScreenMtx, refpoints[4][0], refpoints[4][1]);
+ M23_Transform(HybScreenMtx, refpoints[5][0], refpoints[5][1]);
+ }
+ }
+ else
+ {
+ int primOffset = (sizing == screenSizing_EmphTop) ? 0 : 2;
+ int secOffset = (sizing == screenSizing_EmphTop) ? 2 : 0;
+ float* primMtx = (sizing == screenSizing_EmphTop) ? TopScreenMtx : BotScreenMtx;
+ float* secMtx = (sizing == screenSizing_EmphTop) ? BotScreenMtx : TopScreenMtx;
+
+ float primMinX = refpoints[primOffset][0], primMaxX = primMinX;
+ float primMinY = refpoints[primOffset][1], primMaxY = primMinY;
+ float secMinX = refpoints[secOffset][0], secMaxX = secMinX;
+ float secMinY = refpoints[secOffset][1], secMaxY = secMinY;
+
+ primMinX = std::min(primMinX, refpoints[primOffset+1][0]);
+ primMinY = std::min(primMinY, refpoints[primOffset+1][1]);
+ primMaxX = std::max(primMaxX, refpoints[primOffset+1][0]);
+ primMaxY = std::max(primMaxY, refpoints[primOffset+1][1]);
+
+ secMinX = std::min(secMinX, refpoints[secOffset+1][0]);
+ secMinY = std::min(secMinY, refpoints[secOffset+1][1]);
+ secMaxX = std::max(secMaxX, refpoints[secOffset+1][0]);
+ secMaxY = std::max(secMaxY, refpoints[secOffset+1][1]);
+
+ float primHSize = layout == 1 ? std::max(primMaxX, -primMinX) : primMaxX - primMinX;
+ float primVSize = layout == 0 ? std::max(primMaxY, -primMinY) : primMaxY - primMinY;
+
+ float secHSize = layout == 1 ? std::max(secMaxX, -secMinX) : secMaxX - secMinX;
+ float secVSize = layout == 0 ? std::max(secMaxY, -secMinY) : secMaxY - secMinY;
+
+ float primScale = std::min(screenWidth / primHSize, screenHeight / primVSize);
+ float secScale = 1.f;
+
+ if (integerScale)
+ primScale = floorf(primScale);
+
+ if (layout == 0)
+ {
+ if (screenHeight - primVSize * primScale < secVSize)
+ primScale = std::min(screenWidth / primHSize, (screenHeight - secVSize) / primVSize);
+ else
+ secScale = std::min((screenHeight - primVSize * primScale) / secVSize, screenWidth / secHSize);
+ }
+ else
+ {
+ if (screenWidth - primHSize * primScale < secHSize)
+ primScale = std::min((screenWidth - secHSize) / primHSize, screenHeight / primVSize);
+ else
+ secScale = std::min((screenWidth - primHSize * primScale) / secHSize, screenHeight / secVSize);
+ }
+
+ if (integerScale)
+ {
+ primScale = floorf(primScale);
+ secScale = floorf(secScale);
+ }
+
+ M23_Scale(primMtx, primScale);
+ M23_Scale(secMtx, secScale);
+
+ refpoints[primOffset+0][0] *= primScale;
+ refpoints[primOffset+0][1] *= primScale;
+ refpoints[primOffset+1][0] *= primScale;
+ refpoints[primOffset+1][1] *= primScale;
+ refpoints[secOffset+0][0] *= secScale;
+ refpoints[secOffset+0][1] *= secScale;
+ refpoints[secOffset+1][0] *= secScale;
+ refpoints[secOffset+1][1] *= secScale;
+
+ botScale = (sizing == screenSizing_EmphTop) ? secScale : primScale;
+ }
+ }
+ }
+
+ // position
+ {
+ float minX = refpoints[posRefPointOffset][0], maxX = minX;
+ float minY = refpoints[posRefPointOffset][1], maxY = minY;
+
+ for (int i = posRefPointOffset + 1; i < posRefPointOffset + posRefPointCount; i++)
+ {
+ minX = std::min(minX, refpoints[i][0]);
+ minY = std::min(minY, refpoints[i][1]);
+ maxX = std::max(maxX, refpoints[i][0]);
+ maxY = std::max(maxY, refpoints[i][1]);
+ }
+
+ float width = maxX - minX;
+ float height = maxY - minY;
+
+ float tx = (screenWidth/2) - (width/2) - minX;
+ float ty = (screenHeight/2) - (height/2) - minY;
+
+ M23_Translate(TopScreenMtx, tx, ty);
+ M23_Translate(BotScreenMtx, tx, ty);
+ M23_Translate(HybScreenMtx, tx, ty);
+
+ botTrans[2] += tx; botTrans[3] += ty;
+ hybTrans[0] += tx; hybTrans[1] += ty;
+ }
+
+ // prepare a 'reverse' matrix for the touchscreen
+ // this matrix undoes the transforms applied to the bottom screen
+ // and can be used to calculate touchscreen coords from host screen coords
+ if (BotEnable)
+ {
+ M23_Identity(TouchMtx);
+
+ M23_Translate(TouchMtx, -botTrans[2], -botTrans[3]);
+ M23_Scale(TouchMtx, 1.f / botScale);
+ M23_Translate(TouchMtx, -botTrans[0], -botTrans[1]);
+
+ float rotmtx[6];
+ M23_Identity(rotmtx);
+ M23_RotateFast(rotmtx, (4-rotation) & 3);
+ M23_Multiply(TouchMtx, rotmtx, TouchMtx);
+
+ M23_Scale(TouchMtx, 1.f/botAspect, 1);
+ M23_Translate(TouchMtx, 256/2, 192/2);
+
+ if (HybEnable && HybScreen == 1)
+ {
+ M23_Identity(HybTouchMtx);
+
+ M23_Translate(HybTouchMtx, -hybTrans[0], -hybTrans[1]);
+ M23_Scale(HybTouchMtx, 1.f/hybScale);
+ M23_Multiply(HybTouchMtx, rotmtx, HybTouchMtx);
+ }
+ }
+}
+
+int ScreenLayout::GetScreenTransforms(float* out, int* kind)
+{
+ int num = 0;
+ if (TopEnable)
+ {
+ memcpy(out + 6*num, TopScreenMtx, sizeof(TopScreenMtx));
+ kind[num++] = 0;
+ }
+ if (BotEnable)
+ {
+ memcpy(out + 6*num, BotScreenMtx, sizeof(BotScreenMtx));
+ kind[num++] = 1;
+ }
+ if (HybEnable)
+ {
+ memcpy(out + 6*num, HybScreenMtx, sizeof(HybScreenMtx));
+ kind[num++] = HybScreen;
+ }
+ return num;
+}
+
+bool ScreenLayout::GetTouchCoords(int& x, int& y, bool clamp)
+{
+ if (HybEnable && HybScreen == 1)
+ {
+ float vx = x;
+ float vy = y;
+ float hvx = x;
+ float hvy = y;
+
+ M23_Transform(TouchMtx, vx, vy);
+ M23_Transform(HybTouchMtx, hvx, hvy);
+
+ if (clamp)
+ {
+ if (HybPrevTouchScreen == 1)
+ {
+ x = std::clamp((int)vx, 0, 255);
+ y = std::clamp((int)vy, 0, 191);
+
+ return true;
+ }
+ if (HybPrevTouchScreen == 2)
+ {
+ x = std::clamp((int)hvx, 0, 255);
+ y = std::clamp((int)hvy, 0, 191);
+
+ return true;
+ }
+ }
+ else
+ {
+ if (vx >= 0 && vx < 256 && vy >= 0 && vy < 192)
+ {
+ HybPrevTouchScreen = 1;
+
+ x = (int)vx;
+ y = (int)vy;
+
+ return true;
+ }
+ if (hvx >= 0 && hvx < 256 && hvy >= 0 && hvy < 192)
+ {
+ HybPrevTouchScreen = 2;
+
+ x = (int)hvx;
+ y = (int)hvy;
+
+ return true;
+ }
+ }
+ }
+ else if (BotEnable)
+ {
+ float vx = x;
+ float vy = y;
+
+ M23_Transform(TouchMtx, vx, vy);
+
+ if (clamp)
+ {
+ x = std::clamp((int)vx, 0, 255);
+ y = std::clamp((int)vy, 0, 191);
+
+ return true;
+ }
+ else
+ {
+ if (vx >= 0 && vx < 256 && vy >= 0 && vy < 192)
+ {
+ x = (int)vx;
+ y = (int)vy;
+
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
diff --git a/src/frontend/ScreenLayout.h b/src/frontend/ScreenLayout.h
new file mode 100644
index 00000000..7b69bd40
--- /dev/null
+++ b/src/frontend/ScreenLayout.h
@@ -0,0 +1,104 @@
+/*
+ Copyright 2016-2024 melonDS team
+
+ This file is part of melonDS.
+
+ melonDS is free software: you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation, either version 3 of the License, or (at your option)
+ any later version.
+
+ melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with melonDS. If not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef SCREENLAYOUT_H
+#define SCREENLAYOUT_H
+
+enum ScreenLayoutType
+{
+ screenLayout_Natural, // top screen above bottom screen always
+ screenLayout_Horizontal,
+ screenLayout_Vertical,
+ screenLayout_Hybrid,
+ screenLayout_MAX,
+};
+
+enum ScreenRotation
+{
+ screenRot_0Deg,
+ screenRot_90Deg,
+ screenRot_180Deg,
+ screenRot_270Deg,
+ screenRot_MAX,
+};
+
+enum ScreenSizing
+{
+ screenSizing_Even, // both screens get same size
+ screenSizing_EmphTop, // make top screen as big as possible, fit bottom screen in remaining space
+ screenSizing_EmphBot,
+ screenSizing_Auto, // not applied in SetupScreenLayout
+ screenSizing_TopOnly,
+ screenSizing_BotOnly,
+ screenSizing_MAX,
+};
+
+const int kMaxScreenTransforms = 3;
+
+class ScreenLayout
+{
+public:
+ ScreenLayout();
+ ~ScreenLayout() {}
+
+ // setup the display layout based on the provided display size and parameters
+ // * screenWidth/screenHeight: size of the host display
+ // * screenLayout: how the DS screens are laid out
+ // * rotation: angle at which the DS screens are presented
+ // * sizing: how the display size is shared between the two screens
+ // * screenGap: size of the gap between the two screens in pixels
+ // * integerScale: force screens to be scaled up at integer scaling factors
+ // * screenSwap: whether to swap the position of both screens
+ // * topAspect/botAspect: ratio by which to scale the top and bottom screen respectively
+ void Setup(int screenWidth, int screenHeight,
+ ScreenLayoutType screenLayout,
+ ScreenRotation rotation,
+ ScreenSizing sizing,
+ int screenGap,
+ bool integerScale,
+ bool swapScreens,
+ float topAspect, float botAspect);
+
+ // get a 2x3 transform matrix for each screen and whether it's a top or bottom screen
+ // note: the transform assumes an origin point at the top left of the display,
+ // X going right and Y going down
+ // for each screen the source coordinates should be (0,0) and (256,192)
+ // 'out' should point to an array of 6*MaxScreenTransforms floats
+ // 'kind' should point to an array of MaxScreenTransforms ints
+ // (0 = indicates top screen, 1 = bottom screen)
+ // returns the amount of screens
+ int GetScreenTransforms(float* out, int* kind);
+
+ // de-transform the provided host display coordinates to get coordinates
+ // on the bottom screen
+ bool GetTouchCoords(int& x, int& y, bool clamp);
+
+private:
+ float TopScreenMtx[6];
+ float BotScreenMtx[6];
+ float HybScreenMtx[6];
+ float TouchMtx[6];
+ float HybTouchMtx[6];
+ bool TopEnable;
+ bool BotEnable;
+ bool HybEnable;
+ int HybScreen;
+ int HybPrevTouchScreen; // 0:unknown, 1:buttom screen, 2:hybrid screen
+};
+
+#endif // SCREENLAYOUT_H
diff --git a/src/frontend/Util_Audio.cpp b/src/frontend/Util_Audio.cpp
deleted file mode 100644
index 25e04db3..00000000
--- a/src/frontend/Util_Audio.cpp
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- Copyright 2016-2023 melonDS team
-
- This file is part of melonDS.
-
- melonDS is free software: you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free
- Software Foundation, either version 3 of the License, or (at your option)
- any later version.
-
- melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with melonDS. If not, see http://www.gnu.org/licenses/.
-*/
-
-#include
-#include
-#include
-#include
-
-#include "FrontendUtil.h"
-
-#include "NDS.h"
-
-#include "mic_blow.h"
-
-using namespace melonDS;
-
-namespace Frontend
-{
-
-int AudioOut_Freq;
-float AudioOut_SampleFrac;
-
-s16* MicBuffer;
-u32 MicBufferLength;
-u32 MicBufferReadPos;
-
-
-void Init_Audio(int outputfreq)
-{
- AudioOut_Freq = outputfreq;
- AudioOut_SampleFrac = 0;
-
- MicBuffer = nullptr;
- MicBufferLength = 0;
- MicBufferReadPos = 0;
-}
-
-
-int AudioOut_GetNumSamples(int outlen)
-{
- float f_len_in = (outlen * 32823.6328125) / (float)AudioOut_Freq;
- f_len_in += AudioOut_SampleFrac;
- int len_in = (int)floor(f_len_in);
- AudioOut_SampleFrac = f_len_in - len_in;
-
- return len_in;
-}
-
-void AudioOut_Resample(s16* inbuf, int inlen, s16* outbuf, int outlen, int volume)
-{
- double factor = (double) inlen / (double) outlen;
- double inpos = -(factor / 2);
- double vol = (double) volume / 256.f;
-
- for (int i = 0; i < outlen * 2; i += 2)
- {
- double intpart_d;
- double frac = modf(inpos, &intpart_d);
- int intpart = (int) intpart_d;
-
- double l1 = inbuf[ intpart * 2];
- double l2 = inbuf[(intpart * 2) + 2];
- double r1 = inbuf[(intpart * 2) + 1];
- double r2 = inbuf[(intpart * 2) + 3];
-
- double ldiff = l2 - l1;
- double rdiff = r2 - r1;
-
- outbuf[i] = (s16) round((l1 + ldiff * frac) * vol);
- outbuf[i+1] = (s16) round((r1 + rdiff * frac) * vol);
-
- inpos += factor;
- }
-}
-
-
-void Mic_FeedSilence(NDS& nds)
-{
- MicBufferReadPos = 0;
- nds.MicInputFrame(NULL, 0);
-}
-
-void Mic_FeedNoise(NDS& nds)
-{
- int sample_len = sizeof(mic_blow) / sizeof(u16);
- static int sample_pos = 0;
-
- s16 tmp[735];
-
- for (int i = 0; i < 735; i++)
- {
- tmp[i] = mic_blow[sample_pos];
- sample_pos++;
- if (sample_pos >= sample_len) sample_pos = 0;
- }
-
- nds.MicInputFrame(tmp, 735);
-}
-
-void Mic_FeedExternalBuffer(NDS& nds)
-{
- if (!MicBuffer) return Mic_FeedSilence(nds);
-
- if ((MicBufferReadPos + 735) > MicBufferLength)
- {
- s16 tmp[735];
- u32 len1 = MicBufferLength - MicBufferReadPos;
- memcpy(&tmp[0], &MicBuffer[MicBufferReadPos], len1*sizeof(s16));
- memcpy(&tmp[len1], &MicBuffer[0], (735 - len1)*sizeof(s16));
-
- nds.MicInputFrame(tmp, 735);
- MicBufferReadPos = 735 - len1;
- }
- else
- {
- nds.MicInputFrame(&MicBuffer[MicBufferReadPos], 735);
- MicBufferReadPos += 735;
- }
-}
-
-void Mic_SetExternalBuffer(s16* buffer, u32 len)
-{
- MicBuffer = buffer;
- MicBufferLength = len;
- MicBufferReadPos = 0;
-}
-
-}
diff --git a/src/frontend/libslirp/CMakeLists.txt b/src/frontend/libslirp/CMakeLists.txt
index cb009a6c..67b8ac78 100644
--- a/src/frontend/libslirp/CMakeLists.txt
+++ b/src/frontend/libslirp/CMakeLists.txt
@@ -62,4 +62,6 @@ elseif(HAIKU)
target_Link_libraries(slirp PRIVATE network)
elseif(APPLE)
target_link_libraries(slirp PRIVATE resolv)
+else()
+ set_source_files_properties(glib/glib.c PROPERTIES COMPILE_FLAGS -fvisibility=hidden)
endif()
diff --git a/src/frontend/mic_blow.h b/src/frontend/mic_blow.h
index f8dbc107..f90d8c8e 100644
--- a/src/frontend/mic_blow.h
+++ b/src/frontend/mic_blow.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/frontend/qt_sdl/ArchiveUtil.cpp b/src/frontend/qt_sdl/ArchiveUtil.cpp
index aa508e8d..f4155682 100644
--- a/src/frontend/qt_sdl/ArchiveUtil.cpp
+++ b/src/frontend/qt_sdl/ArchiveUtil.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/frontend/qt_sdl/ArchiveUtil.h b/src/frontend/qt_sdl/ArchiveUtil.h
index 246670e7..c422a84b 100644
--- a/src/frontend/qt_sdl/ArchiveUtil.h
+++ b/src/frontend/qt_sdl/ArchiveUtil.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
diff --git a/src/frontend/qt_sdl/AudioInOut.cpp b/src/frontend/qt_sdl/AudioInOut.cpp
deleted file mode 100644
index 1f1ee1c5..00000000
--- a/src/frontend/qt_sdl/AudioInOut.cpp
+++ /dev/null
@@ -1,390 +0,0 @@
-/*
- Copyright 2016-2023 melonDS team
-
- This file is part of melonDS.
-
- melonDS is free software: you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free
- Software Foundation, either version 3 of the License, or (at your option)
- any later version.
-
- melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with melonDS. If not, see http://www.gnu.org/licenses/.
-*/
-
-#include "AudioInOut.h"
-
-#include
-
-#include "FrontendUtil.h"
-#include "Config.h"
-#include "NDS.h"
-#include "SPU.h"
-#include "Platform.h"
-#include "Input.h"
-#include "main.h"
-
-using namespace melonDS;
-namespace AudioInOut
-{
-
-SDL_AudioDeviceID audioDevice;
-int audioFreq;
-bool audioMuted;
-SDL_cond* audioSync;
-SDL_mutex* audioSyncLock;
-
-SDL_AudioDeviceID micDevice;
-s16 micExtBuffer[2048];
-u32 micExtBufferWritePos;
-
-u32 micWavLength;
-s16* micWavBuffer;
-
-void AudioCallback(void* data, Uint8* stream, int len)
-{
- len /= (sizeof(s16) * 2);
-
- // resample incoming audio to match the output sample rate
-
- int len_in = Frontend::AudioOut_GetNumSamples(len);
- s16 buf_in[1024*2];
- int num_in;
-
- EmuThread* emuThread = (EmuThread*)data;
- SDL_LockMutex(audioSyncLock);
- num_in = emuThread->NDS->SPU.ReadOutput(buf_in, len_in);
- SDL_CondSignal(audioSync);
- SDL_UnlockMutex(audioSyncLock);
-
- if ((num_in < 1) || audioMuted)
- {
- memset(stream, 0, len*sizeof(s16)*2);
- return;
- }
-
- int margin = 6;
- if (num_in < len_in-margin)
- {
- int last = num_in-1;
-
- for (int i = num_in; i < len_in-margin; i++)
- ((u32*)buf_in)[i] = ((u32*)buf_in)[last];
-
- num_in = len_in-margin;
- }
-
- Frontend::AudioOut_Resample(buf_in, num_in, (s16*)stream, len, Config::AudioVolume);
-}
-
-void MicCallback(void* data, Uint8* stream, int len)
-{
- s16* input = (s16*)stream;
- len /= sizeof(s16);
-
- int maxlen = sizeof(micExtBuffer) / sizeof(s16);
-
- if ((micExtBufferWritePos + len) > maxlen)
- {
- u32 len1 = maxlen - micExtBufferWritePos;
- memcpy(&micExtBuffer[micExtBufferWritePos], &input[0], len1*sizeof(s16));
- memcpy(&micExtBuffer[0], &input[len1], (len - len1)*sizeof(s16));
- micExtBufferWritePos = len - len1;
- }
- else
- {
- memcpy(&micExtBuffer[micExtBufferWritePos], input, len*sizeof(s16));
- micExtBufferWritePos += len;
- }
-}
-
-void AudioMute(QMainWindow* mainWindow)
-{
- int inst = Platform::InstanceID();
- audioMuted = false;
-
- switch (Config::MPAudioMode)
- {
- case 1: // only instance 1
- if (inst > 0) audioMuted = true;
- break;
-
- case 2: // only currently focused instance
- if (mainWindow != nullptr)
- audioMuted = !mainWindow->isActiveWindow();
- break;
- }
-}
-
-
-void MicOpen()
-{
- if (Config::MicInputType != micInputType_External)
- {
- micDevice = 0;
- return;
- }
-
- int numMics = SDL_GetNumAudioDevices(1);
- if (numMics == 0)
- return;
-
- SDL_AudioSpec whatIwant, whatIget;
- memset(&whatIwant, 0, sizeof(SDL_AudioSpec));
- whatIwant.freq = 44100;
- whatIwant.format = AUDIO_S16LSB;
- whatIwant.channels = 1;
- whatIwant.samples = 1024;
- whatIwant.callback = MicCallback;
- const char* mic = NULL;
- if (Config::MicDevice != "")
- {
- mic = Config::MicDevice.c_str();
- }
- micDevice = SDL_OpenAudioDevice(mic, 1, &whatIwant, &whatIget, 0);
- if (!micDevice)
- {
- Platform::Log(Platform::LogLevel::Error, "Mic init failed: %s\n", SDL_GetError());
- }
- else
- {
- SDL_PauseAudioDevice(micDevice, 0);
- }
-}
-
-void MicClose()
-{
- if (micDevice)
- SDL_CloseAudioDevice(micDevice);
-
- micDevice = 0;
-}
-
-void MicLoadWav(const std::string& name)
-{
- SDL_AudioSpec format;
- memset(&format, 0, sizeof(SDL_AudioSpec));
-
- if (micWavBuffer) delete[] micWavBuffer;
- micWavBuffer = nullptr;
- micWavLength = 0;
-
- u8* buf;
- u32 len;
- if (!SDL_LoadWAV(name.c_str(), &format, &buf, &len))
- return;
-
- const u64 dstfreq = 44100;
-
- int srcinc = format.channels;
- len /= ((SDL_AUDIO_BITSIZE(format.format) / 8) * srcinc);
-
- micWavLength = (len * dstfreq) / format.freq;
- if (micWavLength < 735) micWavLength = 735;
- micWavBuffer = new s16[micWavLength];
-
- float res_incr = len / (float)micWavLength;
- float res_timer = 0;
- int res_pos = 0;
-
- for (int i = 0; i < micWavLength; i++)
- {
- u16 val = 0;
-
- switch (SDL_AUDIO_BITSIZE(format.format))
- {
- case 8:
- val = buf[res_pos] << 8;
- break;
-
- case 16:
- if (SDL_AUDIO_ISBIGENDIAN(format.format))
- val = (buf[res_pos*2] << 8) | buf[res_pos*2 + 1];
- else
- val = (buf[res_pos*2 + 1] << 8) | buf[res_pos*2];
- break;
-
- case 32:
- if (SDL_AUDIO_ISFLOAT(format.format))
- {
- u32 rawval;
- if (SDL_AUDIO_ISBIGENDIAN(format.format))
- rawval = (buf[res_pos*4] << 24) | (buf[res_pos*4 + 1] << 16) | (buf[res_pos*4 + 2] << 8) | buf[res_pos*4 + 3];
- else
- rawval = (buf[res_pos*4 + 3] << 24) | (buf[res_pos*4 + 2] << 16) | (buf[res_pos*4 + 1] << 8) | buf[res_pos*4];
-
- float fval = *(float*)&rawval;
- s32 ival = (s32)(fval * 0x8000);
- ival = std::clamp(ival, -0x8000, 0x7FFF);
- val = (s16)ival;
- }
- else if (SDL_AUDIO_ISBIGENDIAN(format.format))
- val = (buf[res_pos*4] << 8) | buf[res_pos*4 + 1];
- else
- val = (buf[res_pos*4 + 3] << 8) | buf[res_pos*4 + 2];
- break;
- }
-
- if (SDL_AUDIO_ISUNSIGNED(format.format))
- val ^= 0x8000;
-
- micWavBuffer[i] = val;
-
- res_timer += res_incr;
- while (res_timer >= 1.0)
- {
- res_timer -= 1.0;
- res_pos += srcinc;
- }
- }
-
- SDL_FreeWAV(buf);
-}
-
-void MicProcess(melonDS::NDS& nds)
-{
- int type = Config::MicInputType;
- bool cmd = Input::HotkeyDown(HK_Mic);
-
- if (type != micInputType_External && !cmd)
- {
- type = micInputType_Silence;
- }
-
- switch (type)
- {
- case micInputType_Silence: // no mic
- Frontend::Mic_FeedSilence(nds);
- break;
-
- case micInputType_External: // host mic
- case micInputType_Wav: // WAV
- Frontend::Mic_FeedExternalBuffer(nds);
- break;
-
- case micInputType_Noise: // blowing noise
- Frontend::Mic_FeedNoise(nds);
- break;
- }
-}
-
-void SetupMicInputData()
-{
- if (micWavBuffer != nullptr)
- {
- delete[] micWavBuffer;
- micWavBuffer = nullptr;
- micWavLength = 0;
- }
-
- switch (Config::MicInputType)
- {
- case micInputType_Silence:
- case micInputType_Noise:
- Frontend::Mic_SetExternalBuffer(NULL, 0);
- break;
- case micInputType_External:
- Frontend::Mic_SetExternalBuffer(micExtBuffer, sizeof(micExtBuffer)/sizeof(s16));
- break;
- case micInputType_Wav:
- MicLoadWav(Config::MicWavPath);
- Frontend::Mic_SetExternalBuffer(micWavBuffer, micWavLength);
- break;
- }
-}
-
-void Init(EmuThread* thread)
-{
- audioMuted = false;
- audioSync = SDL_CreateCond();
- audioSyncLock = SDL_CreateMutex();
-
- audioFreq = 48000; // TODO: make configurable?
- SDL_AudioSpec whatIwant, whatIget;
- memset(&whatIwant, 0, sizeof(SDL_AudioSpec));
- whatIwant.freq = audioFreq;
- whatIwant.format = AUDIO_S16LSB;
- whatIwant.channels = 2;
- whatIwant.samples = 1024;
- whatIwant.callback = AudioCallback;
- whatIwant.userdata = thread;
- audioDevice = SDL_OpenAudioDevice(NULL, 0, &whatIwant, &whatIget, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE);
- if (!audioDevice)
- {
- Platform::Log(Platform::LogLevel::Error, "Audio init failed: %s\n", SDL_GetError());
- }
- else
- {
- audioFreq = whatIget.freq;
- Platform::Log(Platform::LogLevel::Info, "Audio output frequency: %d Hz\n", audioFreq);
- SDL_PauseAudioDevice(audioDevice, 1);
- }
-
- micDevice = 0;
-
- memset(micExtBuffer, 0, sizeof(micExtBuffer));
- micExtBufferWritePos = 0;
- micWavBuffer = nullptr;
-
- Frontend::Init_Audio(audioFreq);
-
- SetupMicInputData();
-}
-
-void DeInit()
-{
- if (audioDevice) SDL_CloseAudioDevice(audioDevice);
- audioDevice = 0;
- MicClose();
-
- if (audioSync) SDL_DestroyCond(audioSync);
- audioSync = nullptr;
-
- if (audioSyncLock) SDL_DestroyMutex(audioSyncLock);
- audioSyncLock = nullptr;
-
- if (micWavBuffer) delete[] micWavBuffer;
- micWavBuffer = nullptr;
-}
-
-void AudioSync(NDS& nds)
-{
- if (audioDevice)
- {
- SDL_LockMutex(audioSyncLock);
- while (nds.SPU.GetOutputSize() > 1024)
- {
- int ret = SDL_CondWaitTimeout(audioSync, audioSyncLock, 500);
- if (ret == SDL_MUTEX_TIMEDOUT) break;
- }
- SDL_UnlockMutex(audioSyncLock);
- }
-}
-
-void UpdateSettings(NDS& nds)
-{
- MicClose();
-
- nds.SPU.SetInterpolation(static_cast(Config::AudioInterp));
- SetupMicInputData();
-
- MicOpen();
-}
-
-void Enable()
-{
- if (audioDevice) SDL_PauseAudioDevice(audioDevice, 0);
- MicOpen();
-}
-
-void Disable()
-{
- if (audioDevice) SDL_PauseAudioDevice(audioDevice, 1);
- MicClose();
-}
-
-}
diff --git a/src/frontend/qt_sdl/AudioSettingsDialog.cpp b/src/frontend/qt_sdl/AudioSettingsDialog.cpp
index 8e08ef2b..1ca5c1ce 100644
--- a/src/frontend/qt_sdl/AudioSettingsDialog.cpp
+++ b/src/frontend/qt_sdl/AudioSettingsDialog.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
@@ -16,7 +16,6 @@
with melonDS. If not, see http://www.gnu.org/licenses/.
*/
-#include
#include
#include
@@ -25,7 +24,6 @@
#include "Config.h"
#include "NDS.h"
#include "DSi.h"
-#include "DSi_I2C.h"
#include "AudioSettingsDialog.h"
#include "ui_AudioSettingsDialog.h"
@@ -34,47 +32,56 @@
using namespace melonDS;
AudioSettingsDialog* AudioSettingsDialog::currentDlg = nullptr;
-extern std::string EmuDirectory;
-
-AudioSettingsDialog::AudioSettingsDialog(QWidget* parent, bool emuActive, EmuThread* emuThread) : QDialog(parent), ui(new Ui::AudioSettingsDialog), emuThread(emuThread)
+AudioSettingsDialog::AudioSettingsDialog(QWidget* parent) : QDialog(parent), ui(new Ui::AudioSettingsDialog)
{
ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose);
- oldInterp = Config::AudioInterp;
- oldBitDepth = Config::AudioBitDepth;
- oldVolume = Config::AudioVolume;
- oldDSiSync = Config::DSiVolumeSync;
+ emuInstance = ((MainWindow*)parent)->getEmuInstance();
+ auto& cfg = emuInstance->getGlobalConfig();
+ auto& instcfg = emuInstance->getLocalConfig();
+ bool emuActive = emuInstance->getEmuThread()->emuIsActive();
+
+ oldInterp = cfg.GetInt("Audio.Interpolation");
+ oldBitDepth = cfg.GetInt("Audio.BitDepth");
+ oldVolume = instcfg.GetInt("Audio.Volume");
+ oldDSiSync = instcfg.GetBool("Audio.DSiVolumeSync");
+
+ volume = oldVolume;
+ dsiSync = oldDSiSync;
ui->cbInterpolation->addItem("None");
ui->cbInterpolation->addItem("Linear");
ui->cbInterpolation->addItem("Cosine");
ui->cbInterpolation->addItem("Cubic");
ui->cbInterpolation->addItem("Gaussian (SNES)");
- ui->cbInterpolation->setCurrentIndex(Config::AudioInterp);
+ ui->cbInterpolation->setCurrentIndex(oldInterp);
ui->cbBitDepth->addItem("Automatic");
ui->cbBitDepth->addItem("10-bit");
ui->cbBitDepth->addItem("16-bit");
- ui->cbBitDepth->setCurrentIndex(Config::AudioBitDepth);
+ ui->cbBitDepth->setCurrentIndex(oldBitDepth);
bool state = ui->slVolume->blockSignals(true);
- ui->slVolume->setValue(Config::AudioVolume);
+ ui->slVolume->setValue(oldVolume);
ui->slVolume->blockSignals(state);
- ui->chkSyncDSiVolume->setChecked(Config::DSiVolumeSync);
+ ui->chkSyncDSiVolume->setChecked(oldDSiSync);
// Setup volume slider accordingly
- if (emuActive && emuThread->NDS->ConsoleType == 1)
+ if (emuActive && emuInstance->getNDS()->ConsoleType == 1)
{
- on_chkSyncDSiVolume_clicked(Config::DSiVolumeSync);
+ on_chkSyncDSiVolume_clicked(oldDSiSync);
}
else
{
ui->chkSyncDSiVolume->setEnabled(false);
}
- bool isext = (Config::MicInputType == 1);
+
+ int mictype = cfg.GetInt("Mic.InputType");
+
+ bool isext = (mictype == micInputType_External);
ui->cbMic->setEnabled(isext);
const int count = SDL_GetNumAudioDevices(true);
@@ -82,12 +89,14 @@ AudioSettingsDialog::AudioSettingsDialog(QWidget* parent, bool emuActive, EmuThr
{
ui->cbMic->addItem(SDL_GetAudioDeviceName(i, true));
}
- if (Config::MicDevice == "" && count > 0)
+
+ QString micdev = cfg.GetQString("Mic.Device");
+ if (micdev == "" && count > 0)
{
- Config::MicDevice = SDL_GetAudioDeviceName(0, true);
+ micdev = SDL_GetAudioDeviceName(0, true);
}
- ui->cbMic->setCurrentText(QString::fromStdString(Config::MicDevice));
+ ui->cbMic->setCurrentText(micdev);
grpMicMode = new QButtonGroup(this);
grpMicMode->addButton(ui->rbMicNone, micInputType_Silence);
@@ -95,15 +104,15 @@ AudioSettingsDialog::AudioSettingsDialog(QWidget* parent, bool emuActive, EmuThr
grpMicMode->addButton(ui->rbMicNoise, micInputType_Noise);
grpMicMode->addButton(ui->rbMicWav, micInputType_Wav);
connect(grpMicMode, SIGNAL(buttonClicked(int)), this, SLOT(onChangeMicMode(int)));
- grpMicMode->button(Config::MicInputType)->setChecked(true);
+ grpMicMode->button(mictype)->setChecked(true);
- ui->txtMicWavPath->setText(QString::fromStdString(Config::MicWavPath));
+ ui->txtMicWavPath->setText(cfg.GetQString("Mic.WavPath"));
- bool iswav = (Config::MicInputType == micInputType_Wav);
+ bool iswav = (mictype == micInputType_Wav);
ui->txtMicWavPath->setEnabled(iswav);
ui->btnMicWavBrowse->setEnabled(iswav);
- int inst = Platform::InstanceID();
+ int inst = emuInstance->getInstanceID();
if (inst > 0)
{
ui->lblInstanceNum->setText(QString("Configuring settings for instance %1").arg(inst+1));
@@ -126,26 +135,30 @@ AudioSettingsDialog::~AudioSettingsDialog()
void AudioSettingsDialog::onSyncVolumeLevel()
{
- if (Config::DSiVolumeSync && emuThread->NDS->ConsoleType == 1)
+ if (dsiSync && emuInstance->getNDS()->ConsoleType == 1)
{
- auto& dsi = static_cast(*emuThread->NDS);
+ auto dsi = static_cast(emuInstance->getNDS());
+ volume = dsi->I2C.GetBPTWL()->GetVolumeLevel();
+
bool state = ui->slVolume->blockSignals(true);
- ui->slVolume->setValue(dsi.I2C.GetBPTWL()->GetVolumeLevel());
+ ui->slVolume->setValue(volume);
ui->slVolume->blockSignals(state);
}
}
void AudioSettingsDialog::onConsoleReset()
{
- on_chkSyncDSiVolume_clicked(Config::DSiVolumeSync);
- ui->chkSyncDSiVolume->setEnabled(emuThread->NDS->ConsoleType == 1);
+ on_chkSyncDSiVolume_clicked(dsiSync);
+ ui->chkSyncDSiVolume->setEnabled(emuInstance->getNDS()->ConsoleType == 1);
}
void AudioSettingsDialog::on_AudioSettingsDialog_accepted()
{
- Config::MicDevice = ui->cbMic->currentText().toStdString();
- Config::MicInputType = grpMicMode->checkedId();
- Config::MicWavPath = ui->txtMicWavPath->text().toStdString();
+ auto& cfg = emuInstance->getGlobalConfig();
+ cfg.SetQString("Mic.Device", ui->cbMic->currentText());
+ cfg.SetInt("Mic.InputType", grpMicMode->checkedId());
+ cfg.SetQString("Mic.WavPath", ui->txtMicWavPath->text());
+
Config::Save();
closeDlg();
@@ -153,10 +166,15 @@ void AudioSettingsDialog::on_AudioSettingsDialog_accepted()
void AudioSettingsDialog::on_AudioSettingsDialog_rejected()
{
- Config::AudioInterp = oldInterp;
- Config::AudioBitDepth = oldBitDepth;
- Config::AudioVolume = oldVolume;
- Config::DSiVolumeSync = oldDSiSync;
+ auto& cfg = emuInstance->getGlobalConfig();
+ auto& instcfg = emuInstance->getLocalConfig();
+ cfg.SetInt("Audio.Interpolation", oldInterp);
+ cfg.SetInt("Audio.BitDepth", oldBitDepth);
+ instcfg.SetInt("Audio.Volume", oldVolume);
+ instcfg.SetBool("Audio.DSiVolumeSync", oldDSiSync);
+
+ emit updateAudioVolume(oldVolume, oldDSiSync);
+ emit updateAudioSettings();
closeDlg();
}
@@ -166,7 +184,8 @@ void AudioSettingsDialog::on_cbBitDepth_currentIndexChanged(int idx)
// prevent a spurious change
if (ui->cbBitDepth->count() < 3) return;
- Config::AudioBitDepth = ui->cbBitDepth->currentIndex();
+ auto& cfg = emuInstance->getGlobalConfig();
+ cfg.SetInt("Audio.BitDepth", ui->cbBitDepth->currentIndex());
emit updateAudioSettings();
}
@@ -176,45 +195,56 @@ void AudioSettingsDialog::on_cbInterpolation_currentIndexChanged(int idx)
// prevent a spurious change
if (ui->cbInterpolation->count() < 5) return;
- Config::AudioInterp = ui->cbInterpolation->currentIndex();
+ auto& cfg = emuInstance->getGlobalConfig();
+ cfg.SetInt("Audio.Interpolation", ui->cbInterpolation->currentIndex());
emit updateAudioSettings();
}
void AudioSettingsDialog::on_slVolume_valueChanged(int val)
{
- if (Config::DSiVolumeSync && emuThread->NDS->ConsoleType == 1)
+ auto& cfg = emuInstance->getLocalConfig();
+
+ if (dsiSync && emuInstance->getNDS()->ConsoleType == 1)
{
- auto& dsi = static_cast(*emuThread->NDS);
- dsi.I2C.GetBPTWL()->SetVolumeLevel(val);
+ auto dsi = static_cast(emuInstance->getNDS());
+ dsi->I2C.GetBPTWL()->SetVolumeLevel(val);
return;
}
- Config::AudioVolume = val;
+ volume = val;
+ cfg.SetInt("Audio.Volume", val);
+ emit updateAudioVolume(val, dsiSync);
}
void AudioSettingsDialog::on_chkSyncDSiVolume_clicked(bool checked)
{
- Config::DSiVolumeSync = checked;
+ dsiSync = checked;
+
+ auto& cfg = emuInstance->getLocalConfig();
+ cfg.SetBool("Audio.DSiVolumeSync", dsiSync);
bool state = ui->slVolume->blockSignals(true);
- if (Config::DSiVolumeSync && emuThread->NDS->ConsoleType == 1)
+ if (dsiSync && emuInstance->getNDS()->ConsoleType == 1)
{
- auto& dsi = static_cast(*emuThread->NDS);
+ auto dsi = static_cast(emuInstance->getNDS());
ui->slVolume->setMaximum(31);
- ui->slVolume->setValue(dsi.I2C.GetBPTWL()->GetVolumeLevel());
+ ui->slVolume->setValue(dsi->I2C.GetBPTWL()->GetVolumeLevel());
ui->slVolume->setPageStep(4);
ui->slVolume->setTickPosition(QSlider::TicksBelow);
}
else
{
- Config::AudioVolume = oldVolume;
+ volume = oldVolume;
+ cfg.SetInt("Audio.Volume", oldVolume);
ui->slVolume->setMaximum(256);
- ui->slVolume->setValue(Config::AudioVolume);
+ ui->slVolume->setValue(oldVolume);
ui->slVolume->setPageStep(16);
ui->slVolume->setTickPosition(QSlider::NoTicks);
}
ui->slVolume->blockSignals(state);
+
+ emit updateAudioVolume(volume, dsiSync);
}
void AudioSettingsDialog::onChangeMicMode(int mode)
@@ -230,7 +260,7 @@ void AudioSettingsDialog::on_btnMicWavBrowse_clicked()
{
QString file = QFileDialog::getOpenFileName(this,
"Select WAV file...",
- QString::fromStdString(EmuDirectory),
+ emuDirectory,
"WAV files (*.wav);;Any file (*.*)");
if (file.isEmpty()) return;
diff --git a/src/frontend/qt_sdl/AudioSettingsDialog.h b/src/frontend/qt_sdl/AudioSettingsDialog.h
index ced9bae9..f05cd8dd 100644
--- a/src/frontend/qt_sdl/AudioSettingsDialog.h
+++ b/src/frontend/qt_sdl/AudioSettingsDialog.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
@@ -24,18 +24,19 @@
namespace Ui { class AudioSettingsDialog; }
class AudioSettingsDialog;
-class EmuThread;
+
+class EmuInstance;
class AudioSettingsDialog : public QDialog
{
Q_OBJECT
public:
- explicit AudioSettingsDialog(QWidget* parent, bool emuActive, EmuThread* emuThread);
+ explicit AudioSettingsDialog(QWidget* parent);
~AudioSettingsDialog();
static AudioSettingsDialog* currentDlg;
- static AudioSettingsDialog* openDlg(QWidget* parent, bool emuActive, EmuThread* emuThread)
+ static AudioSettingsDialog* openDlg(QWidget* parent)
{
if (currentDlg)
{
@@ -43,7 +44,7 @@ public:
return currentDlg;
}
- currentDlg = new AudioSettingsDialog(parent, emuActive, emuThread);
+ currentDlg = new AudioSettingsDialog(parent);
currentDlg->show();
return currentDlg;
}
@@ -56,6 +57,7 @@ public:
void onConsoleReset();
signals:
+ void updateAudioVolume(int vol, bool dsisync);
void updateAudioSettings();
private slots:
@@ -70,14 +72,18 @@ private slots:
void on_btnMicWavBrowse_clicked();
private:
- EmuThread* emuThread;
Ui::AudioSettingsDialog* ui;
+ EmuInstance* emuInstance;
+
int oldInterp;
int oldBitDepth;
int oldVolume;
bool oldDSiSync;
QButtonGroup* grpMicMode;
+
+ int volume;
+ bool dsiSync;
};
#endif // AUDIOSETTINGSDIALOG_H
diff --git a/src/frontend/qt_sdl/CMakeLists.txt b/src/frontend/qt_sdl/CMakeLists.txt
index 60962328..f4e1f6e8 100644
--- a/src/frontend/qt_sdl/CMakeLists.txt
+++ b/src/frontend/qt_sdl/CMakeLists.txt
@@ -7,6 +7,9 @@ set(SOURCES_QT_SDL
main_shaders.h
Screen.cpp
Window.cpp
+ EmuInstance.cpp
+ EmuInstanceAudio.cpp
+ EmuInstanceInput.cpp
EmuThread.cpp
CheatsDialog.cpp
Config.cpp
@@ -28,25 +31,22 @@ set(SOURCES_QT_SDL
ROMInfoDialog.cpp
RAMInfoDialog.cpp
TitleManagerDialog.cpp
- Input.cpp
- LAN_PCap.cpp
- LAN_Socket.cpp
+ PacketDispatcher.cpp
+ Net.cpp
+ Net_PCap.cpp
+ Net_Slirp.cpp
LocalMP.cpp
OSD_shaders.h
font.h
Platform.cpp
QPathInput.h
- ROMManager.cpp
SaveManager.cpp
CameraManager.cpp
- AudioInOut.cpp
ArchiveUtil.h
ArchiveUtil.cpp
- ../Util_Video.cpp
- ../Util_Audio.cpp
- ../FrontendUtil.h
+ ../ScreenLayout.cpp
../mic_blow.h
../glad/glad.c
diff --git a/src/frontend/qt_sdl/CameraManager.cpp b/src/frontend/qt_sdl/CameraManager.cpp
index cc575d2c..2306da84 100644
--- a/src/frontend/qt_sdl/CameraManager.cpp
+++ b/src/frontend/qt_sdl/CameraManager.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
@@ -23,6 +23,8 @@
using namespace melonDS;
+const char* kCamConfigPath[] = {"DSi.Camera0", "DSi.Camera1"};
+
#if QT_VERSION >= 0x060000
CameraFrameDumper::CameraFrameDumper(QObject* parent) : QVideoSink(parent)
@@ -116,10 +118,11 @@ QList CameraFrameDumper::supportedPixelFormats(QAbstra
#endif
-CameraManager::CameraManager(int num, int width, int height, bool yuv) : QObject()
+CameraManager::CameraManager(int num, int width, int height, bool yuv)
+ : QObject(),
+ num(num),
+ config(Config::GetGlobalTable().GetTable(kCamConfigPath[num]))
{
- this->num = num;
-
startNum = 0;
// QCamera needs to be controlled from the UI thread, hence this
@@ -136,7 +139,7 @@ CameraManager::CameraManager(int num, int width, int height, bool yuv) : QObject
tempFrameBuffer = new u32[fbsize];
inputType = -1;
- xFlip = false;
+ xFlip = config.GetBool("XFlip");
init();
}
@@ -157,9 +160,9 @@ void CameraManager::init()
startNum = 0;
- inputType = Config::Camera[num].InputType;
- imagePath = QString::fromStdString(Config::Camera[num].ImagePath);
- camDeviceName = QString::fromStdString(Config::Camera[num].CamDeviceName);
+ inputType = config.GetInt("InputType");
+ imagePath = config.GetQString("ImagePath");
+ camDeviceName = config.GetQString("DeviceName");
camDevice = nullptr;
diff --git a/src/frontend/qt_sdl/CameraManager.h b/src/frontend/qt_sdl/CameraManager.h
index 882b051a..806a8ba7 100644
--- a/src/frontend/qt_sdl/CameraManager.h
+++ b/src/frontend/qt_sdl/CameraManager.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
@@ -33,6 +33,7 @@
#include
#include "types.h"
+#include "Config.h"
class CameraManager;
@@ -80,6 +81,8 @@ public:
CameraManager(int num, int width, int height, bool yuv);
~CameraManager();
+ Config::Table& getConfig() { return config; }
+
void init();
void deInit();
@@ -106,6 +109,8 @@ private slots:
private:
int num;
+ Config::Table config;
+
int startNum;
int inputType;
diff --git a/src/frontend/qt_sdl/CameraSettingsDialog.cpp b/src/frontend/qt_sdl/CameraSettingsDialog.cpp
index cf404173..39c05cef 100644
--- a/src/frontend/qt_sdl/CameraSettingsDialog.cpp
+++ b/src/frontend/qt_sdl/CameraSettingsDialog.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
@@ -22,6 +22,7 @@
#include
#include "types.h"
+#include "main.h"
#include "CameraSettingsDialog.h"
#include "ui_CameraSettingsDialog.h"
@@ -30,8 +31,6 @@ using namespace melonDS;
CameraSettingsDialog* CameraSettingsDialog::currentDlg = nullptr;
-extern std::string EmuDirectory;
-
extern CameraManager* camManager[2];
@@ -71,9 +70,16 @@ CameraSettingsDialog::CameraSettingsDialog(QWidget* parent) : QDialog(parent), u
ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose);
+ emuInstance = ((MainWindow*)parent)->getEmuInstance();
+
for (int i = 0; i < 2; i++)
{
- oldCamSettings[i] = Config::Camera[i];
+ auto& cfg = camManager[i]->getConfig();
+
+ oldCamSettings[i].InputType = cfg.GetInt("InputType");
+ oldCamSettings[i].ImagePath = cfg.GetString("ImagePath");
+ oldCamSettings[i].CamDeviceName = cfg.GetString("DeviceName");
+ oldCamSettings[i].XFlip = cfg.GetBool("XFlip");
}
ui->cbCameraSel->addItem("DSi outer camera");
@@ -161,7 +167,13 @@ void CameraSettingsDialog::on_CameraSettingsDialog_rejected()
{
camManager[i]->stop();
camManager[i]->deInit();
- Config::Camera[i] = oldCamSettings[i];
+
+ auto& cfg = camManager[i]->getConfig();
+ cfg.SetInt("InputType", oldCamSettings[i].InputType);
+ cfg.SetString("ImagePath", oldCamSettings[i].ImagePath);
+ cfg.SetString("DeviceName", oldCamSettings[i].CamDeviceName);
+ cfg.SetBool("XFlip", oldCamSettings[i].XFlip);
+
camManager[i]->init();
}
@@ -178,7 +190,7 @@ void CameraSettingsDialog::on_cbCameraSel_currentIndexChanged(int id)
}
currentId = id;
- currentCfg = &Config::Camera[id];
+ currentCfg = &camManager[id]->getConfig();
//currentCam = camManager[id];
currentCam = nullptr;
populateCamControls(id);
@@ -198,16 +210,16 @@ void CameraSettingsDialog::onChangeInputType(int type)
currentCam->deInit();
}
- currentCfg->InputType = type;
+ currentCfg->SetInt("InputType", type);
ui->txtSrcImagePath->setEnabled(type == 1);
ui->btnSrcImageBrowse->setEnabled(type == 1);
ui->cbPhysicalCamera->setEnabled((type == 2) && (ui->cbPhysicalCamera->count()>0));
- currentCfg->ImagePath = ui->txtSrcImagePath->text().toStdString();
+ currentCfg->SetQString("ImagePath", ui->txtSrcImagePath->text());
if (ui->cbPhysicalCamera->count() > 0)
- currentCfg->CamDeviceName = ui->cbPhysicalCamera->currentData().toString().toStdString();
+ currentCfg->SetQString("DeviceName", ui->cbPhysicalCamera->currentData().toString());
if (currentCam)
{
@@ -226,7 +238,7 @@ void CameraSettingsDialog::on_txtSrcImagePath_textChanged()
currentCam->deInit();
}
- currentCfg->ImagePath = ui->txtSrcImagePath->text().toStdString();
+ currentCfg->SetQString("ImagePath", ui->txtSrcImagePath->text());
if (currentCam)
{
@@ -239,7 +251,7 @@ void CameraSettingsDialog::on_btnSrcImageBrowse_clicked()
{
QString file = QFileDialog::getOpenFileName(this,
"Select image file...",
- QString::fromStdString(EmuDirectory),
+ emuDirectory,
"Image files (*.png *.jpg *.jpeg *.bmp);;Any file (*.*)");
if (file.isEmpty()) return;
@@ -257,7 +269,7 @@ void CameraSettingsDialog::on_cbPhysicalCamera_currentIndexChanged(int id)
currentCam->deInit();
}
- currentCfg->CamDeviceName = ui->cbPhysicalCamera->itemData(id).toString().toStdString();
+ currentCfg->SetQString("DeviceName", ui->cbPhysicalCamera->itemData(id).toString());
if (currentCam)
{
@@ -268,16 +280,16 @@ void CameraSettingsDialog::on_cbPhysicalCamera_currentIndexChanged(int id)
void CameraSettingsDialog::populateCamControls(int id)
{
- Config::CameraConfig& cfg = Config::Camera[id];
+ Config::Table& cfg = camManager[id]->getConfig();
- int type = cfg.InputType;
+ int type = cfg.GetInt("InputType");
if (type < 0 || type >= grpInputType->buttons().count()) type = 0;
grpInputType->button(type)->setChecked(true);
- ui->txtSrcImagePath->setText(QString::fromStdString(cfg.ImagePath));
+ ui->txtSrcImagePath->setText(cfg.GetQString("ImagePath"));
bool deviceset = false;
- QString device = QString::fromStdString(cfg.CamDeviceName);
+ QString device = cfg.GetQString("DeviceName");
for (int i = 0; i < ui->cbPhysicalCamera->count(); i++)
{
QString itemdev = ui->cbPhysicalCamera->itemData(i).toString();
@@ -293,13 +305,14 @@ void CameraSettingsDialog::populateCamControls(int id)
onChangeInputType(type);
- ui->chkFlipPicture->setChecked(cfg.XFlip);
+ ui->chkFlipPicture->setChecked(cfg.GetBool("XFlip"));
}
void CameraSettingsDialog::on_chkFlipPicture_clicked()
{
if (!currentCfg) return;
- currentCfg->XFlip = ui->chkFlipPicture->isChecked();
- if (currentCam) currentCam->setXFlip(currentCfg->XFlip);
+ bool xflip = ui->chkFlipPicture->isChecked();
+ currentCfg->SetBool("XFlip", xflip);
+ if (currentCam) currentCam->setXFlip(xflip);
}
diff --git a/src/frontend/qt_sdl/CameraSettingsDialog.h b/src/frontend/qt_sdl/CameraSettingsDialog.h
index a740193a..41caaf63 100644
--- a/src/frontend/qt_sdl/CameraSettingsDialog.h
+++ b/src/frontend/qt_sdl/CameraSettingsDialog.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
@@ -28,6 +28,8 @@
namespace Ui { class CameraSettingsDialog; }
class CameraSettingsDialog;
+class EmuInstance;
+
class CameraPreviewPanel : public QWidget
{
Q_OBJECT
@@ -92,15 +94,22 @@ private slots:
private:
Ui::CameraSettingsDialog* ui;
+ EmuInstance* emuInstance;
QButtonGroup* grpInputType;
CameraPreviewPanel* previewPanel;
int currentId;
- Config::CameraConfig* currentCfg;
+ Config::Table* currentCfg;
CameraManager* currentCam;
- Config::CameraConfig oldCamSettings[2];
+ struct
+ {
+ int InputType; // 0=blank 1=image 2=camera
+ std::string ImagePath;
+ std::string CamDeviceName;
+ bool XFlip;
+ } oldCamSettings[2];
void populateCamControls(int id);
};
diff --git a/src/frontend/qt_sdl/CheatsDialog.cpp b/src/frontend/qt_sdl/CheatsDialog.cpp
index df687230..19065a8d 100644
--- a/src/frontend/qt_sdl/CheatsDialog.cpp
+++ b/src/frontend/qt_sdl/CheatsDialog.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
@@ -24,7 +24,7 @@
#include "types.h"
#include "Platform.h"
#include "Config.h"
-#include "ROMManager.h"
+#include "EmuInstance.h"
#include "CheatsDialog.h"
#include "ui_CheatsDialog.h"
@@ -35,15 +35,15 @@ using Platform::LogLevel;
CheatsDialog* CheatsDialog::currentDlg = nullptr;
-extern std::string EmuDirectory;
-
CheatsDialog::CheatsDialog(QWidget* parent) : QDialog(parent), ui(new Ui::CheatsDialog)
{
ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose);
- codeFile = ROMManager::GetCheatFile();
+ emuInstance = ((MainWindow*)parent)->getEmuInstance();
+
+ codeFile = emuInstance->getCheatFile();
QStandardItemModel* model = new QStandardItemModel();
ui->tvCodeList->setModel(model);
diff --git a/src/frontend/qt_sdl/CheatsDialog.h b/src/frontend/qt_sdl/CheatsDialog.h
index ab2ac309..cafb9684 100644
--- a/src/frontend/qt_sdl/CheatsDialog.h
+++ b/src/frontend/qt_sdl/CheatsDialog.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
@@ -33,6 +33,8 @@ Q_DECLARE_METATYPE(melonDS::ARCodeCatList::iterator)
namespace Ui { class CheatsDialog; }
class CheatsDialog;
+class EmuInstance;
+
class ARCodeChecker : public QSyntaxHighlighter
{
Q_OBJECT
@@ -87,6 +89,8 @@ private slots:
private:
Ui::CheatsDialog* ui;
+ EmuInstance* emuInstance;
+
melonDS::ARCodeFile* codeFile;
ARCodeChecker* codeChecker;
};
diff --git a/src/frontend/qt_sdl/Config.cpp b/src/frontend/qt_sdl/Config.cpp
index d6d01825..98749175 100644
--- a/src/frontend/qt_sdl/Config.cpp
+++ b/src/frontend/qt_sdl/Config.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
@@ -20,387 +20,632 @@
#include
#include
#include
+#include
+#include
+#include
+#include "toml/toml.hpp"
+
#include "Platform.h"
#include "Config.h"
-#include "GPU.h"
+#include "ScreenLayout.h"
+#include "main.h"
+
+using namespace std::string_literals;
namespace Config
{
using namespace melonDS;
-int KeyMapping[12];
-int JoyMapping[12];
-int HKKeyMapping[HK_MAX];
-int HKJoyMapping[HK_MAX];
+const char* kConfigFile = "melonDS.toml";
-int JoystickID;
+const char* kLegacyConfigFile = "melonDS.ini";
+const char* kLegacyUniqueConfigFile = "melonDS.%d.ini";
-int WindowWidth;
-int WindowHeight;
-bool WindowMaximized;
+toml::value RootTable;
-int ScreenRotation;
-int ScreenGap;
-int ScreenLayout;
-bool ScreenSwap;
-int ScreenSizing;
-bool IntegerScaling;
-int ScreenAspectTop;
-int ScreenAspectBot;
-bool ScreenFilter;
-
-bool ScreenUseGL;
-bool ScreenVSync;
-int ScreenVSyncInterval;
-
-int _3DRenderer;
-bool Threaded3D;
-
-int GL_ScaleFactor;
-bool GL_BetterPolygons;
-bool GL_HiresCoordinates;
-
-bool LimitFPS;
-int MaxFPS;
-bool AudioSync;
-bool ShowOSD;
-
-int ConsoleType;
-bool DirectBoot;
-
-#ifdef JIT_ENABLED
-bool JIT_Enable = false;
-int JIT_MaxBlockSize = 32;
-bool JIT_BranchOptimisations = true;
-bool JIT_LiteralOptimisations = true;
-bool JIT_FastMemory = true;
-#endif
-
-bool ExternalBIOSEnable;
-
-std::string BIOS9Path;
-std::string BIOS7Path;
-std::string FirmwarePath;
-
-std::string DSiBIOS9Path;
-std::string DSiBIOS7Path;
-std::string DSiFirmwarePath;
-std::string DSiNANDPath;
-
-bool DLDIEnable;
-std::string DLDISDPath;
-int DLDISize;
-bool DLDIReadOnly;
-bool DLDIFolderSync;
-std::string DLDIFolderPath;
-
-bool DSiSDEnable;
-std::string DSiSDPath;
-int DSiSDSize;
-bool DSiSDReadOnly;
-bool DSiSDFolderSync;
-std::string DSiSDFolderPath;
-
-bool FirmwareOverrideSettings;
-std::string FirmwareUsername;
-int FirmwareLanguage;
-int FirmwareBirthdayMonth;
-int FirmwareBirthdayDay;
-int FirmwareFavouriteColour;
-std::string FirmwareMessage;
-std::string FirmwareMAC;
-std::string WifiSettingsPath = "wfcsettings.bin"; // Should this be configurable?
-
-int MPAudioMode;
-int MPRecvTimeout;
-
-std::string LANDevice;
-bool DirectLAN;
-
-bool SavestateRelocSRAM;
-
-int AudioInterp;
-int AudioBitDepth;
-int AudioVolume;
-bool DSiVolumeSync;
-int MicInputType;
-std::string MicDevice;
-std::string MicWavPath;
-
-std::string LastROMFolder;
-std::string LastBIOSFolder;
-
-std::string RecentROMList[10];
-
-std::string SaveFilePath;
-std::string SavestatePath;
-std::string CheatFilePath;
-
-bool EnableCheats;
-
-bool MouseHide;
-int MouseHideSeconds;
-
-bool PauseLostFocus;
-std::string UITheme;
-
-int64_t RTCOffset;
-
-bool DSBatteryLevelOkay;
-int DSiBatteryLevel;
-bool DSiBatteryCharging;
-
-bool DSiFullBIOSBoot;
-
-#ifdef GDBSTUB_ENABLED
-bool GdbEnabled;
-int GdbPortARM7;
-int GdbPortARM9;
-bool GdbARM7BreakOnStartup;
-bool GdbARM9BreakOnStartup;
-#endif
-
-CameraConfig Camera[2];
-
-
-const char* kConfigFile = "melonDS.ini";
-const char* kUniqueConfigFile = "melonDS.%d.ini";
-
-ConfigEntry ConfigFile[] =
+DefaultList DefaultInts =
{
- {"Key_A", 0, &KeyMapping[0], -1, true},
- {"Key_B", 0, &KeyMapping[1], -1, true},
- {"Key_Select", 0, &KeyMapping[2], -1, true},
- {"Key_Start", 0, &KeyMapping[3], -1, true},
- {"Key_Right", 0, &KeyMapping[4], -1, true},
- {"Key_Left", 0, &KeyMapping[5], -1, true},
- {"Key_Up", 0, &KeyMapping[6], -1, true},
- {"Key_Down", 0, &KeyMapping[7], -1, true},
- {"Key_R", 0, &KeyMapping[8], -1, true},
- {"Key_L", 0, &KeyMapping[9], -1, true},
- {"Key_X", 0, &KeyMapping[10], -1, true},
- {"Key_Y", 0, &KeyMapping[11], -1, true},
+ {"Instance*.Keyboard", -1},
+ {"Instance*.Joystick", -1},
+ {"Instance*.Window*.Width", 256},
+ {"Instance*.Window*.Height", 384},
+ {"Screen.VSyncInterval", 1},
+ {"3D.Renderer", renderer3D_Software},
+ {"3D.GL.ScaleFactor", 1},
+ {"MaxFPS", 1000},
+#ifdef JIT_ENABLED
+ {"JIT.MaxBlockSize", 32},
+#endif
+ {"Instance*.Firmware.Language", 1},
+ {"Instance*.Firmware.BirthdayMonth", 1},
+ {"Instance*.Firmware.BirthdayDay", 1},
+ {"MP.AudioMode", 1},
+ {"MP.RecvTimeout", 25},
+ {"Instance*.Audio.Volume", 256},
+ {"Mic.InputType", 1},
+ {"Mouse.HideSeconds", 5},
+ {"Instance*.DSi.Battery.Level", 0xF},
+#ifdef GDBSTUB_ENABLED
+ {"Instance*.Gdb.ARM7.Port", 3334},
+ {"Instance*.Gdb.ARM9.Port", 3333},
+#endif
+};
- {"Joy_A", 0, &JoyMapping[0], -1, true},
- {"Joy_B", 0, &JoyMapping[1], -1, true},
- {"Joy_Select", 0, &JoyMapping[2], -1, true},
- {"Joy_Start", 0, &JoyMapping[3], -1, true},
- {"Joy_Right", 0, &JoyMapping[4], -1, true},
- {"Joy_Left", 0, &JoyMapping[5], -1, true},
- {"Joy_Up", 0, &JoyMapping[6], -1, true},
- {"Joy_Down", 0, &JoyMapping[7], -1, true},
- {"Joy_R", 0, &JoyMapping[8], -1, true},
- {"Joy_L", 0, &JoyMapping[9], -1, true},
- {"Joy_X", 0, &JoyMapping[10], -1, true},
- {"Joy_Y", 0, &JoyMapping[11], -1, true},
+RangeList IntRanges =
+{
+ {"Emu.ConsoleType", {0, 1}},
+ {"3D.Renderer", {0, renderer3D_Max-1}},
+ {"Screen.VSyncInterval", {1, 20}},
+ {"3D.GL.ScaleFactor", {1, 16}},
+ {"Audio.Interpolation", {0, 3}},
+ {"Instance*.Audio.Volume", {0, 256}},
+ {"Mic.InputType", {0, micInputType_MAX-1}},
+ {"Instance*.Window*.ScreenRotation", {0, screenRot_MAX-1}},
+ {"Instance*.Window*.ScreenGap", {0, 500}},
+ {"Instance*.Window*.ScreenLayout", {0, screenLayout_MAX-1}},
+ {"Instance*.Window*.ScreenSizing", {0, screenSizing_MAX-1}},
+ {"Instance*.Window*.ScreenAspectTop", {0, AspectRatiosNum-1}},
+ {"Instance*.Window*.ScreenAspectBot", {0, AspectRatiosNum-1}},
+ {"MP.AudioMode", {0, 2}},
+};
- {"HKKey_Lid", 0, &HKKeyMapping[HK_Lid], -1, true},
- {"HKKey_Mic", 0, &HKKeyMapping[HK_Mic], -1, true},
- {"HKKey_Pause", 0, &HKKeyMapping[HK_Pause], -1, true},
- {"HKKey_Reset", 0, &HKKeyMapping[HK_Reset], -1, true},
- {"HKKey_FastForward", 0, &HKKeyMapping[HK_FastForward], -1, true},
- {"HKKey_FastForwardToggle", 0, &HKKeyMapping[HK_FastForwardToggle], -1, true},
- {"HKKey_FullscreenToggle", 0, &HKKeyMapping[HK_FullscreenToggle], -1, true},
- {"HKKey_SwapScreens", 0, &HKKeyMapping[HK_SwapScreens], -1, true},
- {"HKKey_SwapScreenEmphasis", 0, &HKKeyMapping[HK_SwapScreenEmphasis], -1, true},
- {"HKKey_SolarSensorDecrease", 0, &HKKeyMapping[HK_SolarSensorDecrease], -1, true},
- {"HKKey_SolarSensorIncrease", 0, &HKKeyMapping[HK_SolarSensorIncrease], -1, true},
- {"HKKey_FrameStep", 0, &HKKeyMapping[HK_FrameStep], -1, true},
- {"HKKey_PowerButton", 0, &HKKeyMapping[HK_PowerButton], -1, true},
- {"HKKey_VolumeUp", 0, &HKKeyMapping[HK_VolumeUp], -1, true},
- {"HKKey_VolumeDown", 0, &HKKeyMapping[HK_VolumeDown], -1, true},
+DefaultList DefaultBools =
+{
+ {"Screen.Filter", true},
+ {"3D.Soft.Threaded", true},
+ {"3D.GL.HiresCoordinates", true},
+ {"LimitFPS", true},
+ {"Window*.ShowOSD", true},
+ {"Emu.DirectBoot", true},
+ {"Instance*.DS.Battery.LevelOkay", true},
+ {"Instance*.DSi.Battery.Charging", true},
+#ifdef JIT_ENABLED
+ {"JIT.BranchOptimisations", true},
+ {"JIT.LiteralOptimisations", true},
+#ifndef __APPLE__
+ {"JIT.FastMemory", true},
+#endif
+#endif
+};
- {"HKJoy_Lid", 0, &HKJoyMapping[HK_Lid], -1, true},
- {"HKJoy_Mic", 0, &HKJoyMapping[HK_Mic], -1, true},
- {"HKJoy_Pause", 0, &HKJoyMapping[HK_Pause], -1, true},
- {"HKJoy_Reset", 0, &HKJoyMapping[HK_Reset], -1, true},
- {"HKJoy_FastForward", 0, &HKJoyMapping[HK_FastForward], -1, true},
- {"HKJoy_FastForwardToggle", 0, &HKJoyMapping[HK_FastForwardToggle], -1, true},
- {"HKJoy_FullscreenToggle", 0, &HKJoyMapping[HK_FullscreenToggle], -1, true},
- {"HKJoy_SwapScreens", 0, &HKJoyMapping[HK_SwapScreens], -1, true},
- {"HKJoy_SwapScreenEmphasis", 0, &HKJoyMapping[HK_SwapScreenEmphasis], -1, true},
- {"HKJoy_SolarSensorDecrease", 0, &HKJoyMapping[HK_SolarSensorDecrease], -1, true},
- {"HKJoy_SolarSensorIncrease", 0, &HKJoyMapping[HK_SolarSensorIncrease], -1, true},
- {"HKJoy_FrameStep", 0, &HKJoyMapping[HK_FrameStep], -1, true},
- {"HKJoy_PowerButton", 0, &HKJoyMapping[HK_PowerButton], -1, true},
- {"HKJoy_VolumeUp", 0, &HKJoyMapping[HK_VolumeUp], -1, true},
- {"HKJoy_VolumeDown", 0, &HKJoyMapping[HK_VolumeDown], -1, true},
+DefaultList DefaultStrings =
+{
+ {"DLDI.ImagePath", "dldi.bin"},
+ {"DSi.SD.ImagePath", "dsisd.bin"},
+ {"Instance*.Firmware.Username", "melonDS"}
+};
- {"JoystickID", 0, &JoystickID, 0, true},
+LegacyEntry LegacyFile[] =
+{
+ {"Key_A", 0, "Keyboard.A", true},
+ {"Key_B", 0, "Keyboard.B", true},
+ {"Key_Select", 0, "Keyboard.Select", true},
+ {"Key_Start", 0, "Keyboard.Start", true},
+ {"Key_Right", 0, "Keyboard.Right", true},
+ {"Key_Left", 0, "Keyboard.Left", true},
+ {"Key_Up", 0, "Keyboard.Up", true},
+ {"Key_Down", 0, "Keyboard.Down", true},
+ {"Key_R", 0, "Keyboard.R", true},
+ {"Key_L", 0, "Keyboard.L", true},
+ {"Key_X", 0, "Keyboard.X", true},
+ {"Key_Y", 0, "Keyboard.Y", true},
- {"WindowWidth", 0, &WindowWidth, 256, true},
- {"WindowHeight", 0, &WindowHeight, 384, true},
- {"WindowMax", 1, &WindowMaximized, false, true},
+ {"Joy_A", 0, "Joystick.A", true},
+ {"Joy_B", 0, "Joystick.B", true},
+ {"Joy_Select", 0, "Joystick.Select", true},
+ {"Joy_Start", 0, "Joystick.Start", true},
+ {"Joy_Right", 0, "Joystick.Right", true},
+ {"Joy_Left", 0, "Joystick.Left", true},
+ {"Joy_Up", 0, "Joystick.Up", true},
+ {"Joy_Down", 0, "Joystick.Down", true},
+ {"Joy_R", 0, "Joystick.R", true},
+ {"Joy_L", 0, "Joystick.L", true},
+ {"Joy_X", 0, "Joystick.X", true},
+ {"Joy_Y", 0, "Joystick.Y", true},
- {"ScreenRotation", 0, &ScreenRotation, 0, true},
- {"ScreenGap", 0, &ScreenGap, 0, true},
- {"ScreenLayout", 0, &ScreenLayout, 0, true},
- {"ScreenSwap", 1, &ScreenSwap, false, true},
- {"ScreenSizing", 0, &ScreenSizing, 0, true},
- {"IntegerScaling", 1, &IntegerScaling, false, true},
- {"ScreenAspectTop",0, &ScreenAspectTop,0, true},
- {"ScreenAspectBot",0, &ScreenAspectBot,0, true},
- {"ScreenFilter", 1, &ScreenFilter, true, true},
+ {"HKKey_Lid", 0, "Keyboard.HK_Lid", true},
+ {"HKKey_Mic", 0, "Keyboard.HK_Mic", true},
+ {"HKKey_Pause", 0, "Keyboard.HK_Pause", true},
+ {"HKKey_Reset", 0, "Keyboard.HK_Reset", true},
+ {"HKKey_FastForward", 0, "Keyboard.HK_FastForward", true},
+ {"HKKey_FastForwardToggle", 0, "Keyboard.HK_FastForwardToggle", true},
+ {"HKKey_FullscreenToggle", 0, "Keyboard.HK_FullscreenToggle", true},
+ {"HKKey_SwapScreens", 0, "Keyboard.HK_SwapScreens", true},
+ {"HKKey_SwapScreenEmphasis", 0, "Keyboard.HK_SwapScreenEmphasis", true},
+ {"HKKey_SolarSensorDecrease", 0, "Keyboard.HK_SolarSensorDecrease", true},
+ {"HKKey_SolarSensorIncrease", 0, "Keyboard.HK_SolarSensorIncrease", true},
+ {"HKKey_FrameStep", 0, "Keyboard.HK_FrameStep", true},
+ {"HKKey_PowerButton", 0, "Keyboard.HK_PowerButton", true},
+ {"HKKey_VolumeUp", 0, "Keyboard.HK_VolumeUp", true},
+ {"HKKey_VolumeDown", 0, "Keyboard.HK_VolumeDown", true},
- {"ScreenUseGL", 1, &ScreenUseGL, false, false},
- {"ScreenVSync", 1, &ScreenVSync, false, false},
- {"ScreenVSyncInterval", 0, &ScreenVSyncInterval, 1, false},
+ {"HKJoy_Lid", 0, "Joystick.HK_Lid", true},
+ {"HKJoy_Mic", 0, "Joystick.HK_Mic", true},
+ {"HKJoy_Pause", 0, "Joystick.HK_Pause", true},
+ {"HKJoy_Reset", 0, "Joystick.HK_Reset", true},
+ {"HKJoy_FastForward", 0, "Joystick.HK_FastForward", true},
+ {"HKJoy_FastForwardToggle", 0, "Joystick.HK_FastForwardToggle", true},
+ {"HKJoy_FullscreenToggle", 0, "Joystick.HK_FullscreenToggle", true},
+ {"HKJoy_SwapScreens", 0, "Joystick.HK_SwapScreens", true},
+ {"HKJoy_SwapScreenEmphasis", 0, "Joystick.HK_SwapScreenEmphasis", true},
+ {"HKJoy_SolarSensorDecrease", 0, "Joystick.HK_SolarSensorDecrease", true},
+ {"HKJoy_SolarSensorIncrease", 0, "Joystick.HK_SolarSensorIncrease", true},
+ {"HKJoy_FrameStep", 0, "Joystick.HK_FrameStep", true},
+ {"HKJoy_PowerButton", 0, "Joystick.HK_PowerButton", true},
+ {"HKJoy_VolumeUp", 0, "Joystick.HK_VolumeUp", true},
+ {"HKJoy_VolumeDown", 0, "Joystick.HK_VolumeDown", true},
- {"3DRenderer", 0, &_3DRenderer, renderer3D_Software, false},
- {"Threaded3D", 1, &Threaded3D, true, false},
+ {"JoystickID", 0, "JoystickID", true},
- {"GL_ScaleFactor", 0, &GL_ScaleFactor, 1, false},
- {"GL_BetterPolygons", 1, &GL_BetterPolygons, false, false},
- {"GL_HiresCoordinates", 1, &GL_HiresCoordinates, true, false},
+ {"ScreenRotation", 0, "Window0.ScreenRotation", true},
+ {"ScreenGap", 0, "Window0.ScreenGap", true},
+ {"ScreenLayout", 0, "Window0.ScreenLayout", true},
+ {"ScreenSwap", 1, "Window0.ScreenSwap", true},
+ {"ScreenSizing", 0, "Window0.ScreenSizing", true},
+ {"IntegerScaling", 1, "Window0.IntegerScaling", true},
+ {"ScreenAspectTop",0, "Window0.ScreenAspectTop", true},
+ {"ScreenAspectBot",0, "Window0.ScreenAspectBot", true},
- {"LimitFPS", 1, &LimitFPS, true, false},
- {"MaxFPS", 0, &MaxFPS, 1000, false},
- {"AudioSync", 1, &AudioSync, false},
- {"ShowOSD", 1, &ShowOSD, true, false},
+ {"ScreenFilter", 1, "Screen.Filter", false},
+ {"ScreenUseGL", 1, "Screen.UseGL", false},
+ {"ScreenVSync", 1, "Screen.VSync", false},
+ {"ScreenVSyncInterval", 0, "Screen.VSyncInterval", false},
- {"ConsoleType", 0, &ConsoleType, 0, false},
- {"DirectBoot", 1, &DirectBoot, true, false},
+ {"3DRenderer", 0, "3D.Renderer", false},
+ {"Threaded3D", 1, "3D.Soft.Threaded", false},
+
+ {"GL_ScaleFactor", 0, "3D.GL.ScaleFactor", false},
+ {"GL_BetterPolygons", 1, "3D.GL.BetterPolygons", false},
+ {"GL_HiresCoordinates", 1, "3D.GL.HiresCoordinates", false},
+
+ {"LimitFPS", 1, "LimitFPS", false},
+ {"MaxFPS", 0, "MaxFPS", false},
+ {"AudioSync", 1, "AudioSync", false},
+ {"ShowOSD", 1, "Window0.ShowOSD", true},
+
+ {"ConsoleType", 0, "Emu.ConsoleType", false},
+ {"DirectBoot", 1, "Emu.DirectBoot", false},
#ifdef JIT_ENABLED
- {"JIT_Enable", 1, &JIT_Enable, false, false},
- {"JIT_MaxBlockSize", 0, &JIT_MaxBlockSize, 32, false},
- {"JIT_BranchOptimisations", 1, &JIT_BranchOptimisations, true, false},
- {"JIT_LiteralOptimisations", 1, &JIT_LiteralOptimisations, true, false},
- #ifdef __APPLE__
- {"JIT_FastMemory", 1, &JIT_FastMemory, false, false},
- #else
- {"JIT_FastMemory", 1, &JIT_FastMemory, true, false},
- #endif
+ {"JIT_Enable", 1, "JIT.Enable", false},
+ {"JIT_MaxBlockSize", 0, "JIT.MaxBlockSize", false},
+ {"JIT_BranchOptimisations", 1, "JIT.BranchOptimisations", false},
+ {"JIT_LiteralOptimisations", 1, "JIT.LiteralOptimisations", false},
+ {"JIT_FastMemory", 1, "JIT.FastMemory", false},
#endif
- {"ExternalBIOSEnable", 1, &ExternalBIOSEnable, false, false},
+ {"ExternalBIOSEnable", 1, "Emu.ExternalBIOSEnable", false},
- {"BIOS9Path", 2, &BIOS9Path, (std::string)"", false},
- {"BIOS7Path", 2, &BIOS7Path, (std::string)"", false},
- {"FirmwarePath", 2, &FirmwarePath, (std::string)"", false},
+ {"BIOS9Path", 2, "DS.BIOS9Path", false},
+ {"BIOS7Path", 2, "DS.BIOS7Path", false},
+ {"FirmwarePath", 2, "DS.FirmwarePath", false},
- {"DSiBIOS9Path", 2, &DSiBIOS9Path, (std::string)"", false},
- {"DSiBIOS7Path", 2, &DSiBIOS7Path, (std::string)"", false},
- {"DSiFirmwarePath", 2, &DSiFirmwarePath, (std::string)"", false},
- {"DSiNANDPath", 2, &DSiNANDPath, (std::string)"", false},
+ {"DSiBIOS9Path", 2, "DSi.BIOS9Path", false},
+ {"DSiBIOS7Path", 2, "DSi.BIOS7Path", false},
+ {"DSiFirmwarePath", 2, "DSi.FirmwarePath", false},
+ {"DSiNANDPath", 2, "DSi.NANDPath", false},
- {"DLDIEnable", 1, &DLDIEnable, false, false},
- {"DLDISDPath", 2, &DLDISDPath, (std::string)"dldi.bin", false},
- {"DLDISize", 0, &DLDISize, 0, false},
- {"DLDIReadOnly", 1, &DLDIReadOnly, false, false},
- {"DLDIFolderSync", 1, &DLDIFolderSync, false, false},
- {"DLDIFolderPath", 2, &DLDIFolderPath, (std::string)"", false},
+ {"DLDIEnable", 1, "DLDI.Enable", false},
+ {"DLDISDPath", 2, "DLDI.ImagePath", false},
+ {"DLDISize", 0, "DLDI.ImageSize", false},
+ {"DLDIReadOnly", 1, "DLDI.ReadOnly", false},
+ {"DLDIFolderSync", 1, "DLDI.FolderSync", false},
+ {"DLDIFolderPath", 2, "DLDI.FolderPath", false},
- {"DSiSDEnable", 1, &DSiSDEnable, false, false},
- {"DSiSDPath", 2, &DSiSDPath, (std::string)"dsisd.bin", false},
- {"DSiSDSize", 0, &DSiSDSize, 0, false},
- {"DSiSDReadOnly", 1, &DSiSDReadOnly, false, false},
- {"DSiSDFolderSync", 1, &DSiSDFolderSync, false, false},
- {"DSiSDFolderPath", 2, &DSiSDFolderPath, (std::string)"", false},
+ {"DSiSDEnable", 1, "DSi.SD.Enable", false},
+ {"DSiSDPath", 2, "DSi.SD.ImagePath", false},
+ {"DSiSDSize", 0, "DSi.SD.ImageSize", false},
+ {"DSiSDReadOnly", 1, "DSi.SD.ReadOnly", false},
+ {"DSiSDFolderSync", 1, "DSi.SD.FolderSync", false},
+ {"DSiSDFolderPath", 2, "DSi.SD.FolderPath", false},
- {"FirmwareOverrideSettings", 1, &FirmwareOverrideSettings, false, true},
- {"FirmwareUsername", 2, &FirmwareUsername, (std::string)"melonDS", true},
- {"FirmwareLanguage", 0, &FirmwareLanguage, 1, true},
- {"FirmwareBirthdayMonth", 0, &FirmwareBirthdayMonth, 1, true},
- {"FirmwareBirthdayDay", 0, &FirmwareBirthdayDay, 1, true},
- {"FirmwareFavouriteColour", 0, &FirmwareFavouriteColour, 0, true},
- {"FirmwareMessage", 2, &FirmwareMessage, (std::string)"", true},
- {"FirmwareMAC", 2, &FirmwareMAC, (std::string)"", true},
+ {"FirmwareOverrideSettings", 1, "Firmware.OverrideSettings", true},
+ {"FirmwareUsername", 2, "Firmware.Username", true},
+ {"FirmwareLanguage", 0, "Firmware.Language", true},
+ {"FirmwareBirthdayMonth", 0, "Firmware.BirthdayMonth", true},
+ {"FirmwareBirthdayDay", 0, "Firmware.BirthdayDay", true},
+ {"FirmwareFavouriteColour", 0, "Firmware.FavouriteColour", true},
+ {"FirmwareMessage", 2, "Firmware.Message", true},
+ {"FirmwareMAC", 2, "Firmware.MAC", true},
- {"MPAudioMode", 0, &MPAudioMode, 1, false},
- {"MPRecvTimeout", 0, &MPRecvTimeout, 25, false},
+ {"MPAudioMode", 0, "MP.AudioMode", false},
+ {"MPRecvTimeout", 0, "MP.RecvTimeout", false},
- {"LANDevice", 2, &LANDevice, (std::string)"", false},
- {"DirectLAN", 1, &DirectLAN, false, false},
+ {"LANDevice", 2, "LAN.Device", false},
+ {"DirectLAN", 1, "LAN.DirectMode", false},
- {"SavStaRelocSRAM", 1, &SavestateRelocSRAM, false, false},
+ {"SavStaRelocSRAM", 1, "Savestate.RelocSRAM", false},
- {"AudioInterp", 0, &AudioInterp, 0, false},
- {"AudioBitDepth", 0, &AudioBitDepth, 0, false},
- {"AudioVolume", 0, &AudioVolume, 256, true},
- {"DSiVolumeSync", 1, &DSiVolumeSync, false, true},
- {"MicInputType", 0, &MicInputType, 1, false},
- {"MicDevice", 2, &MicDevice, (std::string)"", false},
- {"MicWavPath", 2, &MicWavPath, (std::string)"", false},
+ {"AudioInterp", 0, "Audio.Interpolation", false},
+ {"AudioBitDepth", 0, "Audio.BitDepth", false},
+ {"AudioVolume", 0, "Audio.Volume", true},
+ {"DSiVolumeSync", 1, "Audio.DSiVolumeSync", true},
+ {"MicInputType", 0, "Mic.InputType", false},
+ {"MicDevice", 2, "Mic.Device", false},
+ {"MicWavPath", 2, "Mic.WavPath", false},
- {"LastROMFolder", 2, &LastROMFolder, (std::string)"", true},
- {"LastBIOSFolder", 2, &LastBIOSFolder, (std::string)"", true},
+ {"LastROMFolder", 2, "LastROMFolder", false},
+ {"LastBIOSFolder", 2, "LastBIOSFolder", false},
- {"RecentROM_0", 2, &RecentROMList[0], (std::string)"", true},
- {"RecentROM_1", 2, &RecentROMList[1], (std::string)"", true},
- {"RecentROM_2", 2, &RecentROMList[2], (std::string)"", true},
- {"RecentROM_3", 2, &RecentROMList[3], (std::string)"", true},
- {"RecentROM_4", 2, &RecentROMList[4], (std::string)"", true},
- {"RecentROM_5", 2, &RecentROMList[5], (std::string)"", true},
- {"RecentROM_6", 2, &RecentROMList[6], (std::string)"", true},
- {"RecentROM_7", 2, &RecentROMList[7], (std::string)"", true},
- {"RecentROM_8", 2, &RecentROMList[8], (std::string)"", true},
- {"RecentROM_9", 2, &RecentROMList[9], (std::string)"", true},
+ {"RecentROM_0", 4, "RecentROM[0]", false},
+ {"RecentROM_1", 4, "RecentROM[1]", false},
+ {"RecentROM_2", 4, "RecentROM[2]", false},
+ {"RecentROM_3", 4, "RecentROM[3]", false},
+ {"RecentROM_4", 4, "RecentROM[4]", false},
+ {"RecentROM_5", 4, "RecentROM[5]", false},
+ {"RecentROM_6", 4, "RecentROM[6]", false},
+ {"RecentROM_7", 4, "RecentROM[7]", false},
+ {"RecentROM_8", 4, "RecentROM[8]", false},
+ {"RecentROM_9", 4, "RecentROM[9]", false},
- {"SaveFilePath", 2, &SaveFilePath, (std::string)"", true},
- {"SavestatePath", 2, &SavestatePath, (std::string)"", true},
- {"CheatFilePath", 2, &CheatFilePath, (std::string)"", true},
+ {"SaveFilePath", 2, "SaveFilePath", true},
+ {"SavestatePath", 2, "SavestatePath", true},
+ {"CheatFilePath", 2, "CheatFilePath", true},
- {"EnableCheats", 1, &EnableCheats, false, true},
+ {"EnableCheats", 1, "EnableCheats", true},
- {"MouseHide", 1, &MouseHide, false, false},
- {"MouseHideSeconds", 0, &MouseHideSeconds, 5, false},
- {"PauseLostFocus", 1, &PauseLostFocus, false, false},
- {"UITheme", 2, &UITheme, (std::string)"", false},
+ {"MouseHide", 1, "Mouse.Hide", false},
+ {"MouseHideSeconds", 0, "Mouse.HideSeconds", false},
+ {"PauseLostFocus", 1, "PauseLostFocus", false},
+ {"UITheme", 2, "UITheme", false},
- {"RTCOffset", 3, &RTCOffset, (int64_t)0, true},
+ {"RTCOffset", 3, "RTC.Offset", true},
- {"DSBatteryLevelOkay", 1, &DSBatteryLevelOkay, true, true},
- {"DSiBatteryLevel", 0, &DSiBatteryLevel, 0xF, true},
- {"DSiBatteryCharging", 1, &DSiBatteryCharging, true, true},
+ {"DSBatteryLevelOkay", 1, "DS.Battery.LevelOkay", true},
+ {"DSiBatteryLevel", 0, "DSi.Battery.Level", true},
+ {"DSiBatteryCharging", 1, "DSi.Battery.Charging", true},
- {"DSiFullBIOSBoot", 1, &DSiFullBIOSBoot, false, true},
+ {"DSiFullBIOSBoot", 1, "DSi.FullBIOSBoot", true},
#ifdef GDBSTUB_ENABLED
- {"GdbEnabled", 1, &GdbEnabled, false, false},
- {"GdbPortARM7", 0, &GdbPortARM7, 3334, true},
- {"GdbPortARM9", 0, &GdbPortARM9, 3333, true},
- {"GdbARM7BreakOnStartup", 1, &GdbARM7BreakOnStartup, false, true},
- {"GdbARM9BreakOnStartup", 1, &GdbARM9BreakOnStartup, false, true},
+ {"GdbEnabled", 1, "Gdb.Enabled", false},
+ {"GdbPortARM7", 0, "Gdb.ARM7.Port", true},
+ {"GdbPortARM9", 0, "Gdb.ARM9.Port", true},
+ {"GdbARM7BreakOnStartup", 1, "Gdb.ARM7.BreakOnStartup", true},
+ {"GdbARM9BreakOnStartup", 1, "Gdb.ARM9.BreakOnStartup", true},
#endif
- // TODO!!
- // we need a more elegant way to deal with this
- {"Camera0_InputType", 0, &Camera[0].InputType, 0, false},
- {"Camera0_ImagePath", 2, &Camera[0].ImagePath, (std::string)"", false},
- {"Camera0_CamDeviceName", 2, &Camera[0].CamDeviceName, (std::string)"", false},
- {"Camera0_XFlip", 1, &Camera[0].XFlip, false, false},
- {"Camera1_InputType", 0, &Camera[1].InputType, 0, false},
- {"Camera1_ImagePath", 2, &Camera[1].ImagePath, (std::string)"", false},
- {"Camera1_CamDeviceName", 2, &Camera[1].CamDeviceName, (std::string)"", false},
- {"Camera1_XFlip", 1, &Camera[1].XFlip, false, false},
+ {"Camera0_InputType", 0, "DSi.Camera0.InputType", false},
+ {"Camera0_ImagePath", 2, "DSi.Camera0.ImagePath", false},
+ {"Camera0_CamDeviceName", 2, "DSi.Camera0.DeviceName", false},
+ {"Camera0_XFlip", 1, "DSi.Camera0.XFlip", false},
+ {"Camera1_InputType", 0, "DSi.Camera1.InputType", false},
+ {"Camera1_ImagePath", 2, "DSi.Camera1.ImagePath", false},
+ {"Camera1_CamDeviceName", 2, "DSi.Camera1.DeviceName", false},
+ {"Camera1_XFlip", 1, "DSi.Camera1.XFlip", false},
- {"", -1, nullptr, 0, false}
+ {"", -1, "", false}
};
-bool LoadFile(int inst, int actualinst)
+static std::string GetDefaultKey(std::string path)
+{
+ std::string tables[] = {"Instance", "Window", "Camera"};
+
+ std::string ret = "";
+ int plen = path.length();
+ for (int i = 0; i < plen;)
+ {
+ bool found = false;
+
+ for (auto& tbl : tables)
+ {
+ int tlen = tbl.length();
+ if ((plen-i) <= tlen) continue;
+ if (path.substr(i, tlen) != tbl) continue;
+ if (path[i+tlen] < '0' || path[i+tlen] > '9') continue;
+
+ ret += tbl + "*";
+ i = path.find('.', i+tlen);
+ if (i == std::string::npos) return ret;
+
+ found = true;
+ break;
+ }
+
+ if (!found)
+ {
+ ret += path[i];
+ i++;
+ }
+ }
+
+ return ret;
+}
+
+
+Array::Array(toml::value& data) : Data(data)
+{
+}
+
+size_t Array::Size()
+{
+ return Data.size();
+}
+
+void Array::Clear()
+{
+ toml::array newarray;
+ Data = newarray;
+}
+
+Array Array::GetArray(const int id)
+{
+ while (Data.size() < id+1)
+ Data.push_back(toml::array());
+
+ toml::value& arr = Data[id];
+ if (!arr.is_array())
+ arr = toml::array();
+
+ return Array(arr);
+}
+
+int Array::GetInt(const int id)
+{
+ while (Data.size() < id+1)
+ Data.push_back(0);
+
+ toml::value& tval = Data[id];
+ if (!tval.is_integer())
+ tval = 0;
+
+ return (int)tval.as_integer();
+}
+
+int64_t Array::GetInt64(const int id)
+{
+ while (Data.size() < id+1)
+ Data.push_back(0);
+
+ toml::value& tval = Data[id];
+ if (!tval.is_integer())
+ tval = 0;
+
+ return tval.as_integer();
+}
+
+bool Array::GetBool(const int id)
+{
+ while (Data.size() < id+1)
+ Data.push_back(false);
+
+ toml::value& tval = Data[id];
+ if (!tval.is_boolean())
+ tval = false;
+
+ return tval.as_boolean();
+}
+
+std::string Array::GetString(const int id)
+{
+ while (Data.size() < id+1)
+ Data.push_back("");
+
+ toml::value& tval = Data[id];
+ if (!tval.is_string())
+ tval = "";
+
+ return tval.as_string();
+}
+
+void Array::SetInt(const int id, int val)
+{
+ while (Data.size() < id+1)
+ Data.push_back(0);
+
+ toml::value& tval = Data[id];
+ tval = val;
+}
+
+void Array::SetInt64(const int id, int64_t val)
+{
+ while (Data.size() < id+1)
+ Data.push_back(0);
+
+ toml::value& tval = Data[id];
+ tval = val;
+}
+
+void Array::SetBool(const int id, bool val)
+{
+ while (Data.size() < id+1)
+ Data.push_back(false);
+
+ toml::value& tval = Data[id];
+ tval = val;
+}
+
+void Array::SetString(const int id, const std::string& val)
+{
+ while (Data.size() < id+1)
+ Data.push_back("");
+
+ toml::value& tval = Data[id];
+ tval = val;
+}
+
+
+/*Table::Table()// : Data(toml::value())
+{
+ Data = toml::value();
+ PathPrefix = "";
+}*/
+
+Table::Table(toml::value& data, const std::string& path) : Data(data)
+{
+ if (path.empty())
+ PathPrefix = "";
+ else
+ PathPrefix = path + ".";
+}
+
+Table& Table::operator=(const Table& b)
+{
+ Data = b.Data;
+ PathPrefix = b.PathPrefix;
+
+ return *this;
+}
+
+Array Table::GetArray(const std::string& path)
+{
+ toml::value& arr = ResolvePath(path);
+ if (!arr.is_array())
+ arr = toml::array();
+
+ return Array(arr);
+}
+
+Table Table::GetTable(const std::string& path, const std::string& defpath)
+{
+ toml::value& tbl = ResolvePath(path);
+ if (!tbl.is_table())
+ {
+ toml::value defval = toml::table();
+ if (!defpath.empty())
+ defval = ResolvePath(defpath);
+
+ tbl = defval;
+ }
+
+ return Table(tbl, PathPrefix + path);
+}
+
+int Table::GetInt(const std::string& path)
+{
+ toml::value& tval = ResolvePath(path);
+ if (!tval.is_integer())
+ tval = FindDefault(path, 0, DefaultInts);
+
+ int ret = (int)tval.as_integer();
+
+ std::string rngkey = GetDefaultKey(PathPrefix+path);
+ if (IntRanges.count(rngkey) != 0)
+ {
+ auto& range = IntRanges[rngkey];
+ ret = std::clamp(ret, std::get<0>(range), std::get<1>(range));
+ }
+
+ return ret;
+}
+
+int64_t Table::GetInt64(const std::string& path)
+{
+ toml::value& tval = ResolvePath(path);
+ if (!tval.is_integer())
+ tval = 0;
+
+ return tval.as_integer();
+}
+
+bool Table::GetBool(const std::string& path)
+{
+ toml::value& tval = ResolvePath(path);
+ if (!tval.is_boolean())
+ tval = FindDefault(path, false, DefaultBools);
+
+ return tval.as_boolean();
+}
+
+std::string Table::GetString(const std::string& path)
+{
+ toml::value& tval = ResolvePath(path);
+ if (!tval.is_string())
+ tval = FindDefault(path, ""s, DefaultStrings);
+
+ return tval.as_string();
+}
+
+void Table::SetInt(const std::string& path, int val)
+{
+ std::string rngkey = GetDefaultKey(PathPrefix+path);
+ if (IntRanges.count(rngkey) != 0)
+ {
+ auto& range = IntRanges[rngkey];
+ val = std::clamp(val, std::get<0>(range), std::get<1>(range));
+ }
+
+ toml::value& tval = ResolvePath(path);
+ tval = val;
+}
+
+void Table::SetInt64(const std::string& path, int64_t val)
+{
+ toml::value& tval = ResolvePath(path);
+ tval = val;
+}
+
+void Table::SetBool(const std::string& path, bool val)
+{
+ toml::value& tval = ResolvePath(path);
+ tval = val;
+}
+
+void Table::SetString(const std::string& path, const std::string& val)
+{
+ toml::value& tval = ResolvePath(path);
+ tval = val;
+}
+
+toml::value& Table::ResolvePath(const std::string& path)
+{
+ toml::value* ret = &Data;
+ std::string tmp = path;
+
+ size_t sep;
+ while ((sep = tmp.find('.')) != std::string::npos)
+ {
+ ret = &(*ret)[tmp.substr(0, sep)];
+ tmp = tmp.substr(sep+1);
+ }
+
+ return (*ret)[tmp];
+}
+
+template T Table::FindDefault(const std::string& path, T def, DefaultList list)
+{
+ std::string defkey = GetDefaultKey(PathPrefix+path);
+
+ T ret = def;
+ while (list.count(defkey) == 0)
+ {
+ if (defkey.empty()) break;
+ size_t sep = defkey.rfind('.');
+ if (sep == std::string::npos) break;
+ defkey = defkey.substr(0, sep);
+ }
+ if (list.count(defkey) != 0)
+ ret = list[defkey];
+
+ return ret;
+}
+
+
+bool LoadLegacyFile(int inst)
{
Platform::FileHandle* f;
if (inst > 0)
{
char name[100] = {0};
- snprintf(name, 99, kUniqueConfigFile, inst+1);
+ snprintf(name, 99, kLegacyUniqueConfigFile, inst+1);
f = Platform::OpenLocalFile(name, Platform::FileMode::ReadText);
-
- if (!Platform::CheckLocalFileWritable(name)) return false;
}
else
{
- f = Platform::OpenLocalFile(kConfigFile, Platform::FileMode::ReadText);
-
- if (actualinst == 0 && !Platform::CheckLocalFileWritable(kConfigFile)) return false;
+ f = Platform::OpenLocalFile(kLegacyConfigFile, Platform::FileMode::ReadText);
}
if (!f) return true;
+ toml::value* root;// = GetLocalTable(inst);
+ if (inst == -1)
+ root = &RootTable;
+ else
+ root = &RootTable["Instance" + std::to_string(inst)];
+
char linebuf[1024];
char entryname[32];
char entryval[1024];
@@ -413,19 +658,56 @@ bool LoadFile(int inst, int actualinst)
entryname[31] = '\0';
if (ret < 2) continue;
- for (ConfigEntry* entry = &ConfigFile[0]; entry->Value; entry++)
+ for (LegacyEntry* entry = &LegacyFile[0]; entry->Type != -1; entry++)
{
if (!strncmp(entry->Name, entryname, 32))
{
- if ((inst > 0) && (!entry->InstanceUnique))
+ if (!(entry->InstanceUnique ^ (inst == -1)))
break;
+ std::string path = entry->TOMLPath;
+ toml::value* table = root;
+ size_t sep;
+ while ((sep = path.find('.')) != std::string::npos)
+ {
+ table = &(*table)[path.substr(0, sep)];
+ path = path.substr(sep+1);
+ }
+
+ int arrayid = -1;
+ if (path[path.size()-1] == ']')
+ {
+ size_t tmp = path.rfind('[');
+ arrayid = std::stoi(path.substr(tmp+1, path.size()-tmp-2));
+ path = path.substr(0, tmp);
+ }
+
+ toml::value& val = (*table)[path];
+
switch (entry->Type)
{
- case 0: *(int*)entry->Value = strtol(entryval, NULL, 10); break;
- case 1: *(bool*)entry->Value = strtol(entryval, NULL, 10) ? true:false; break;
- case 2: *(std::string*)entry->Value = entryval; break;
- case 3: *(int64_t*)entry->Value = strtoll(entryval, NULL, 10); break;
+ case 0:
+ val = strtol(entryval, nullptr, 10);
+ break;
+
+ case 1:
+ val = !!strtol(entryval, nullptr, 10);
+ break;
+
+ case 2:
+ val = entryval;
+ break;
+
+ case 3:
+ val = strtoll(entryval, nullptr, 10);
+ break;
+
+ case 4:
+ if (!val.is_array()) val = toml::array();
+ while (val.size() < arrayid+1)
+ val.push_back("");
+ val[arrayid] = entryval;
+ break;
}
break;
@@ -437,60 +719,62 @@ bool LoadFile(int inst, int actualinst)
return true;
}
+bool LoadLegacy()
+{
+ for (int i = -1; i < 16; i++)
+ LoadLegacyFile(i);
+
+ return true;
+}
+
bool Load()
{
+ auto cfgpath = Platform::GetLocalFilePath(kConfigFile);
- for (ConfigEntry* entry = &ConfigFile[0]; entry->Value; entry++)
+ if (!Platform::CheckFileWritable(cfgpath))
+ return false;
+
+ RootTable = toml::value();
+
+ if (!Platform::FileExists(cfgpath))
+ return LoadLegacy();
+
+ try
{
- switch (entry->Type)
- {
- case 0: *(int*)entry->Value = std::get(entry->Default); break;
- case 1: *(bool*)entry->Value = std::get(entry->Default); break;
- case 2: *(std::string*)entry->Value = std::get(entry->Default); break;
- case 3: *(int64_t*)entry->Value = std::get(entry->Default); break;
- }
+ RootTable = toml::parse(cfgpath);
+ }
+ catch (toml::syntax_error& err)
+ {
+ //RootTable = toml::table();
}
-
- int inst = Platform::InstanceID();
- bool ret = LoadFile(0, inst);
- if (inst > 0)
- ret = LoadFile(inst, inst);
-
- return ret;
+ return true;
}
void Save()
{
- int inst = Platform::InstanceID();
+ auto cfgpath = Platform::GetLocalFilePath(kConfigFile);
+ if (!Platform::CheckFileWritable(cfgpath))
+ return;
- Platform::FileHandle* f;
- if (inst > 0)
- {
- char name[100] = {0};
- snprintf(name, 99, kUniqueConfigFile, inst+1);
- f = Platform::OpenLocalFile(name, Platform::FileMode::WriteText);
- }
- else
- f = Platform::OpenLocalFile(kConfigFile, Platform::FileMode::WriteText);
+ std::ofstream file;
+ file.open(cfgpath, std::ofstream::out | std::ofstream::trunc);
+ file << RootTable;
+ file.close();
+}
- if (!f) return;
- for (ConfigEntry* entry = &ConfigFile[0]; entry->Value; entry++)
- {
- if ((inst > 0) && (!entry->InstanceUnique))
- continue;
+Table GetLocalTable(int instance)
+{
+ if (instance == -1)
+ return Table(RootTable, "");
- switch (entry->Type)
- {
- case 0: Platform::FileWriteFormatted(f, "%s=%d\n", entry->Name, *(int*)entry->Value); break;
- case 1: Platform::FileWriteFormatted(f, "%s=%d\n", entry->Name, *(bool*)entry->Value ? 1:0); break;
- case 2: Platform::FileWriteFormatted(f, "%s=%s\n", entry->Name, (*(std::string*)entry->Value).c_str()); break;
- case 3: Platform::FileWriteFormatted(f, "%s=%" PRId64 "\n", entry->Name, *(int64_t*)entry->Value); break;
- }
- }
+ std::string key = "Instance" + std::to_string(instance);
+ toml::value& tbl = RootTable[key];
+ if (tbl.is_uninitialized())
+ RootTable[key] = RootTable["Instance0"];
- CloseFile(f);
+ return Table(tbl, key);
}
}
diff --git a/src/frontend/qt_sdl/Config.h b/src/frontend/qt_sdl/Config.h
index 38a1c34c..4ca88b46 100644
--- a/src/frontend/qt_sdl/Config.h
+++ b/src/frontend/qt_sdl/Config.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
@@ -16,208 +16,122 @@
with melonDS. If not, see http://www.gnu.org/licenses/.
*/
-#ifndef PLATFORMCONFIG_H
-#define PLATFORMCONFIG_H
+#ifndef CONFIG_H
+#define CONFIG_H
#include
#include
+#include
+#include
+#include
-enum
-{
- HK_Lid = 0,
- HK_Mic,
- HK_Pause,
- HK_Reset,
- HK_FastForward,
- HK_FastForwardToggle,
- HK_FullscreenToggle,
- HK_SwapScreens,
- HK_SwapScreenEmphasis,
- HK_SolarSensorDecrease,
- HK_SolarSensorIncrease,
- HK_FrameStep,
- HK_PowerButton,
- HK_VolumeUp,
- HK_VolumeDown,
- HK_MAX
-};
-
-enum
-{
- micInputType_Silence,
- micInputType_External,
- micInputType_Noise,
- micInputType_Wav,
- micInputType_MAX,
-};
-
-enum
-{
- renderer3D_Software = 0,
-#ifdef OGLRENDERER_ENABLED
- renderer3D_OpenGL,
- renderer3D_OpenGLCompute,
-#endif
- renderer3D_Max,
-};
+#include "toml/toml/value.hpp"
namespace Config
{
-struct ConfigEntry
+struct LegacyEntry
{
char Name[32];
int Type; // 0=int 1=bool 2=string 3=64bit int
- void* Value; // pointer to the value variable
- std::variant Default;
+ char TOMLPath[64];
bool InstanceUnique; // whether the setting can exist individually for each instance in multiplayer
};
-struct CameraConfig
+template
+using DefaultList = std::unordered_map;
+
+using RangeList = std::unordered_map>;
+
+class Table;
+
+class Array
{
- int InputType; // 0=blank 1=image 2=camera
- std::string ImagePath;
- std::string CamDeviceName;
- bool XFlip;
+public:
+ Array(toml::value& data);
+ ~Array() {}
+
+ size_t Size();
+
+ void Clear();
+
+ Array GetArray(const int id);
+
+ int GetInt(const int id);
+ int64_t GetInt64(const int id);
+ bool GetBool(const int id);
+ std::string GetString(const int id);
+
+ void SetInt(const int id, int val);
+ void SetInt64(const int id, int64_t val);
+ void SetBool(const int id, bool val);
+ void SetString(const int id, const std::string& val);
+
+ // convenience
+
+ QString GetQString(const int id)
+ {
+ return QString::fromStdString(GetString(id));
+ }
+
+ void SetQString(const int id, const QString& val)
+ {
+ return SetString(id, val.toStdString());
+ }
+
+private:
+ toml::value& Data;
};
+class Table
+{
+public:
+ //Table();
+ Table(toml::value& data, const std::string& path);
+ ~Table() {}
-extern int KeyMapping[12];
-extern int JoyMapping[12];
+ Table& operator=(const Table& b);
-extern int HKKeyMapping[HK_MAX];
-extern int HKJoyMapping[HK_MAX];
+ Array GetArray(const std::string& path);
+ Table GetTable(const std::string& path, const std::string& defpath = "");
-extern int JoystickID;
+ int GetInt(const std::string& path);
+ int64_t GetInt64(const std::string& path);
+ bool GetBool(const std::string& path);
+ std::string GetString(const std::string& path);
-extern int WindowWidth;
-extern int WindowHeight;
-extern bool WindowMaximized;
+ void SetInt(const std::string& path, int val);
+ void SetInt64(const std::string& path, int64_t val);
+ void SetBool(const std::string& path, bool val);
+ void SetString(const std::string& path, const std::string& val);
-extern int ScreenRotation;
-extern int ScreenGap;
-extern int ScreenLayout;
-extern bool ScreenSwap;
-extern int ScreenSizing;
-extern int ScreenAspectTop;
-extern int ScreenAspectBot;
-extern bool IntegerScaling;
-extern bool ScreenFilter;
+ // convenience
-extern bool ScreenUseGL;
-extern bool ScreenVSync;
-extern int ScreenVSyncInterval;
+ QString GetQString(const std::string& path)
+ {
+ return QString::fromStdString(GetString(path));
+ }
-extern int _3DRenderer;
-extern bool Threaded3D;
+ void SetQString(const std::string& path, const QString& val)
+ {
+ return SetString(path, val.toStdString());
+ }
-extern int GL_ScaleFactor;
-extern bool GL_BetterPolygons;
-extern bool GL_HiresCoordinates;
+private:
+ toml::value& Data;
+ std::string PathPrefix;
-extern bool LimitFPS;
-extern int MaxFPS;
-extern bool AudioSync;
-extern bool ShowOSD;
-
-extern int ConsoleType;
-extern bool DirectBoot;
-
-#ifdef JIT_ENABLED
-extern bool JIT_Enable;
-extern int JIT_MaxBlockSize;
-extern bool JIT_BranchOptimisations;
-extern bool JIT_LiteralOptimisations;
-extern bool JIT_FastMemory;
-#endif
-
-extern bool ExternalBIOSEnable;
-
-extern std::string BIOS9Path;
-extern std::string BIOS7Path;
-extern std::string FirmwarePath;
-
-extern std::string DSiBIOS9Path;
-extern std::string DSiBIOS7Path;
-extern std::string DSiFirmwarePath;
-extern std::string DSiNANDPath;
-
-extern bool DLDIEnable;
-extern std::string DLDISDPath;
-extern int DLDISize;
-extern bool DLDIReadOnly;
-extern bool DLDIFolderSync;
-extern std::string DLDIFolderPath;
-
-extern bool DSiSDEnable;
-extern std::string DSiSDPath;
-extern int DSiSDSize;
-extern bool DSiSDReadOnly;
-extern bool DSiSDFolderSync;
-extern std::string DSiSDFolderPath;
-
-extern bool FirmwareOverrideSettings;
-extern std::string FirmwareUsername;
-extern int FirmwareLanguage;
-extern int FirmwareBirthdayMonth;
-extern int FirmwareBirthdayDay;
-extern int FirmwareFavouriteColour;
-extern std::string FirmwareMessage;
-extern std::string FirmwareMAC;
-extern std::string WifiSettingsPath;
-
-extern int MPAudioMode;
-extern int MPRecvTimeout;
-
-extern std::string LANDevice;
-extern bool DirectLAN;
-
-extern bool SavestateRelocSRAM;
-
-extern int AudioInterp;
-extern int AudioBitDepth;
-extern int AudioVolume;
-extern bool DSiVolumeSync;
-extern int MicInputType;
-extern std::string MicDevice;
-extern std::string MicWavPath;
-
-extern std::string LastROMFolder;
-extern std::string LastBIOSFolder;
-
-extern std::string RecentROMList[10];
-
-extern std::string SaveFilePath;
-extern std::string SavestatePath;
-extern std::string CheatFilePath;
-
-extern bool EnableCheats;
-
-extern bool MouseHide;
-extern int MouseHideSeconds;
-extern bool PauseLostFocus;
-extern std::string UITheme;
-
-extern int64_t RTCOffset;
-
-extern bool DSBatteryLevelOkay;
-extern int DSiBatteryLevel;
-extern bool DSiBatteryCharging;
-
-extern bool DSiFullBIOSBoot;
-
-extern CameraConfig Camera[2];
-
-extern bool GdbEnabled;
-extern int GdbPortARM7;
-extern int GdbPortARM9;
-extern bool GdbARM7BreakOnStartup;
-extern bool GdbARM9BreakOnStartup;
+ toml::value& ResolvePath(const std::string& path);
+ template T FindDefault(const std::string& path, T def, DefaultList list);
+};
bool Load();
void Save();
+Table GetLocalTable(int instance);
+inline Table GetGlobalTable() { return GetLocalTable(-1); }
+
}
-#endif // PLATFORMCONFIG_H
+#endif // CONFIG_H
diff --git a/src/frontend/qt_sdl/DateTimeDialog.cpp b/src/frontend/qt_sdl/DateTimeDialog.cpp
index 88ae6942..ac98300e 100644
--- a/src/frontend/qt_sdl/DateTimeDialog.cpp
+++ b/src/frontend/qt_sdl/DateTimeDialog.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
@@ -20,6 +20,7 @@
#include "types.h"
#include "Config.h"
+#include "main.h"
#include "DateTimeDialog.h"
#include "ui_DateTimeDialog.h"
@@ -32,8 +33,11 @@ DateTimeDialog::DateTimeDialog(QWidget* parent) : QDialog(parent), ui(new Ui::Da
ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose);
+ emuInstance = ((MainWindow*)parent)->getEmuInstance();
+
+ auto& cfg = emuInstance->getLocalConfig();
QDateTime now = QDateTime::currentDateTime();
- customTime = now.addSecs(Config::RTCOffset);
+ customTime = now.addSecs(cfg.GetInt64("RTC.Offset"));
ui->chkChangeTime->setChecked(false);
ui->chkResetTime->setChecked(false);
@@ -59,13 +63,15 @@ void DateTimeDialog::done(int r)
{
if (r == QDialog::Accepted)
{
+ auto& cfg = emuInstance->getLocalConfig();
+
if (ui->chkChangeTime->isChecked())
{
QDateTime now = QDateTime::currentDateTime();
- Config::RTCOffset = now.secsTo(ui->txtNewCustomTime->dateTime());
+ cfg.SetInt64("RTC.Offset", now.secsTo(ui->txtNewCustomTime->dateTime()));
}
else if (ui->chkResetTime->isChecked())
- Config::RTCOffset = 0;
+ cfg.SetInt64("RTC.Offset", 0);
Config::Save();
}
diff --git a/src/frontend/qt_sdl/DateTimeDialog.h b/src/frontend/qt_sdl/DateTimeDialog.h
index 22dabcd0..9763f306 100644
--- a/src/frontend/qt_sdl/DateTimeDialog.h
+++ b/src/frontend/qt_sdl/DateTimeDialog.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
@@ -26,6 +26,8 @@
namespace Ui {class DateTimeDialog; }
class DateTimeDialog;
+class EmuInstance;
+
class DateTimeDialog : public QDialog
{
Q_OBJECT
@@ -63,6 +65,7 @@ private slots:
private:
Ui::DateTimeDialog* ui;
+ EmuInstance* emuInstance;
QDateTime customTime;
};
diff --git a/src/frontend/qt_sdl/ROMManager.cpp b/src/frontend/qt_sdl/EmuInstance.cpp
similarity index 54%
rename from src/frontend/qt_sdl/ROMManager.cpp
rename to src/frontend/qt_sdl/EmuInstance.cpp
index 9607c848..8c041c3c 100644
--- a/src/frontend/qt_sdl/ROMManager.cpp
+++ b/src/frontend/qt_sdl/EmuInstance.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2023 melonDS team
+ Copyright 2016-2024 melonDS team
This file is part of melonDS.
@@ -35,9 +35,11 @@
#ifdef ARCHIVE_SUPPORT_ENABLED
#include "ArchiveUtil.h"
#endif
-#include "ROMManager.h"
+#include "EmuInstance.h"
#include "Config.h"
#include "Platform.h"
+#include "Net.h"
+#include "LocalMP.h"
#include "NDS.h"
#include "DSi.h"
@@ -56,32 +58,221 @@ using std::wstring_convert;
using namespace melonDS;
using namespace melonDS::Platform;
-namespace ROMManager
+
+MainWindow* topWindow = nullptr;
+
+const string kWifiSettingsPath = "wfcsettings.bin";
+
+
+EmuInstance::EmuInstance(int inst) : instanceID(inst),
+ globalCfg(Config::GetGlobalTable()),
+ localCfg(Config::GetLocalTable(inst))
{
+ consoleType = globalCfg.GetInt("Emu.ConsoleType");
-int CartType = -1;
-std::string BaseROMDir = "";
-std::string BaseROMName = "";
-std::string BaseAssetName = "";
+ ndsSave = nullptr;
+ cartType = -1;
+ baseROMDir = "";
+ baseROMName = "";
+ baseAssetName = "";
-int GBACartType = -1;
-std::string BaseGBAROMDir = "";
-std::string BaseGBAROMName = "";
-std::string BaseGBAAssetName = "";
+ gbaSave = nullptr;
+ gbaCartType = -1;
+ baseGBAROMDir = "";
+ baseGBAROMName = "";
+ baseGBAAssetName = "";
-std::unique_ptr NDSSave = nullptr;
-std::unique_ptr GBASave = nullptr;
-std::unique_ptr FirmwareSave = nullptr;
+ cheatFile = nullptr;
+ cheatsOn = localCfg.GetBool("EnableCheats");
-std::unique_ptr BackupState = nullptr;
-bool SavestateLoaded = false;
-std::string PreviousSaveFile = "";
+ doLimitFPS = globalCfg.GetBool("LimitFPS");
+ maxFPS = globalCfg.GetInt("MaxFPS");
+ doAudioSync = globalCfg.GetBool("AudioSync");
-ARCodeFile* CheatFile = nullptr;
-bool CheatsOn = false;
+ mpAudioMode = globalCfg.GetInt("MP.AudioMode");
+
+ nds = nullptr;
+ updateConsole(nullptr, nullptr);
+
+ audioInit();
+ inputInit();
+
+ Net::RegisterInstance(instanceID);
+
+ emuThread = new EmuThread(this);
+
+ numWindows = 0;
+ mainWindow = nullptr;
+ for (int i = 0; i < kMaxWindows; i++)
+ windowList[i] = nullptr;
+
+ if (inst == 0) topWindow = nullptr;
+ createWindow();
+
+ emuThread->start();
+ emuThread->emuPause();
+}
+
+EmuInstance::~EmuInstance()
+{
+ // TODO window cleanup and shit?
+
+ LocalMP::End(instanceID);
+
+ emuThread->emuExit();
+ emuThread->wait();
+ delete emuThread;
+
+ Net::UnregisterInstance(instanceID);
+
+ audioDeInit();
+ inputDeInit();
+}
-int LastSep(const std::string& path)
+std::string EmuInstance::instanceFileSuffix()
+{
+ if (instanceID == 0) return "";
+
+ char suffix[16] = {0};
+ snprintf(suffix, 15, ".%d", instanceID+1);
+ return suffix;
+}
+
+void EmuInstance::createWindow()
+{
+ if (numWindows >= kMaxWindows)
+ {
+ // TODO
+ return;
+ }
+
+ int id = -1;
+ for (int i = 0; i < kMaxWindows; i++)
+ {
+ if (windowList[i]) continue;
+ id = i;
+ break;
+ }
+
+ if (id == -1)
+ return;
+
+ MainWindow* win = new MainWindow(id, this, topWindow);
+ if (!topWindow) topWindow = win;
+ if (!mainWindow) mainWindow = win;
+ windowList[id] = win;
+ numWindows++;
+
+ emuThread->attachWindow(win);
+}
+
+
+void EmuInstance::osdAddMessage(unsigned int color, const char* fmt, ...)
+{
+ if (fmt == nullptr)
+ return;
+
+ char msg[256];
+ va_list args;
+ va_start(args, fmt);
+ vsnprintf(msg, 256, fmt, args);
+ va_end(args);
+
+ for (int i = 0; i < kMaxWindows; i++)
+ {
+ if (windowList[i])
+ windowList[i]->osdAddMessage(color, msg);
+ }
+}
+
+
+bool EmuInstance::emuIsActive()
+{
+ return emuThread->emuIsActive();
+}
+
+void EmuInstance::emuStop(StopReason reason)
+{
+ if (reason != StopReason::External)
+ emuThread->emuStop(false);
+
+ switch (reason)
+ {
+ case StopReason::GBAModeNotSupported:
+ osdAddMessage(0xFFA0A0, "GBA mode not supported");
+ break;
+ case StopReason::BadExceptionRegion:
+ osdAddMessage(0xFFA0A0, "Internal error");
+ break;
+ case StopReason::PowerOff:
+ case StopReason::External:
+ osdAddMessage(0xFFC040, "Shutdown");
+ default:
+ break;
+ }
+}
+
+
+bool EmuInstance::usesOpenGL()
+{
+ return globalCfg.GetBool("Screen.UseGL") ||
+ (globalCfg.GetInt("3D.Renderer") != renderer3D_Software);
+}
+
+void EmuInstance::initOpenGL()
+{
+ for (int i = 0; i < kMaxWindows; i++)
+ {
+ if (windowList[i])
+ windowList[i]->initOpenGL();
+ }
+
+ setVSyncGL(true);
+}
+
+void EmuInstance::deinitOpenGL()
+{
+ for (int i = 0; i < kMaxWindows; i++)
+ {
+ if (windowList[i])
+ windowList[i]->deinitOpenGL();
+ }
+}
+
+void EmuInstance::setVSyncGL(bool vsync)
+{
+ int intv;
+
+ vsync = vsync && globalCfg.GetBool("Screen.VSync");
+ if (vsync)
+ intv = globalCfg.GetInt("Screen.VSyncInterval");
+ else
+ intv = 0;
+
+ for (int i = 0; i < kMaxWindows; i++)
+ {
+ if (windowList[i])
+ windowList[i]->setGLSwapInterval(intv);
+ }
+}
+
+void EmuInstance::makeCurrentGL()
+{
+ mainWindow->makeCurrentGL();
+}
+
+void EmuInstance::drawScreenGL()
+{
+ for (int i = 0; i < kMaxWindows; i++)
+ {
+ if (windowList[i])
+ windowList[i]->drawScreenGL();
+ }
+}
+
+
+int EmuInstance::lastSep(const std::string& path)
{
int i = path.length() - 1;
while (i >= 0)
@@ -95,12 +286,12 @@ int LastSep(const std::string& path)
return -1;
}
-std::string GetAssetPath(bool gba, const std::string& configpath, const std::string& ext, const std::string& file = "")
+string EmuInstance::getAssetPath(bool gba, const string& configpath, const string& ext, const string& file = "")
{
- std::string result;
+ string result;
if (configpath.empty())
- result = gba ? BaseGBAROMDir : BaseROMDir;
+ result = gba ? baseGBAROMDir : baseROMDir;
else
result = configpath;
@@ -120,7 +311,7 @@ std::string GetAssetPath(bool gba, const std::string& configpath, const std::str
if (file.empty())
{
- std::string& baseName = gba ? BaseGBAAssetName : BaseAssetName;
+ std::string& baseName = gba ? baseGBAAssetName : baseAssetName;
if (baseName.empty())
result += "firmware";
else
@@ -137,12 +328,12 @@ std::string GetAssetPath(bool gba, const std::string& configpath, const std::str
}
-QString VerifyDSBIOS()
+QString EmuInstance::verifyDSBIOS()
{
FileHandle* f;
long len;
- f = Platform::OpenLocalFile(Config::BIOS9Path, FileMode::Read);
+ f = Platform::OpenLocalFile(globalCfg.GetString("DS.BIOS9Path"), FileMode::Read);
if (!f) return "DS ARM9 BIOS was not found or could not be accessed. Check your emu settings.";
len = FileLength(f);
@@ -154,7 +345,7 @@ QString VerifyDSBIOS()
CloseFile(f);
- f = Platform::OpenLocalFile(Config::BIOS7Path, FileMode::Read);
+ f = Platform::OpenLocalFile(globalCfg.GetString("DS.BIOS7Path"), FileMode::Read);
if (!f) return "DS ARM7 BIOS was not found or could not be accessed. Check your emu settings.";
len = FileLength(f);
@@ -169,14 +360,14 @@ QString VerifyDSBIOS()
return "";
}
-QString VerifyDSiBIOS()
+QString EmuInstance::verifyDSiBIOS()
{
FileHandle* f;
long len;
// TODO: check the first 32 bytes
- f = Platform::OpenLocalFile(Config::DSiBIOS9Path, FileMode::Read);
+ f = Platform::OpenLocalFile(globalCfg.GetString("DSi.BIOS9Path"), FileMode::Read);
if (!f) return "DSi ARM9 BIOS was not found or could not be accessed. Check your emu settings.";
len = FileLength(f);
@@ -188,7 +379,7 @@ QString VerifyDSiBIOS()
CloseFile(f);
- f = Platform::OpenLocalFile(Config::DSiBIOS7Path, FileMode::Read);
+ f = Platform::OpenLocalFile(globalCfg.GetString("DSi.BIOS7Path"), FileMode::Read);
if (!f) return "DSi ARM7 BIOS was not found or could not be accessed. Check your emu settings.";
len = FileLength(f);
@@ -203,15 +394,17 @@ QString VerifyDSiBIOS()
return "";
}
-QString VerifyDSFirmware()
+QString EmuInstance::verifyDSFirmware()
{
FileHandle* f;
long len;
- f = Platform::OpenLocalFile(Config::FirmwarePath, FileMode::Read);
+ std::string fwpath = globalCfg.GetString("DS.FirmwarePath");
+
+ f = Platform::OpenLocalFile(fwpath, FileMode::Read);
if (!f) return "DS firmware was not found or could not be accessed. Check your emu settings.";
- if (!Platform::CheckFileWritable(Config::FirmwarePath))
+ if (!Platform::CheckFileWritable(fwpath))
return "DS firmware is unable to be written to.\nPlease check file/folder write permissions.";
len = FileLength(f);
@@ -233,15 +426,17 @@ QString VerifyDSFirmware()
return "";
}
-QString VerifyDSiFirmware()
+QString EmuInstance::verifyDSiFirmware()
{
FileHandle* f;
long len;
- f = Platform::OpenLocalFile(Config::DSiFirmwarePath, FileMode::Read);
+ std::string fwpath = globalCfg.GetString("DSi.FirmwarePath");
+
+ f = Platform::OpenLocalFile(fwpath, FileMode::Read);
if (!f) return "DSi firmware was not found or could not be accessed. Check your emu settings.";
- if (!Platform::CheckFileWritable(Config::FirmwarePath))
+ if (!Platform::CheckFileWritable(fwpath))
return "DSi firmware is unable to be written to.\nPlease check file/folder write permissions.";
len = FileLength(f);
@@ -258,15 +453,17 @@ QString VerifyDSiFirmware()
return "";
}
-QString VerifyDSiNAND()
+QString EmuInstance::verifyDSiNAND()
{
FileHandle* f;
long len;
- f = Platform::OpenLocalFile(Config::DSiNANDPath, FileMode::ReadWriteExisting);
+ std::string nandpath = globalCfg.GetString("DSi.NANDPath");
+
+ f = Platform::OpenLocalFile(nandpath, FileMode::ReadWriteExisting);
if (!f) return "DSi NAND was not found or could not be accessed. Check your emu settings.";
- if (!Platform::CheckFileWritable(Config::FirmwarePath))
+ if (!Platform::CheckFileWritable(nandpath))
return "DSi NAND is unable to be written to.\nPlease check file/folder write permissions.";
// TODO: some basic checks
@@ -277,35 +474,38 @@ QString VerifyDSiNAND()
return "";
}
-QString VerifySetup()
+QString EmuInstance::verifySetup()
{
QString res;
- if (Config::ExternalBIOSEnable)
+ bool extbios = globalCfg.GetBool("Emu.ExternalBIOSEnable");
+ int console = globalCfg.GetInt("Emu.ConsoleType");
+
+ if (extbios)
{
- res = VerifyDSBIOS();
+ res = verifyDSBIOS();
if (!res.isEmpty()) return res;
}
- if (Config::ConsoleType == 1)
+ if (console == 1)
{
- res = VerifyDSiBIOS();
+ res = verifyDSiBIOS();
if (!res.isEmpty()) return res;
- if (Config::ExternalBIOSEnable)
+ if (extbios)
{
- res = VerifyDSiFirmware();
+ res = verifyDSiFirmware();
if (!res.isEmpty()) return res;
}
- res = VerifyDSiNAND();
+ res = verifyDSiNAND();
if (!res.isEmpty()) return res;
}
else
{
- if (Config::ExternalBIOSEnable)
+ if (extbios)
{
- res = VerifyDSFirmware();
+ res = verifyDSFirmware();
if (!res.isEmpty()) return res;
}
}
@@ -313,43 +513,44 @@ QString VerifySetup()
return "";
}
-std::string GetEffectiveFirmwareSavePath(EmuThread* thread)
+
+std::string EmuInstance::getEffectiveFirmwareSavePath()
{
- if (!Config::ExternalBIOSEnable)
+ if (!globalCfg.GetBool("Emu.ExternalBIOSEnable"))
{
- return Config::WifiSettingsPath;
+ return kWifiSettingsPath;
}
- if (thread->NDS->ConsoleType == 1)
+ if (consoleType == 1)
{
- return Config::DSiFirmwarePath;
+ return globalCfg.GetString("DSi.FirmwarePath");
}
else
{
- return Config::FirmwarePath;
+ return globalCfg.GetString("DS.FirmwarePath");
}
}
// Initializes the firmware save manager with the selected firmware image's path
// OR the path to the wi-fi settings.
-void InitFirmwareSaveManager(EmuThread* thread) noexcept
+void EmuInstance::initFirmwareSaveManager() noexcept
{
- FirmwareSave = std::make_unique(GetEffectiveFirmwareSavePath(thread));
+ firmwareSave = std::make_unique(getEffectiveFirmwareSavePath() + instanceFileSuffix());
}
-std::string GetSavestateName(int slot)
+std::string EmuInstance::getSavestateName(int slot)
{
std::string ext = ".ml";
ext += (char)('0'+slot);
- return GetAssetPath(false, Config::SavestatePath, ext);
+ return getAssetPath(false, globalCfg.GetString("SavestatePath"), ext);
}
-bool SavestateExists(int slot)
+bool EmuInstance::savestateExists(int slot)
{
- std::string ssfile = GetSavestateName(slot);
+ std::string ssfile = getSavestateName(slot);
return Platform::FileExists(ssfile);
}
-bool LoadState(NDS& nds, const std::string& filename)
+bool EmuInstance::loadState(const std::string& filename)
{
FILE* file = fopen(filename.c_str(), "rb");
if (file == nullptr)
@@ -366,7 +567,7 @@ bool LoadState(NDS& nds, const std::string& filename)
return false;
}
- if (!nds.DoSavestate(backup.get()) || backup->Error)
+ if (!nds->DoSavestate(backup.get()) || backup->Error)
{ // Back up the emulator's state. If that failed...
Platform::Log(Platform::LogLevel::Error, "Failed to back up state, aborting load (from \"%s\")\n", filename.c_str());
fclose(file);
@@ -398,32 +599,32 @@ bool LoadState(NDS& nds, const std::string& filename)
// Get ready to load the state from the buffer into the emulator
std::unique_ptr state = std::make_unique(buffer.data(), size, false);
- if (!nds.DoSavestate(state.get()) || state->Error)
+ if (!nds->DoSavestate(state.get()) || state->Error)
{ // If we couldn't load the savestate from the buffer...
Platform::Log(Platform::LogLevel::Error, "Failed to load state file \"%s\" into emulator\n", filename.c_str());
return false;
}
// The backup was made and the state was loaded, so we can store the backup now.
- BackupState = std::move(backup); // This will clean up any existing backup
+ backupState = std::move(backup); // This will clean up any existing backup
assert(backup == nullptr);
- if (Config::SavestateRelocSRAM && NDSSave)
+ if (globalCfg.GetBool("Savestate.RelocSRAM") && ndsSave)
{
- PreviousSaveFile = NDSSave->GetPath();
+ previousSaveFile = ndsSave->GetPath();
- std::string savefile = filename.substr(LastSep(filename)+1);
- savefile = GetAssetPath(false, Config::SaveFilePath, ".sav", savefile);
- savefile += Platform::InstanceFileSuffix();
- NDSSave->SetPath(savefile, true);
+ std::string savefile = filename.substr(lastSep(filename)+1);
+ savefile = getAssetPath(false, globalCfg.GetString("SaveFilePath"), ".sav", savefile);
+ savefile += instanceFileSuffix();
+ ndsSave->SetPath(savefile, true);
}
- SavestateLoaded = true;
+ savestateLoaded = true;
return true;
}
-bool SaveState(NDS& nds, const std::string& filename)
+bool EmuInstance::saveState(const std::string& filename)
{
FILE* file = fopen(filename.c_str(), "wb");
@@ -440,7 +641,7 @@ bool SaveState(NDS& nds, const std::string& filename)
}
// Write the savestate to the in-memory buffer
- nds.DoSavestate(&state);
+ nds->DoSavestate(&state);
if (state.Error)
{
@@ -451,9 +652,9 @@ bool SaveState(NDS& nds, const std::string& filename)
if (fwrite(state.Buffer(), state.Length(), 1, file) == 0)
{ // Write the Savestate buffer to the file. If that fails...
Platform::Log(Platform::Error,
- "Failed to write %d-byte savestate to %s\n",
- state.Length(),
- filename.c_str()
+ "Failed to write %d-byte savestate to %s\n",
+ state.Length(),
+ filename.c_str()
);
fclose(file);
return false;
@@ -461,71 +662,73 @@ bool SaveState(NDS& nds, const std::string& filename)
fclose(file);
- if (Config::SavestateRelocSRAM && NDSSave)
+ if (globalCfg.GetBool("Savestate.RelocSRAM") && ndsSave)
{
- std::string savefile = filename.substr(LastSep(filename)+1);
- savefile = GetAssetPath(false, Config::SaveFilePath, ".sav", savefile);
- savefile += Platform::InstanceFileSuffix();
- NDSSave->SetPath(savefile, false);
+ std::string savefile = filename.substr(lastSep(filename)+1);
+ savefile = getAssetPath(false, globalCfg.GetString("SaveFilePath"), ".sav", savefile);
+ savefile += instanceFileSuffix();
+ ndsSave->SetPath(savefile, false);
}
return true;
}
-void UndoStateLoad(NDS& nds)
+void EmuInstance::undoStateLoad()
{
- if (!SavestateLoaded || !BackupState) return;
+ if (!savestateLoaded || !backupState) return;
// Rewind the backup state and put it in load mode
- BackupState->Rewind(false);
+ backupState->Rewind(false);
// pray that this works
// what do we do if it doesn't???
// but it should work.
- nds.DoSavestate(BackupState.get());
+ nds->DoSavestate(backupState.get());
- if (NDSSave && (!PreviousSaveFile.empty()))
+ if (ndsSave && (!previousSaveFile.empty()))
{
- NDSSave->SetPath(PreviousSaveFile, true);
+ ndsSave->SetPath(previousSaveFile, true);
}
}
-void UnloadCheats(NDS& nds)
+void EmuInstance::unloadCheats()
{
- if (CheatFile)
+ if (cheatFile)
{
- delete CheatFile;
- CheatFile = nullptr;
- nds.AREngine.SetCodeFile(nullptr);
+ delete cheatFile;
+ cheatFile = nullptr;
+ nds->AREngine.SetCodeFile(nullptr);
}
}
-void LoadCheats(NDS& nds)
+void EmuInstance::loadCheats()
{
- UnloadCheats(nds);
+ unloadCheats();
- std::string filename = GetAssetPath(false, Config::CheatFilePath, ".mch");
+ std::string filename = getAssetPath(false, globalCfg.GetString("CheatFilePath"), ".mch");
// TODO: check for error (malformed cheat file, ...)
- CheatFile = new ARCodeFile(filename);
+ cheatFile = new ARCodeFile(filename);
- nds.AREngine.SetCodeFile(CheatsOn ? CheatFile : nullptr);
+ nds->AREngine.SetCodeFile(cheatsOn ? cheatFile : nullptr);
}
-std::unique_ptr LoadARM9BIOS() noexcept
+std::unique_ptr EmuInstance::loadARM9BIOS() noexcept
{
- if (!Config::ExternalBIOSEnable)
+ if (!globalCfg.GetBool("Emu.ExternalBIOSEnable"))
{
- return Config::ConsoleType == 0 ? std::make_unique(bios_arm9_bin) : nullptr;
+ return globalCfg.GetInt("Emu.ConsoleType") == 0 ? std::make_unique(bios_arm9_bin) : nullptr;
}
- if (FileHandle* f = OpenLocalFile(Config::BIOS9Path, Read))
+ string path = globalCfg.GetString("DS.BIOS9Path");
+
+ if (FileHandle* f = OpenLocalFile(path, Read))
{
std::unique_ptr bios = std::make_unique();
FileRewind(f);
FileRead(bios->data(), bios->size(), 1, f);
CloseFile(f);
- Log(Info, "ARM9 BIOS loaded from %s\n", Config::BIOS9Path.c_str());
+ Log(Info, "ARM9 BIOS loaded from %s\n", path.c_str());
return bios;
}
@@ -533,19 +736,21 @@ std::unique_ptr LoadARM9BIOS() noexcept
return nullptr;
}
-std::unique_ptr LoadARM7BIOS() noexcept
+std::unique_ptr EmuInstance::loadARM7BIOS() noexcept
{
- if (!Config::ExternalBIOSEnable)
+ if (!globalCfg.GetBool("Emu.ExternalBIOSEnable"))
{
- return Config::ConsoleType == 0 ? std::make_unique(bios_arm7_bin) : nullptr;
+ return globalCfg.GetInt("Emu.ConsoleType") == 0 ? std::make_unique