all repos — mgba @ 3d8cfda57d900bc744571944533301f9ce83ae59

mGBA Game Boy Advance Emulator

src/gba/rr/vbm.c (view raw)

  1/* Copyright (c) 2013-2015 Jeffrey Pfau
  2 *
  3 * This Source Code Form is subject to the terms of the Mozilla Public
  4 * License, v. 2.0. If a copy of the MPL was not distributed with this
  5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6#include "vbm.h"
  7
  8#include "gba/gba.h"
  9#include "gba/serialize.h"
 10#include "util/vfs.h"
 11
 12static const char VBM_MAGIC[] = "VBM\x1A";
 13
 14static void GBAVBMContextDestroy(struct GBARRContext*);
 15
 16static bool GBAVBMStartPlaying(struct GBARRContext*, bool autorecord);
 17static void GBAVBMStopPlaying(struct GBARRContext*);
 18static bool GBAVBMStartRecording(struct GBARRContext*);
 19static void GBAVBMStopRecording(struct GBARRContext*);
 20
 21static bool GBAVBMIsPlaying(const struct GBARRContext*);
 22static bool GBAVBMIsRecording(const struct GBARRContext*);
 23
 24static void GBAVBMNextFrame(struct GBARRContext*);
 25static uint16_t GBAVBMQueryInput(struct GBARRContext*);
 26
 27static void GBAVBMStateSaved(struct GBARRContext* rr, struct GBASerializedState* state);
 28static void GBAVBMStateLoaded(struct GBARRContext* rr, const struct GBASerializedState* state);
 29
 30static struct VFile* GBAVBMOpenSavedata(struct GBARRContext*, int flags);
 31static struct VFile* GBAVBMOpenSavestate(struct GBARRContext*, int flags);
 32
 33void GBAVBMContextCreate(struct GBAVBMContext* vbm) {
 34	memset(vbm, 0, sizeof(*vbm));
 35
 36	vbm->d.destroy = GBAVBMContextDestroy;
 37
 38	vbm->d.startPlaying = GBAVBMStartPlaying;
 39	vbm->d.stopPlaying = GBAVBMStopPlaying;
 40	vbm->d.startRecording = GBAVBMStartRecording;
 41	vbm->d.stopRecording = GBAVBMStopRecording;
 42
 43	vbm->d.isPlaying = GBAVBMIsPlaying;
 44	vbm->d.isRecording = GBAVBMIsRecording;
 45
 46	vbm->d.nextFrame = GBAVBMNextFrame;
 47	vbm->d.logInput = 0;
 48	vbm->d.queryInput = GBAVBMQueryInput;
 49
 50	vbm->d.stateSaved = GBAVBMStateSaved;
 51	vbm->d.stateLoaded = GBAVBMStateLoaded;
 52
 53	vbm->d.openSavedata = GBAVBMOpenSavedata;
 54	vbm->d.openSavestate = GBAVBMOpenSavestate;
 55}
 56
 57bool GBAVBMStartPlaying(struct GBARRContext* rr, bool autorecord) {
 58	if (rr->isRecording(rr) || rr->isPlaying(rr) || autorecord) {
 59		return false;
 60	}
 61
 62	struct GBAVBMContext* vbm = (struct GBAVBMContext*) rr;
 63	vbm->isPlaying = true;
 64	vbm->vbmFile->seek(vbm->vbmFile, vbm->inputOffset, SEEK_SET);
 65	return true;
 66}
 67
 68void GBAVBMStopPlaying(struct GBARRContext* rr) {
 69	if (!rr->isPlaying(rr)) {
 70		return;
 71	}
 72
 73	struct GBAVBMContext* vbm = (struct GBAVBMContext*) rr;
 74	vbm->isPlaying = false;
 75}
 76
 77bool GBAVBMStartRecording(struct GBARRContext* rr) {
 78	UNUSED(rr);
 79	return false;
 80}
 81
 82void GBAVBMStopRecording(struct GBARRContext* rr) {
 83	UNUSED(rr);
 84}
 85
 86bool GBAVBMIsPlaying(const struct GBARRContext* rr) {
 87	struct GBAVBMContext* vbm = (struct GBAVBMContext*) rr;
 88	return vbm->isPlaying;
 89}
 90
 91bool GBAVBMIsRecording(const struct GBARRContext* rr) {
 92	UNUSED(rr);
 93	return false;
 94}
 95
 96void GBAVBMNextFrame(struct GBARRContext* rr) {
 97	UNUSED(rr);
 98}
 99
100uint16_t GBAVBMQueryInput(struct GBARRContext* rr) {
101	if (!rr->isPlaying(rr)) {
102		return 0;
103	}
104
105	struct GBAVBMContext* vbm = (struct GBAVBMContext*) rr;
106	uint16_t input;
107	vbm->vbmFile->read(vbm->vbmFile, &input, sizeof(input));
108	return input & 0x3FF;
109}
110
111void GBAVBMStateSaved(struct GBARRContext* rr, struct GBASerializedState* state) {
112	UNUSED(rr);
113	UNUSED(state);
114}
115
116void GBAVBMStateLoaded(struct GBARRContext* rr, const struct GBASerializedState* state) {
117	UNUSED(rr);
118	UNUSED(state);
119}
120
121struct VFile* GBAVBMOpenSavedata(struct GBARRContext* rr, int flags) {
122	UNUSED(rr);
123	UNUSED(flags);
124	return 0;
125}
126
127struct VFile* GBAVBMOpenSavestate(struct GBARRContext* rr, int flags) {
128	UNUSED(rr);
129	UNUSED(flags);
130	return 0;
131}
132
133void GBAVBMContextDestroy(struct GBARRContext* rr) {
134	struct GBAVBMContext* vbm = (struct GBAVBMContext*) rr;
135	if (vbm->vbmFile) {
136		vbm->vbmFile->close(vbm->vbmFile);
137	}
138}
139
140bool GBAVBMSetStream(struct GBAVBMContext* vbm, struct VFile* vf) {
141	vf->seek(vf, 0, SEEK_SET);
142	char magic[4];
143	vf->read(vf, magic, sizeof(magic));
144	if (memcmp(magic, VBM_MAGIC, sizeof(magic)) != 0) {
145		return false;
146	}
147
148	uint32_t id;
149	vf->read(vf, &id, sizeof(id));
150	if (id != 1) {
151		return false;
152	}
153
154	vf->seek(vf, 4, SEEK_CUR);
155	vf->read(vf, &vbm->d.frames, sizeof(vbm->d.frames));
156	vf->read(vf, &vbm->d.rrCount, sizeof(vbm->d.rrCount));
157
158	uint8_t flags;
159	vf->read(vf, &flags, sizeof(flags));
160	if (flags & 1) {
161		// Incompatible savestate format
162		return false;
163	}
164	if (flags & 2) {
165		// TODO: Implement SRAM loading
166		return false;
167	}
168
169	vf->seek(vf, 1, SEEK_CUR);
170	vf->read(vf, &flags, sizeof(flags));
171	if ((flags & 0x7) != 1) {
172		// Non-GBA movie
173		return false;
174	}
175
176	// TODO: parse more flags
177
178	vf->seek(vf, 0x3C, SEEK_SET);
179	vf->read(vf, &vbm->inputOffset, sizeof(vbm->inputOffset));
180	vf->seek(vf, vbm->inputOffset, SEEK_SET);
181	vbm->vbmFile = vf;
182	return true;
183}