diff --git a/Makefile b/Makefile
index e67e9891d9..2da091af2c 100644
--- a/Makefile
+++ b/Makefile
@@ -92,7 +92,7 @@ ifeq ($(HAVE_CG), 1)
endif
ifeq ($(HAVE_XML), 1)
- OBJ += gfx/shader_glsl.o gfx/image.o sha256.o cheats.o
+ OBJ += gfx/shader_glsl.o gfx/image.o gfx/snes_state.o sha256.o cheats.o
LIBS += $(XML_LIBS)
DEFINES += $(XML_CFLAGS)
endif
diff --git a/Makefile.win32 b/Makefile.win32
index d294194b1c..143288d088 100644
--- a/Makefile.win32
+++ b/Makefile.win32
@@ -58,7 +58,7 @@ ifeq ($(HAVE_RSOUND), 1)
endif
ifeq ($(HAVE_XML), 1)
- OBJ += gfx/shader_glsl.o gfx/image.o sha256.o cheats.o
+ OBJ += gfx/shader_glsl.o gfx/image.o gfx/snes_state.o sha256.o cheats.o
DEFINES += $(XML_CFLAGS) -DHAVE_XML
LIBS += -lxml2
endif
diff --git a/Makefile.win64 b/Makefile.win64
index f28c51dd0c..161a9c5998 100644
--- a/Makefile.win64
+++ b/Makefile.win64
@@ -58,7 +58,7 @@ ifeq ($(HAVE_RSOUND), 1)
endif
ifeq ($(HAVE_XML), 1)
- OBJ += gfx/shader_glsl.o gfx/image.o sha256.o cheats.o
+ OBJ += gfx/shader_glsl.o gfx/image.o gfx/snes_state.o sha256.o cheats.o
DEFINES += $(XML_CFLAGS) -DHAVE_XML -DLIBXML_STATIC
LIBS += -lxml2 -lz -lws2_32
endif
diff --git a/gfx/snes_state.c b/gfx/snes_state.c
new file mode 100644
index 0000000000..591d58e418
--- /dev/null
+++ b/gfx/snes_state.c
@@ -0,0 +1,142 @@
+/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
+ * Copyright (C) 2010-2011 - Hans-Kristian Arntzen
+ *
+ * Some code herein may be based on code found in BSNES.
+ *
+ * SSNES 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 Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * SSNES 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 SSNES.
+ * If not, see .
+ */
+
+#include "snes_state.h"
+#include
+#include
+#include "strl.h"
+
+struct snes_tracker_internal
+{
+ char id[64];
+
+ const uint8_t *ptr;
+ uint32_t addr;
+
+ enum snes_tracker_type type;
+
+ uint8_t prev[2];
+ int frame_count;
+ uint8_t old_value;
+};
+
+struct snes_tracker
+{
+ struct snes_tracker_internal *info;
+ unsigned info_elem;
+};
+
+snes_tracker_t* snes_tracker_init(const struct snes_tracker_info *info)
+{
+ snes_tracker_t *tracker = calloc(1, sizeof(*tracker));
+ if (!tracker)
+ return NULL;
+
+ tracker->info = calloc(info->info_elem, sizeof(struct snes_tracker_internal));
+ tracker->info_elem = info->info_elem;
+
+ for (unsigned i = 0; i < info->info_elem; i++)
+ {
+ strlcpy(tracker->info[i].id, info->info[i].id, sizeof(tracker->info[i].id));
+ tracker->info[i].addr = info->info[i].addr;
+ tracker->info[i].type = info->info[i].type;
+
+ assert(info->wram && info->vram && info->cgram &&
+ info->oam && info->apuram);
+
+ switch (info->info[i].ram_type)
+ {
+ case SSNES_STATE_WRAM:
+ tracker->info[i].ptr = info->wram;
+ break;
+ case SSNES_STATE_APURAM:
+ tracker->info[i].ptr = info->apuram;
+ break;
+ case SSNES_STATE_OAM:
+ tracker->info[i].ptr = info->oam;
+ break;
+ case SSNES_STATE_CGRAM:
+ tracker->info[i].ptr = info->cgram;
+ break;
+ case SSNES_STATE_VRAM:
+ tracker->info[i].ptr = info->vram;
+ break;
+
+ default:
+ tracker->info[i].ptr = NULL;
+ }
+ }
+
+
+ return tracker;
+}
+
+void snes_tracker_free(snes_tracker_t *tracker)
+{
+ free(tracker->info);
+ free(tracker);
+}
+
+static void update_element(
+ struct snes_tracker_uniform *uniform,
+ struct snes_tracker_internal *info,
+ unsigned frame_count)
+{
+ uniform->id = info->id;
+
+ switch (info->type)
+ {
+ case SSNES_STATE_CAPTURE:
+ uniform->value = info->ptr[info->addr];
+ break;
+
+ case SSNES_STATE_TRANSITION:
+ if (info->old_value != info->ptr[info->addr])
+ {
+ info->old_value = info->ptr[info->addr];
+ info->frame_count = frame_count;
+ uniform->value = info->frame_count;
+ }
+ else
+ uniform->value = info->frame_count;
+
+ break;
+
+ case SSNES_STATE_CAPTURE_PREV:
+ if (info->prev[0] != info->ptr[info->addr])
+ {
+ info->prev[1] = info->prev[0];
+ info->prev[0] = info->ptr[info->addr];
+ }
+ uniform->value = info->prev[1];
+ break;
+
+ default:
+ break;
+ }
+}
+
+unsigned snes_get_uniform(snes_tracker_t *tracker, struct snes_tracker_uniform *uniforms, unsigned elem, unsigned frame_count)
+{
+ unsigned elems = tracker->info_elem < elem ? tracker->info_elem : elem;
+
+ for (unsigned i = 0; i < elems; i++)
+ update_element(&uniforms[i], &tracker->info[i], frame_count);
+
+ return elems;
+}
+
diff --git a/gfx/snes_state.h b/gfx/snes_state.h
new file mode 100644
index 0000000000..fbb6cb449d
--- /dev/null
+++ b/gfx/snes_state.h
@@ -0,0 +1,72 @@
+/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
+ * Copyright (C) 2010-2011 - Hans-Kristian Arntzen
+ *
+ * Some code herein may be based on code found in BSNES.
+ *
+ * SSNES 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 Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * SSNES 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 SSNES.
+ * If not, see .
+ */
+
+#ifndef __SSNES_SNES_STATE_H
+#define __SSNES_SNES_STATE_H
+
+#include
+
+enum snes_tracker_type
+{
+ SSNES_STATE_CAPTURE,
+ SSNES_STATE_TRANSITION,
+ SSNES_STATE_CAPTURE_PREV
+};
+
+enum snes_ram_type
+{
+ SSNES_STATE_WRAM,
+ SSNES_STATE_APURAM,
+ SSNES_STATE_OAM,
+ SSNES_STATE_CGRAM,
+ SSNES_STATE_VRAM
+};
+
+struct snes_tracker_uniform_info
+{
+ const char *id;
+ uint32_t addr;
+ enum snes_tracker_type type;
+ enum snes_ram_type ram_type;
+};
+
+struct snes_tracker_info
+{
+ const uint8_t *wram;
+ const uint8_t *vram;
+ const uint8_t *cgram;
+ const uint8_t *oam;
+ const uint8_t *apuram;
+
+ const struct snes_tracker_uniform_info *info;
+ unsigned info_elem;
+};
+
+struct snes_tracker_uniform
+{
+ const char *id;
+ int value;
+};
+
+typedef struct snes_tracker snes_tracker_t;
+
+snes_tracker_t* snes_tracker_init(const struct snes_tracker_info *info);
+void snes_tracker_free(snes_tracker_t *tracker);
+
+unsigned snes_get_uniform(snes_tracker_t *tracker, struct snes_tracker_uniform *uniforms, unsigned elem, unsigned frame_count);
+
+#endif