Skip to content

Commit

Permalink
Save states
Browse files Browse the repository at this point in the history
  • Loading branch information
drhelius committed Jan 22, 2025
1 parent 995d557 commit c2c8f23
Show file tree
Hide file tree
Showing 32 changed files with 911 additions and 326 deletions.
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@
"queue": "cpp",
"stack": "cpp",
"variant": "cpp",
"cassert": "cpp"
"cassert": "cpp",
"__config": "cpp"
},
"todo-tree.tree.showBadges": true,
"todo-tree.tree.disableCompactFolders": false,
Expand Down
79 changes: 53 additions & 26 deletions platforms/shared/desktop/emu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ static void destroy_debug(void);
static void update_debug(void);
static void update_debug_background(void);
static void update_debug_sprites(void);
static void update_savestates_data(void);

void emu_init(void)
{
Expand All @@ -57,6 +58,9 @@ void emu_init(void)
sound_queue = new SoundQueue();
sound_queue->Start(GG_AUDIO_SAMPLE_RATE, 2, GG_AUDIO_BUFFER_SIZE, GG_AUDIO_BUFFER_COUNT);

for (int i = 0; i < 5; i++)
InitPointer(emu_savestates_screenshots[i].data);

audio_enabled = true;
emu_audio_sync = true;
emu_savefiles_dir_option = 0;
Expand All @@ -77,6 +81,9 @@ void emu_destroy(void)
SafeDelete(geargrafx);
SafeDeleteArray(emu_frame_buffer);
destroy_debug();

for (int i = 0; i < 5; i++)
SafeDeleteArray(emu_savestates_screenshots[i].data);
}

void emu_load_rom(const char* file_path)
Expand All @@ -87,6 +94,8 @@ void emu_load_rom(const char* file_path)
save_ram();
geargrafx->LoadROM(file_path);
load_ram();

update_savestates_data();
}

void emu_update(void)
Expand Down Expand Up @@ -217,44 +226,38 @@ void emu_load_ram(const char* file_path)

void emu_save_state_slot(int index)
{
// TODO Implement save states
// if (!emu_is_empty())
// {
// if ((emu_savestates_dir_option == 0) && (strcmp(emu_savestates_path, "")))
// geargrafx->SaveState(emu_savestates_path, index);
// else
// geargrafx->SaveState(index);
// }
UNUSED(index);
if (!emu_is_empty())
{
if ((emu_savestates_dir_option == 0) && (strcmp(emu_savestates_path, "")))
geargrafx->SaveState(emu_savestates_path, index, true);
else
geargrafx->SaveState(NULL, index, true);

update_savestates_data();
}
}

void emu_load_state_slot(int index)
{
// TODO Implement save states
// if (!emu_is_empty())
// {
// if ((emu_savestates_dir_option == 0) && (strcmp(emu_savestates_path, "")))
// geargrafx->LoadState(emu_savestates_path, index);
// else
// geargrafx->LoadState(index);
// }
UNUSED(index);
if (!emu_is_empty())
{
if ((emu_savestates_dir_option == 0) && (strcmp(emu_savestates_path, "")))
geargrafx->LoadState(emu_savestates_path, index);
else
geargrafx->LoadState(NULL, index);
}
}

void emu_save_state_file(const char* file_path)
{
// TODO Implement save states
// if (!emu_is_empty())
// geargrafx->SaveState(file_path, -1);
UNUSED(file_path);
if (!emu_is_empty())
geargrafx->SaveState(file_path, -1, true);
}

void emu_load_state_file(const char* file_path)
{
// TODO Implement save states
// if (!emu_is_empty())
// geargrafx->LoadState(file_path, -1);
UNUSED(file_path);
if (!emu_is_empty())
geargrafx->LoadState(file_path);
}

void emu_get_runtime(GG_Runtime_Info& runtime)
Expand Down Expand Up @@ -582,3 +585,27 @@ static void update_debug_sprites(void)
}
}
}

static void update_savestates_data(void)
{
if (emu_is_empty())
return;

bool using_path = (emu_savestates_dir_option == 0) && (strcmp(emu_savestates_path, ""));

for (int i = 0; i < 5; i++)
{
emu_savestates[i].rom_name[0] = 0;
SafeDeleteArray(emu_savestates_screenshots[i].data);

if (!geargrafx->GetSaveStateHeader(i + 1, using_path ? emu_savestates_path : NULL, &emu_savestates[i]))
continue;

if (emu_savestates[i].screenshot_size > 0)
{
emu_savestates_screenshots[i].data = new u8[emu_savestates[i].screenshot_size];
emu_savestates_screenshots[i].size = emu_savestates[i].screenshot_size;
geargrafx->GetSaveStateScreenshot(i + 1, using_path ? emu_savestates_path : NULL, &emu_savestates_screenshots[i]);
}
}
}
2 changes: 2 additions & 0 deletions platforms/shared/desktop/emu.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ enum Debug_Command


