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}