1 /*
2 ===========================================================================
3 Copyright (C) 1999-2005 Id Software, Inc.
4 
5 This file is part of Quake III Arena source code.
6 
7 Quake III Arena source code is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the License,
10 or (at your option) any later version.
11 
12 Quake III Arena source code is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Quake III Arena source code; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 ===========================================================================
21 */
22 
23 #include "tr_local.h"
24 
25 typedef struct
26 {
27 	char id[2];
28 	unsigned fileSize;
29 	unsigned reserved0;
30 	unsigned bitmapDataOffset;
31 	unsigned bitmapHeaderSize;
32 	unsigned width;
33 	unsigned height;
34 	unsigned short planes;
35 	unsigned short bitsPerPixel;
36 	unsigned compression;
37 	unsigned bitmapDataSize;
38 	unsigned hRes;
39 	unsigned vRes;
40 	unsigned colors;
41 	unsigned importantColors;
42 	unsigned char palette[256][4];
43 } BMPHeader_t;
44 
R_LoadBMP(const char * name,byte ** pic,int * width,int * height)45 void R_LoadBMP( const char *name, byte **pic, int *width, int *height )
46 {
47 	int		columns, rows;
48 	unsigned	numPixels;
49 	byte	*pixbuf;
50 	int		row, column;
51 	byte	*buf_p;
52 	byte	*end;
53 	union {
54 		byte *b;
55 		void *v;
56 	} buffer;
57 	int		length;
58 	BMPHeader_t bmpHeader;
59 	byte		*bmpRGBA;
60 
61 	*pic = NULL;
62 
63 	if(width)
64 		*width = 0;
65 
66 	if(height)
67 		*height = 0;
68 
69 	//
70 	// load the file
71 	//
72 	length = ri.FS_ReadFile( ( char * ) name, &buffer.v);
73 	if (!buffer.b || length < 0) {
74 		return;
75 	}
76 
77 	if (length < 54)
78 	{
79 		ri.Error( ERR_DROP, "LoadBMP: header too short (%s)\n", name );
80 	}
81 
82 	buf_p = buffer.b;
83 	end = buffer.b + length;
84 
85 	bmpHeader.id[0] = *buf_p++;
86 	bmpHeader.id[1] = *buf_p++;
87 	bmpHeader.fileSize = LittleLong( * ( int * ) buf_p );
88 	buf_p += 4;
89 	bmpHeader.reserved0 = LittleLong( * ( int * ) buf_p );
90 	buf_p += 4;
91 	bmpHeader.bitmapDataOffset = LittleLong( * ( int * ) buf_p );
92 	buf_p += 4;
93 	bmpHeader.bitmapHeaderSize = LittleLong( * ( int * ) buf_p );
94 	buf_p += 4;
95 	bmpHeader.width = LittleLong( * ( int * ) buf_p );
96 	buf_p += 4;
97 	bmpHeader.height = LittleLong( * ( int * ) buf_p );
98 	buf_p += 4;
99 	bmpHeader.planes = LittleShort( * ( short * ) buf_p );
100 	buf_p += 2;
101 	bmpHeader.bitsPerPixel = LittleShort( * ( short * ) buf_p );
102 	buf_p += 2;
103 	bmpHeader.compression = LittleLong( * ( int * ) buf_p );
104 	buf_p += 4;
105 	bmpHeader.bitmapDataSize = LittleLong( * ( int * ) buf_p );
106 	buf_p += 4;
107 	bmpHeader.hRes = LittleLong( * ( int * ) buf_p );
108 	buf_p += 4;
109 	bmpHeader.vRes = LittleLong( * ( int * ) buf_p );
110 	buf_p += 4;
111 	bmpHeader.colors = LittleLong( * ( int * ) buf_p );
112 	buf_p += 4;
113 	bmpHeader.importantColors = LittleLong( * ( int * ) buf_p );
114 	buf_p += 4;
115 
116 	if ( bmpHeader.bitsPerPixel == 8 )
117 	{
118 		if (buf_p + sizeof(bmpHeader.palette) > end)
119 			ri.Error( ERR_DROP, "LoadBMP: header too short (%s)\n", name );
120 
121 		Com_Memcpy( bmpHeader.palette, buf_p, sizeof( bmpHeader.palette ) );
122 		buf_p += sizeof(bmpHeader.palette);
123 	}
124 
125 	if (buffer.b + bmpHeader.bitmapDataOffset > end)
126 	{
127 		ri.Error( ERR_DROP, "LoadBMP: invalid offset value in header (%s)\n", name );
128 	}
129 
130 	buf_p = buffer.b + bmpHeader.bitmapDataOffset;
131 
132 	if ( bmpHeader.id[0] != 'B' && bmpHeader.id[1] != 'M' )
133 	{
134 		ri.Error( ERR_DROP, "LoadBMP: only Windows-style BMP files supported (%s)\n", name );
135 	}
136 	if ( bmpHeader.fileSize != length )
137 	{
138 		ri.Error( ERR_DROP, "LoadBMP: header size does not match file size (%u vs. %u) (%s)\n", bmpHeader.fileSize, length, name );
139 	}
140 	if ( bmpHeader.compression != 0 )
141 	{
142 		ri.Error( ERR_DROP, "LoadBMP: only uncompressed BMP files supported (%s)\n", name );
143 	}
144 	if ( bmpHeader.bitsPerPixel < 8 )
145 	{
146 		ri.Error( ERR_DROP, "LoadBMP: monochrome and 4-bit BMP files not supported (%s)\n", name );
147 	}
148 
149 	switch ( bmpHeader.bitsPerPixel )
150 	{
151 		case 8:
152 		case 16:
153 		case 24:
154 		case 32:
155 			break;
156 		default:
157 			ri.Error( ERR_DROP, "LoadBMP: illegal pixel_size '%hu' in file '%s'\n", bmpHeader.bitsPerPixel, name );
158 			break;
159 	}
160 
161 	columns = bmpHeader.width;
162 	rows = bmpHeader.height;
163 	if ( rows < 0 )
164 		rows = -rows;
165 	numPixels = columns * rows;
166 
167 	if(columns <= 0 || !rows || numPixels > 0x1FFFFFFF // 4*1FFFFFFF == 0x7FFFFFFC < 0x7FFFFFFF
168 	    || ((numPixels * 4) / columns) / 4 != rows)
169 	{
170 	  ri.Error (ERR_DROP, "LoadBMP: %s has an invalid image size\n", name);
171 	}
172 	if(buf_p + numPixels*bmpHeader.bitsPerPixel/8 > end)
173 	{
174 	  ri.Error (ERR_DROP, "LoadBMP: file truncated (%s)\n", name);
175 	}
176 
177 	if ( width )
178 		*width = columns;
179 	if ( height )
180 		*height = rows;
181 
182 	bmpRGBA = ri.Malloc( numPixels * 4 );
183 	*pic = bmpRGBA;
184 
185 
186 	for ( row = rows-1; row >= 0; row-- )
187 	{
188 		pixbuf = bmpRGBA + row*columns*4;
189 
190 		for ( column = 0; column < columns; column++ )
191 		{
192 			unsigned char red, green, blue, alpha;
193 			int palIndex;
194 			unsigned short shortPixel;
195 
196 			switch ( bmpHeader.bitsPerPixel )
197 			{
198 			case 8:
199 				palIndex = *buf_p++;
200 				*pixbuf++ = bmpHeader.palette[palIndex][2];
201 				*pixbuf++ = bmpHeader.palette[palIndex][1];
202 				*pixbuf++ = bmpHeader.palette[palIndex][0];
203 				*pixbuf++ = 0xff;
204 				break;
205 			case 16:
206 				shortPixel = * ( unsigned short * ) pixbuf;
207 				pixbuf += 2;
208 				*pixbuf++ = ( shortPixel & ( 31 << 10 ) ) >> 7;
209 				*pixbuf++ = ( shortPixel & ( 31 << 5 ) ) >> 2;
210 				*pixbuf++ = ( shortPixel & ( 31 ) ) << 3;
211 				*pixbuf++ = 0xff;
212 				break;
213 
214 			case 24:
215 				blue = *buf_p++;
216 				green = *buf_p++;
217 				red = *buf_p++;
218 				*pixbuf++ = red;
219 				*pixbuf++ = green;
220 				*pixbuf++ = blue;
221 				*pixbuf++ = 255;
222 				break;
223 			case 32:
224 				blue = *buf_p++;
225 				green = *buf_p++;
226 				red = *buf_p++;
227 				alpha = *buf_p++;
228 				*pixbuf++ = red;
229 				*pixbuf++ = green;
230 				*pixbuf++ = blue;
231 				*pixbuf++ = alpha;
232 				break;
233 			}
234 		}
235 	}
236 
237 	ri.FS_FreeFile( buffer.v );
238 
239 }
240