1 #include "gb.h"
2 #include <stdint.h>
3 #include <stddef.h>
4 #include <stdlib.h>
5 #include <math.h>
6
state_compress(const uint8_t * prev,const uint8_t * data,size_t uncompressed_size)7 static uint8_t *state_compress(const uint8_t *prev, const uint8_t *data, size_t uncompressed_size)
8 {
9 size_t malloc_size = 0x1000;
10 uint8_t *compressed = malloc(malloc_size);
11 size_t counter_pos = 0;
12 size_t data_pos = sizeof(uint16_t);
13 bool prev_mode = true;
14 *(uint16_t *)compressed = 0;
15 #define COUNTER (*(uint16_t *)&compressed[counter_pos])
16 #define DATA (compressed[data_pos])
17
18 while (uncompressed_size) {
19 if (prev_mode) {
20 if (*data == *prev && COUNTER != 0xffff) {
21 COUNTER++;
22 data++;
23 prev++;
24 uncompressed_size--;
25 }
26 else {
27 prev_mode = false;
28 counter_pos += sizeof(uint16_t);
29 data_pos = counter_pos + sizeof(uint16_t);
30 if (data_pos >= malloc_size) {
31 malloc_size *= 2;
32 compressed = realloc(compressed, malloc_size);
33 }
34 COUNTER = 0;
35 }
36 }
37 else {
38 if (*data != *prev && COUNTER != 0xffff) {
39 COUNTER++;
40 DATA = *data;
41 data_pos++;
42 data++;
43 prev++;
44 uncompressed_size--;
45 if (data_pos >= malloc_size) {
46 malloc_size *= 2;
47 compressed = realloc(compressed, malloc_size);
48 }
49 }
50 else {
51 prev_mode = true;
52 counter_pos = data_pos;
53 data_pos = counter_pos + sizeof(uint16_t);
54 if (counter_pos >= malloc_size - 1) {
55 malloc_size *= 2;
56 compressed = realloc(compressed, malloc_size);
57 }
58 COUNTER = 0;
59 }
60 }
61 }
62
63 return realloc(compressed, data_pos);
64 #undef DATA
65 #undef COUNTER
66 }
67
68
state_decompress(const uint8_t * prev,uint8_t * data,uint8_t * dest,size_t uncompressed_size)69 static void state_decompress(const uint8_t *prev, uint8_t *data, uint8_t *dest, size_t uncompressed_size)
70 {
71 size_t counter_pos = 0;
72 size_t data_pos = sizeof(uint16_t);
73 bool prev_mode = true;
74 #define COUNTER (*(uint16_t *)&data[counter_pos])
75 #define DATA (data[data_pos])
76
77 while (uncompressed_size) {
78 if (prev_mode) {
79 if (COUNTER) {
80 COUNTER--;
81 *(dest++) = *(prev++);
82 uncompressed_size--;
83 }
84 else {
85 prev_mode = false;
86 counter_pos += sizeof(uint16_t);
87 data_pos = counter_pos + sizeof(uint16_t);
88 }
89 }
90 else {
91 if (COUNTER) {
92 COUNTER--;
93 *(dest++) = DATA;
94 data_pos++;
95 prev++;
96 uncompressed_size--;
97 }
98 else {
99 prev_mode = true;
100 counter_pos = data_pos;
101 data_pos += sizeof(uint16_t);
102 }
103 }
104 }
105 #undef DATA
106 #undef COUNTER
107 }
108
GB_rewind_push(GB_gameboy_t * gb)109 void GB_rewind_push(GB_gameboy_t *gb)
110 {
111 const size_t save_size = GB_get_save_state_size_no_bess(gb);
112 if (!gb->rewind_sequences) {
113 if (gb->rewind_buffer_length) {
114 gb->rewind_sequences = malloc(sizeof(*gb->rewind_sequences) * gb->rewind_buffer_length);
115 memset(gb->rewind_sequences, 0, sizeof(*gb->rewind_sequences) * gb->rewind_buffer_length);
116 gb->rewind_pos = 0;
117 }
118 else {
119 return;
120 }
121 }
122
123 if (gb->rewind_sequences[gb->rewind_pos].pos == GB_REWIND_FRAMES_PER_KEY) {
124 gb->rewind_pos++;
125 if (gb->rewind_pos == gb->rewind_buffer_length) {
126 gb->rewind_pos = 0;
127 }
128 if (gb->rewind_sequences[gb->rewind_pos].key_state) {
129 free(gb->rewind_sequences[gb->rewind_pos].key_state);
130 gb->rewind_sequences[gb->rewind_pos].key_state = NULL;
131 }
132 for (unsigned i = 0; i < GB_REWIND_FRAMES_PER_KEY; i++) {
133 if (gb->rewind_sequences[gb->rewind_pos].compressed_states[i]) {
134 free(gb->rewind_sequences[gb->rewind_pos].compressed_states[i]);
135 gb->rewind_sequences[gb->rewind_pos].compressed_states[i] = 0;
136 }
137 }
138 gb->rewind_sequences[gb->rewind_pos].pos = 0;
139 }
140
141 if (!gb->rewind_sequences[gb->rewind_pos].key_state) {
142 gb->rewind_sequences[gb->rewind_pos].key_state = malloc(save_size);
143 GB_save_state_to_buffer_no_bess(gb, gb->rewind_sequences[gb->rewind_pos].key_state);
144 }
145 else {
146 uint8_t *save_state = malloc(save_size);
147 GB_save_state_to_buffer_no_bess(gb, save_state);
148 gb->rewind_sequences[gb->rewind_pos].compressed_states[gb->rewind_sequences[gb->rewind_pos].pos++] =
149 state_compress(gb->rewind_sequences[gb->rewind_pos].key_state, save_state, save_size);
150 free(save_state);
151 }
152
153 }
154
GB_rewind_pop(GB_gameboy_t * gb)155 bool GB_rewind_pop(GB_gameboy_t *gb)
156 {
157 if (!gb->rewind_sequences || !gb->rewind_sequences[gb->rewind_pos].key_state) {
158 return false;
159 }
160
161 const size_t save_size = GB_get_save_state_size_no_bess(gb);
162 if (gb->rewind_sequences[gb->rewind_pos].pos == 0) {
163 GB_load_state_from_buffer(gb, gb->rewind_sequences[gb->rewind_pos].key_state, save_size);
164 free(gb->rewind_sequences[gb->rewind_pos].key_state);
165 gb->rewind_sequences[gb->rewind_pos].key_state = NULL;
166 gb->rewind_pos = gb->rewind_pos == 0? gb->rewind_buffer_length - 1 : gb->rewind_pos - 1;
167 return true;
168 }
169
170 uint8_t *save_state = malloc(save_size);
171 state_decompress(gb->rewind_sequences[gb->rewind_pos].key_state,
172 gb->rewind_sequences[gb->rewind_pos].compressed_states[--gb->rewind_sequences[gb->rewind_pos].pos],
173 save_state,
174 save_size);
175 free(gb->rewind_sequences[gb->rewind_pos].compressed_states[gb->rewind_sequences[gb->rewind_pos].pos]);
176 gb->rewind_sequences[gb->rewind_pos].compressed_states[gb->rewind_sequences[gb->rewind_pos].pos] = NULL;
177 GB_load_state_from_buffer(gb, save_state, save_size);
178 free(save_state);
179 return true;
180 }
181
GB_rewind_free(GB_gameboy_t * gb)182 void GB_rewind_free(GB_gameboy_t *gb)
183 {
184 if (!gb->rewind_sequences) return;
185 for (unsigned i = 0; i < gb->rewind_buffer_length; i++) {
186 if (gb->rewind_sequences[i].key_state) {
187 free(gb->rewind_sequences[i].key_state);
188 }
189 for (unsigned j = 0; j < GB_REWIND_FRAMES_PER_KEY; j++) {
190 if (gb->rewind_sequences[i].compressed_states[j]) {
191 free(gb->rewind_sequences[i].compressed_states[j]);
192 }
193 }
194 }
195 free(gb->rewind_sequences);
196 gb->rewind_sequences = NULL;
197 }
198
GB_set_rewind_length(GB_gameboy_t * gb,double seconds)199 void GB_set_rewind_length(GB_gameboy_t *gb, double seconds)
200 {
201 GB_rewind_free(gb);
202 if (seconds == 0) {
203 gb->rewind_buffer_length = 0;
204 }
205 else {
206 gb->rewind_buffer_length = (size_t) ceil(seconds * CPU_FREQUENCY / LCDC_PERIOD / GB_REWIND_FRAMES_PER_KEY);
207 }
208 }
209