nitro-engine/source/NEFormats.c
Antonio Niño Díaz 82171bbf69 chore: Simplify copyright years in notices
Instead of listing every individual year, keep only the first and last
years.
2024-03-09 01:42:29 +00:00

376 lines
10 KiB
C

// SPDX-License-Identifier: MIT
//
// Copyright (c) 2008-2022 Antonio Niño Díaz
//
// This file is part of Nitro Engine
#include "NEMain.h"
/// @file NEFormats.c
static int lastx = 0, lasty = 0;
static u32 numcolors = 0;
static void *NE_ConvertBMPtoRGBA(void *pointer, bool transpcolor)
{
NE_BMPHeader *header = pointer;
NE_BMPInfoHeader *infoheader = (void *)(u8 *)header + sizeof(NE_BMPHeader);
u8 *IMAGEDATA = (void *)((u8 *)infoheader + sizeof(NE_BMPInfoHeader));
if (header->type != 0x4D42)
{
NE_DebugPrint("Not a BMP file");
return NULL;
}
int sizex = infoheader->width;
int sizey = infoheader->height;
if (sizex > 1024 || sizey > 1024)
{
NE_DebugPrint("BMP file too big (%d, %d)", sizex, sizey);
return NULL;
}
if (infoheader->compression != 0)
{
NE_DebugPrint("Compressed BMP not supported");
return NULL;
}
if (infoheader->bits != 16 && infoheader->bits != 24)
{
NE_DebugPrint("Unsuported depth for NE_A1RGB5 conversion (%d)",
infoheader->bits);
return NULL;
}
// Decode
u16 *buffer = malloc(2 * sizex * sizey);
NE_AssertPointer(buffer, "Couldn't allocate temporary buffer");
u8 transr = 0, transb = 0, transg = 0;
u16 transcolor16bit = 0;
if (transpcolor)
{
if (infoheader->bits == 16) // X1RGB5
{
u16 red, green, blue;
transcolor16bit = (u16)IMAGEDATA[2 * sizey * (sizex - 1)]
| (((u16)IMAGEDATA[2 * sizey * (sizex - 1) + 1]) << 8);
// Swap R and B channels
red = (transcolor16bit & 0x7C00) >> 10;
green = (transcolor16bit & 0x3E0);
blue = (transcolor16bit & 0x1F);
transcolor16bit = red | green | (blue << 10);
}
else // 24 bits
{
transr = IMAGEDATA[3 * sizey * (sizex - 1) + 2];
transg = IMAGEDATA[3 * sizey * (sizex - 1) + 1];
transb = IMAGEDATA[3 * sizey * (sizex - 1) + 0];
}
}
// IMAGEDATA -> buffer
int disalign = ((sizex * infoheader->bits) >> 3) & 3;
if (disalign)
disalign = 4 - disalign;
if (infoheader->bits == 16) // X1RGB5
{
for (int y = 0; y < sizey; y++)
{
for (int x = 0; x < sizex; x++)
{
u16 red, green, blue;
int base_pos = (sizex * (sizey - y - 1) + x) << 1;
if (disalign)
base_pos += disalign * (sizey - y - 1);
u16 color = (u16) IMAGEDATA[base_pos]
| ((u16)IMAGEDATA[base_pos + 1] << 8);
// Swap R and B channels
red = (color & 0x7C00) >> 10;
green = (color & 0x3E0);
blue = (color & 0x1F);
color = red | green | (blue << 10);
if (!(transpcolor && color == transcolor16bit))
buffer[y * sizex + x] = color | BIT(15);
else
buffer[y * sizex + x] = 0;
}
}
}
else // 24 bits
{
for (int y = 0; y < sizey; y++)
{
for (int x = 0; x < sizex; x++)
{
u8 r, g, b;
int base_pos = 3 * (sizex * (sizey - y - 1) + x);
if (disalign)
base_pos += disalign * (sizey - y - 1);
r = IMAGEDATA[base_pos + 2];
g = IMAGEDATA[base_pos + 1];
b = IMAGEDATA[base_pos + 0];
if (!(transpcolor && r == transr && g == transg && b == transb))
{
buffer[y * sizex + x] = RGB15((r >> 3) & 31, (g >> 3) & 31,
(b >> 3) & 31) | BIT(15);
}
else
{
buffer[y * sizex + x] = 0;
}
}
}
}
lasty = sizey;
lastx = sizex;
return (void *)buffer;
}
static void *NE_ConvertBMPtoRGB256(void *pointer, u16 *palettebuffer)
{
NE_BMPHeader *header = pointer;
NE_BMPInfoHeader *infoheader = (void *)((u8 *)header + sizeof(NE_BMPHeader));
if (header->type != 0x4D42)
{
NE_DebugPrint("Not a BMP file");
return NULL;
}
int sizex = infoheader->width;
int sizey = infoheader->height;
if (sizex > 1024 || sizey > 1024)
{
NE_DebugPrint("BMP file too big (%d, %d)", sizex, sizey);
return NULL;
}
if (infoheader->compression != 0)
{
NE_DebugPrint("Compressed BMP not supported");
return NULL;
}
if (infoheader->bits != 8 && infoheader->bits != 4)
{
NE_DebugPrint("Unsupported depth for NE_PAL256 conversion (%d)",
infoheader->bits);
return NULL;
}
// Decode
int colornumber = (infoheader->bits == 8) ? 256 : 16;
u8 *PALETTEDATA = (u8 *)infoheader + sizeof(NE_BMPInfoHeader);
u8 *IMAGEDATA = (u8 *)header + header->offset;
// numcolors is used by the other functions (look at the start of this
// file)
numcolors = colornumber;
// First, we read the palette
int i = 0;
while (i < numcolors)
{
u8 r, g, b;
g = PALETTEDATA[(i << 2) + 1] & 0xFF;
r = PALETTEDATA[(i << 2) + 2] & 0xFF;
b = PALETTEDATA[(i << 2) + 0] & 0xFF;
palettebuffer[i] = RGB15(r >> 3, g >> 3, b >> 3);
i++;
}
u8 *buffer = malloc(sizex * sizey);
NE_AssertPointer(buffer, "Couldn't allocate temporary buffer");
// Then, the image
if (colornumber == 256)
{
// For BMPs with width not multiple of 4
int disalign = sizex & 3;
if (disalign)
{
disalign = 4 - disalign;
for (int y = 0; y < sizey; y++)
{
for (int x = 0; x < sizex; x++)
{
buffer[y * sizex + x] = IMAGEDATA[(sizex * (sizey - y - 1)) + x
+ (((disalign) * (sizey - y - 1)) * 1)];
}
}
}
else
{
for (int y = 0; y < sizey; y++)
{
for (int x = 0; x < sizex; x++)
{
buffer[y * sizex + x] =
IMAGEDATA[(sizex * (sizey - y - 1)) + x];
}
}
}
}
else // colornumber == 16
{
// For BMPs with width not multiple of 8
int disalign = sizex & 7;
if (disalign)
{
disalign = 8 - disalign;
for (int y = 0; y < sizey; y++)
{
for (int x = 0; x < sizex; x++)
{
u32 value;
u32 srcidx = ((sizex * (sizey - y - 1) + x)
+ (disalign * (sizey - y - 1))) >> 1;
if (x & 1)
value = IMAGEDATA[srcidx] & 0x0F;
else
value = (IMAGEDATA[srcidx] >> 4) & 0x0F;
buffer[y * sizex + x] = value;
}
}
}
else
{
for (int y = 0; y < sizey; y++)
{
for (int x = 0; x < sizex; x++)
{
u32 value;
u32 srcidx = (sizex * (sizey - y - 1) + x) >> 1;
if (x & 1)
value = IMAGEDATA[srcidx] & 0x0F;
else
value = (IMAGEDATA[srcidx] >> 4) & 0x0F;
buffer[y * sizex + x] = value;
}
}
}
}
lastx = sizex;
lasty = sizey;
return (void *)buffer;
}
int NE_FATMaterialTexLoadBMPtoRGBA(NE_Material *tex, char *filename,
bool transpcolor)
{
NE_AssertPointer(tex, "NULL material pointer");
NE_AssertPointer(filename, "NULL filename pointer");
void *pointer = NE_FATLoadData(filename);
int ret = NE_MaterialTexLoadBMPtoRGBA(tex, pointer, transpcolor);
free(pointer);
return ret;
}
int NE_FATMaterialTexLoadBMPtoRGB256(NE_Material *tex, NE_Palette *pal,
char *filename, bool transpcolor)
{
NE_AssertPointer(tex, "NULL material pointer");
NE_AssertPointer(pal, "NULL palette pointer");
NE_AssertPointer(filename, "NULL filename pointer");
char *pointer = NE_FATLoadData(filename);
int ret = NE_MaterialTexLoadBMPtoRGB256(tex, pal, pointer, transpcolor);
free(pointer);
return ret;
}
int NE_MaterialTexLoadBMPtoRGBA(NE_Material *tex, void *pointer,
bool transpcolor)
{
NE_AssertPointer(tex, "NULL material pointer");
NE_AssertPointer(pointer, "NULL data pointer");
void *temp = NE_ConvertBMPtoRGBA(pointer, transpcolor);
if (temp == NULL)
return 0;
int ret = NE_MaterialTexLoad(tex, NE_A1RGB5, lastx, lasty,
NE_TEXGEN_TEXCOORD, (u8 *)temp);
free(temp);
if (ret == 0)
return 0;
return 1;
}
int NE_MaterialTexLoadBMPtoRGB256(NE_Material *tex, NE_Palette *pal,
void *pointer, bool transpcolor)
{
NE_AssertPointer(tex, "NULL material pointer");
NE_AssertPointer(pal, "NULL palette pointer");
NE_AssertPointer(pointer, "NULL data pointer");
u16 *palettebuffer = malloc(256 * sizeof(u16));
NE_AssertPointer(palettebuffer, "Couldn't allocate temp palette buffer");
if (palettebuffer == NULL)
return 0;
void *texturepointer = NE_ConvertBMPtoRGB256(pointer, palettebuffer);
NE_AssertPointer(texturepointer, "Couldn't convert BMP file to NE_PAL256");
if (texturepointer == NULL)
{
free(palettebuffer);
return 0;
}
u32 transp = transpcolor ? NE_TEXTURE_COLOR0_TRANSPARENT : 0;
int ret = NE_MaterialTexLoad(tex, NE_PAL256, lastx, lasty,
NE_TEXGEN_TEXCOORD | transp,
(u8 *)texturepointer);
free(texturepointer);
if (ret == 0)
{
NE_DebugPrint("Error while loading texture");
free(palettebuffer);
return 0;
}
ret = NE_PaletteLoad(pal, palettebuffer, numcolors, NE_PAL256);
free(palettebuffer);
if (ret == 0)
{
NE_DebugPrint("Error while loading palette");
NE_MaterialDelete(tex);
return 0;
}
NE_MaterialSetPalette(tex, pal);
return 1;
}