Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
pret
GitHub Repository: pret/pokered
Path: blob/master/tools/pkmncompress.c
1270 views
1
#define PROGRAM_NAME "pkmncompress"
2
#define USAGE_OPTS "[-h|--help] [-u|--uncompress] infile.2bpp outfile.pic"
3
4
#include "common.h"
5
6
void parse_args(int argc, char *argv[], bool *uncomp) {
7
struct option long_options[] = {
8
{"uncompress", no_argument, 0, 'u'},
9
{"help", no_argument, 0, 'h'},
10
{0}
11
};
12
for (int opt; (opt = getopt_long(argc, argv, "uh", long_options)) != -1;) {
13
switch (opt) {
14
case 'u':
15
*uncomp = true;
16
break;
17
case 'h':
18
usage_exit(0);
19
break;
20
default:
21
usage_exit(1);
22
}
23
}
24
}
25
26
uint8_t output[15 * 15 * 0x10];
27
int cur_bit;
28
int cur_byte;
29
30
void write_bit(int bit) {
31
if (++cur_bit == 8) {
32
cur_byte++;
33
cur_bit = 0;
34
}
35
output[cur_byte] |= bit << (7 - cur_bit);
36
}
37
38
int read_bit(uint8_t *data) {
39
if (cur_bit == -1) {
40
cur_byte++;
41
cur_bit = 7;
42
}
43
return (data[cur_byte] >> cur_bit--) & 1;
44
}
45
46
void transpose_tiles(uint8_t *data, int width) {
47
int size = width * width;
48
for (int i = 0; i < size; i++) {
49
int j = (i * width + i / width) % size;
50
if (i < j) {
51
uint8_t tmp[0x10];
52
uint8_t *p = data + i * COUNTOF(tmp);
53
uint8_t *q = data + j * COUNTOF(tmp);
54
memcpy(tmp, p, COUNTOF(tmp));
55
memcpy(p, q, COUNTOF(tmp));
56
memcpy(q, tmp, COUNTOF(tmp));
57
}
58
}
59
}
60
61
void compress_plane(uint8_t *plane, int width) {
62
static int gray_codes[2][0x10] = {
63
{0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4, 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9, 0x8},
64
{0x8, 0x9, 0xB, 0xA, 0xE, 0xF, 0xD, 0xC, 0x4, 0x5, 0x7, 0x6, 0x2, 0x3, 0x1, 0x0},
65
};
66
int ram_size = width * width * 8;
67
for (int i = 0, nybble_lo = 0; i < ram_size; i++) {
68
int m = i % width;
69
if (!m) {
70
nybble_lo = 0;
71
}
72
int j = i / width + m * width * 8;
73
int nybble_hi = (plane[j] >> 4) & 0xF;
74
int code_hi = gray_codes[nybble_lo & 1][nybble_hi];
75
nybble_lo = plane[j] & 0xF;
76
int code_lo = gray_codes[nybble_hi & 1][nybble_lo];
77
plane[j] = (code_hi << 4) | code_lo;
78
}
79
}
80
81
void rle_encode_number(int n) {
82
int bit_count = -1;
83
int v = ++n;
84
v++;
85
v |= v >> 1;
86
v |= v >> 2;
87
v |= v >> 4;
88
v |= v >> 8;
89
v |= v >> 16;
90
v -= v >> 1;
91
v--;
92
int number = n - v;
93
while (v) {
94
v >>= 1;
95
bit_count++;
96
}
97
for (int j = 0; j < bit_count; j++) {
98
write_bit(1);
99
}
100
write_bit(0);
101
for (int j = bit_count; j >= 0; j--) {
102
write_bit((number >> j) & 1);
103
}
104
}
105
106
void write_data_packet(uint8_t *bit_groups, int n) {
107
for (int i = 0; i < n; i++) {
108
write_bit((bit_groups[i] >> 1) & 1);
109
write_bit(bit_groups[i] & 1);
110
}
111
}
112
113
int interpret_compress(uint8_t *planes[2], int mode, int order, int width) {
114
int ram_size = width * width * 8;
115
uint8_t *rams[2] = {xmalloc(ram_size), xmalloc(ram_size)};
116
memcpy(rams[0], planes[order], ram_size);
117
memcpy(rams[1], planes[order ^ 1], ram_size);
118
if (mode != 0) {
119
for (int i = 0; i < ram_size; i++) {
120
rams[1][i] ^= rams[0][i];
121
}
122
}
123
compress_plane(rams[0], width);
124
if (mode != 1) {
125
compress_plane(rams[1], width);
126
}
127
cur_bit = 7;
128
cur_byte = 0;
129
memset(output, 0, COUNTOF(output));
130
output[0] = (width << 4) | width;
131
write_bit(order);
132
uint8_t bit_groups[15 * 4 * 15 * 8] = {0};
133
int index = 0;
134
for (int plane = 0; plane < 2; plane++) {
135
int type = 0;
136
int nums = 0;
137
memset(bit_groups, 0, COUNTOF(bit_groups));
138
for (int x = 0; x < width; x++) {
139
for (int bit = 0; bit < 8; bit += 2) {
140
for (int y = 0, byte = x * width * 8; y < width * 8; y++, byte++) {
141
int bit_group = (rams[plane][byte] >> (6 - bit)) & 3;
142
if (bit_group) {
143
if (type == 0) {
144
write_bit(1);
145
} else if (type == 1) {
146
rle_encode_number(nums);
147
}
148
type = 2;
149
bit_groups[index++] = bit_group;
150
nums = 0;
151
} else {
152
if (type == 0) {
153
write_bit(0);
154
} else if (type == 1) {
155
nums++;
156
} else {
157
write_data_packet(bit_groups, index);
158
write_bit(0);
159
write_bit(0);
160
}
161
type = 1;
162
memset(bit_groups, 0, COUNTOF(bit_groups));
163
index = 0;
164
}
165
}
166
}
167
}
168
if (type == 1) {
169
rle_encode_number(nums);
170
} else {
171
write_data_packet(bit_groups, index);
172
}
173
if (!plane) {
174
if (mode == 0) {
175
write_bit(0);
176
} else {
177
write_bit(1);
178
write_bit(mode - 1);
179
}
180
}
181
}
182
free(rams[0]);
183
free(rams[1]);
184
return (cur_byte + 1) * 8 + cur_bit;
185
}
186
187
int get_width(long filesize) {
188
int width = 0;
189
for (int w = 1; w < 16; w++) {
190
if (filesize == w * w * 0x10) {
191
width = w;
192
break;
193
}
194
}
195
if (!width) {
196
error_exit("Image is not a square, or is larger than 15x15 tiles");
197
}
198
return width;
199
}
200
201
int compress(uint8_t *data, long filesize) {
202
int width = get_width(filesize);
203
int ram_size = width * width * 8;
204
uint8_t *planes[2] = {xmalloc(ram_size), xmalloc(ram_size)};
205
transpose_tiles(data, width);
206
for (int i = 0; i < ram_size; i++) {
207
planes[0][i] = data[i * 2];
208
planes[1][i] = data[i * 2 + 1];
209
}
210
uint8_t current[COUNTOF(output)] = {0};
211
int compressed_size = -1;
212
for (int mode = 0; mode < 3; mode++) {
213
for (int order = 0; order < 2; order++) {
214
if (mode == 0 && order == 0) {
215
continue;
216
}
217
int new_size = interpret_compress(planes, mode, order, width);
218
if (compressed_size == -1 || new_size < compressed_size) {
219
compressed_size = new_size;
220
memset(current, 0, COUNTOF(current));
221
memcpy(current, output, compressed_size / 8);
222
}
223
}
224
}
225
memset(output, 0, COUNTOF(output));
226
memcpy(output, current, compressed_size / 8);
227
free(planes[0]);
228
free(planes[1]);
229
return compressed_size / 8;
230
}
231
232
int read_int(uint8_t *data, int count) {
233
int n = 0;
234
while (count--) {
235
n = (n << 1) | read_bit(data);
236
}
237
return n;
238
}
239
240
uint8_t *fill_plane(uint8_t *data, int width) {
241
static int table[0x10] = {
242
0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF,
243
0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF,
244
};
245
int mode = read_bit(data);
246
int size = width * width * 0x20;
247
uint8_t *plane = xmalloc(size);
248
int len = 0;
249
while (len < size) {
250
if (mode) {
251
while (len < size) {
252
int bit_group = read_int(data, 2);
253
if (!bit_group) {
254
break;
255
}
256
plane[len++] = bit_group;
257
}
258
} else {
259
size_t w = 0;
260
while (read_bit(data)) {
261
w++;
262
}
263
if (w >= COUNTOF(table)) {
264
error_exit("Invalid compressed data");
265
}
266
int n = table[w] + read_int(data, w + 1);
267
while (len < size && n--) {
268
plane[len++] = 0;
269
}
270
}
271
mode ^= 1;
272
}
273
if (len > size) {
274
error_exit("Invalid compressed data");
275
}
276
uint8_t *ram = xmalloc(size);
277
len = 0;
278
for (int y = 0; y < width; y++) {
279
for (int x = 0; x < width * 8; x++) {
280
for (int i = 0; i < 4; i++) {
281
ram[len++] = plane[(y * 4 + i) * width * 8 + x];
282
}
283
}
284
}
285
for (int i = 0; i < size - 3; i += 4) {
286
ram[i / 4] = (ram[i] << 6) | (ram[i + 1] << 4) | (ram[i + 2] << 2) | ram[i + 3];
287
}
288
free(plane);
289
return ram;
290
}
291
292
void uncompress_plane(uint8_t *plane, int width) {
293
static int codes[2][0x10] = {
294
{0x0, 0x1, 0x3, 0x2, 0x7, 0x6, 0x4, 0x5, 0xF, 0xE, 0xC, 0xD, 0x8, 0x9, 0xB, 0xA},
295
{0xF, 0xE, 0xC, 0xD, 0x8, 0x9, 0xB, 0xA, 0x0, 0x1, 0x3, 0x2, 0x7, 0x6, 0x4, 0x5},
296
};
297
for (int x = 0; x < width * 8; x++) {
298
int bit = 0;
299
for (int y = 0; y < width; y++) {
300
int i = y * width * 8 + x;
301
int nybble_hi = (plane[i] >> 4) & 0xF;
302
int code_hi = codes[bit][nybble_hi];
303
bit = code_hi & 1;
304
int nybble_lo = plane[i] & 0xF;
305
int code_lo = codes[bit][nybble_lo];
306
bit = code_lo & 1;
307
plane[i] = (code_hi << 4) | code_lo;
308
}
309
}
310
}
311
312
int uncompress(uint8_t *data) {
313
cur_bit = 7;
314
int width = read_int(data, 4);
315
if (read_int(data, 4) != width) {
316
error_exit("Image is not a square");
317
}
318
int size = width * width * 8;
319
uint8_t *rams[2];
320
int order = read_bit(data);
321
rams[order] = fill_plane(data, width);
322
int mode = read_bit(data);
323
if (mode) {
324
mode += read_bit(data);
325
}
326
rams[order ^ 1] = fill_plane(data, width);
327
uncompress_plane(rams[order], width);
328
if (mode != 1) {
329
uncompress_plane(rams[order ^ 1], width);
330
}
331
if (mode != 0) {
332
for (int i = 0; i < size; i++) {
333
rams[order ^ 1][i] ^= rams[order][i];
334
}
335
}
336
for (int i = 0; i < size; i++) {
337
output[i * 2] = rams[0][i];
338
output[i * 2 + 1] = rams[1][i];
339
}
340
transpose_tiles(output, width);
341
free(rams[0]);
342
free(rams[1]);
343
return size * 2;
344
}
345
346
int main(int argc, char *argv[]) {
347
bool uncomp = false;
348
parse_args(argc, argv, &uncomp);
349
350
argc -= optind;
351
argv += optind;
352
if (argc < 1) {
353
usage_exit(1);
354
}
355
356
long filesize;
357
uint8_t *data = read_u8(argv[0], &filesize);
358
359
int output_size = uncomp ? uncompress(data) : compress(data, filesize);
360
write_u8(argv[1], output, output_size);
361
362
free(data);
363
return 0;
364
}
365
366