2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
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
29 static void BMPLineNone( FILE *f, char *sline, int pixbytes, int width ){
35 nbytes = ( width + 3 ) / 4;
38 fread( sline, width, 1, f );
41 while ( nbytes-- > 0 ) fgetc( f );
45 nbytes = ( ( width * 3 ) + 3 ) / 4;
48 fread( sline, width, 3, f );
51 while ( nbytes-- > 0 ) fgetc( f );
54 for ( i = 0, j = 0; i < width; i++, j += 3 )
57 sline[j] = sline[j + 2];
64 Error( "BMPLineNone failed." );
68 static void BMPLineRLE8( FILE *f, char *sline, int pixbytes, int width ){
69 Error( "RLE8 not yet supported." );
73 static void BMPLineRLE4( FILE *f, char *sline, int pixbytes, int width ){
74 Error( "RLE4 not yet supported." );
78 static void BMPLine( FILE *f, char *scanline, int pixbytes, int width, int rle ){
81 case xBI_NONE: BMPLineNone( f, scanline, pixbytes, width ); return;
82 case xBI_RLE8: BMPLineRLE8( f, scanline, pixbytes, width ); return;
83 case xBI_RLE4: BMPLineRLE4( f, scanline, pixbytes, width ); return;
86 Error( "Unknown compression type." );
91 static void PrintHeader(binfo_t *b)
93 printf("biSize : %ld\n", b->biSize);
94 printf("biWidth : %ld\n", b->biWidth);
95 printf("biHeight : %ld\n", b->biHeight);
96 printf("biPlanes : %d\n", b->biPlanes);
97 printf("biBitCount : %d\n", b->biBitCount);
98 printf("biCompression : %ld\n", b->biCompression);
99 printf("biSizeImage : %ld\n", b->biSizeImage);
100 printf("biXPelsPerMeter: %ld\n", b->biXPelsPerMeter);
101 printf("biYPelsPerMeter: %ld\n", b->biYPelsPerMeter);
102 printf("biClrUsed : %ld\n", b->biClrUsed);
103 printf("biClrImportant : %ld\n", b->biClrImportant);
107 // FIXME: calls to Error(const char *, ... ) are dependant on qe3.cpp
108 void LoadBMP( char *filename, bitmap_t *bit ){
113 int rowbytes, i, pixbytes;
117 if ( ( f = fopen( filename, "rb" ) ) == NULL ) {
118 Error( "Unable to open file" ); // %s.", filename);
121 // read in bitmap header
122 if ( fread( &bhd, sizeof( bhd ), 1, f ) != 1 ) {
124 Error( "Unable to read in bitmap header." );
127 // make sure we have a valid bitmap file
128 if ( bhd.bfType != BMP_SIGNATURE_WORD ) {
130 Error( "Invalid BMP file" ); //: %s", filename);
133 // load in info header
134 if ( fread( &info, sizeof( info ), 1, f ) != 1 ) {
136 Error( "Unable to read bitmap info header." );
139 // make sure this is an info type of bitmap
140 if ( info.biSize != sizeof( binfo_t ) ) {
142 Error( "We only support the info bitmap type." );
145 // PrintHeader(&info);
147 bit->bpp = info.biBitCount;
148 bit->width = info.biWidth;
149 bit->height = info.biHeight;
153 //currently we only read in 8 and 24 bit bmp files
154 if ( info.biBitCount == 8 ) {
157 else if ( info.biBitCount == 24 ) {
162 Error( "Only 8BPP and 24BPP supported" );
163 //Error("BPP %d not supported.", info.biBitCount);
166 // if this is an eight bit image load palette
167 if ( pixbytes == 1 ) {
170 bit->palette = reinterpret_cast<rgb_t*>( g_malloc( sizeof( rgb_t ) * 256 ) );
172 for ( i = 0; i < 256; i++ )
174 if ( fread( &q, sizeof( drgb_t ), 1, f ) != 1 ) {
175 fclose( f ); g_free( bit->palette );
176 Error( "Unable to read palette." );
179 bit->palette[i].r = q.red;
180 bit->palette[i].g = q.green;
181 bit->palette[i].b = q.blue;
185 // position to start of bitmap
186 fseek( f, bhd.bfOffBits, SEEK_SET );
188 // create scanline to read data into
189 rowbytes = ( ( info.biWidth * pixbytes ) + 3 ) / 4;
192 scanline = reinterpret_cast<char*>( g_malloc( rowbytes ) );
194 // alloc space for new bitmap
195 bit->data = reinterpret_cast<unsigned char*>( g_malloc( info.biWidth * pixbytes * info.biHeight ) );
198 for ( i = 0; i < info.biHeight; i++ )
200 BMPLine( f, scanline, pixbytes, info.biWidth, info.biCompression );
203 memcpy( &bit->data[info.biWidth * pixbytes * ( info.biHeight - i - 1 )], scanline, info.biWidth * pixbytes );
212 static void BMPEncodeLine( FILE *f, unsigned char *data, int npxls, int pixbytes ){
218 nbytes = ( npxls + 3 ) / 4;
221 fwrite( data, npxls, 1, f );
224 while ( nbytes-- > 0 ) fputc( 0, f );
228 // reorder rgb to bgr
229 for ( i = 0, j = 0; i < npxls; i++, j += 3 )
232 data[j] = data[j + 2];
236 nbytes = ( ( npxls * 3 ) + 3 ) / 4;
239 fwrite( data, npxls, 3, f );
242 while ( nbytes-- > 0 ) fputc( 0, f );
246 Error( "BMPEncodeLine Failed." );
251 void WriteBMP( char *filename, bitmap_t *bit ){
255 drgb_t q; // palette that gets written
260 if ( bit->bpp == 8 ) {
263 else if ( bit->bpp == 24 ) {
269 Error( "Only 8BPP and 24BPP supported" );
270 //Error("BPP %d not supported.", bit->bpp);
274 if ( ( f = fopen( filename, "wb" ) ) == NULL ) {
275 Error( "Unable to open file" ); //%s.", filename);
278 // write out an empty header as a place holder
279 if ( fwrite( &header, sizeof( header ), 1, f ) != 1 ) {
280 Error( "Unable to fwrite." );
283 // init and write info header
284 info.biSize = sizeof( binfo_t );
285 info.biWidth = bit->width;
286 info.biHeight = bit->height;
288 info.biBitCount = bit->bpp;
289 info.biCompression = xBI_NONE;
290 info.biSizeImage = bit->width * bit->height;
291 info.biXPelsPerMeter = 0;
292 info.biYPelsPerMeter = 0;
293 info.biClrUsed = 256;
294 info.biClrImportant = 256;
296 if ( fwrite( &info, sizeof( binfo_t ), 1, f ) != 1 ) {
297 Error( "fwrite failed." );
300 // write out palette if we need to
301 if ( bit->bpp == 8 ) {
302 for ( i = 0; i < 256; i++ )
304 q.red = bit->palette[i].r;
305 q.green = bit->palette[i].g;
306 q.blue = bit->palette[i].b;
308 fwrite( &q, sizeof( q ), 1, f );
312 // save offset to start of bitmap
319 for ( i = h - 1; i >= 0; i-- )
321 BMPEncodeLine( f, &bit->data[w * pixbytes * i], w, pixbytes );
324 // update and rewrite file header
325 header.bfType = BMP_SIGNATURE_WORD;
326 header.bfSize = ftell( f );
327 header.bfOffBits = bmofs;
329 fseek( f, 0L, SEEK_SET );
330 fwrite( &header, sizeof( header ), 1, f );
336 void NewBMP( int width, int height, int bpp, bitmap_t *bit ){
342 else if ( bpp == 24 ) {
348 Error( "NewBMP: 8 or 24 bit only." );
353 bit->height = height;
355 bit->data = reinterpret_cast<unsigned char*>( g_malloc( width * height * pixbytes ) );
357 if ( bit->data == NULL ) {
358 Error( "NewBMP: g_malloc failed." );
361 // see if we need to create a palette
362 if ( pixbytes == 1 ) {
363 bit->palette = (rgb_t *) g_malloc( 768 );
365 if ( bit->palette == NULL ) {
366 Error( "NewBMP: unable to g_malloc palette." );
377 void FreeBMP( bitmap_t *bitmap ){
378 if ( bitmap->palette ) {
379 g_free( bitmap->palette );
380 bitmap->palette = NULL;
383 if ( bitmap->data ) {
384 g_free( bitmap->data );