EXTERN u8* emu_frame_buffer;
EXTERN GG_SaveState_Header emu_savestates[5];
EXTERN GG_SaveState_Screenshot emu_savestates_screenshots[5];
EXTERN u8* emu_debug_sprite_buffers[64];
EXTERN u8* emu_debug_background_buffer;
EXTERN int emu_debug_background_buffer_width;
Expand Down
36 changes: 36 additions & 0 deletions platforms/shared/desktop/gui_menus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "config.h"
#include "application.h"
#include "emu.h"
#include "renderer.h"
#include "../../../src/geargrafx.h"

static char savefiles_path[4096] = "";
Expand All @@ -50,6 +51,7 @@ static void menu_about(void);
static void file_dialogs(void);
static void keyboard_configuration_item(const char* text, SDL_Scancode* key, int player);
static void gamepad_configuration_item(const char* text, int* button, int player);
static void draw_savestate_slot_info(int slot);

void gui_init_menus(void)
{
Expand Down Expand Up @@ -165,6 +167,10 @@ static void menu_geargrafx(void)
ImGui::PushItemWidth(100.0f);
ImGui::Combo("##slot", &config_emulator.save_slot, "Slot 1\0Slot 2\0Slot 3\0Slot 4\0Slot 5\0\0");
ImGui::PopItemWidth();

ImGui::Separator();
draw_savestate_slot_info(config_emulator.save_slot);

ImGui::EndMenu();
}

Expand All @@ -183,6 +189,14 @@ static void menu_geargrafx(void)
gui_set_status_message(message.c_str(), 3000);
emu_load_state_slot(config_emulator.save_slot + 1);
}
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text("Slot: %d", config_emulator.save_slot + 1);
ImGui::Separator();
draw_savestate_slot_info(config_emulator.save_slot);
ImGui::EndTooltip();
}

ImGui::Separator();

Expand Down Expand Up @@ -640,3 +654,25 @@ static void gamepad_configuration_item(const char* text, int* button, int player
*button = SDL_CONTROLLER_BUTTON_INVALID;
}
}

static void draw_savestate_slot_info(int slot)
{
if (emu_savestates[slot].rom_name[0] != 0)
{
ImGui::Text("%s", emu_savestates[slot].rom_name);
char date[64];
GetDateTimeString(emu_savestates[slot].timestamp, date, sizeof(date));
ImGui::Text("%s", date);

if (IsValidPointer(emu_savestates_screenshots[slot].data))
{
float width = emu_savestates_screenshots[slot].width;
float height = emu_savestates_screenshots[slot].height;
ImGui::Image((ImTextureID)(intptr_t)renderer_emu_savestates[slot], ImVec2((height / 3.0f) * 4.0f, height), ImVec2(0, 0), ImVec2(width / 512.0f, height / 512.0f));
}
}
else
{
ImGui::TextColored(ImVec4(0.50f, 0.50f, 0.50f, 1.0f), "Slot %d is empty", slot + 1);
}
}
33 changes: 33 additions & 0 deletions platforms/shared/desktop/renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ static u32 scanlines[16] = {
static void init_ogl_gui(void);
static void init_ogl_emu(void);
static void init_ogl_debug(void);
static void init_ogl_savestates(void);
static void init_scanlines_texture(void);
static void render_gui(void);
static void render_emu_normal(void);
Expand All @@ -56,6 +57,7 @@ static void render_emu_bilinear(void);
static void render_quad(void);
static void update_system_texture(void);
static void update_debug_textures(void);
static void update_savestates_textures(void);
static void render_scanlines(void);

void renderer_init(void)
Expand All @@ -77,6 +79,7 @@ void renderer_init(void)
init_ogl_gui();
init_ogl_emu();
init_ogl_debug();
init_ogl_savestates();

first_frame = true;
}
Expand All @@ -89,6 +92,8 @@ void renderer_destroy(void)
glDeleteTextures(1, &scanlines_texture);
glDeleteTextures(1, &renderer_emu_debug_huc6270_background);
glDeleteTextures(64, renderer_emu_debug_huc6270_sprites);
glDeleteTextures(5, renderer_emu_savestates);

ImGui_ImplOpenGL2_Shutdown();
}

Expand All @@ -106,6 +111,8 @@ void renderer_render(void)
update_debug_textures();
}

update_savestates_textures();

