changeset 1478:da1dce39e846 nuklear_ui

Refactored save slot related logic to reduce duplication and allow reuse in new UI. Get state loading/saving mostly working in new UI
author Michael Pavone <pavone@retrodev.com>
date Fri, 24 Nov 2017 12:04:02 -0800
parents 1cdd7f492af8
children a568dca999b2
files Makefile blastem.h genesis.c io.c menu.c nuklear_ui/blastem_nuklear.c saves.c saves.h sms.c
diffstat 9 files changed, 173 insertions(+), 137 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Wed Nov 22 11:18:36 2017 -0800
+++ b/Makefile	Fri Nov 24 12:04:02 2017 -0800
@@ -130,7 +130,7 @@
 
 MAINOBJS=blastem.o system.o genesis.o debug.o gdb_remote.o vdp.o render_sdl.o ppm.o io.o romdb.o hash.o menu.o xband.o \
 	realtec.o i2c.o nor.o sega_mapper.o multi_game.o serialize.o $(TERMINAL) $(CONFIGOBJS) gst.o $(M68KOBJS) \
-	$(TRANSOBJS) $(AUDIOOBJS) $(NUKLEAROBJS) paths.o
+	$(TRANSOBJS) $(AUDIOOBJS) $(NUKLEAROBJS) paths.o saves.o
 
 ifeq ($(CPU),x86_64)
 CFLAGS+=-DX86_64 -m64
--- a/blastem.h	Wed Nov 22 11:18:36 2017 -0800
+++ b/blastem.h	Fri Nov 24 12:04:02 2017 -0800
@@ -15,7 +15,6 @@
 extern char *save_state_path;
 extern char *save_filename;
 extern uint8_t use_native_states;
-#define QUICK_SAVE_SLOT 10
 void reload_media(void);
 void lockon_media(char *lock_on_path);
 
--- a/genesis.c	Wed Nov 22 11:18:36 2017 -0800
+++ b/genesis.c	Fri Nov 24 12:04:02 2017 -0800
@@ -15,6 +15,7 @@
 #include "util.h"
 #include "debug.h"
 #include "gdb_remote.h"
+#include "saves.h"
 #define MCLKS_NTSC 53693175
 #define MCLKS_PAL  53203395
 
@@ -359,18 +360,7 @@
 					sync_z80(z_context, z_context->current_cycle + MCLKS_PER_Z80);
 				}
 			}
-			char *save_path;
-			if (slot == QUICK_SAVE_SLOT) {
-				save_path = save_state_path;
-			} else {
-				char slotname[] = "slot_0.state";
-				slotname[5] = '0' + slot;
-				if (!use_native_states) {
-					strcpy(slotname + 7, "gst");
-				}
-				char const *parts[] = {gen->header.save_dir, PATH_SEP, slotname};
-				save_path = alloc_concat_m(3, parts);
-			}
+			char *save_path = get_slot_name(&gen->header, slot, use_native_states ? "state" : "gst");
 			if (use_native_states) {
 				serialize_buffer state;
 				init_serialize(&state);
@@ -381,9 +371,7 @@
 				save_gst(gen, save_path, address);
 			}
 			printf("Saved state to %s\n", save_path);
-			if (slot != QUICK_SAVE_SLOT) {
-				free(save_path);
-			}
+			free(save_path);
 		} else if(gen->header.save_state) {
 			context->sync_cycle = context->current_cycle + 1;
 		}
--- a/io.c	Wed Nov 22 11:18:36 2017 -0800
+++ b/io.c	Fri Nov 24 12:04:02 2017 -0800
@@ -23,6 +23,7 @@
 #include "render.h"
 #include "util.h"
 #include "menu.h"
+#include "saves.h"
 #ifndef DISABLE_NUKLEAR
 #include "nuklear_ui/blastem_nuklear.h"
 #endif
--- a/menu.c	Wed Nov 22 11:18:36 2017 -0800
+++ b/menu.c	Fri Nov 24 12:04:02 2017 -0800
@@ -9,7 +9,7 @@
 #include "util.h"
 #include "gst.h"
 #include "paths.h"
