Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Rubberduckycooly
GitHub Repository: Rubberduckycooly/RSDKv5-Decompilation
Path: blob/master/RSDKv5/RSDK/Graphics/Sprite.cpp
1163 views
1
#include "RSDK/Core/RetroEngine.hpp"
2
3
using namespace RSDK;
4
5
#if RETRO_REV0U
6
#include "Legacy/SpriteLegacy.cpp"
7
#endif
8
9
const int32 LOADING_IMAGE = 0;
10
const int32 LOAD_COMPLETE = 1;
11
const int32 LZ_MAX_CODE = 4095;
12
const int32 LZ_BITS = 12;
13
const int32 FIRST_CODE = 4097;
14
const int32 NO_SUCH_CODE = 4098;
15
16
int32 codeMasks[] = { 0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095 };
17
18
int32 ReadGifCode(ImageGIF *image);
19
uint8 ReadGifByte(ImageGIF *image);
20
uint8 TraceGifPrefix(uint32 *prefix, int32 code, int32 clearCode);
21
22
void InitGifDecoder(ImageGIF *image)
23
{
24
uint8 initCodeSize = ReadInt8(&image->info);
25
image->decoder->fileState = LOADING_IMAGE;
26
image->decoder->position = 0;
27
image->decoder->bufferSize = 0;
28
image->decoder->buffer[0] = 0;
29
image->decoder->depth = initCodeSize;
30
image->decoder->clearCode = 1 << initCodeSize;
31
image->decoder->eofCode = image->decoder->clearCode + 1;
32
image->decoder->runningCode = image->decoder->eofCode + 1;
33
image->decoder->runningBits = initCodeSize + 1;
34
image->decoder->maxCodePlusOne = 1 << image->decoder->runningBits;
35
image->decoder->stackPtr = 0;
36
image->decoder->prevCode = NO_SUCH_CODE;
37
image->decoder->shiftState = 0;
38
image->decoder->shiftData = 0;
39
40
for (int32 i = 0; i <= LZ_MAX_CODE; ++i) image->decoder->prefix[i] = (uint8)NO_SUCH_CODE;
41
}
42
void ReadGifLine(ImageGIF *image, uint8 *line, int32 length, int32 offset)
43
{
44
int32 i = 0;
45
int32 stackPtr = image->decoder->stackPtr;
46
int32 eofCode = image->decoder->eofCode;
47
int32 clearCode = image->decoder->clearCode;
48
int32 prevCode = image->decoder->prevCode;
49
50
if (stackPtr != 0) {
51
while (stackPtr != 0) {
52
if (i >= length)
53
break;
54
55
line[offset++] = image->decoder->stack[--stackPtr];
56
i++;
57
}
58
}
59
60
while (i < length) {
61
int32 gifCode = ReadGifCode(image);
62
if (gifCode == eofCode) {
63
if (i != length - 1 || image->decoder->pixelCount != 0)
64
return;
65
66
i++;
67
}
68
else {
69
if (gifCode == clearCode) {
70
for (int32 p = 0; p <= LZ_MAX_CODE; p++) image->decoder->prefix[p] = NO_SUCH_CODE;
71
72
image->decoder->runningCode = image->decoder->eofCode + 1;
73
image->decoder->runningBits = image->decoder->depth + 1;
74
image->decoder->maxCodePlusOne = 1 << image->decoder->runningBits;
75
76
prevCode = image->decoder->prevCode = NO_SUCH_CODE;
77
}
78
else {
79
if (gifCode < clearCode) {
80
line[offset++] = (uint8)gifCode;
81
i++;
82
}
83
else {
84
if (gifCode < 0 || gifCode > LZ_MAX_CODE)
85
return;
86
87
int32 code = gifCode;
88
if (image->decoder->prefix[gifCode] == NO_SUCH_CODE) {
89
if (gifCode != image->decoder->runningCode - 2)
90
return;
91
92
code = prevCode;
93
94
image->decoder->suffix[image->decoder->runningCode - 2] = image->decoder->stack[stackPtr++] =
95
TraceGifPrefix(image->decoder->prefix, prevCode, clearCode);
96
}
97
98
int32 c = 0;
99
while (c++ <= LZ_MAX_CODE && code > clearCode && code <= LZ_MAX_CODE) {
100
image->decoder->stack[stackPtr++] = image->decoder->suffix[code];
101
code = image->decoder->prefix[code];
102
}
103
104
if (c >= LZ_MAX_CODE || code > LZ_MAX_CODE)
105
return;
106
107
image->decoder->stack[stackPtr++] = (uint8)code;
108
109
while (stackPtr != 0 && i++ < length) line[offset++] = image->decoder->stack[--stackPtr];
110
}
111
112
if (prevCode != NO_SUCH_CODE) {
113
if (image->decoder->runningCode < 2 || image->decoder->runningCode > FIRST_CODE)
114
return;
115
116
image->decoder->prefix[image->decoder->runningCode - 2] = prevCode;
117
118
if (gifCode == image->decoder->runningCode - 2)
119
image->decoder->suffix[image->decoder->runningCode - 2] = TraceGifPrefix(image->decoder->prefix, prevCode, clearCode);
120
else
121
image->decoder->suffix[image->decoder->runningCode - 2] = TraceGifPrefix(image->decoder->prefix, gifCode, clearCode);
122
}
123
124
prevCode = gifCode;
125
}
126
}
127
}
128
129
image->decoder->prevCode = prevCode;
130
image->decoder->stackPtr = stackPtr;
131
}
132
133
int32 ReadGifCode(ImageGIF *image)
134
{
135
while (image->decoder->shiftState < image->decoder->runningBits) {
136
uint8 b = ReadGifByte(image);
137
image->decoder->shiftData |= (uint32)b << image->decoder->shiftState;
138
image->decoder->shiftState += 8;
139
}
140
141
int32 result = (int32)(image->decoder->shiftData & (uint32)codeMasks[image->decoder->runningBits]);
142
image->decoder->shiftData >>= image->decoder->runningBits;
143
image->decoder->shiftState -= image->decoder->runningBits;
144
if (++image->decoder->runningCode > image->decoder->maxCodePlusOne && image->decoder->runningBits < LZ_BITS) {
145
image->decoder->maxCodePlusOne <<= 1;
146
image->decoder->runningBits++;
147
}
148
149
return result;
150
}
151
152
uint8 ReadGifByte(ImageGIF *image)
153
{
154
uint8 c = '\0';
155
if (image->decoder->fileState == LOAD_COMPLETE)
156
return c;
157
158
uint8 b;
159
if (image->decoder->position == image->decoder->bufferSize) {
160
b = ReadInt8(&image->info);
161
image->decoder->bufferSize = b;
162
if (image->decoder->bufferSize == 0) {
163
image->decoder->fileState = LOAD_COMPLETE;
164
return c;
165
}
166
167
ReadBytes(&image->info, image->decoder->buffer, image->decoder->bufferSize);
168
b = image->decoder->buffer[0];
169
image->decoder->position = 1;
170
}
171
else {
172
b = image->decoder->buffer[image->decoder->position++];
173
}
174
175
return b;
176
}
177
178
uint8 TraceGifPrefix(uint32 *prefix, int32 code, int32 clearCode)
179
{
180
int32 i = 0;
181
while (code > clearCode && i++ <= LZ_MAX_CODE) code = prefix[code];
182
183
return code;
184
}
185
void ReadGifPictureData(ImageGIF *image, int32 width, int32 height, bool32 interlaced, uint8 *pixels)
186
{
187
int32 initialRows[] = { 0, 4, 2, 1 };
188
int32 rowInc[] = { 8, 8, 4, 2 };
189
190
InitGifDecoder(image);
191
if (interlaced) {
192
for (int32 p = 0; p < 4; ++p) {
193
for (int32 y = initialRows[p]; y < height; y += rowInc[p]) {
194
ReadGifLine(image, pixels, width, y * width);
195
}
196
}
197
return;
198
}
199
for (int32 h = 0; h < height; ++h) ReadGifLine(image, pixels, width, h * width);
200
}
201
202
bool32 ImageGIF::Load(const char *fileName, bool32 loadHeader)
203
{
204
if (!decoder)
205
return false;
206
207
if (fileName) {
208
if (!LoadFile(&info, fileName, FMODE_RB))
209
return false;
210
211
Seek_Set(&info, 6);
212
width = ReadInt16(&info);
213
height = ReadInt16(&info);
214
215
if (loadHeader)
216
return true;
217
}
218
219
int32 data = ReadInt8(&info);
220
// int32 has_pallete = (data & 0x80) >> 7;
221
// int32 colors = ((data & 0x70) >> 4) + 1;
222
int32 palette_size = (data & 0x7) + 1;
223
if (palette_size > 0)
224
palette_size = 1 << palette_size;
225
226
Seek_Cur(&info, 2);
227
228
if (!palette)
229
AllocateStorage((void **)&palette, 0x100 * sizeof(int32), DATASET_TMP, true);
230
231
if (!pixels)
232
AllocateStorage((void **)&pixels, width * height, DATASET_TMP, false);
233
234
if (palette && pixels) {
235
uint8 clr[3];
236
int32 c = 0;
237
do {
238
ReadBytes(&info, clr, 3);
239
palette[c] = (clr[0] << 16) | (clr[1] << 8) | (clr[2] << 0);
240
++c;
241
} while (c != palette_size);
242
243
uint8 buf = ReadInt8(&info);
244
while (buf != ',') buf = ReadInt8(&info); // gif image start identifier
245
246
ReadInt16(&info);
247
ReadInt16(&info);
248
ReadInt16(&info);
249
ReadInt16(&info);
250
data = ReadInt8(&info);
251
bool32 interlaced = (data & 0x40) >> 6;
252
if (data >> 7 == 1) {
253
int32 c = 0x80;
254
do {
255
++c;
256
ReadBytes(&info, clr, 3);
257
palette[c] = (clr[0] << 16) | (clr[1] << 8) | (clr[2] << 0);
258
} while (c != 0x100);
259
}
260
261
ReadGifPictureData(this, width, height, interlaced, pixels);
262
263
Close();
264
return true;
265
}
266
return false;
267
}
268
269
#if RETRO_PLATFORM == RETRO_ANDROID
270
#define _REDOFF 0
271
#define _GREENOFF 8
272
#define _BLUEOFF 16
273
#else
274
#define _REDOFF 16
275
#define _GREENOFF 8
276
#define _BLUEOFF 0
277
#endif
278
279
#if RETRO_REV02
280
void RSDK::ImagePNG::UnpackPixels_Greyscale(uint8 *pixelData)
281
{
282
uint8 *pixels = this->pixels;
283
for (int32 p = 0; p < this->width * this->height; ++p) {
284
uint8 brightness = *pixelData;
285
pixelData++;
286
287
uint32 color = 0;
288
289
// red channel
290
color = brightness << _REDOFF;
291
292
// green channel
293
color |= brightness << _GREENOFF;
294
295
// blue channel
296
color |= brightness << _BLUEOFF;
297
298
// alpha channel
299
color |= brightness << 24;
300
301
*pixels = color;
302
303
pixels += 2;
304
}
305
}
306
307
void RSDK::ImagePNG::UnpackPixels_GreyscaleA(uint8 *pixelData)
308
{
309
color *pixels = (color *)this->pixels;
310
for (int32 p = 0; p < this->width * this->height; ++p) {
311
uint8 brightness = *pixelData;
312
pixelData++;
313
314
uint32 color = 0;
315
316
// red channel
317
color = brightness << _REDOFF;
318
319
// green channel
320
color |= brightness << _GREENOFF;
321
322
// blue channel
323
color |= brightness << _BLUEOFF;
324
325
// alpha channel
326
color |= 0xFF << 24;
327
328
*pixels = color;
329
330
pixels++;
331
}
332
}
333
334
void RSDK::ImagePNG::UnpackPixels_Indexed(uint8 *pixelData)
335
{
336
color *pixels = (color *)this->pixels;
337
for (int32 p = 0; p < this->width * this->height; ++p) {
338
pixels[p] = palette[pixelData[p]] | 0xFF000000;
339
}
340
}
341
342
void RSDK::ImagePNG::UnpackPixels_RGB(uint8 *pixelData)
343
{
344
color *pixels = (color *)this->pixels;
345
for (int32 p = 0; p < this->width * this->height; ++p) {
346
uint32 color = 0;
347
348
// R
349
color = *pixelData << _REDOFF;
350
pixelData++;
351
352
// G
353
color |= *pixelData << _GREENOFF;
354
pixelData++;
355
356
// B
357
color |= *pixelData << _BLUEOFF;
358
pixelData++;
359
360
// A
361
color |= 0xFF << 24;
362
363
*pixels++ = color;
364
}
365
}
366
367
void RSDK::ImagePNG::UnpackPixels_RGBA(uint8 *pixelData)
368
{
369
color *pixels = (color *)this->pixels;
370
for (int32 p = 0; p < this->width * this->height; ++p) {
371
uint32 color = 0;
372
373
// R
374
color |= *pixelData << _REDOFF;
375
pixelData++;
376
377
// G
378
color |= *pixelData << _GREENOFF;
379
pixelData++;
380
381
// B
382
color |= *pixelData << _BLUEOFF;
383
pixelData++;
384
385
// A
386
color |= *pixelData << 24;
387
pixelData++;
388
389
*pixels++ = color;
390
}
391
}
392
393
// from: https://raw.githubusercontent.com/lvandeve/lodepng/master/lodepng.cpp - paethPredictor()
394
uint8 paethPredictor(int16 a, int16 b, int16 c)
395
{
396
int16 pa = abs(b - c);
397
int16 pb = abs(a - c);
398
int16 pc = abs(a + b - c - c);
399
/* return input value associated with smallest of pa, pb, pc (with certain priority if equal) */
400
if (pb < pa) {
401
a = b;
402
pa = pb;
403
}
404
405
return (pc < pa) ? c : a;
406
}
407
408
void RSDK::ImagePNG::Unfilter(uint8 *recon)
409
{
410
int32 bpp = (this->bitDepth + 7) >> 3;
411
switch (this->colorFormat) {
412
default: break;
413
414
case PNGCLR_RGB: bpp *= sizeof(color) - 1; break;
415
416
case PNGCLR_GREYSCALEA: bpp *= 2 * sizeof(uint8); break;
417
418
case PNGCLR_RGBA: bpp *= sizeof(color); break;
419
}
420
421
int32 pitch = bpp * this->width;
422
uint8 *scanline = recon;
423
424
for (int32 y = 0; y < this->height; ++y) {
425
int32 filter = *scanline++;
426
427
// prev scanline
428
uint8 *precon = y ? &recon[-pitch] : NULL;
429
430
switch (filter) {
431
default:
432
#if !RETRO_USE_ORIGINAL_CODE
433
PrintLog(PRINT_NORMAL, "Invalid PNG Filter: %d", filter);
434
return;
435
#else
436
// [Fallthrough]
437
#endif
438
case PNGFILTER_NONE:
439
for (int32 c = 0; c < pitch; ++c) {
440
recon[c] = scanline[c];
441
}
442
break;
443
444
case PNGFILTER_SUB:
445
for (int32 c = 0; c < bpp; ++c) {
446
recon[c] = scanline[c];
447
}
448
449
for (int32 c = bpp, p = 0; c < pitch; ++c, ++p) {
450
recon[c] = scanline[c] + recon[p];
451
}
452
break;
453
454
case PNGFILTER_UP:
455
if (precon) {
456
for (int32 c = 0; c < pitch; ++c) {
457
recon[c] = precon[c] + scanline[c];
458
}
459
}
460
else {
461
for (int32 c = 0; c < pitch; ++c) {
462
recon[c] = scanline[c];
463
}
464
}
465
break;
466
467
case PNGFILTER_AVG:
468
if (precon) {
469
for (int32 c = 0; c < bpp; ++c) {
470
recon[c] = scanline[c] + (precon[c] >> 1);
471
}
472
473
for (int32 c = bpp, p = 0; c < pitch; ++c, ++p) {
474
recon[c] = scanline[c] + ((recon[p] + precon[c]) >> 1);
475
}
476
}
477
else {
478
for (int32 c = 0; c < bpp; ++c) {
479
recon[c] = scanline[c];
480
}
481
482
for (int32 c = bpp, p = 0; c < pitch; ++c, ++p) {
483
recon[c] = scanline[c] + (recon[p] >> 1);
484
}
485
}
486
break;
487
488
case PNGFILTER_PAETH:
489
if (precon) {
490
for (int32 c = 0; c < bpp; ++c) {
491
recon[c] = (scanline[c] + precon[c]);
492
}
493
494
for (int32 c = bpp, p = 0; c < pitch; ++c, ++p) {
495
recon[c] = (scanline[c] + paethPredictor(recon[c - bpp], precon[c], precon[p]));
496
}
497
}
498
else {
499
for (int32 c = 0; c < bpp; ++c) {
500
recon[c] = scanline[c];
501
}
502
503
for (int32 c = bpp, p = 0; c < pitch; ++c, ++p) {
504
recon[c] = scanline[c] + recon[p];
505
}
506
}
507
break;
508
}
509
510
recon += pitch;
511
scanline += pitch;
512
}
513
}
514
515
bool32 RSDK::ImagePNG::AllocatePixels()
516
{
517
dataSize = sizeof(color) * height * (width + 1);
518
if (!pixels) {
519
AllocateStorage((void **)&pixels, dataSize, DATASET_TMP, false);
520
521
if (!pixels) {
522
Close();
523
return false;
524
}
525
}
526
527
return true;
528
}
529
530
void RSDK::ImagePNG::ProcessScanlines()
531
{
532
uint8 *pixelsPtr = NULL;
533
switch (colorFormat) {
534
case PNGCLR_GREYSCALE:
535
case PNGCLR_INDEXED: pixelsPtr = &pixels[3 * width * height]; break;
536
537
case PNGCLR_RGB: pixelsPtr = &pixels[1 * width * height]; break;
538
539
case PNGCLR_GREYSCALEA: pixelsPtr = &pixels[2 * width * height]; break;
540
541
case PNGCLR_RGBA:
542
default: pixelsPtr = &pixels[0 * width * height]; break;
543
}
544
545
// the original v5 decodes IDAT sections one at a time, so the compressed buffer is extracted into pixels every time here
546
// again, this is a BAD idea!! IDAT chunks should be stored and processed as a group at the end of reading
547
548
// decode all loaded IDAT chunks into pixels
549
Uncompress((uint8 **)&chunkBuffer, chunkSize, (uint8 **)&pixelsPtr, dataSize);
550
551
Unfilter(pixelsPtr);
552
553
switch (colorFormat) {
554
case PNGCLR_GREYSCALE: UnpackPixels_Greyscale(pixelsPtr); break;
555
556
case PNGCLR_RGB: UnpackPixels_RGB(pixelsPtr); break;
557
558
case PNGCLR_INDEXED: UnpackPixels_Indexed(pixelsPtr); break;
559
560
case PNGCLR_GREYSCALEA: UnpackPixels_GreyscaleA(pixelsPtr); break;
561
562
case PNGCLR_RGBA: UnpackPixels_RGBA(pixelsPtr); break;
563
564
default: break;
565
}
566
}
567
568
// PNG format signature
569
#define PNG_SIGNATURE 0xA1A0A0D474E5089LL // PNG (and other bytes I don't care about)
570
571
// PNG chunk header signatures
572
#define PNG_SIG_HEADER 0x52444849 // IHDR
573
#define PNG_SIG_END 0x444E4549 // IEND
574
#define PNG_SIG_PALETTE 0x45544C50 // PLTE
575
#define PNG_SIG_DATA 0x54414449 // IDAT
576
577
bool32 RSDK::ImagePNG::Load(const char *fileName, bool32 loadHeader)
578
{
579
if (fileName) {
580
if (LoadFile(&info, fileName, FMODE_RB)) {
581
if (ReadInt64(&info) == PNG_SIGNATURE) {
582
while (true) {
583
chunkSize = ReadInt32(&info, true);
584
chunkHeader = ReadInt32(&info, false);
585
586
bool32 finished = false;
587
if (chunkHeader == PNG_SIG_HEADER && chunkSize == 13) {
588
width = ReadInt32(&info, true);
589
height = ReadInt32(&info, true);
590
bitDepth = ReadInt8(&info);
591
colorFormat = ReadInt8(&info);
592
compression = ReadInt8(&info);
593
filter = ReadInt8(&info);
594
interlaced = ReadInt8(&info);
595
if (interlaced || bitDepth != 8) {
596
Close();
597
return false;
598
}
599
depth = 32;
600
601
#if !RETRO_USE_ORIGINAL_CODE
602
// image size should be enough space to hold all the IDAT chunks
603
AllocateStorage((void **)&chunkBuffer, sizeof(color) * height * (width + 1), DATASET_TMP, true);
604
dataSize = 0;
605
#endif
606
607
if (loadHeader)
608
return true;
609
}
610
else if (chunkHeader == PNG_SIG_END) {
611
finished = true;
612
}
613
else if (chunkHeader == PNG_SIG_PALETTE) {
614
int32 colorCnt = chunkSize / 3;
615
if (!(chunkSize % 3)) {
616
chunkSize = colorCnt;
617
if (colorCnt <= 0x100) {
618
if (!palette)
619
AllocateStorage((void **)&palette, sizeof(uint32) * colorCnt, DATASET_TMP, true);
620
621
uint8 channels[3];
622
for (int32 c = 0; c < colorCnt; ++c) {
623
ReadBytes(&info, channels, 3 * sizeof(uint8));
624
palette[c] = (channels[0] << 16) | (channels[1] << 8) | (channels[2] << 0);
625
}
626
}
627
}
628
}
629
else if (chunkHeader == PNG_SIG_DATA) {
630
#if RETRO_USE_ORIGINAL_CODE
631
if (!AllocatePixels())
632
return false;
633
634
// read this chunk into the chunk buffer storage (we're processing each IDAT section by itself
635
// this is a BAD idea!!! though it's kept here for reference as to how the original v5 works
636
AllocateStorage((void **)&chunkBuffer, chunkSize, DATASET_TMP, false);
637
ReadBytes(&info, chunkBuffer, chunkSize);
638
639
// decode the scanlines into usable RGBA pixels
640
ProcessScanlines();
641
#else
642
// read this chunk into the chunk buffer storage (we process em all at the end)
643
dataSize += ReadBytes(&info, chunkBuffer + dataSize, chunkSize);
644
#endif
645
}
646
else {
647
Seek_Cur(&info, chunkSize);
648
}
649
650
chunkCRC = ReadInt32(&info, false);
651
652
if (finished) {
653
Close();
654
655
#if !RETRO_USE_ORIGINAL_CODE
656
// copy this over, since we only "borrowed" it after all :)
657
// chunkSize is the size of chunkBuffer
658
chunkSize = dataSize;
659
if (!AllocatePixels())
660
return false;
661
662
// decode the scanlines into usable RGBA pixels
663
ProcessScanlines();
664
665
RemoveStorageEntry((void **)&chunkBuffer);
666
#endif
667
668
return true;
669
}
670
}
671
}
672
else {
673
Close();
674
}
675
}
676
}
677
678
return false;
679
}
680
#endif
681
682
#if !RETRO_REV02
683
bool32 RSDK::ImageTGA::Load(const char *fileName, bool32 loadHeader)
684
{
685
if (LoadFile(&info, fileName, FMODE_RB)) {
686
// header
687
uint8 idLength = ReadInt8(&info);
688
689
// color map type
690
uint8 colormaptype = ReadInt8(&info);
691
692
// image type
693
uint8 datatypecode = ReadInt8(&info);
694
695
// color map specification
696
int16 colormaporigin = ReadInt16(&info);
697
int16 colormaplength = ReadInt16(&info);
698
uint8 colormapdepth = ReadInt8(&info);
699
700
// image specification
701
int16 originX = ReadInt16(&info);
702
int16 originY = ReadInt16(&info);
703
width = ReadInt16(&info);
704
height = ReadInt16(&info);
705
uint8 bpp = ReadInt8(&info);
706
uint8 descriptor = ReadInt8(&info);
707
708
bool32 reverse = (~descriptor >> 4) & 1;
709
if (bpp >= 16) {
710
if (idLength)
711
Seek_Cur(&info, idLength);
712
713
AllocateStorage((void **)&pixels, sizeof(uint32) * height * width, DATASET_TMP, false);
714
uint32 *pixelsPtr = (uint32 *)pixels;
715
if (reverse)
716
pixelsPtr += (height * width) - width;
717
718
int32 x = 0;
719
switch (datatypecode) {
720
case 2: // Uncompressed, RGB images
721
switch (bpp) {
722
case 16:
723
for (int32 i = 0; i < height * width; ++i) {
724
uint8 channels[2];
725
ReadBytes(&info, channels, sizeof(uint16));
726
727
uint16 color16 = channels[0] + (channels[1] << 8);
728
*pixelsPtr = 0;
729
730
if (color16 & 0x8000) { // alpha bit (0 = invisible, 1 = visible)
731
uint32 R = (color16 >> 10) & 0x1F;
732
uint32 G = (color16 >> 5) & 0x1F;
733
uint32 B = (color16 >> 0) & 0x1F;
734
735
R = (R << 3) | (R >> 2);
736
G = (G << 3) | (G >> 2);
737
B = (B << 3) | (B >> 2);
738
739
*pixelsPtr = (R << 16) | (G << 8) | (B << 0);
740
}
741
742
pixelsPtr++;
743
744
if (reverse && ++x == width) {
745
x = 0;
746
pixelsPtr -= width << 1;
747
}
748
}
749
break;
750
751
case 24:
752
for (int32 i = 0; i < height * width; ++i) {
753
uint8 channels[3];
754
ReadBytes(&info, channels, sizeof(color) - 1);
755
756
*pixelsPtr = (channels[0] << 0) | (channels[1] << 8) | (channels[2] << 16) | (0xFF << 24);
757
pixelsPtr++;
758
759
if (reverse && ++x == width) {
760
x = 0;
761
pixelsPtr -= width << 1;
762
}
763
}
764
break;
765
766
case 32:
767
for (int32 i = 0; i < height * width; ++i) {
768
uint8 channels[4];
769
ReadBytes(&info, channels, sizeof(color));
770
771
*pixelsPtr = (channels[0] << 0) | (channels[1] << 8) | (channels[2] << 16) | (channels[3] << 24);
772
pixelsPtr++;
773
774
if (reverse && ++x == width) {
775
x = 0;
776
pixelsPtr -= width << 1;
777
}
778
}
779
break;
780
}
781
break;
782
783
case 10: // Runlength encoded RGB images
784
switch (bpp) {
785
case 16: {
786
uint8 channels[2];
787
memset(channels, 0, sizeof(channels));
788
789
uint8 count = 0;
790
bool32 decodingRLE = false;
791
for (int32 p = 0; p < height * width; ++p) {
792
if (count) {
793
if (!decodingRLE)
794
ReadBytes(&info, channels, sizeof(uint16));
795
796
--count;
797
}
798
else {
799
count = ReadInt8(&info);
800
decodingRLE = count & 0x80;
801
count &= 0x7F;
802
803
ReadBytes(&info, channels, sizeof(uint16));
804
}
805
806
uint16 color16 = channels[0] + (channels[1] << 8);
807
*pixelsPtr = 0;
808
809
if (color16 & 0x8000) { // alpha bit (0 = invisible, 1 = visible)
810
uint32 R = (color16 >> 10) & 0x1F;
811
uint32 G = (color16 >> 5) & 0x1F;
812
uint32 B = (color16 >> 0) & 0x1F;
813
814
R = (R << 3) | (R >> 2);
815
G = (G << 3) | (G >> 2);
816
B = (B << 3) | (B >> 2);
817
818
*pixelsPtr = (R << 16) | (G << 8) | (B << 0);
819
}
820
821
++pixelsPtr;
822
if (reverse && ++x == width) {
823
x = 0;
824
pixelsPtr -= width << 1;
825
}
826
}
827
break;
828
}
829
830
case 24: {
831
uint8 channels[3];
832
memset(channels, 0, sizeof(channels));
833
834
uint8 count = 0;
835
bool32 decodingRLE = false;
836
for (int32 p = 0; p < height * width; ++p) {
837
if (count) {
838
if (!decodingRLE)
839
ReadBytes(&info, channels, sizeof(color) - 1);
840
841
--count;
842
}
843
else {
844
count = ReadInt8(&info);
845
decodingRLE = count & 0x80;
846
count &= 0x7F;
847
848
ReadBytes(&info, channels, sizeof(color) - 1);
849
}
850
851
*pixelsPtr = (channels[0] << 0) | (channels[1] << 8) | (channels[2] << 16) | (0xFF << 24);
852
pixelsPtr++;
853
854
if (reverse && ++x == width) {
855
x = 0;
856
pixelsPtr -= width << 1;
857
}
858
}
859
break;
860
}
861
862
case 32: {
863
uint8 channels[sizeof(color)];
864
memset(channels, 0, sizeof(channels));
865
866
uint8 count = 0;
867
bool32 decodingRLE = false;
868
for (int32 p = 0; p < height * width; ++p) {
869
if (count) {
870
if (!decodingRLE)
871
ReadBytes(&info, channels, sizeof(uint32));
872
873
--count;
874
}
875
else {
876
count = ReadInt8(&info);
877
decodingRLE = count & 0x80;
878
count &= 0x7F;
879
880
ReadBytes(&info, channels, sizeof(color));
881
}
882
883
*pixelsPtr = (channels[0] << 0) | (channels[1] << 8) | (channels[2] << 16) | (channels[3] << 24);
884
pixelsPtr++;
885
886
if (reverse && ++x == width) {
887
x = 0;
888
pixelsPtr -= width << 1;
889
}
890
}
891
break;
892
}
893
}
894
break;
895
}
896
897
Close();
898
return true;
899
}
900
}
901
902
return false;
903
}
904
#endif
905
906
uint16 RSDK::LoadSpriteSheet(const char *filename, uint8 scope)
907
{
908
char fullFilePath[0x100];
909
sprintf_s(fullFilePath, sizeof(fullFilePath), "Data/Sprites/%s", filename);
910
911
if (!scope || scope > SCOPE_STAGE)
912
return -1;
913
914
RETRO_HASH_MD5(hash);
915
GEN_HASH_MD5(filename, hash);
916
917
for (int32 i = 0; i < SURFACE_COUNT; ++i) {
918
if (HASH_MATCH_MD5(gfxSurface[i].hash, hash)) {
919
return i;
920
}
921
}
922
923
uint16 id = -1;
924
for (id = 0; id < SURFACE_COUNT; ++id) {
925
if (gfxSurface[id].scope == SCOPE_NONE)
926
break;
927
}
928
929
if (id >= SURFACE_COUNT)
930
return -1;
931
932
933
GFXSurface *surface = &gfxSurface[id];
934
ImageGIF image;
935
936
if (image.Load(fullFilePath, true)) {
937
surface->scope = scope;
938
surface->width = image.width;
939
surface->height = image.height;
940
surface->lineSize = 0;
941
memcpy(surface->hash, hash, 4 * sizeof(int32));
942
943
int32 w = surface->width;
944
if (w > 1) {
945
int32 ls = 0;
946
do {
947
w >>= 1;
948
++ls;
949
} while (w > 1);
950
surface->lineSize = ls;
951
}
952
953
surface->pixels = NULL;
954
AllocateStorage((void **)&surface->pixels, surface->width * surface->height, DATASET_STG, false);
955
#if !RETRO_USE_ORIGINAL_CODE
956
// Bug details: On a failed allocation, image.pixels will end up being reallocated in image.Load().
957
// Pixel data would then be loaded in this temporary buffer, but surface->pixels would never point to the actual data.
958
// This issue would only happen on cases where the STG mempool is full, such as ports with lower storage limits
959
// or with mods that use a lot of spritesheets.
960
// As a last resort, let's try a new allocation in TMP for surface->pixels.
961
// NOTE: This is a workaround, and will still cause a crash if the TMP allocation fails as well.
962
if (!surface->pixels)
963
AllocateStorage((void **)&surface->pixels, surface->width * surface->height, DATASET_TMP, false);
964
#endif
965
image.pixels = surface->pixels;
966
image.Load(NULL, false);
967
968
#if RETRO_USE_ORIGINAL_CODE
969
image.palette = NULL;
970
image.decoder = NULL;
971
#endif
972
image.Close();
973
974
return id;
975
}
976
else {
977
#if RETRO_USE_ORIGINAL_CODE
978
image.palette = NULL;
979
image.decoder = NULL;
980
#endif
981
image.pixels = NULL;
982
image.Close();
983
return -1;
984
}
985
}
986
987
bool32 RSDK::LoadImage(const char *filename, double displayLength, double fadeSpeed, bool32 (*skipCallback)())
988
{
989
char fullFilePath[0x100];
990
sprintf_s(fullFilePath, sizeof(fullFilePath), "Data/Images/%s", filename);
991
992
#if RETRO_REV02
993
ImagePNG image;
994
#else
995
ImageTGA image;
996
#endif
997
InitFileInfo(&image.info);
998
999
#if RETRO_REV02
1000
if (image.Load(fullFilePath, false)) {
1001
if (image.width == RETRO_VIDEO_TEXTURE_W && image.height == RETRO_VIDEO_TEXTURE_H) {
1002
RenderDevice::SetupImageTexture(image.width, image.height, image.pixels);
1003
}
1004
#if !RETRO_USE_ORIGINAL_CODE
1005
else {
1006
PrintLog(PRINT_NORMAL, "ERROR: Images must be 1024x512!");
1007
}
1008
#endif
1009
1010
engine.displayTime = displayLength;
1011
engine.storedShaderID = videoSettings.shaderID;
1012
engine.storedState = sceneInfo.state;
1013
videoSettings.dimMax = 0.0;
1014
videoSettings.shaderID = SHADER_RGB_IMAGE;
1015
videoSettings.screenCount = 0; // "Image Display Mode"
1016
engine.skipCallback = skipCallback;
1017
sceneInfo.state = ENGINESTATE_SHOWIMAGE;
1018
engine.imageFadeSpeed = fadeSpeed / 60.0;
1019
1020
image.pixels = NULL;
1021
image.Close();
1022
return true;
1023
}
1024
#elif !RETRO_REV02
1025
if (image.Load(fullFilePath, true)) {
1026
if (image.width == RETRO_VIDEO_TEXTURE_W && image.height == RETRO_VIDEO_TEXTURE_H) {
1027
RenderDevice::SetupImageTexture(image.width, image.height, image.pixels);
1028
}
1029
#if !RETRO_USE_ORIGINAL_CODE
1030
else {
1031
PrintLog(PRINT_NORMAL, "ERROR: Images must be 1024x512!");
1032
}
1033
#endif
1034
1035
engine.displayTime = displayLength;
1036
engine.storedShaderID = videoSettings.shaderID;
1037
engine.storedState = sceneInfo.state;
1038
videoSettings.dimMax = 0.0;
1039
videoSettings.shaderID = SHADER_RGB_IMAGE;
1040
videoSettings.screenCount = 0; // "Image Display Mode"
1041
engine.skipCallback = skipCallback;
1042
sceneInfo.state = ENGINESTATE_SHOWIMAGE;
1043
engine.imageFadeSpeed = fadeSpeed / 60.0;
1044
1045
image.pixels = NULL;
1046
image.Close();
1047
return true;
1048
}
1049
#endif
1050
else {
1051
image.pixels = NULL;
1052
image.Close();
1053
}
1054
return false;
1055
}
1056
1057