I'm writing custom Save/LoadBMP functions to save/load SDL_Surface to/from .bmp in RGBA format, which I need for antialiasing sprite rotation later on.
Right now I'm working on the save function but I don't get it to work. First I tried to write the BITMAPHEADER***(Both with BITMAPV4HEADER(Specially for the RGBA format) and BITMAPINFOHEADER) structs as saving method which didn't work, probably because it stored integer members in big-endian which the valid ones are in little-endian. Then I modify the SDL_SaveBMP from it's source(Copying it ofcoarse). First I tried with the BITMAPINFOHEADER info header format as it was orginally but it didn't work all the way, it only got to display its dimension but you didn't see the image. And so I tried with the V4 info header(BITMAPV4HEADER) and same fault. I'm out of ideas what the problem is to make this work so I wonder if you know why it doesn't get displayed.
Here's that latest code version:
bool SaveRGBA32BMP_RW(SDL_Surface *surf, SDL_RWops *dst, bool freedst)
{
bool success = true;
long fp_offset;
Uint32 *bits;
/* The Win32 BMP file header (14 bytes) */
char magic[2] = {'B','M'};
Uint32 bfSize;
Uint16 bfReserved1;
Uint16 bfReserved2;
Uint32 bfOffBits;
/* The Win32 BITMAPINFOHEADER struct (40 bytes) */
Uint32 biSize;
Sint32 biWidth;
Sint32 biHeight;
Uint16 biPlanes;
Uint16 biBitCount;
Uint32 biCompression;
Uint32 biSizeImage;
Sint32 biXPelsPerMeter;
Sint32 biYPelsPerMeter;
Uint32 biClrUsed;
Uint32 biClrImportant;
Uint32 bV4RedMask;
Uint32 bV4GreenMask;
Uint32 bV4BlueMask;
Uint32 bV4AlphaMask;
Uint32 bV4CSType;
// CIEXYZTRIPLE bV4Endpoints;
long bV4Endpoints;
Uint32 bV4GammaRed;
Uint32 bV4GammaGreen;
Uint32 bV4GammaBlue;
/* Make sure we have somewhere to save */
if (surf && dst)
{
if (surf->format->BitsPerPixel != 32)
{
success = false;
goto done;
}
const int bw = surf->w * surf->format->BytesPerPixel;
/* Set the BMP file header values */
bfSize = 0; /* We'll write this when we're done */
bfReserved1 = 0;
bfReserved2 = 0;
bfOffBits = 0; /* We'll write this when we're done */
/* Write the BMP file header values */
fp_offset = SDL_RWtell(dst);
SDL_ClearError();
SDL_RWwrite(dst, magic, 2, 1);
SDL_WriteLE32(dst, bfSize);
SDL_WriteLE16(dst, bfReserved1);
SDL_WriteLE16(dst, bfReserved2);
SDL_WriteLE32(dst, bfOffBits);
/* Set the BMP info values */
biSize = 40; //180; // 40;
biWidth = surf->w;
biHeight = surf->h;
biPlanes = 1;
biBitCount = surf->format->BitsPerPixel;
biCompression = BI_RGB;
biSizeImage = surf->h * surf->pitch;
biXPelsPerMeter = 0;
biYPelsPerMeter = 0;
biClrUsed = 0;
biClrImportant = 0;
bV4RedMask = /*surf->format->*/Rmask;
bV4GreenMask = /*surf->format->*/Gmask;
bV4BlueMask = /*surf->format->*/Bmask;
bV4AlphaMask = /*surf->format->*/Amask;
bV4CSType = 0;
// CIEXYZTRIPLE bV4Endpoints;
bV4Endpoints = 0;
bV4GammaRed = 0;
bV4GammaGreen = 0;
bV4GammaBlue = 0;
/* Write the BMP info values */
SDL_WriteLE32(dst, biSize);
SDL_WriteLE32(dst, biWidth);
SDL_WriteLE32(dst, biHeight);
SDL_WriteLE16(dst, biPlanes);
SDL_WriteLE16(dst, biBitCount);
SDL_WriteLE32(dst, biCompression);
SDL_WriteLE32(dst, biSizeImage);
SDL_WriteLE32(dst, biXPelsPerMeter);
SDL_WriteLE32(dst, biYPelsPerMeter);
SDL_WriteLE32(dst, biClrUsed);
SDL_WriteLE32(dst, biClrImportant);
SDL_WriteLE32(dst,bV4RedMask);
SDL_WriteLE32(dst,bV4GreenMask);
SDL_WriteLE32(dst,bV4BlueMask);
SDL_WriteLE32(dst,bV4AlphaMask);
SDL_WriteLE32(dst,bV4CSType);
for (int i = 0; i < 9; i++)
{
// SDL_RWwrite(dst,&bV4Endpoints,4,1);
SDL_WriteLE32(dst,0);
}
SDL_WriteLE32(dst,bV4GammaRed);
SDL_WriteLE32(dst,bV4GammaGreen);
SDL_WriteLE32(dst,bV4GammaBlue);
/* Write the bitmap offset */
bfOffBits = SDL_RWtell(dst)-fp_offset;
if ( SDL_RWseek(dst, fp_offset+10, RW_SEEK_SET) < 0 ) {
SDL_Error(SDL_EFSEEK);
}
SDL_WriteLE32(dst, bfOffBits);
if ( SDL_RWseek(dst, fp_offset+bfOffBits, RW_SEEK_SET) < 0 ) {
SDL_Error(SDL_EFSEEK);
}
/* Write the bitmap image upside down */
bits = (Uint32 *)surf->pixels + (surf->h * surf->pitch);
while (bits > (Uint32 *)surf->pixels)
{
bits -= surf->pitch;
if (SDL_RWwrite(dst, bits, bw, 1) < 0)
{
SDL_Error(SDL_EFWRITE);
break;
}
}
// Get the file size:
bfSize = SDL_RWtell(dst)-fp_offset;
// Set the file pointer back to:
if (SDL_RWseek(dst, fp_offset+2, RW_SEEK_SET) < 0)
{
SDL_Error(SDL_EFSEEK);
}
// Write the file size:
SDL_WriteLE32(dst, bfSize);
// Set it back to the end once again:
if (SDL_RWseek(dst, fp_offset+bfSize, RW_SEEK_SET) < 0)
{
SDL_Error(SDL_EFSEEK);
}
}
done:
if (freedst && dst)
{
SDL_RWclose(dst);
}
return success;
}
Here's the Palette/RGB to RGBA converting function BTW:
SDL_Surface *ConvRGBA32(SDL_Surface *orig)
{
int width = orig->w;
int height = orig->h;
SDL_Surface *rgba = SDL_CreateRGBSurface(SDL_SWSURFACE,width,height,32,Rmask,Gmask,Bmask,Amask);
Uint32 npixels = width * height;
SDL_PixelFormat *format = orig->format;
SDL_Palette *palette = format->palette;
SDL_Color *entry;
Uint8 bpp = format->BytesPerPixel;
Uint32 *dstpix = (Uint32 *)rgba->pixels;
Uint8 *srcpix = (Uint8 *)orig->pixels;
Uint8 r, g, b, a;
Uint32 color;
for (Uint32 i = 0; i < npixels; i++)
{
if (format->BitsPerPixel == 8 && palette)
{
entry = palette->colors + *srcpix;
r = entry->r;
g = entry->g;
b = entry->b;
color = SDL_MapRGB(format,r,g,b);
}
else
{
color = *(Uint32 *)srcpix;
SDL_GetRGB(color,format,&r,&g,&b);
}
if (color == format->colorkey)
a = 0x00;
else
a = 0xff;
*dstpix++ = SDL_MapRGBA(rgba->format,r,g,b,a);
srcpix += bpp;
}
return rgba;
}
Thanks for your help.