Experimental save state support
This commit is contained in:
@@ -90,4 +90,29 @@ void Core::Run(float volumeL, float volumeR) {
|
|||||||
scheduler.tick(frameCycles, mem, regs);
|
scheduler.tick(frameCycles, mem, regs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Core::Serialize() {
|
||||||
|
auto sMEM = cpu->mem.Serialize();
|
||||||
|
auto sCPU = cpu->Serialize();
|
||||||
|
auto sVER = std::vector<u8>{KAIZEN_VERSION >> 8, KAIZEN_VERSION >> 4, KAIZEN_VERSION & 0xFF};
|
||||||
|
memSize = sMEM.size();
|
||||||
|
cpuSize = sCPU.size();
|
||||||
|
verSize = sVER.size();
|
||||||
|
serialized[slot].insert(serialized[slot].begin(), sVER.begin(), sVER.end());
|
||||||
|
serialized[slot].insert(serialized[slot].end(), sMEM.begin(), sMEM.end());
|
||||||
|
serialized[slot].insert(serialized[slot].end(), sCPU.begin(), sCPU.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::Deserialize() {
|
||||||
|
std::vector<u8> dVER(serialized[slot].begin(), serialized[slot].begin() + verSize);
|
||||||
|
if(dVER[0] != (KAIZEN_VERSION >> 8)
|
||||||
|
|| dVER[1] != (KAIZEN_VERSION >> 4)
|
||||||
|
|| dVER[2] != (KAIZEN_VERSION & 0xFF)) {
|
||||||
|
Util::panic("PROBLEMI!");
|
||||||
|
}
|
||||||
|
|
||||||
|
cpu->mem.Deserialize(std::vector<u8>(serialized[slot].begin() + verSize, serialized[slot].begin() + verSize + memSize));
|
||||||
|
cpu->Deserialize(std::vector<u8>(serialized[slot].begin() + verSize + memSize, serialized[slot].begin() + verSize + memSize + cpuSize));
|
||||||
|
serialized[slot].erase(serialized[slot].begin(), serialized[slot].end());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ struct Core {
|
|||||||
void Stop();
|
void Stop();
|
||||||
void LoadROM(const std::string&);
|
void LoadROM(const std::string&);
|
||||||
void Run(float volumeL, float volumeR);
|
void Run(float volumeL, float volumeR);
|
||||||
|
void Serialize();
|
||||||
|
void Deserialize();
|
||||||
void TogglePause() { pause = !pause; }
|
void TogglePause() { pause = !pause; }
|
||||||
[[nodiscard]] VI& GetVI() { return cpu->mem.mmio.vi; }
|
[[nodiscard]] VI& GetVI() { return cpu->mem.mmio.vi; }
|
||||||
|
|
||||||
@@ -25,5 +27,8 @@ struct Core {
|
|||||||
bool romLoaded = false;
|
bool romLoaded = false;
|
||||||
std::string rom;
|
std::string rom;
|
||||||
std::unique_ptr<BaseCPU> cpu;
|
std::unique_ptr<BaseCPU> cpu;
|
||||||
|
std::vector<u8> serialized[10]{};
|
||||||
|
int memSize, cpuSize, verSize;
|
||||||
|
int slot = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ struct BaseCPU {
|
|||||||
}
|
}
|
||||||
virtual bool ShouldServiceInterrupt() = 0;
|
virtual bool ShouldServiceInterrupt() = 0;
|
||||||
virtual void CheckCompareInterrupt() = 0;
|
virtual void CheckCompareInterrupt() = 0;
|
||||||
|
virtual std::vector<u8> Serialize() = 0;
|
||||||
|
virtual void Deserialize(const std::vector<u8>&) = 0;
|
||||||
Registers regs;
|
Registers regs;
|
||||||
Mem mem;
|
Mem mem;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -55,4 +55,18 @@ int Interpreter::Step() {
|
|||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<u8> Interpreter::Serialize() {
|
||||||
|
std::vector<u8> res{};
|
||||||
|
|
||||||
|
res.resize(sizeof(Registers));
|
||||||
|
|
||||||
|
memcpy(res.data(), ®s, sizeof(Registers));
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Interpreter::Deserialize(const std::vector<u8> &data) {
|
||||||
|
memcpy(®s, data.data(), sizeof(Registers));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -15,6 +15,9 @@ private:
|
|||||||
#define check_address_error(mask, vaddr) (((!regs.cop0.is_64bit_addressing) && (s32)(vaddr) != (vaddr)) || (((vaddr) & (mask)) != 0))
|
#define check_address_error(mask, vaddr) (((!regs.cop0.is_64bit_addressing) && (s32)(vaddr) != (vaddr)) || (((vaddr) & (mask)) != 0))
|
||||||
bool ShouldServiceInterrupt() override;
|
bool ShouldServiceInterrupt() override;
|
||||||
void CheckCompareInterrupt() override;
|
void CheckCompareInterrupt() override;
|
||||||
|
std::vector<u8> Serialize() override;
|
||||||
|
void Deserialize(const std::vector<u8>&) override;
|
||||||
|
|
||||||
void cop2Decode(u32);
|
void cop2Decode(u32);
|
||||||
void special(u32);
|
void special(u32);
|
||||||
void regimm(u32);
|
void regimm(u32);
|
||||||
|
|||||||
@@ -101,6 +101,9 @@ private:
|
|||||||
return mem.Read8(regs, addr);
|
return mem.Read8(regs, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<u8> Serialize() override { return {}; }
|
||||||
|
void Deserialize(const std::vector<u8>&) override { }
|
||||||
|
|
||||||
void cop2Decode(u32);
|
void cop2Decode(u32);
|
||||||
void special(u32);
|
void special(u32);
|
||||||
void regimm(u32);
|
void regimm(u32);
|
||||||
|
|||||||
@@ -44,4 +44,80 @@ void MMIO::Write(Mem& mem, Registers& regs, u32 addr, u32 val) {
|
|||||||
Util::panic("Unhandled mmio write at addr {:08X} with val {:08X}", addr, val);
|
Util::panic("Unhandled mmio write at addr {:08X} with val {:08X}", addr, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<u8> MMIO::Serialize() {
|
||||||
|
std::vector<u8> res{};
|
||||||
|
|
||||||
|
auto sPIF = si.pif.Serialize();
|
||||||
|
constexpr u32 rdpSize = sizeof(DPC) +
|
||||||
|
0xFFFFF +
|
||||||
|
RDRAM_SIZE;
|
||||||
|
res.resize(
|
||||||
|
rdpSize +
|
||||||
|
sizeof(RSP) +
|
||||||
|
sizeof(MI) +
|
||||||
|
sizeof(VI) +
|
||||||
|
sizeof(SI) +
|
||||||
|
sizeof(PI) +
|
||||||
|
sizeof(RI) +
|
||||||
|
sizeof(AI) +
|
||||||
|
sizeof(u32)*2 +
|
||||||
|
sizeof(SIStatus));
|
||||||
|
|
||||||
|
u32 index = 0;
|
||||||
|
memcpy(res.data(), &rsp, sizeof(RSP));
|
||||||
|
index += sizeof(RSP);
|
||||||
|
memcpy(res.data() + index, &rdp.dpc, sizeof(DPC));
|
||||||
|
index += sizeof(DPC);
|
||||||
|
memcpy(res.data() + index, rdp.cmd_buf, 0xFFFFF);
|
||||||
|
index += 0xFFFFF;
|
||||||
|
memcpy(res.data() + index, rdp.rdram, RDRAM_SIZE);
|
||||||
|
index += RDRAM_SIZE;
|
||||||
|
memcpy(res.data() + index, &mi, sizeof(MI));
|
||||||
|
index += sizeof(MI);
|
||||||
|
memcpy(res.data() + index, &vi, sizeof(VI));
|
||||||
|
index += sizeof(VI);
|
||||||
|
memcpy(res.data() + index, &ai, sizeof(AI));
|
||||||
|
index += sizeof(AI);
|
||||||
|
memcpy(res.data() + index, &pi, sizeof(PI));
|
||||||
|
index += sizeof(PI);
|
||||||
|
memcpy(res.data() + index, &ri, sizeof(RI));
|
||||||
|
index += sizeof(RI);
|
||||||
|
memcpy(res.data() + index, &si.dramAddr, sizeof(u32));
|
||||||
|
index += sizeof(u32);
|
||||||
|
memcpy(res.data() + index, &si.pifAddr, sizeof(u32));
|
||||||
|
index += sizeof(u32);
|
||||||
|
memcpy(res.data() + index, &si.status, sizeof(SIStatus));
|
||||||
|
|
||||||
|
res.insert(res.end(), sPIF.begin(), sPIF.end());
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MMIO::Deserialize(const std::vector<u8> &data) {
|
||||||
|
u32 index = 0;
|
||||||
|
memcpy(&rsp, data.data(), sizeof(RSP));
|
||||||
|
index += sizeof(RSP);
|
||||||
|
memcpy(&rdp.dpc, data.data() + index, sizeof(DPC));
|
||||||
|
index += sizeof(DPC);
|
||||||
|
memcpy(rdp.cmd_buf, data.data() + index, 0xFFFFF);
|
||||||
|
index += 0xFFFFF;
|
||||||
|
memcpy(rdp.rdram, data.data() + index, RDRAM_SIZE);
|
||||||
|
index += RDRAM_SIZE;
|
||||||
|
memcpy(&mi, data.data() + index, sizeof(MI));
|
||||||
|
index += sizeof(MI);
|
||||||
|
memcpy(&vi, data.data() + index, sizeof(VI));
|
||||||
|
index += sizeof(VI);
|
||||||
|
memcpy(&ai, data.data() + index, sizeof(AI));
|
||||||
|
index += sizeof(AI);
|
||||||
|
memcpy(&pi, data.data() + index, sizeof(PI));
|
||||||
|
index += sizeof(PI);
|
||||||
|
memcpy(&ri, data.data() + index, sizeof(RI));
|
||||||
|
index += sizeof(RI);
|
||||||
|
memcpy(&si.dramAddr, data.data() + index, sizeof(u32));
|
||||||
|
index += sizeof(u32);
|
||||||
|
memcpy(&si.pifAddr, data.data() + index, sizeof(u32));
|
||||||
|
index += sizeof(u32);
|
||||||
|
memcpy(&si.status, data.data() + index, sizeof(SIStatus));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,5 +27,7 @@ struct MMIO {
|
|||||||
|
|
||||||
u32 Read(u32);
|
u32 Read(u32);
|
||||||
void Write(Mem&, Registers&, u32, u32);
|
void Write(Mem&, Registers&, u32, u32);
|
||||||
|
std::vector<u8> Serialize();
|
||||||
|
void Deserialize(const std::vector<u8>&);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -601,4 +601,25 @@ void Mem::Write64(Registers& regs, u32 paddr, u64 val) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<u8> Mem::Serialize() {
|
||||||
|
std::vector<u8> res{};
|
||||||
|
|
||||||
|
auto sMMIO = mmio.Serialize();
|
||||||
|
auto sFLASH = flash.Serialize();
|
||||||
|
mmioSize = sMMIO.size();
|
||||||
|
flashSize = sFLASH.size();
|
||||||
|
|
||||||
|
res.insert(res.begin(), sMMIO.begin(), sMMIO.end());
|
||||||
|
res.insert(res.end(), sFLASH.begin(), sFLASH.end());
|
||||||
|
res.insert(res.end(), sram.begin(), sram.end());
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mem::Deserialize(const std::vector<u8>& data) {
|
||||||
|
mmio.Deserialize(std::vector<u8>(data.begin(), data.begin() + mmioSize));
|
||||||
|
flash.Deserialize(std::vector<u8>(data.begin() + mmioSize, data.begin() + mmioSize + flashSize));
|
||||||
|
memcpy(sram.data(), data.data() + mmioSize + flashSize, sram.size());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -73,6 +73,45 @@ struct Flash {
|
|||||||
void CommandWrite();
|
void CommandWrite();
|
||||||
void CommandRead();
|
void CommandRead();
|
||||||
|
|
||||||
|
FORCE_INLINE std::vector<u8> Serialize() {
|
||||||
|
std::vector<u8> res{};
|
||||||
|
|
||||||
|
res.resize(
|
||||||
|
sizeof(state) +
|
||||||
|
sizeof(status) +
|
||||||
|
sizeof(eraseOffs) +
|
||||||
|
sizeof(writeOffs) +
|
||||||
|
128);
|
||||||
|
|
||||||
|
u32 index = 0;
|
||||||
|
memcpy(res.data() + index, &state, sizeof(state));
|
||||||
|
index += sizeof(state);
|
||||||
|
memcpy(res.data() + index, &status, sizeof(status));
|
||||||
|
index += sizeof(status);
|
||||||
|
memcpy(res.data() + index, &eraseOffs, sizeof(eraseOffs));
|
||||||
|
index += sizeof(eraseOffs);
|
||||||
|
memcpy(res.data() + index, &writeOffs, sizeof(writeOffs));
|
||||||
|
index += sizeof(writeOffs);
|
||||||
|
memcpy(res.data() + index, writeBuf, 128);
|
||||||
|
|
||||||
|
res.insert(res.begin(), flash.begin(), flash.end());
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE void Deserialize(const std::vector<u8>& data) {
|
||||||
|
u32 index = 0;
|
||||||
|
memcpy(&state, data.data() + index, sizeof(state));
|
||||||
|
index += sizeof(state);
|
||||||
|
memcpy(&status, data.data() + index, sizeof(status));
|
||||||
|
index += sizeof(status);
|
||||||
|
memcpy(&eraseOffs, data.data() + index, sizeof(eraseOffs));
|
||||||
|
index += sizeof(eraseOffs);
|
||||||
|
memcpy(&writeOffs, data.data() + index, sizeof(writeOffs));
|
||||||
|
index += sizeof(writeOffs);
|
||||||
|
memcpy(writeBuf, data.data() + index, 128);
|
||||||
|
}
|
||||||
|
|
||||||
FORCE_INLINE void Write32(u32 index, u32 val) {
|
FORCE_INLINE void Write32(u32 index, u32 val) {
|
||||||
if(index > 0) {
|
if(index > 0) {
|
||||||
u8 cmd = val >> 24;
|
u8 cmd = val >> 24;
|
||||||
@@ -141,6 +180,9 @@ struct Mem {
|
|||||||
return mmio.rdp.rdram;
|
return mmio.rdp.rdram;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<u8> Serialize();
|
||||||
|
void Deserialize(const std::vector<u8>&);
|
||||||
|
|
||||||
u8 Read8(Registers&, u32);
|
u8 Read8(Registers&, u32);
|
||||||
u16 Read16(Registers&, u32);
|
u16 Read16(Registers&, u32);
|
||||||
u32 Read32(Registers&, u32);
|
u32 Read32(Registers&, u32);
|
||||||
@@ -194,6 +236,7 @@ private:
|
|||||||
mio::mmap_sink sram;
|
mio::mmap_sink sram;
|
||||||
u8 isviewer[ISVIEWER_SIZE]{};
|
u8 isviewer[ISVIEWER_SIZE]{};
|
||||||
std::string sramPath{};
|
std::string sramPath{};
|
||||||
|
int mmioSize, flashSize;
|
||||||
|
|
||||||
FORCE_INLINE bool IsROMPAL() {
|
FORCE_INLINE bool IsROMPAL() {
|
||||||
static const char pal_codes[] = {'D', 'F', 'I', 'P', 'S', 'U', 'X', 'Y'};
|
static const char pal_codes[] = {'D', 'F', 'I', 'P', 'S', 'U', 'X', 'Y'};
|
||||||
|
|||||||
@@ -988,5 +988,4 @@ void Interpreter::ctc2(u32) {
|
|||||||
void Interpreter::cfc2(u32) {
|
void Interpreter::cfc2(u32) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -627,4 +627,30 @@ void PIF::ExecutePIF(Mem& mem, Registers& regs) {
|
|||||||
|
|
||||||
DoPIFHLE(mem, regs, pal, cicType);
|
DoPIFHLE(mem, regs, pal, cicType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<u8> PIF::Serialize() {
|
||||||
|
std::vector<u8> res{};
|
||||||
|
res.resize(
|
||||||
|
6*sizeof(JoybusDevice) +
|
||||||
|
PIF_BOOTROM_SIZE +
|
||||||
|
PIF_RAM_SIZE +
|
||||||
|
mempak.size() +
|
||||||
|
eeprom.size() +
|
||||||
|
sizeof(int));
|
||||||
|
|
||||||
|
u32 index = 0;
|
||||||
|
memcpy(res.data() + index, joybusDevices, 6*sizeof(JoybusDevice));
|
||||||
|
index += 6*sizeof(JoybusDevice);
|
||||||
|
memcpy(res.data() + index, bootrom, PIF_BOOTROM_SIZE);
|
||||||
|
index += PIF_BOOTROM_SIZE;
|
||||||
|
memcpy(res.data() + index, ram, PIF_RAM_SIZE);
|
||||||
|
index += PIF_RAM_SIZE;
|
||||||
|
memcpy(res.data() + index, mempak.data(), mempak.size());
|
||||||
|
index += mempak.size();
|
||||||
|
memcpy(res.data() + index, eeprom.data(), eeprom.size());
|
||||||
|
index += eeprom.size();
|
||||||
|
memcpy(res.data() + index, &channel, sizeof(int));
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -122,6 +122,7 @@ struct PIF {
|
|||||||
void MempakWrite(u8*, u8*);
|
void MempakWrite(u8*, u8*);
|
||||||
void EepromRead(const u8*, u8*, const Mem&) const;
|
void EepromRead(const u8*, u8*, const Mem&) const;
|
||||||
void EepromWrite(const u8*, u8*, const Mem&);
|
void EepromWrite(const u8*, u8*, const Mem&);
|
||||||
|
std::vector<u8> Serialize();
|
||||||
|
|
||||||
bool gamepadConnected = false, mempakOpen = false;
|
bool gamepadConnected = false, mempakOpen = false;
|
||||||
SDL_GameController* gamepad{};
|
SDL_GameController* gamepad{};
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ using m128i = __m128i;
|
|||||||
#define FORCE_INLINE inline __attribute__((always_inline))
|
#define FORCE_INLINE inline __attribute__((always_inline))
|
||||||
|
|
||||||
constexpr u32 N64_CPU_FREQ = 93750000;
|
constexpr u32 N64_CPU_FREQ = 93750000;
|
||||||
|
constexpr u16 KAIZEN_VERSION = 0x010;
|
||||||
|
|
||||||
static FORCE_INLINE constexpr u32 GetCyclesPerFrame(bool pal) {
|
static FORCE_INLINE constexpr u32 GetCyclesPerFrame(bool pal) {
|
||||||
if (pal) {
|
if (pal) {
|
||||||
|
|||||||
@@ -41,6 +41,64 @@ void App::Run() {
|
|||||||
case SDLK_o: {
|
case SDLK_o: {
|
||||||
OpenROMDialog(window, core);
|
OpenROMDialog(window, core);
|
||||||
} break;
|
} break;
|
||||||
|
case SDLK_F1: {
|
||||||
|
if(core.romLoaded && event.key.keysym.mod == KMOD_SHIFT) {
|
||||||
|
core.slot = 0;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case SDLK_F2: {
|
||||||
|
if(core.romLoaded && event.key.keysym.mod == KMOD_SHIFT) {
|
||||||
|
core.slot = 1;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case SDLK_F3: {
|
||||||
|
if(core.romLoaded && event.key.keysym.mod == KMOD_SHIFT) {
|
||||||
|
core.slot = 2;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case SDLK_F4: {
|
||||||
|
if(core.romLoaded && event.key.keysym.mod == KMOD_SHIFT) {
|
||||||
|
core.slot = 3;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case SDLK_F5: {
|
||||||
|
if(core.romLoaded) {
|
||||||
|
if(event.key.keysym.mod == KMOD_SHIFT) {
|
||||||
|
core.slot = 4;
|
||||||
|
} else {
|
||||||
|
core.Deserialize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case SDLK_F6: {
|
||||||
|
if(core.romLoaded) {
|
||||||
|
if(event.key.keysym.mod == KMOD_SHIFT) {
|
||||||
|
core.slot = 5;
|
||||||
|
} else {
|
||||||
|
core.Serialize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case SDLK_F7: {
|
||||||
|
if(core.romLoaded && event.key.keysym.mod == KMOD_SHIFT) {
|
||||||
|
core.slot = 6;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case SDLK_F8: {
|
||||||
|
if(core.romLoaded && event.key.keysym.mod == KMOD_SHIFT) {
|
||||||
|
core.slot = 7;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case SDLK_F9: {
|
||||||
|
if(core.romLoaded && event.key.keysym.mod == KMOD_SHIFT) {
|
||||||
|
core.slot = 8;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case SDLK_F10: {
|
||||||
|
if(core.romLoaded && event.key.keysym.mod == KMOD_SHIFT) {
|
||||||
|
core.slot = 9;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SDL_DROPFILE: {
|
case SDL_DROPFILE: {
|
||||||
|
|||||||
@@ -15,6 +15,10 @@ enum StringID {
|
|||||||
EMULATION_ITEM_PAUSE,
|
EMULATION_ITEM_PAUSE,
|
||||||
EMULATION_ITEM_RESUME,
|
EMULATION_ITEM_RESUME,
|
||||||
EMULATION_ITEM_SETTINGS,
|
EMULATION_ITEM_SETTINGS,
|
||||||
|
EMULATION_ITEM_LOAD_STATE,
|
||||||
|
EMULATION_ITEM_SAVE_STATE,
|
||||||
|
EMULATION_MENU_STATES,
|
||||||
|
STATES_ITEM_SLOT,
|
||||||
SETTINGS_CATEGORY_CPU,
|
SETTINGS_CATEGORY_CPU,
|
||||||
SETTINGS_CATEGORY_AUDIO,
|
SETTINGS_CATEGORY_AUDIO,
|
||||||
SETTINGS_CATEGORY_INTERFACE,
|
SETTINGS_CATEGORY_INTERFACE,
|
||||||
@@ -38,6 +42,10 @@ static const std::map <StringID, const char*> english = {
|
|||||||
{EMULATION_ITEM_PAUSE, "Pause"},
|
{EMULATION_ITEM_PAUSE, "Pause"},
|
||||||
{EMULATION_ITEM_RESUME, "Resume"},
|
{EMULATION_ITEM_RESUME, "Resume"},
|
||||||
{EMULATION_ITEM_SETTINGS, "Settings"},
|
{EMULATION_ITEM_SETTINGS, "Settings"},
|
||||||
|
{EMULATION_ITEM_LOAD_STATE, "Load state..."},
|
||||||
|
{EMULATION_ITEM_SAVE_STATE, "Save state..."},
|
||||||
|
{EMULATION_MENU_STATES, "Select save slot"},
|
||||||
|
{STATES_ITEM_SLOT, "Slot {}"},
|
||||||
{SETTINGS_CATEGORY_CPU, "CPU"},
|
{SETTINGS_CATEGORY_CPU, "CPU"},
|
||||||
{SETTINGS_CATEGORY_AUDIO, "Audio"},
|
{SETTINGS_CATEGORY_AUDIO, "Audio"},
|
||||||
{SETTINGS_CATEGORY_INTERFACE, "Interface"},
|
{SETTINGS_CATEGORY_INTERFACE, "Interface"},
|
||||||
@@ -60,6 +68,10 @@ static const std::map <StringID, const char*> italian = {
|
|||||||
{EMULATION_ITEM_PAUSE, "Pausa"},
|
{EMULATION_ITEM_PAUSE, "Pausa"},
|
||||||
{EMULATION_ITEM_RESUME, "Riprendi"},
|
{EMULATION_ITEM_RESUME, "Riprendi"},
|
||||||
{EMULATION_ITEM_SETTINGS, "Opzioni"},
|
{EMULATION_ITEM_SETTINGS, "Opzioni"},
|
||||||
|
{EMULATION_ITEM_LOAD_STATE, "Carica stato..."},
|
||||||
|
{EMULATION_ITEM_SAVE_STATE, "Salva stato..."},
|
||||||
|
{EMULATION_MENU_STATES, "Seleziona slot"},
|
||||||
|
{STATES_ITEM_SLOT, "Slot {}"},
|
||||||
{SETTINGS_CATEGORY_CPU, "CPU"},
|
{SETTINGS_CATEGORY_CPU, "CPU"},
|
||||||
{SETTINGS_CATEGORY_AUDIO, "Audio"},
|
{SETTINGS_CATEGORY_AUDIO, "Audio"},
|
||||||
{SETTINGS_CATEGORY_INTERFACE, "Interfaccia"},
|
{SETTINGS_CATEGORY_INTERFACE, "Interfaccia"},
|
||||||
|
|||||||
@@ -219,6 +219,27 @@ void Window::RenderMainMenuBar(n64::Core &core) {
|
|||||||
}
|
}
|
||||||
SDL_SetWindowTitle(window, windowTitle.c_str());
|
SDL_SetWindowTitle(window, windowTitle.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(ImGui::BeginMenu(GET_TRANSLATED_STRING(Language::EMULATION_MENU_STATES))) {
|
||||||
|
if(ImGui::MenuItem(fmt::format(GET_TRANSLATED_STRING(Language::STATES_ITEM_SLOT), 0).c_str())) { core.slot = 0; }
|
||||||
|
if(ImGui::MenuItem(fmt::format(GET_TRANSLATED_STRING(Language::STATES_ITEM_SLOT), 1).c_str())) { core.slot = 1; }
|
||||||
|
if(ImGui::MenuItem(fmt::format(GET_TRANSLATED_STRING(Language::STATES_ITEM_SLOT), 2).c_str())) { core.slot = 2; }
|
||||||
|
if(ImGui::MenuItem(fmt::format(GET_TRANSLATED_STRING(Language::STATES_ITEM_SLOT), 3).c_str())) { core.slot = 3; }
|
||||||
|
if(ImGui::MenuItem(fmt::format(GET_TRANSLATED_STRING(Language::STATES_ITEM_SLOT), 4).c_str())) { core.slot = 4; }
|
||||||
|
if(ImGui::MenuItem(fmt::format(GET_TRANSLATED_STRING(Language::STATES_ITEM_SLOT), 5).c_str())) { core.slot = 5; }
|
||||||
|
if(ImGui::MenuItem(fmt::format(GET_TRANSLATED_STRING(Language::STATES_ITEM_SLOT), 6).c_str())) { core.slot = 6; }
|
||||||
|
if(ImGui::MenuItem(fmt::format(GET_TRANSLATED_STRING(Language::STATES_ITEM_SLOT), 7).c_str())) { core.slot = 7; }
|
||||||
|
if(ImGui::MenuItem(fmt::format(GET_TRANSLATED_STRING(Language::STATES_ITEM_SLOT), 8).c_str())) { core.slot = 8; }
|
||||||
|
if(ImGui::MenuItem(fmt::format(GET_TRANSLATED_STRING(Language::STATES_ITEM_SLOT), 9).c_str())) { core.slot = 9; }
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ImGui::MenuItem(GET_TRANSLATED_STRING(Language::EMULATION_ITEM_LOAD_STATE), "F5", false, core.romLoaded)) {
|
||||||
|
core.Deserialize();
|
||||||
|
}
|
||||||
|
if(ImGui::MenuItem(GET_TRANSLATED_STRING(Language::EMULATION_ITEM_SAVE_STATE), "F6", false, core.romLoaded)) {
|
||||||
|
core.Serialize();
|
||||||
|
}
|
||||||
if (ImGui::MenuItem(GET_TRANSLATED_STRING(Language::EMULATION_ITEM_SETTINGS))) {
|
if (ImGui::MenuItem(GET_TRANSLATED_STRING(Language::EMULATION_ITEM_SETTINGS))) {
|
||||||
showSettings = true;
|
showSettings = true;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user