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