2 Copyright (C) 2001-2006, William Joseph.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 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.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 #include "ifilesystem.h"
26 typedef unsigned char byte;
29 #include "bytestreamutils.h"
32 typedef unsigned char PaletteEntry[4];
36 unsigned long fileSize;
37 unsigned long reserved0;
38 unsigned long bitmapDataOffset;
39 unsigned long bitmapHeaderSize;
42 unsigned short planes;
43 unsigned short bitsPerPixel;
44 unsigned long compression;
45 unsigned long bitmapDataSize;
49 unsigned long importantColors;
50 PaletteEntry palette[256];
55 PaletteEntry* m_palette;
57 ReadPixel8( PaletteEntry* palette ) : m_palette( palette ){
59 void operator()( PointerInputStream& inputStream, byte*& pixbuf ) const {
61 inputStream.read( &palIndex, 1 );
62 *pixbuf++ = m_palette[palIndex][2];
63 *pixbuf++ = m_palette[palIndex][1];
64 *pixbuf++ = m_palette[palIndex][0];
72 void operator()( PointerInputStream& inputStream, byte*& pixbuf ) const {
73 unsigned short shortPixel;
74 inputStream.read( reinterpret_cast<byte*>( &shortPixel ), sizeof( unsigned short ) ); //!\todo Is this endian safe?
75 *pixbuf++ = static_cast<byte>( shortPixel & ( 31 << 10 ) ) >> 7;
76 *pixbuf++ = static_cast<byte>( shortPixel & ( 31 << 5 ) ) >> 2;
77 *pixbuf++ = static_cast<byte>( shortPixel & ( 31 ) ) << 3;
85 void operator()( PointerInputStream& inputStream, byte*& pixbuf ) const {
87 inputStream.read( bgr, 3 );
98 void operator()( PointerInputStream& inputStream, byte*& pixbuf ) const {
100 inputStream.read( bgra, 4 );
108 template<typename ReadPixel>
109 void ReadBMP( PointerInputStream& inputStream, byte* bmpRGBA, int rows, int columns, ReadPixel readPixel ){
110 for ( int row = rows - 1; row >= 0; row-- )
112 byte* pixbuf = bmpRGBA + row * columns * 4;
114 for ( int column = 0; column < columns; column++ )
116 readPixel( inputStream, pixbuf );
121 Image* LoadBMPBuff( PointerInputStream& inputStream, std::size_t length ){
122 BMPHeader_t bmpHeader;
123 inputStream.read( reinterpret_cast<byte*>( bmpHeader.id ), 2 );
124 bmpHeader.fileSize = istream_read_uint32_le( inputStream );
125 bmpHeader.reserved0 = istream_read_uint32_le( inputStream );
126 bmpHeader.bitmapDataOffset = istream_read_uint32_le( inputStream );
127 bmpHeader.bitmapHeaderSize = istream_read_uint32_le( inputStream );
128 bmpHeader.width = istream_read_uint32_le( inputStream );
129 bmpHeader.height = istream_read_uint32_le( inputStream );
130 bmpHeader.planes = istream_read_uint16_le( inputStream );
131 bmpHeader.bitsPerPixel = istream_read_uint16_le( inputStream );
132 bmpHeader.compression = istream_read_uint32_le( inputStream );
133 bmpHeader.bitmapDataSize = istream_read_uint32_le( inputStream );
134 bmpHeader.hRes = istream_read_uint32_le( inputStream );
135 bmpHeader.vRes = istream_read_uint32_le( inputStream );
136 bmpHeader.colors = istream_read_uint32_le( inputStream );
137 bmpHeader.importantColors = istream_read_uint32_le( inputStream );
139 if ( bmpHeader.bitsPerPixel == 8 ) {
140 int paletteSize = bmpHeader.colors * 4;
141 inputStream.read( reinterpret_cast<byte*>( bmpHeader.palette ), paletteSize );
144 if ( bmpHeader.id[0] != 'B' && bmpHeader.id[1] != 'M' ) {
145 globalErrorStream() << "LoadBMP: only Windows-style BMP files supported\n";
148 if ( bmpHeader.fileSize != length ) {
149 globalErrorStream() << "LoadBMP: header size does not match file size (" << Unsigned( bmpHeader.fileSize ) << " vs. " << Unsigned( length ) << ")\n";
152 if ( bmpHeader.compression != 0 ) {
153 globalErrorStream() << "LoadBMP: only uncompressed BMP files supported\n";
156 if ( bmpHeader.bitsPerPixel < 8 ) {
157 globalErrorStream() << "LoadBMP: monochrome and 4-bit BMP files not supported\n";
161 int columns = bmpHeader.width;
162 int rows = bmpHeader.height;
167 RGBAImage* image = new RGBAImage( columns, rows );
169 switch ( bmpHeader.bitsPerPixel )
172 ReadBMP( inputStream, image->getRGBAPixels(), rows, columns, ReadPixel8( bmpHeader.palette ) );
175 ReadBMP( inputStream, image->getRGBAPixels(), rows, columns, ReadPixel16() );
178 ReadBMP( inputStream, image->getRGBAPixels(), rows, columns, ReadPixel24() );
181 ReadBMP( inputStream, image->getRGBAPixels(), rows, columns, ReadPixel32() );
184 globalErrorStream() << "LoadBMP: illegal pixel_size '" << bmpHeader.bitsPerPixel << "'\n";
191 Image* LoadBMP( ArchiveFile& file ){
192 ScopedArchiveBuffer buffer( file );
193 PointerInputStream inputStream( buffer.buffer );
194 return LoadBMPBuff( inputStream, buffer.length );