mirror of
https://github.com/AntonioND/ulibrary.git
synced 2025-06-18 23:05:50 -04:00

The compiler will be able to warn us if we use a value that doesn't correspond to the expected enum, which can be a source of bugs.
419 lines
14 KiB
C
419 lines
14 KiB
C
#include "ulib.h"
|
|
#include "gif/gif_lib.h"
|
|
|
|
// Other instances of this function may exist elsewhere!
|
|
static bool isColorTransparent32(u8 r, u8 g, u8 b)
|
|
{
|
|
if (ul_colorKeyEnabled == 32)
|
|
{
|
|
u32 color = RGBA32(r, g, b, 0);
|
|
if (color == (ul_colorKeyValue32 & 0xffffff))
|
|
return true;
|
|
}
|
|
else if (ul_colorKeyEnabled == 16)
|
|
{
|
|
if ((r >> 3) == (ul_colorKeyValue & 0x1f) &&
|
|
(g >> 3) == ((ul_colorKeyValue >> 5) & 0x1f) &&
|
|
(b >> 3) == ((ul_colorKeyValue >> 10) & 0x1f))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Note: la palette temporaire ici est 16 bits parce qu'on est sur DS mais ce
|
|
// serait facile de l'adapter au 32 bits, regarder GAMMA et le remplissage de
|
|
// cette palette (nommée Palette dans ulLoadImageGif) Le swap de palette par
|
|
// rapport à la couleur transparente n'est utile que sur DS où seule la première
|
|
// couleur d'une palette est (et doit être) transparente! Sur DS, à cause du
|
|
// fait que le mode paletté requiert que la première couleur soit transparente,
|
|
// tous les gifs auront leur première couleur comme transparente! Par contre en
|
|
// mode 16 bits (5551) le fonctionnement est normal.
|
|
|
|
u16 *temppalette; // Utilisé pour stocker la palette des gifs...
|
|
|
|
const short InterlacedOffset[] = { 0, 4, 2, 1 }; // The way Interlaced image should.
|
|
const short InterlacedJumps[] = { 8, 8, 4, 2 }; // be read - offsets and jumps...
|
|
|
|
GifPixelType LineBuf[2048]; // Buffer temporaire
|
|
|
|
int fnGifReadFunc(GifFileType* GifFile, GifByteType* buf, int count)
|
|
{
|
|
/*
|
|
char* ptr = (char*)GifFile->UserData;
|
|
memcpy(buf, ptr, count);
|
|
GifFile->UserData = ptr + count;
|
|
*/
|
|
VirtualFileRead(buf, 1, count, (VIRTUAL_FILE *)GifFile->UserData);
|
|
|
|
return count;
|
|
}
|
|
|
|
static void fnCopyLine(void *dst, void *src, int count,
|
|
UL_IMAGE_FORMATS pixelFormat, int transparentColor)
|
|
{
|
|
int x;
|
|
u8 *p_dest1 = (u8 *)dst;
|
|
u16 *p_dest2 = (u16 *)dst;
|
|
u8 *p_src = (u8 *)src;
|
|
u8 r = 0, g = 0, b = 0, a = 0, pixel_value;
|
|
|
|
for (x = 0; x < count; x++)
|
|
{
|
|
// Prochain pixel
|
|
pixel_value = p_src[x];
|
|
if (pixel_value == transparentColor)
|
|
pixel_value = 0;
|
|
else if (pixel_value < transparentColor)
|
|
pixel_value++;
|
|
|
|
if (temppalette)
|
|
{
|
|
r = temppalette[pixel_value] & 0x1f;
|
|
g = (temppalette[pixel_value] >> 5) & 0x1f;
|
|
b = (temppalette[pixel_value] >> 10) & 0x1f;
|
|
a = temppalette[pixel_value] >> 15;
|
|
}
|
|
|
|
if (pixelFormat == UL_PF_5551)
|
|
{
|
|
p_dest2[x] = RGB15(r, g, b) | (a << 15);
|
|
}
|
|
else if (pixelFormat == UL_PF_5550)
|
|
{
|
|
p_dest2[x] = RGB15(r, g, b);
|
|
}
|
|
// Tous les 8 bits
|
|
else if (ul_pixelSizes[pixelFormat] == 8)
|
|
{
|
|
p_dest1[x] = pixel_value;
|
|
}
|
|
else if (pixelFormat == UL_PF_PAL4)
|
|
{
|
|
p_dest1[x >> 1] &= ~(15 << ((x & 1) << 2));
|
|
p_dest1[x >> 1] |= (pixel_value & 15) << ((x & 1) << 2);
|
|
}
|
|
else if (pixelFormat == UL_PF_PAL2)
|
|
{
|
|
p_dest1[x >> 2] &= ~(3 << ((x & 3) << 1));
|
|
p_dest1[x >> 2] |= (pixel_value & 3) << ((x & 3) << 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
int DGifGetLineByte(GifFileType *GifFile, GifPixelType *Line, int LineLen,
|
|
UL_IMAGE_FORMATS pixelFormat, int transparentColor)
|
|
{
|
|
// Nouvelle ligne
|
|
int result = DGifGetLine(GifFile, LineBuf, LineLen);
|
|
// Ecrit dans le buffer
|
|
fnCopyLine(Line, LineBuf, LineLen, pixelFormat, transparentColor);
|
|
return result;
|
|
}
|
|
|
|
#define GAMMA(x) ((x) >> 3)
|
|
|
|
/*
|
|
#ifdef _NO_FILEIO
|
|
#define PrintGifError()
|
|
#endif
|
|
*/
|
|
|
|
//#define EXIT_FAILURE 1
|
|
|
|
// Gerer les 16 bits!!
|
|
//
|
|
// ulCreateImage()
|
|
UL_IMAGE *ulLoadImageGIF(VIRTUAL_FILE *f, UL_IMAGE_LOCATION location,
|
|
UL_IMAGE_FORMATS pixelFormat)
|
|
{
|
|
UL_IMAGE *img = NULL;
|
|
|
|
int i, j, Row, Col, Width, Height, ExtCode, Count __attribute__((unused));
|
|
u16 *Palette = NULL;
|
|
GifRecordType RecordType;
|
|
GifByteType *Extension;
|
|
GifFileType *GifFile;
|
|
ColorMapObject *ColorMap;
|
|
int transparentColor = -1;
|
|
|
|
GifFile = DGifOpen(f, fnGifReadFunc);
|
|
if (!GifFile)
|
|
return NULL;
|
|
|
|
if (ul_pixelSizes[pixelFormat] > 8)
|
|
{
|
|
temppalette = (u16 *)malloc(512); // Ecran temporaire
|
|
Palette = temppalette;
|
|
}
|
|
else
|
|
{
|
|
// En mode true color, on utilise une palette temporaire...
|
|
temppalette = NULL;
|
|
}
|
|
|
|
// Scan the content of the GIF file and load the image(s) in:
|
|
do { // Je vire les messages d'erreur pour gagner de la place
|
|
DGifGetRecordType(GifFile, &RecordType);
|
|
|
|
switch (RecordType)
|
|
{
|
|
case IMAGE_DESC_RECORD_TYPE:
|
|
DGifGetImageDesc(GifFile);
|
|
/*
|
|
if (DGifGetImageDesc(GifFile) == GIF_ERROR)
|
|
{
|
|
PrintGifError();
|
|
return EXIT_FAILURE;
|
|
}
|
|
*/
|
|
//Row = GifFile->Image.Top; // Image Position relative to Screen.
|
|
//Col = GifFile->Image.Left;
|
|
|
|
// Je n'en tiens pas compte car il faudrait aggrandir l'image,
|
|
// c'est peut être utile pour les gifs animés remarque
|
|
Row = Col = 0;
|
|
Width = GifFile->Image.Width;
|
|
Height = GifFile->Image.Height;
|
|
|
|
// Update Color map
|
|
ColorMap = (GifFile->Image.ColorMap ? GifFile->Image.ColorMap: GifFile->SColorMap);
|
|
|
|
// Crée l'image dans laquelle on mettra nos données.
|
|
|
|
// Faire attention de ne pas créer trop de couleurs, mais en
|
|
// réserver une pour le décalage si jamais aucune couleur
|
|
// transparente n'a été trouvée
|
|
img = ulCreateImage(Width, Height, UL_IN_RAM, pixelFormat,
|
|
ulMin(ColorMap->ColorCount + 1,
|
|
1 << ul_paletteSizes[pixelFormat]));
|
|
|
|
if (!img)
|
|
goto failed;
|
|
|
|
if (img->palette)
|
|
{
|
|
Palette = img->palette;
|
|
ColorMap->ColorCount = ulMin(ColorMap->ColorCount, img->palCount);
|
|
}
|
|
|
|
// Pas de couleur transparente trouvée mais une palette dispo =>
|
|
// utilise la couleur par défaut (color key)
|
|
if (img->palette && transparentColor == -1 && ul_colorKeyEnabled)
|
|
{
|
|
for (i = 0; i < ColorMap->ColorCount; i++)
|
|
{
|
|
GifColorType* pColor = &ColorMap->Colors[i];
|
|
|
|
if (isColorTransparent32(pColor->Red, pColor->Green, pColor->Blue))
|
|
{
|
|
transparentColor = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Bon ben ici si on a toujours rien trouvé, la première couleur
|
|
// sera transparente sur DS en mode paletté, aucune sinon, on
|
|
// doit donc faire en sorte que la première couleur NE SOIT PAS
|
|
// utilisée.
|
|
//
|
|
// Cela devrait être suffisant: cette couleur n'existe pas, le
|
|
// moteur cherchera à l'utiliser et incrémentera tout d'un cran
|
|
// pour que ça fonctionne ^^
|
|
if (img->palette && transparentColor == -1 && !ul_firstPaletteColorOpaque)
|
|
{
|
|
transparentColor = ColorMap->ColorCount;
|
|
Palette[0] = 0;
|
|
for (i = 0; i < ColorMap->ColorCount; i++)
|
|
{
|
|
GifColorType* pColor = &ColorMap->Colors[i];
|
|
// Vérifie qu'on ne déborde pas
|
|
if (i + 1 < img->palCount)
|
|
{
|
|
Palette[i + 1] = RGB15(GAMMA(pColor->Red),
|
|
GAMMA(pColor->Green),
|
|
GAMMA(pColor->Blue)) | 0x8000;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Tenons compte de la couleur transparente
|
|
i = ColorMap->ColorCount;
|
|
j = ColorMap->ColorCount;
|
|
while (--i >= 0) {
|
|
GifColorType* pColor = &ColorMap->Colors[i];
|
|
if (i == transparentColor)
|
|
{
|
|
Palette[0] = RGB15(GAMMA(pColor->Red),
|
|
GAMMA(pColor->Green),
|
|
GAMMA(pColor->Blue));
|
|
}
|
|
else
|
|
{
|
|
// Cette couleur est affichée (0x8000 = alpha à 1)
|
|
Palette[--j] = RGB15(GAMMA(pColor->Red),
|
|
GAMMA(pColor->Green),
|
|
GAMMA(pColor->Blue)) | 0x8000;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
if (GifFile->Image.Left + GifFile->Image.Width > GifFile->SWidth ||
|
|
GifFile->Image.Top + GifFile->Image.Height > GifFile->SHeight)
|
|
{
|
|
return EXIT_FAILURE;
|
|
}
|
|
*/
|
|
|
|
if (GifFile->Image.Interlace)
|
|
{
|
|
// Need to perform 4 passes on the images:
|
|
for (Count = i = 0; i < 4; i++)
|
|
{
|
|
for (j = Row + InterlacedOffset[i]; j < Row + Height; j += InterlacedJumps[i])
|
|
{
|
|
DGifGetLineByte(GifFile,
|
|
(GifPixelType*)ulGetImagePixelAddr(img, Col, j),
|
|
Width, pixelFormat, transparentColor);
|
|
/*
|
|
if (DGifGetLineByte(GifFile, &ScreenBuff[j][Col], Width) == GIF_ERROR)
|
|
{
|
|
PrintGifError();
|
|
return EXIT_FAILURE;
|
|
}
|
|
*/
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < Height; i++)
|
|
{
|
|
DGifGetLineByte(GifFile, (GifPixelType*)ulGetImagePixelAddr(img, Col, Row), Width, pixelFormat, transparentColor);
|
|
Row++;
|
|
/*
|
|
if (DGifGetLineByte(GifFile, &ScreenBuff[Row++][Col], Width) == GIF_ERROR)
|
|
{
|
|
PrintGifError();
|
|
return EXIT_FAILURE;
|
|
}
|
|
*/
|
|
}
|
|
}
|
|
break;
|
|
|
|
case EXTENSION_RECORD_TYPE:
|
|
// Skip any extension blocks in file:
|
|
DGifGetExtension(GifFile, &ExtCode, &Extension);
|
|
|
|
while (Extension != NULL)
|
|
{
|
|
// Couleur transparente
|
|
if (ExtCode == 249)
|
|
{
|
|
if (Extension[1] & 1)
|
|
transparentColor = Extension[4];
|
|
}
|
|
DGifGetExtensionNext(GifFile, &Extension);
|
|
}
|
|
break;
|
|
|
|
case TERMINATE_RECORD_TYPE:
|
|
break;
|
|
default: // Should be traps by DGifGetRecordType.
|
|
break;
|
|
}
|
|
} while (RecordType != TERMINATE_RECORD_TYPE);
|
|
|
|
if (ul_pixelSizes[pixelFormat] > 8 && temppalette)
|
|
free(temppalette); // Libère la mémoire allouée pour la palette fixe
|
|
|
|
if (location == UL_IN_VRAM)
|
|
{
|
|
if (!ulRealizeImage(img))
|
|
{
|
|
ulDeleteImage(img);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
failed:
|
|
// Close file when done
|
|
DGifCloseFile(GifFile);
|
|
|
|
return img;
|
|
}
|
|
|
|
/*
|
|
#include "jpeg/gba-jpeg.h"
|
|
#include "jpeg/gba-jpeg-decode.h"
|
|
|
|
//Par blocs de 16 ko
|
|
#define BLOCK_SIZE (16 << 10)
|
|
|
|
//Lit un fichier entier vers la mémoire
|
|
void *ulReadEntireFileToMemory(VIRTUAL_FILE *f)
|
|
{
|
|
void *block = NULL;
|
|
int add = 0;
|
|
int size = 0, readSize;
|
|
|
|
do
|
|
{
|
|
size += BLOCK_SIZE;
|
|
if (block)
|
|
block = realloc(block, size);
|
|
else
|
|
block = malloc(size);
|
|
|
|
// L'allocation a échoué?
|
|
if (!block)
|
|
return NULL;
|
|
|
|
readSize = VirtualFileRead((char*)block + add, 1, BLOCK_SIZE, f);
|
|
add += BLOCK_SIZE;
|
|
} while (readSize >= BLOCK_SIZE);
|
|
|
|
return block;
|
|
}
|
|
|
|
UL_IMAGE *ulLoadImageJPG(VIRTUAL_FILE *f, int flags, int pixelFormat)
|
|
{
|
|
UL_IMAGE *img = NULL;
|
|
const unsigned char *input;
|
|
|
|
// Format 16 bits obligatoire pour le JPG!
|
|
if (ul_pixelWidth[pixelFormat] != 16)
|
|
return NULL;
|
|
|
|
input = (const unsigned char*)ulReadEntireFileToMemory(f);
|
|
|
|
if (input)
|
|
{
|
|
int width, height;
|
|
JPEG_Decoder decoder;
|
|
|
|
JPEG_Decoder_ReadHeaders(&decoder, &input);
|
|
width = decoder.frame.width;
|
|
height = decoder.frame.height;
|
|
|
|
// Crée l'image dans laquelle on mettra notre bitmap
|
|
img = ulCreateImage(width, height, pixelFormat, 0);
|
|
|
|
if (img)
|
|
{
|
|
if (!JPEG_Decoder_ReadImage (&decoder, &input, img->texture, img->sysSizeX, img->sysSizeY))
|
|
{
|
|
ulDeleteImage(img);
|
|
img = NULL;
|
|
}
|
|
}
|
|
|
|
free((void*)input);
|
|
}
|
|
return img;
|
|
}
|
|
*/
|