146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/*
246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    SDL - Simple DirectMedia Layer
346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    Copyright (C) 1997-2006 Sam Lantinga
446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    This library is free software; you can redistribute it and/or
646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    modify it under the terms of the GNU Lesser General Public
746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    License as published by the Free Software Foundation; either
846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    version 2.1 of the License, or (at your option) any later version.
946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
1046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    This library is distributed in the hope that it will be useful,
1146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    but WITHOUT ANY WARRANTY; without even the implied warranty of
1246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    Lesser General Public License for more details.
1446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
1546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    You should have received a copy of the GNU Lesser General Public
1646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    License along with this library; if not, write to the Free Software
1746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
1846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
1946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    Sam Lantinga
2046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    slouken@libsdl.org
2146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner*/
2246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include "SDL_config.h"
2346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
2446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/*
2546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner   Code to load and save surfaces in Windows BMP format.
2646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
2746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner   Why support BMP format?  Well, it's a native format for Windows, and
2846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner   most image processing programs can read and write it.  It would be nice
2946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner   to be able to have at least one image format that we can natively load
3046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner   and save, and since PNG is so complex that it would bloat the library,
3146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner   BMP is a good alternative.
3246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
3346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner   This code currently supports Win32 DIBs in uncompressed 8 and 24 bpp.
3446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner*/
3546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
3646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include "SDL_video.h"
3746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include "SDL_endian.h"
3846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
3946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* Compression encodings for BMP files */
4046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#ifndef BI_RGB
4146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#define BI_RGB		0
4246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#define BI_RLE8		1
4346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#define BI_RLE4		2
4446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#define BI_BITFIELDS	3
4546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#endif
4646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
4746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
4846be48730333120a7b939116cef075e61c12c703David 'Digit' TurnerSDL_Surface * SDL_LoadBMP_RW (SDL_RWops *src, int freesrc)
4946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
5046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	int was_error;
5146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	long fp_offset;
5246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	int bmpPitch;
5346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	int i, pad;
5446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	SDL_Surface *surface;
5546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Uint32 Rmask;
5646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Uint32 Gmask;
5746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Uint32 Bmask;
5846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	SDL_Palette *palette;
5946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Uint8 *bits;
6046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	int ExpandBMP;
6146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
6246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* The Win32 BMP file header (14 bytes) */
6346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	char   magic[2];
6446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Uint32 bfSize;
6546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Uint16 bfReserved1;
6646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Uint16 bfReserved2;
6746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Uint32 bfOffBits;
6846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
6946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* The Win32 BITMAPINFOHEADER struct (40 bytes) */
7046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Uint32 biSize;
7146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Sint32 biWidth;
7246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Sint32 biHeight;
7346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Uint16 biPlanes;
7446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Uint16 biBitCount;
7546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Uint32 biCompression;
7646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Uint32 biSizeImage;
7746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Sint32 biXPelsPerMeter;
7846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Sint32 biYPelsPerMeter;
7946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Uint32 biClrUsed;
8046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Uint32 biClrImportant;
8146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
8246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Make sure we are passed a valid data source */
8346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	surface = NULL;
8446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	was_error = 0;
8546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( src == NULL ) {
8646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		was_error = 1;
8746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		goto done;
8846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
8946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
9046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Read in the BMP file header */
9146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	fp_offset = SDL_RWtell(src);
9246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	SDL_ClearError();
9346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( SDL_RWread(src, magic, 1, 2) != 2 ) {
9446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_Error(SDL_EFREAD);
9546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		was_error = 1;
9646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		goto done;
9746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
9846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( SDL_strncmp(magic, "BM", 2) != 0 ) {
9946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_SetError("File is not a Windows BMP file");
10046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		was_error = 1;
10146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		goto done;
10246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
10346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	bfSize		= SDL_ReadLE32(src);
10446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	bfReserved1	= SDL_ReadLE16(src);
10546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	bfReserved2	= SDL_ReadLE16(src);
10646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	bfOffBits	= SDL_ReadLE32(src);
10746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
10846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Read the Win32 BITMAPINFOHEADER */
10946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	biSize		= SDL_ReadLE32(src);
11046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( biSize == 12 ) {
11146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		biWidth		= (Uint32)SDL_ReadLE16(src);
11246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		biHeight	= (Uint32)SDL_ReadLE16(src);
11346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		biPlanes	= SDL_ReadLE16(src);
11446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		biBitCount	= SDL_ReadLE16(src);
11546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		biCompression	= BI_RGB;
11646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		biSizeImage	= 0;
11746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		biXPelsPerMeter	= 0;
11846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		biYPelsPerMeter	= 0;
11946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		biClrUsed	= 0;
12046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		biClrImportant	= 0;
12146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	} else {
12246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		biWidth		= SDL_ReadLE32(src);
12346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		biHeight	= SDL_ReadLE32(src);
12446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		biPlanes	= SDL_ReadLE16(src);
12546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		biBitCount	= SDL_ReadLE16(src);
12646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		biCompression	= SDL_ReadLE32(src);
12746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		biSizeImage	= SDL_ReadLE32(src);
12846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		biXPelsPerMeter	= SDL_ReadLE32(src);
12946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		biYPelsPerMeter	= SDL_ReadLE32(src);
13046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		biClrUsed	= SDL_ReadLE32(src);
13146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		biClrImportant	= SDL_ReadLE32(src);
13246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
13346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
13446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Check for read error */
13546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( SDL_strcmp(SDL_GetError(), "") != 0 ) {
13646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		was_error = 1;
13746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		goto done;
13846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
13946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
14046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Expand 1 and 4 bit bitmaps to 8 bits per pixel */
14146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	switch (biBitCount) {
14246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		case 1:
14346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		case 4:
14446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			ExpandBMP = biBitCount;
14546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			biBitCount = 8;
14646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			break;
14746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		default:
14846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			ExpandBMP = 0;
14946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			break;
15046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
15146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
15246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* We don't support any BMP compression right now */
15346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Rmask = Gmask = Bmask = 0;
15446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	switch (biCompression) {
15546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		case BI_RGB:
15646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			/* If there are no masks, use the defaults */
15746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			if ( bfOffBits == (14+biSize) ) {
15846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				/* Default values for the BMP format */
15946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				switch (biBitCount) {
16046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner					case 15:
16146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner					case 16:
16246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner						Rmask = 0x7C00;
16346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner						Gmask = 0x03E0;
16446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner						Bmask = 0x001F;
16546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner						break;
16646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner					case 24:
16746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#if SDL_BYTEORDER == SDL_BIG_ENDIAN
16846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner					        Rmask = 0x000000FF;
16946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner					        Gmask = 0x0000FF00;
17046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner					        Bmask = 0x00FF0000;
17146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner						break;
17246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#endif
17346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner					case 32:
17446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner						Rmask = 0x00FF0000;
17546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner						Gmask = 0x0000FF00;
17646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner						Bmask = 0x000000FF;
17746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner						break;
17846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner					default:
17946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner						break;
18046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				}
18146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				break;
18246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			}
18346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			/* Fall through -- read the RGB masks */
18446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
18546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		case BI_BITFIELDS:
18646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			switch (biBitCount) {
18746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				case 15:
18846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				case 16:
18946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				case 32:
19046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner					Rmask = SDL_ReadLE32(src);
19146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner					Gmask = SDL_ReadLE32(src);
19246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner					Bmask = SDL_ReadLE32(src);
19346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner					break;
19446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				default:
19546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner					break;
19646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			}
19746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			break;
19846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		default:
19946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			SDL_SetError("Compressed BMP files not supported");
20046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			was_error = 1;
20146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			goto done;
20246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
20346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
20446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Create a compatible surface, note that the colors are RGB ordered */
20546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
20646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			biWidth, biHeight, biBitCount, Rmask, Gmask, Bmask, 0);
20746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( surface == NULL ) {
20846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		was_error = 1;
20946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		goto done;
21046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
21146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
21246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Load the palette, if any */
21346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	palette = (surface->format)->palette;
21446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( palette ) {
21546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		if ( biClrUsed == 0 ) {
21646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			biClrUsed = 1 << biBitCount;
21746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		}
21846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		if ( biSize == 12 ) {
21946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			for ( i = 0; i < (int)biClrUsed; ++i ) {
22046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				SDL_RWread(src, &palette->colors[i].b, 1, 1);
22146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				SDL_RWread(src, &palette->colors[i].g, 1, 1);
22246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				SDL_RWread(src, &palette->colors[i].r, 1, 1);
22346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				palette->colors[i].unused = 0;
22446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			}
22546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		} else {
22646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			for ( i = 0; i < (int)biClrUsed; ++i ) {
22746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				SDL_RWread(src, &palette->colors[i].b, 1, 1);
22846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				SDL_RWread(src, &palette->colors[i].g, 1, 1);
22946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				SDL_RWread(src, &palette->colors[i].r, 1, 1);
23046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				SDL_RWread(src, &palette->colors[i].unused, 1, 1);
23146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			}
23246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		}
23346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		palette->ncolors = biClrUsed;
23446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
23546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
23646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Read the surface pixels.  Note that the bmp image is upside down */
23746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( SDL_RWseek(src, fp_offset+bfOffBits, RW_SEEK_SET) < 0 ) {
23846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_Error(SDL_EFSEEK);
23946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		was_error = 1;
24046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		goto done;
24146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
24246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	bits = (Uint8 *)surface->pixels+(surface->h*surface->pitch);
24346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	switch (ExpandBMP) {
24446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		case 1:
24546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			bmpPitch = (biWidth + 7) >> 3;
24646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			pad  = (((bmpPitch)%4) ? (4-((bmpPitch)%4)) : 0);
24746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			break;
24846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		case 4:
24946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			bmpPitch = (biWidth + 1) >> 1;
25046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			pad  = (((bmpPitch)%4) ? (4-((bmpPitch)%4)) : 0);
25146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			break;
25246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		default:
25346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			pad  = ((surface->pitch%4) ?
25446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner					(4-(surface->pitch%4)) : 0);
25546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			break;
25646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
25746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	while ( bits > (Uint8 *)surface->pixels ) {
25846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		bits -= surface->pitch;
25946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		switch (ExpandBMP) {
26046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			case 1:
26146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			case 4: {
26246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			Uint8 pixel = 0;
26346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			int   shift = (8-ExpandBMP);
26446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			for ( i=0; i<surface->w; ++i ) {
26546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				if ( i%(8/ExpandBMP) == 0 ) {
26646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner					if ( !SDL_RWread(src, &pixel, 1, 1) ) {
26746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner						SDL_SetError(
26846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner					"Error reading from BMP");
26946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner						was_error = 1;
27046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner						goto done;
27146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner					}
27246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				}
27346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				*(bits+i) = (pixel>>shift);
27446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				pixel <<= ExpandBMP;
27546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			} }
27646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			break;
27746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
27846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			default:
27946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			if ( SDL_RWread(src, bits, 1, surface->pitch)
28046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner							 != surface->pitch ) {
28146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				SDL_Error(SDL_EFREAD);
28246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				was_error = 1;
28346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				goto done;
28446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			}
28546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#if SDL_BYTEORDER == SDL_BIG_ENDIAN
28646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			/* Byte-swap the pixels if needed. Note that the 24bpp
28746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			   case has already been taken care of above. */
28846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			switch(biBitCount) {
28946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				case 15:
29046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				case 16: {
29146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				        Uint16 *pix = (Uint16 *)bits;
29246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner					for(i = 0; i < surface->w; i++)
29346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner					        pix[i] = SDL_Swap16(pix[i]);
29446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner					break;
29546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				}
29646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
29746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				case 32: {
29846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				        Uint32 *pix = (Uint32 *)bits;
29946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner					for(i = 0; i < surface->w; i++)
30046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner					        pix[i] = SDL_Swap32(pix[i]);
30146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner					break;
30246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				}
30346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			}
30446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#endif
30546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			break;
30646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		}
30746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		/* Skip padding bytes, ugh */
30846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		if ( pad ) {
30946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			Uint8 padbyte;
31046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			for ( i=0; i<pad; ++i ) {
31146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				SDL_RWread(src, &padbyte, 1, 1);
31246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			}
31346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		}
31446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
31546be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerdone:
31646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( was_error ) {
31746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		if ( src ) {
31846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			SDL_RWseek(src, fp_offset, RW_SEEK_SET);
31946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		}
32046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		if ( surface ) {
32146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			SDL_FreeSurface(surface);
32246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		}
32346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		surface = NULL;
32446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
32546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( freesrc && src ) {
32646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_RWclose(src);
32746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
32846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	return(surface);
32946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
33046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
33146be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerint SDL_SaveBMP_RW (SDL_Surface *saveme, SDL_RWops *dst, int freedst)
33246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
33346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	long fp_offset;
33446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	int i, pad;
33546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	SDL_Surface *surface;
33646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Uint8 *bits;
33746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
33846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* The Win32 BMP file header (14 bytes) */
33946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	char   magic[2] = { 'B', 'M' };
34046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Uint32 bfSize;
34146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Uint16 bfReserved1;
34246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Uint16 bfReserved2;
34346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Uint32 bfOffBits;
34446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
34546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* The Win32 BITMAPINFOHEADER struct (40 bytes) */
34646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Uint32 biSize;
34746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Sint32 biWidth;
34846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Sint32 biHeight;
34946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Uint16 biPlanes;
35046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Uint16 biBitCount;
35146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Uint32 biCompression;
35246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Uint32 biSizeImage;
35346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Sint32 biXPelsPerMeter;
35446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Sint32 biYPelsPerMeter;
35546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Uint32 biClrUsed;
35646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Uint32 biClrImportant;
35746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
35846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Make sure we have somewhere to save */
35946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	surface = NULL;
36046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( dst ) {
36146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		if ( saveme->format->palette ) {
36246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			if ( saveme->format->BitsPerPixel == 8 ) {
36346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				surface = saveme;
36446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			} else {
36546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				SDL_SetError("%d bpp BMP files not supported",
36646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner						saveme->format->BitsPerPixel);
36746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			}
36846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		}
36946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		else if ( (saveme->format->BitsPerPixel == 24) &&
37046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#if SDL_BYTEORDER == SDL_LIL_ENDIAN
37146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				(saveme->format->Rmask == 0x00FF0000) &&
37246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				(saveme->format->Gmask == 0x0000FF00) &&
37346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				(saveme->format->Bmask == 0x000000FF)
37446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#else
37546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				(saveme->format->Rmask == 0x000000FF) &&
37646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				(saveme->format->Gmask == 0x0000FF00) &&
37746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				(saveme->format->Bmask == 0x00FF0000)
37846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#endif
37946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			  ) {
38046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			surface = saveme;
38146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		} else {
38246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			SDL_Rect bounds;
38346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
38446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			/* Convert to 24 bits per pixel */
38546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
38646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner					saveme->w, saveme->h, 24,
38746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#if SDL_BYTEORDER == SDL_LIL_ENDIAN
38846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner					0x00FF0000, 0x0000FF00, 0x000000FF,
38946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#else
39046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner					0x000000FF, 0x0000FF00, 0x00FF0000,
39146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#endif
39246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner					0);
39346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			if ( surface != NULL ) {
39446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				bounds.x = 0;
39546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				bounds.y = 0;
39646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				bounds.w = saveme->w;
39746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				bounds.h = saveme->h;
39846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				if ( SDL_LowerBlit(saveme, &bounds, surface,
39946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner							&bounds) < 0 ) {
40046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner					SDL_FreeSurface(surface);
40146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner					SDL_SetError(
40246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner					"Couldn't convert image to 24 bpp");
40346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner					surface = NULL;
40446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				}
40546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			}
40646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		}
40746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
40846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
40946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( surface && (SDL_LockSurface(surface) == 0) ) {
41046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		const int bw = surface->w*surface->format->BytesPerPixel;
41146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
41246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		/* Set the BMP file header values */
41346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		bfSize = 0;		 /* We'll write this when we're done */
41446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		bfReserved1 = 0;
41546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		bfReserved2 = 0;
41646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		bfOffBits = 0;		/* We'll write this when we're done */
41746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
41846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		/* Write the BMP file header values */
41946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		fp_offset = SDL_RWtell(dst);
42046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_ClearError();
42146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_RWwrite(dst, magic, 2, 1);
42246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_WriteLE32(dst, bfSize);
42346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_WriteLE16(dst, bfReserved1);
42446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_WriteLE16(dst, bfReserved2);
42546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_WriteLE32(dst, bfOffBits);
42646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
42746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		/* Set the BMP info values */
42846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		biSize = 40;
42946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		biWidth = surface->w;
43046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		biHeight = surface->h;
43146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		biPlanes = 1;
43246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		biBitCount = surface->format->BitsPerPixel;
43346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		biCompression = BI_RGB;
43446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		biSizeImage = surface->h*surface->pitch;
43546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		biXPelsPerMeter = 0;
43646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		biYPelsPerMeter = 0;
43746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		if ( surface->format->palette ) {
43846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			biClrUsed = surface->format->palette->ncolors;
43946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		} else {
44046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			biClrUsed = 0;
44146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		}
44246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		biClrImportant = 0;
44346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
44446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		/* Write the BMP info values */
44546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_WriteLE32(dst, biSize);
44646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_WriteLE32(dst, biWidth);
44746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_WriteLE32(dst, biHeight);
44846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_WriteLE16(dst, biPlanes);
44946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_WriteLE16(dst, biBitCount);
45046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_WriteLE32(dst, biCompression);
45146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_WriteLE32(dst, biSizeImage);
45246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_WriteLE32(dst, biXPelsPerMeter);
45346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_WriteLE32(dst, biYPelsPerMeter);
45446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_WriteLE32(dst, biClrUsed);
45546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_WriteLE32(dst, biClrImportant);
45646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
45746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		/* Write the palette (in BGR color order) */
45846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		if ( surface->format->palette ) {
45946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			SDL_Color *colors;
46046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			int       ncolors;
46146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
46246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			colors = surface->format->palette->colors;
46346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			ncolors = surface->format->palette->ncolors;
46446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			for ( i=0; i<ncolors; ++i ) {
46546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				SDL_RWwrite(dst, &colors[i].b, 1, 1);
46646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				SDL_RWwrite(dst, &colors[i].g, 1, 1);
46746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				SDL_RWwrite(dst, &colors[i].r, 1, 1);
46846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				SDL_RWwrite(dst, &colors[i].unused, 1, 1);
46946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			}
47046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		}
47146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
47246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		/* Write the bitmap offset */
47346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		bfOffBits = SDL_RWtell(dst)-fp_offset;
47446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		if ( SDL_RWseek(dst, fp_offset+10, RW_SEEK_SET) < 0 ) {
47546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			SDL_Error(SDL_EFSEEK);
47646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		}
47746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_WriteLE32(dst, bfOffBits);
47846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		if ( SDL_RWseek(dst, fp_offset+bfOffBits, RW_SEEK_SET) < 0 ) {
47946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			SDL_Error(SDL_EFSEEK);
48046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		}
48146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
48246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		/* Write the bitmap image upside down */
48346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		bits = (Uint8 *)surface->pixels+(surface->h*surface->pitch);
48446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		pad  = ((bw%4) ? (4-(bw%4)) : 0);
48546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		while ( bits > (Uint8 *)surface->pixels ) {
48646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			bits -= surface->pitch;
48746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			if ( SDL_RWwrite(dst, bits, 1, bw) != bw) {
48846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				SDL_Error(SDL_EFWRITE);
48946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				break;
49046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			}
49146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			if ( pad ) {
49246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				const Uint8 padbyte = 0;
49346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				for ( i=0; i<pad; ++i ) {
49446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner					SDL_RWwrite(dst, &padbyte, 1, 1);
49546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				}
49646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			}
49746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		}
49846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
49946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		/* Write the BMP file size */
50046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		bfSize = SDL_RWtell(dst)-fp_offset;
50146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		if ( SDL_RWseek(dst, fp_offset+2, RW_SEEK_SET) < 0 ) {
50246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			SDL_Error(SDL_EFSEEK);
50346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		}
50446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_WriteLE32(dst, bfSize);
50546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		if ( SDL_RWseek(dst, fp_offset+bfSize, RW_SEEK_SET) < 0 ) {
50646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			SDL_Error(SDL_EFSEEK);
50746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		}
50846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
50946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		/* Close it up.. */
51046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_UnlockSurface(surface);
51146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		if ( surface != saveme ) {
51246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			SDL_FreeSurface(surface);
51346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		}
51446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
51546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
51646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( freedst && dst ) {
51746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_RWclose(dst);
51846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
51946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	return((SDL_strcmp(SDL_GetError(), "") == 0) ? 0 : -1);
52046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
521