Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-1-2-2013-Decompilation
Path: blob/main/RSDKv4/Sprite.cpp
817 views
1
#include "RetroEngine.hpp"
2
3
struct GifDecoder {
4
int depth;
5
int clearCode;
6
int eofCode;
7
int runningCode;
8
int runningBits;
9
int prevCode;
10
int currentCode;
11
int maxCodePlusOne;
12
int stackPtr;
13
int shiftState;
14
int fileState;
15
int position;
16
int bufferSize;
17
uint shiftData;
18
uint pixelCount;
19
byte buffer[256];
20
byte stack[4096];
21
byte suffix[4096];
22
uint prefix[4096];
23
};
24
25
const int LOADING_IMAGE = 0;
26
const int LOAD_COMPLETE = 1;
27
const int LZ_MAX_CODE = 4095;
28
const int LZ_BITS = 12;
29
const int FIRST_CODE = 4097;
30
const int NO_SUCH_CODE = 4098;
31
32
GifDecoder gifDecoder;
33
int codeMasks[] = { 0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095 };
34
35
int ReadGifCode(void);
36
byte ReadGifByte(void);
37
byte TraceGifPrefix(uint *prefix, int code, int clearCode);
38
39
void InitGifDecoder()
40
{
41
byte code = 0;
42
FileRead(&code, 1);
43
gifDecoder.fileState = LOADING_IMAGE;
44
gifDecoder.position = 0;
45
gifDecoder.bufferSize = 0;
46
gifDecoder.buffer[0] = 0;
47
gifDecoder.depth = code;
48
gifDecoder.clearCode = 1 << code;
49
gifDecoder.eofCode = gifDecoder.clearCode + 1;
50
gifDecoder.runningCode = gifDecoder.eofCode + 1;
51
gifDecoder.runningBits = code + 1;
52
gifDecoder.maxCodePlusOne = 1 << gifDecoder.runningBits;
53
gifDecoder.stackPtr = 0;
54
gifDecoder.prevCode = NO_SUCH_CODE;
55
gifDecoder.shiftState = 0;
56
gifDecoder.shiftData = 0;
57
for (int i = 0; i <= LZ_MAX_CODE; ++i) gifDecoder.prefix[i] = (byte)NO_SUCH_CODE;
58
}
59
void ReadGifLine(byte *line, int length, int offset)
60
{
61
int i = 0;
62
int stackPtr = gifDecoder.stackPtr;
63
int eofCode = gifDecoder.eofCode;
64
int clearCode = gifDecoder.clearCode;
65
int prevCode = gifDecoder.prevCode;
66
if (stackPtr != 0) {
67
while (stackPtr != 0) {
68
if (i >= length)
69
break;
70
line[offset++] = gifDecoder.stack[--stackPtr];
71
i++;
72
}
73
}
74
while (i < length) {
75
int gifCode = ReadGifCode();
76
if (gifCode == eofCode) {
77
if (i != length - 1 || gifDecoder.pixelCount != 0)
78
return;
79
i++;
80
}
81
else {
82
if (gifCode == clearCode) {
83
for (int p = 0; p <= LZ_MAX_CODE; p++) gifDecoder.prefix[p] = NO_SUCH_CODE;
84
gifDecoder.runningCode = gifDecoder.eofCode + 1;
85
gifDecoder.runningBits = gifDecoder.depth + 1;
86
gifDecoder.maxCodePlusOne = 1 << gifDecoder.runningBits;
87
prevCode = (gifDecoder.prevCode = NO_SUCH_CODE);
88
}
89
else {
90
if (gifCode < clearCode) {
91
line[offset] = (byte)gifCode;
92
offset++;
93
i++;
94
}
95
else {
96
if (gifCode < 0 || gifCode > LZ_MAX_CODE)
97
return;
98
99
int code = 0;
100
if (gifDecoder.prefix[gifCode] == NO_SUCH_CODE) {
101
if (gifCode != gifDecoder.runningCode - 2)
102
return;
103
104
code = prevCode;
105
gifDecoder.suffix[gifDecoder.runningCode - 2] = gifDecoder.stack[stackPtr++] =
106
TraceGifPrefix(gifDecoder.prefix, prevCode, clearCode);
107
}
108
else {
109
code = gifCode;
110
}
111
int c = 0;
112
while (c++ <= LZ_MAX_CODE && code > clearCode && code <= LZ_MAX_CODE) {
113
gifDecoder.stack[stackPtr++] = gifDecoder.suffix[code];
114
code = gifDecoder.prefix[code];
115
}
116
if (c >= LZ_MAX_CODE || code > LZ_MAX_CODE)
117
return;
118
119
gifDecoder.stack[stackPtr++] = (byte)code;
120
while (stackPtr != 0 && i++ < length) line[offset++] = gifDecoder.stack[--stackPtr];
121
}
122
if (prevCode != NO_SUCH_CODE) {
123
if (gifDecoder.runningCode < 2 || gifDecoder.runningCode > FIRST_CODE)
124
return;
125
126
gifDecoder.prefix[gifDecoder.runningCode - 2] = prevCode;
127
if (gifCode == gifDecoder.runningCode - 2)
128
gifDecoder.suffix[gifDecoder.runningCode - 2] = TraceGifPrefix(gifDecoder.prefix, prevCode, clearCode);
129
else
130
gifDecoder.suffix[gifDecoder.runningCode - 2] = TraceGifPrefix(gifDecoder.prefix, gifCode, clearCode);
131
}
132
prevCode = gifCode;
133
}
134
}
135
}
136
gifDecoder.prevCode = prevCode;
137
gifDecoder.stackPtr = stackPtr;
138
}
139
140
int ReadGifCode()
141
{
142
while (gifDecoder.shiftState < gifDecoder.runningBits) {
143
byte b = ReadGifByte();
144
gifDecoder.shiftData |= (uint)((uint)b << gifDecoder.shiftState);
145
gifDecoder.shiftState += 8;
146
}
147
int code = (gifDecoder.shiftData & codeMasks[gifDecoder.runningBits]);
148
gifDecoder.shiftData >>= gifDecoder.runningBits;
149
gifDecoder.shiftState -= gifDecoder.runningBits;
150
if (++gifDecoder.runningCode > gifDecoder.maxCodePlusOne && gifDecoder.runningBits < LZ_BITS) {
151
gifDecoder.maxCodePlusOne <<= 1;
152
gifDecoder.runningBits++;
153
}
154
return code;
155
}
156
157
byte ReadGifByte()
158
{
159
byte c = 0;
160
if (gifDecoder.fileState == LOAD_COMPLETE)
161
return c;
162
163
byte b;
164
if (gifDecoder.position == gifDecoder.bufferSize) {
165
FileRead(&b, 1);
166
gifDecoder.bufferSize = (int)b;
167
if (gifDecoder.bufferSize == 0) {
168
gifDecoder.fileState = LOAD_COMPLETE;
169
return c;
170
}
171
FileRead(gifDecoder.buffer, gifDecoder.bufferSize);
172
b = gifDecoder.buffer[0];
173
gifDecoder.position = 1;
174
}
175
else {
176
b = gifDecoder.buffer[gifDecoder.position++];
177
}
178
return b;
179
}
180
181
byte TraceGifPrefix(uint *prefix, int code, int clearCode)
182
{
183
int i = 0;
184
while (code > clearCode && i++ <= LZ_MAX_CODE) code = prefix[code];
185
186
return code;
187
}
188
void ReadGifPictureData(int width, int height, bool interlaced, byte *gfxData, int offset)
189
{
190
int initialRow[] = { 0, 4, 2, 1 };
191
int rowInc[] = { 8, 8, 4, 2 };
192
InitGifDecoder();
193
if (interlaced) {
194
for (int p = 0; p < 4; ++p) {
195
for (int y = initialRow[p]; y < height; y += rowInc[p]) ReadGifLine(gfxData, width, y * width + offset);
196
}
197
}
198
else {
199
for (int y = 0; y < height; ++y) ReadGifLine(gfxData, width, y * width + offset);
200
}
201
}
202
203
int AddGraphicsFile(const char *filePath)
204
{
205
char sheetPath[0x100];
206
207
StrCopy(sheetPath, "Data/Sprites/");
208
StrAdd(sheetPath, filePath);
209
int sheetID = 0;
210
while (StrLength(gfxSurface[sheetID].fileName) > 0) {
211
if (StrComp(gfxSurface[sheetID].fileName, sheetPath))
212
return sheetID;
213
if (++sheetID == SURFACE_COUNT) // Max Sheet cnt
214
return 0;
215
}
216
byte fileExtension = (byte)sheetPath[(StrLength(sheetPath) - 1) & 0xFF];
217
switch (fileExtension) {
218
case 'f': LoadGIFFile(sheetPath, sheetID); break;
219
case 'p': LoadBMPFile(sheetPath, sheetID); break;
220
case 'r': LoadPVRFile(sheetPath, sheetID); break;
221
}
222
223
return sheetID;
224
}
225
void RemoveGraphicsFile(const char *filePath, int sheetID)
226
{
227
if (sheetID < 0) {
228
for (int i = 0; i < SURFACE_COUNT; ++i) {
229
if (StrLength(gfxSurface[i].fileName) > 0 && StrComp(gfxSurface[i].fileName, filePath))
230
sheetID = i;
231
}
232
}
233
234
if (sheetID >= 0 && StrLength(gfxSurface[sheetID].fileName)) {
235
StrCopy(gfxSurface[sheetID].fileName, "");
236
int dataPosStart = gfxSurface[sheetID].dataPosition;
237
int dataPosEnd = gfxSurface[sheetID].dataPosition + gfxSurface[sheetID].height * gfxSurface[sheetID].width;
238
for (int i = GFXDATA_SIZE - dataPosEnd; i > 0; --i) graphicData[dataPosStart++] = graphicData[dataPosEnd++];
239
gfxDataPosition -= gfxSurface[sheetID].height * gfxSurface[sheetID].width;
240
for (int i = 0; i < SURFACE_COUNT; ++i) {
241
if (gfxSurface[i].dataPosition > gfxSurface[sheetID].dataPosition)
242
gfxSurface[i].dataPosition -= gfxSurface[sheetID].height * gfxSurface[sheetID].width;
243
}
244
}
245
}
246
247
int LoadBMPFile(const char *filePath, byte sheetID)
248
{
249
FileInfo info;
250
if (LoadFile(filePath, &info)) {
251
GFXSurface *surface = &gfxSurface[sheetID];
252
StrCopy(surface->fileName, filePath);
253
254
byte fileBuffer = 0;
255
256
SetFilePosition(18);
257
FileRead(&fileBuffer, 1);
258
surface->width = fileBuffer;
259
FileRead(&fileBuffer, 1);
260
surface->width |= fileBuffer << 8;
261
FileRead(&fileBuffer, 1);
262
surface->width |= fileBuffer << 16;
263
FileRead(&fileBuffer, 1);
264
surface->width |= fileBuffer << 24;
265
266
FileRead(&fileBuffer, 1);
267
surface->height = fileBuffer;
268
FileRead(&fileBuffer, 1);
269
surface->height |= fileBuffer << 8;
270
FileRead(&fileBuffer, 1);
271
surface->height |= fileBuffer << 16;
272
FileRead(&fileBuffer, 1);
273
surface->height |= fileBuffer << 24;
274
275
SetFilePosition(info.vfileSize - surface->height * surface->width);
276
surface->dataPosition = gfxDataPosition;
277
byte *gfxData = &graphicData[surface->dataPosition + surface->width * (surface->height - 1)];
278
for (int y = 0; y < surface->height; ++y) {
279
for (int x = 0; x < surface->width; ++x) {
280
FileRead(&fileBuffer, 1);
281
*gfxData++ = fileBuffer;
282
}
283
gfxData -= 2 * surface->width;
284
}
285
gfxDataPosition += surface->height * surface->width;
286
287
#if RETRO_SOFTWARE_RENDER
288
surface->widthShift = 0;
289
int w = surface->width;
290
while (w > 1) {
291
w >>= 1;
292
++surface->widthShift;
293
}
294
#endif
295
296
if (gfxDataPosition >= GFXDATA_SIZE) {
297
gfxDataPosition = 0;
298
PrintLog("WARNING: Exceeded max gfx size!");
299
}
300
301
CloseFile();
302
return true;
303
}
304
return false;
305
}
306
int LoadGIFFile(const char *filePath, byte sheetID)
307
{
308
FileInfo info;
309
if (LoadFile(filePath, &info)) {
310
GFXSurface *surface = &gfxSurface[sheetID];
311
StrCopy(surface->fileName, filePath);
312
313
byte fileBuffer = 0;
314
315
SetFilePosition(6); // GIF89a
316
FileRead(&fileBuffer, 1);
317
surface->width = fileBuffer;
318
FileRead(&fileBuffer, 1);
319
surface->width |= fileBuffer << 8;
320
FileRead(&fileBuffer, 1);
321
surface->height = fileBuffer;
322
FileRead(&fileBuffer, 1);
323
surface->height |= fileBuffer << 8;
324
325
FileRead(&fileBuffer, 1); // Palette Size
326
// int has_pallete = (fileBuffer & 0x80) >> 7;
327
// int colors = ((fileBuffer & 0x70) >> 4) + 1;
328
int palette_size = (fileBuffer & 0x7) + 1;
329
if (palette_size > 0)
330
palette_size = 1 << palette_size;
331
FileRead(&fileBuffer, 1); // BG Color index (thrown away)
332
FileRead(&fileBuffer, 1); // idk actually (still thrown away)
333
334
int c = 0;
335
byte clr[3];
336
do {
337
++c;
338
FileRead(clr, 3);
339
} while (c != palette_size);
340
341
FileRead(&fileBuffer, 1);
342
while (fileBuffer != ',') FileRead(&fileBuffer, 1); // gif image start identifier
343
344
ushort fileBuffer2 = 0;
345
FileRead(&fileBuffer2, 2);
346
FileRead(&fileBuffer2, 2);
347
FileRead(&fileBuffer2, 2);
348
FileRead(&fileBuffer2, 2);
349
FileRead(&fileBuffer, 1);
350
bool interlaced = (fileBuffer & 0x40) >> 6;
351
if (fileBuffer >> 7 == 1) {
352
int c = 0x80;
353
do {
354
++c;
355
FileRead(clr, 3);
356
} while (c != 0x100);
357
}
358
359
surface->dataPosition = gfxDataPosition;
360
361
#if RETRO_SOFTWARE_RENDER
362
surface->widthShift = 0;
363
int w = surface->width;
364
while (w > 1) {
365
w >>= 1;
366
++surface->widthShift;
367
}
368
#endif
369
370
gfxDataPosition += surface->width * surface->height;
371
if (gfxDataPosition < GFXDATA_SIZE) {
372
ReadGifPictureData(surface->width, surface->height, interlaced, graphicData, surface->dataPosition);
373
}
374
else {
375
gfxDataPosition = 0;
376
PrintLog("WARNING: Exceeded max gfx size!");
377
}
378
379
CloseFile();
380
return true;
381
}
382
return false;
383
}
384
int LoadPVRFile(const char *filePath, byte sheetID)
385
{
386
// ONLY READS "PVRTC 2bpp RGB" PVR FILES
387
FileInfo info;
388
if (LoadFile(filePath, &info)) {
389
GFXSurface *surface = &gfxSurface[sheetID];
390
StrCopy(surface->fileName, filePath);
391
392
byte fileBuffer[2];
393
394
SetFilePosition(28);
395
FileRead(fileBuffer, 1);
396
int width = fileBuffer[0];
397
FileRead(fileBuffer, 1);
398
width |= fileBuffer[0] << 8;
399
FileRead(fileBuffer, 1);
400
int height = fileBuffer[0];
401
FileRead(fileBuffer, 1);
402
height = fileBuffer[0] << 8;
403
404
surface->width = width;
405
surface->height = height;
406
surface->dataPosition = gfxDataPosition;
407
gfxDataPosition += surface->width * surface->height;
408
409
if (gfxDataPosition >= GFXDATA_SIZE) {
410
gfxDataPosition = 0;
411
PrintLog("WARNING: Exceeded max gfx size!");
412
}
413
414
#if RETRO_SOFTWARE_RENDER
415
surface->widthShift = 0;
416
int w = surface->width;
417
while (w > 1) {
418
w >>= 1;
419
++surface->widthShift;
420
}
421
#endif
422
423
return false; // yeah I have no clue how to handle this, cd lite has this be loaded every frame on framebuffer update and does it that way
424
425
ushort *buffer = NULL;
426
for (int h = 0; h < height; ++h) {
427
for (int w = 0; w < width; ++w) {
428
FileRead(fileBuffer, 2);
429
buffer[w] = 2 * (fileBuffer[0] + (fileBuffer[1] << 8)) | 1;
430
}
431
buffer += width;
432
}
433
buffer += 0x400 - width;
434
435
CloseFile();
436
return true;
437
}
438
return false;
439
}
440
441