all repos — mgba @ 534d4fe5baffae9dca0dfe915c7c379752374ba4

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	if (!rr->isPlaying(rr)) {
 98		return;
 99	}
100
101	struct GBAVBMContext* vbm = (struct GBAVBMContext*) rr;
102	vbm->vbmFile->seek(vbm->vbmFile, sizeof(uint16_t), SEEK_CUR);
103}
104
105uint16_t GBAVBMQueryInput(struct GBARRContext* rr) {
106	if (!rr->isPlaying(rr)) {
107		return 0;
108	}
109
110	struct GBAVBMContext* vbm = (struct GBAVBMContext*) rr;
111	uint16_t input;
112	vbm->vbmFile->read(vbm->vbmFile, &input, sizeof(input));
113	vbm->vbmFile->seek(vbm->vbmFile, -sizeof(input), SEEK_CUR);
114	return input & 0x3FF;
115}
116
117void GBAVBMStateSaved(struct GBARRContext* rr, struct GBASerializedState* state) {
118	UNUSED(rr);
119	UNUSED(state);
120}
121
122void GBAVBMStateLoaded(struct GBARRContext* rr, const struct GBASerializedState* state) {
123	UNUSED(rr);
124	UNUSED(state);
125}
126
127struct VFile* GBAVBMOpenSavedata(struct GBARRContext* rr, int flags) {
128	UNUSED(rr);
129	UNUSED(flags);
130	return 0;
131}
132
133struct VFile* GBAVBMOpenSavestate(struct GBARRContext* rr, int flags) {
134	UNUSED(rr);
135	UNUSED(flags);
136	return 0;
137}
138
139void GBAVBMContextDestroy(struct GBARRContext* rr) {
140	struct GBAVBMContext* vbm = (struct GBAVBMContext*) rr;
141	if (vbm->vbmFile) {
142		vbm->vbmFile->close(vbm->vbmFile);
143	}
144}
145
146bool GBAVBMSetStream(struct GBAVBMContext* vbm, struct VFile* vf) {
147	vf->seek(vf, 0, SEEK_SET);
148	char magic[4];
149	vf->read(vf, magic, sizeof(magic));
150	if (memcmp(magic, VBM_MAGIC, sizeof(magic)) != 0) {
151		return false;
152	}
153
154	uint32_t id;
155	vf->read(vf, &id, sizeof(id));
156	if (id != 1) {
157		return false;
158	}
159
160	vf->seek(vf, 4, SEEK_CUR);
161	vf->read(vf, &vbm->d.frames, sizeof(vbm->d.frames));
162	vf->read(vf, &vbm->d.rrCount, sizeof(vbm->d.rrCount));
163
164	uint8_t flags;
165	vf->read(vf, &flags, sizeof(flags));
166	if (flags & 1) {
167		// Incompatible savestate format
168		return false;
169	}
170	if (flags & 2) {
171		// TODO: Implement SRAM loading
172		return false;
173	}
174
175	vf->seek(vf, 1, SEEK_CUR);
176	vf->read(vf, &flags, sizeof(flags));
177	if ((flags & 0x7) != 1) {
178		// Non-GBA movie
179		return false;
180	}
181
182	// TODO: parse more flags
183
184	vf->seek(vf, 0x3C, SEEK_SET);
185	vf->read(vf, &vbm->inputOffset, sizeof(vbm->inputOffset));
186	vf->seek(vf, vbm->inputOffset, SEEK_SET);
187	vbm->vbmFile = vf;
188	return true;
189}