-#include "m68k_internal.h" //needed for get_native_address_trans, should be eliminated once handling of PC is cleaned up
+#include "saves.h"
 
 static menu_context *get_menu(genesis_context *gen)
 {
@@ -94,18 +94,6 @@
 
 #define SAVE_INFO_BUFFER_SIZE (11*40)
 
-#ifdef _WIN32
-#define localtime_r(a,b) localtime(a)
-//windows inclues seem not to like certain single letter defines from m68k_internal.h
-//get rid of them here
-#undef X
-#undef N
-#undef Z
-#undef V
-#undef C
-#include <windows.h>
-#endif
-
 uint32_t copy_dir_entry_to_guest(uint32_t dst, m68k_context *m68k, char *name, uint8_t is_dir)
 {
 	uint8_t *dest = get_native_pointer(dst, (void **)m68k->mem_pointers, &m68k->options->gen);
@@ -307,63 +295,19 @@
 			char *cur = buffer;
 			if (gen->header.next_context && gen->header.next_context->save_dir) {
 				char *end = buffer + SAVE_INFO_BUFFER_SIZE;
-				char slotfile[] = "slot_0.state";
-				char slotfilegst[] = "slot_0.gst";
-				char const * parts[3] = {gen->header.next_context->save_dir, PATH_SEP, slotfile};
-				char const * partsgst[3] = {gen->header.next_context->save_dir, PATH_SEP, slotfilegst};
-				struct tm ltime;
-				char *fname;
-				time_t modtime;
-				for (int i = 0; i < 10 && cur < end; i++)
+				uint32_t num_slots;
+				save_slot_info *slots = get_slot_info(gen->header.next_context, &num_slots);
+				for (uint32_t i = 0; i < num_slots; i++)
 				{
-					slotfile[5] = i + '0';
-					fname = alloc_concat_m(3, parts);
-					modtime = get_modification_time(fname);
-					free(fname);
-					if (modtime) {
-						cur += snprintf(cur, end-cur, "Slot %d - ", i);
-						cur += strftime(cur, end-cur, "%c", localtime_r(&modtime, &ltime));
-						
-					} else {
-						slotfilegst[5] = i + '0';
-						fname = alloc_concat_m(3, partsgst);
-						modtime = get_modification_time(fname);
-						free(fname);
-						if (modtime) {
-							cur += snprintf(cur, end-cur, "Slot %d - ", i);
-							cur += strftime(cur, end-cur, "%c", localtime_r(&modtime, &ltime));
-						} else {
-							cur += snprintf(cur, end-cur, "Slot %d - EMPTY", i);
-						}
+					size_t desc_len = strlen(slots[i].desc) + 1;//+1 for string terminator
+					char *after = cur + desc_len + 1;//+1 for list terminator
+					if (after > cur) {
+						desc_len -= after - cur;
 					}
-					//advance past the null terminator for this entry
-					cur++;
+					memcpy(cur, slots[i].desc, desc_len);
+					cur = after;
 				}
-				if (cur < end) {
-					parts[2] = "quicksave.state";
-					fname = alloc_concat_m(3, parts);
-					modtime = get_modification_time(fname);
-					free(fname);
-					if (modtime) {
-						cur += strftime(cur, end-cur, "Quick  - %c", localtime_r(&modtime, &ltime));
-					} else {
-						parts[2] = "quicksave.gst";
-						fname = alloc_concat_m(3, parts);
-						modtime = get_modification_time(fname);
-						free(fname);
-						if (modtime) {
-							cur += strftime(cur, end-cur, "Quick  - %c", localtime_r(&modtime, &ltime));
-						} else if ((end-cur) > strlen("Quick  - EMPTY")){
-							cur += strlen(strcpy(cur, "Quick  - EMPTY"));
-						}
-					}
-					//advance past the null terminator for this entry
-					cur++;
-					if (cur < end) {
-						//terminate the list
-						*(cur++) = 0;
-					}
-				}
+				*cur = 0;//terminate list
 			} else {
 				*(cur++) = 0;
 				*(cur++) = 0;
@@ -383,36 +327,7 @@
 			if (gen->header.next_context && gen->header.next_context->save_dir) {
 				if (!gen->header.next_context->load_state(gen->header.next_context, dst)) {
 					break;
-				}/*
-				char numslotname[] = "slot_0.state";
-				char *slotname;
-				if (dst == QUICK_SAVE_SLOT) {
-					slotname = "quicksave.state";
-				} else {
-					numslotname[5] = '0' + dst;
-					slotname = numslotname;
 				}
-				char const *parts[] = {gen->header.next_context->save_dir, PATH_SEP, slotname};
-				char *statepath = alloc_concat_m(3, parts);
-				gen->header.next_context->load_state
-				genesis_context *next = (genesis_context *)gen->header.next_context;
-				deserialize_buffer state;
-				uint32_t pc = 0;
-				if (load_from_file(&state, statepath)) {
-					genesis_deserialize(&state, next);
-					free(state.data);
-					//HACK
-					pc = next->m68k->last_prefetch_address;
-				} else {
-					strcpy(statepath + strlen(statepath)-strlen("state"), "gst");
-					pc = load_gst(next, statepath);
-				}
-				free(statepath);
-				if (!pc) {
-					break;
-				}
-				next->m68k->resume_pc = get_native_address_trans(next->m68k, pc);
-				*/
 			}
 			m68k->should_return = 1;
 			break;
--- a/nuklear_ui/blastem_nuklear.c	Wed Nov 22 11:18:36 2017 -0800
+++ b/nuklear_ui/blastem_nuklear.c	Fri Nov 24 12:04:02 2017 -0800
@@ -8,6 +8,7 @@
 #include "../render_sdl.h"
 #include "../util.h"
 #include "../paths.h"
+#include "../saves.h"
 #include "../blastem.h"
 
 static struct nk_context *context;
@@ -78,6 +79,59 @@
 	view_fun   next_view;
 } menu_item;
 
+static save_slot_info *slots;
+static uint32_t num_slots, selected_slot;
+
+void view_choose_state(struct nk_context *context, uint8_t is_load)
+{
+	uint32_t width = render_width();
+	uint32_t height = render_height();
+	if (nk_begin(context, "Slot Picker", nk_rect(0, 0, width, height), 0)) {
+		nk_layout_row_static(context, height - 100, width - 60, 1);
+		if (nk_group_begin(context, "Select Save Slot", NK_WINDOW_BORDER | NK_WINDOW_TITLE)) {
+			nk_layout_row_static(context, 28, width-100, 1);
+			if (!slots) {
+				slots = get_slot_info(current_system, &num_slots);
+			}
+			for (uint32_t i = 0; i < num_slots; i++)
+			{
+				int selected = i == selected_slot;
+				nk_selectable_label(context, slots[i].desc, NK_TEXT_ALIGN_LEFT, &selected);
+				if (selected && (slots[i].modification_time || !is_load)) {
+					selected_slot = i;
+				}
+			}
+			nk_group_end(context);
+		}
+		nk_layout_row_static(context, 52, width > 600 ? 300 : width / 2, 2);
+		if (nk_button_label(context, "Back")) {
+			current_view = previous_view;
+		}
+		if (is_load) {
+			if (nk_button_label(context, "Load")) {
+				current_system->load_state(current_system, selected_slot);
+				current_view = view_play;
+			}
+		} else {
+			if (nk_button_label(context, "Save")) {
+				current_system->save_state = selected_slot + 1;
+				current_view = view_play;
+			}
+		}
+		nk_end(context);
+	}
+}
+
+void view_save_state(struct nk_context *context)
+{
+	view_choose_state(context, 0);
+}
+
+void view_load_state(struct nk_context *context)
+{
+	view_choose_state(context, 1);
+}
+
 static void menu(struct nk_context *context, uint32_t num_entries, const menu_item *items)
 {
 	const uint32_t button_height = 52;
@@ -100,26 +154,15 @@
 			if (!current_view) {
 				exit(0);
 			}
+			if (current_view == view_save_state || current_view == view_load_state) {
+				free_slot_info(slots);
+				slots = NULL;
+			}
 		}
 	}
 	nk_layout_space_end(context);
 }
 
-void view_choose_state(struct nk_context *context, uint8_t is_load)
-{
-	
-}
-
-void view_save_state(struct nk_context *context)
-{
-	view_choose_state(context, 0);
-}
-
-void view_load_state(struct nk_context *context)
-{
-	view_choose_state(context, 1);
-}
-
 void view_pause(struct nk_context *context)
 {
 	static menu_item items[] = {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/saves.c	Fri Nov 24 12:04:02 2017 -0800
@@ -0,0 +1,77 @@
+#include <string.h>
+#include <stdlib.h>
+#include "saves.h"
+#include "util.h"
+
+#ifdef _WIN32
+#define localtime_r(a,b) localtime(a)
+#include <windows.h>
+#endif
+//0123456789012345678901234678
+//Slot N - December 31st, XXXX
+#define MAX_DESC_SIZE 40
+
+char *get_slot_name(system_header *system, uint32_t slot_index, char *ext)
+{
+	if (!system->save_dir) {
+		return NULL;
+	}
+	char *fname;
+	if (slot_index < 10) {
+		size_t name_len = strlen("slot_N.") + strlen(ext) + 1;
+		fname = malloc(name_len);
+		snprintf(fname, name_len, "slot_%d.%s", slot_index, ext);
+	} else {
+		size_t name_len = strlen("quicksave.") + strlen(ext) + 1;
+		fname = malloc(name_len);
+		snprintf(fname, name_len, "quicksave.%s", ext);
+	}
+	char const *parts[] = {system->save_dir, PATH_SEP, fname};
+	char *ret = alloc_concat_m(3, parts);
+	free(fname);
+	return ret;
+}
+
+save_slot_info *get_slot_info(system_header *system, uint32_t *num_out)
+{
+	save_slot_info *dst = calloc(11, sizeof(save_slot_info));
+	time_t modtime;
+	struct tm ltime;
+	for (uint32_t i = 0; i <= QUICK_SAVE_SLOT; i++)
+	{
+		char * cur = dst[i].desc = malloc(MAX_DESC_SIZE);
+		char * fname = get_slot_name(system, i, "state");
+		modtime = get_modification_time(fname);
+		free(fname);
+		if (!modtime && system->type == SYSTEM_GENESIS) {
+			fname = get_slot_name(system, i, "gst");
+			modtime = get_modification_time(fname);
+			free(fname);
+		}
+		if (i == QUICK_SAVE_SLOT) {
+			cur += snprintf(cur, MAX_DESC_SIZE, "Quick - ");
+		} else {
+			cur += snprintf(cur, MAX_DESC_SIZE, "Slot %d - ", i);
+		}
+		if (modtime) {
+			strftime(cur, MAX_DESC_SIZE - (cur - dst->desc), "%c", localtime_r(&modtime, &ltime));
+		} else {
+			strcpy(cur, "EMPTY");
+		}
+		dst[i].modification_time;
+	}
+	*num_out = QUICK_SAVE_SLOT + 1;
+	return dst;
+}
+
+void free_slot_info(save_slot_info *slots)
+{
+	if (!slots) {
+		return;
+	}
+	for (uint32_t i = 0; i <= QUICK_SAVE_SLOT; i++)
+	{
+		free(slots[i].desc);
+	}
+	free(slots);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/saves.h	Fri Nov 24 12:04:02 2017 -0800
@@ -0,0 +1,19 @@
+#ifndef SAVES_H_
+#define SAVES_H_
+
+#include <time.h>
+#include <stdint.h>
+#include "system.h"
+
+#define QUICK_SAVE_SLOT 10
+
+typedef struct {
+	char   *desc;
+	time_t modification_time;
+} save_slot_info;
+
+char *get_slot_name(system_header *system, uint32_t slot_index, char *ext);
+save_slot_info *get_slot_info(system_header *system, uint32_t *num_out);
+void free_slot_info(save_slot_info *slots);
+
+#endif //SAVES_H_
--- a/sms.c	Wed Nov 22 11:18:36 2017 -0800
+++ b/sms.c	Fri Nov 24 12:04:02 2017 -0800
@@ -6,6 +6,7 @@
 #include "render.h"
 #include "util.h"
 #include "debug.h"
+#include "saves.h"
 
 static void *memory_io_write(uint32_t location, void *vcontext, uint8_t value)
 {
@@ -292,20 +293,13 @@
 
 static void save_state(sms_context *sms, uint8_t slot)
 {
-	char *save_path;
-	if (slot == QUICK_SAVE_SLOT) {
-		save_path = save_state_path;
-	} else {
-		char slotname[] = "slot_0.state";
-		slotname[5] = '0' + slot;
-		char const *parts[] = {sms->header.save_dir, PATH_SEP, slotname};
-		save_path = alloc_concat_m(3, parts);
-	}
+	char *save_path = get_slot_name(&sms->header, slot, "state");
 	serialize_buffer state;
 	init_serialize(&state);
 	sms_serialize(sms, &state);
 	save_to_file(&state, save_path);
 	printf("Saved state to %s\n", save_path);
+	free(save_path);
 	free(state.data);
 }