if (config_video.mix_frames)
render_emu_mix();
else
Expand Down Expand Up @@ -188,6 +195,18 @@ static void init_ogl_debug(void)
}
}

static void init_ogl_savestates(void)
{
for (int i = 0; i < 5; i++)
{
glGenTextures(1, &renderer_emu_savestates[i]);
glBindTexture(GL_TEXTURE_2D, renderer_emu_savestates[i]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 512, 512, 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
}

static void init_scanlines_texture(void)
{
glGenTextures(1, &scanlines_texture);
Expand Down Expand Up @@ -284,6 +303,20 @@ static void update_debug_textures(void)
}
}

static void update_savestates_textures(void)
{
for (int i = 0; i < 5; i++)
{
if (IsValidPointer(emu_savestates_screenshots[i].data))
{
int width = emu_savestates_screenshots[i].width;
int height = emu_savestates_screenshots[i].height;
glBindTexture(GL_TEXTURE_2D, renderer_emu_savestates[i]);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*) emu_savestates_screenshots[i].data);
}
}
}

static void render_emu_bilinear(void)
{
glBindTexture(GL_TEXTURE_2D, renderer_emu_texture);
Expand Down
1 change: 1 addition & 0 deletions platforms/shared/desktop/renderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
EXTERN uint32_t renderer_emu_texture;
EXTERN uint32_t renderer_emu_debug_huc6270_background;
EXTERN uint32_t renderer_emu_debug_huc6270_sprites[64];
EXTERN uint32_t renderer_emu_savestates[5];
EXTERN const char* renderer_glew_version;
EXTERN const char* renderer_opengl_version;

Expand Down
22 changes: 13 additions & 9 deletions src/audio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,16 @@ HuC6280PSG* Audio::GetPSG()
return m_psg;
}

// void Audio::SaveState(std::ostream& stream)
// {
// stream.write(reinterpret_cast<const char*> (&m_elapsed_cycles), sizeof(m_ElapsedCycles));
// }

// void Audio::LoadState(std::istream& stream)
// {
// stream.read(reinterpret_cast<char*> (&m_elapsed_cycles), sizeof(m_ElapsedCycles));
// }
void Audio::SaveState(std::ostream& stream)
{
using namespace std;
stream.write(reinterpret_cast<const char*> (m_psg_buffer), sizeof(s16) * GG_AUDIO_BUFFER_SIZE);
m_psg->SaveState(stream);
}

void Audio::LoadState(std::istream& stream)
{
using namespace std;
stream.read(reinterpret_cast<char*> (m_psg_buffer), sizeof(s16) * GG_AUDIO_BUFFER_SIZE);
m_psg->LoadState(stream);
}
6 changes: 4 additions & 2 deletions src/audio.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
#ifndef AUDIO_H
#define AUDIO_H

#include <iostream>
#include <fstream>
#include "types.h"

class HuC6280PSG;
Expand All @@ -36,8 +38,8 @@ class Audio
void WritePSG(u32 address, u8 value);
void EndFrame(s16* sample_buffer, int* sample_count);
HuC6280PSG* GetPSG();
// void SaveState(std::ostream& stream);
// void LoadState(std::istream& stream);
void SaveState(std::ostream& stream);
void LoadState(std::istream& stream);

private:
bool m_mute;
Expand Down
13 changes: 13 additions & 0 deletions src/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#ifndef COMMON_H
#define COMMON_H

#include <time.h>
#include "defines.h"
#include "types.h"
#include "log.h"
Expand All @@ -41,4 +42,16 @@ inline unsigned int Pow2Ceil(u16 n)
return n;
}

inline void GetDateTimeString(time_t timestamp, char* buffer, size_t size)
{
struct tm* timeinfo = localtime(&timestamp);
strftime(buffer, size, "%Y-%m-%d %H:%M:%S", timeinfo);
}

inline void GetCurrentDateTimeString(char* buffer, size_t size)
{
time_t timestamp = time(NULL);
GetDateTimeString(timestamp, buffer, size);
}

#endif /* COMMON_H */
5 changes: 3 additions & 2 deletions src/defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,13 @@
" \\____|\\___|\\__,_|_| \\__, |_| \\__,_|_| /_/\\_\\\n" \
" |___/ \n"

#define GG_CLOCK_RATE 21477273

#if defined(DEBUG)
#define GG_DEBUG 1
#endif

#define GG_SAVESTATE_VERSION 1
#define GG_SAVESTATE_MAGIC 0x82190619

#if !defined(NULL)
#define NULL 0
#endif
Expand Down
Loading

0 comments on commit c2c8f23

Please sign in to comment.