www.pudn.com > flightsim.rar > bitmap.c


/* 
 * Windows BMP file functions for OpenGL. 
 * 
 * Written by Michael Sweet. 
 */ 
 
#include "bitmap.h" 
#include  
#include  
#include  
 
 
#ifdef WIN32 
/* 
 * 'LoadDIBitmap()' - Load a DIB/BMP file from disk. 
 * 
 * Returns a pointer to the bitmap if successful, NULL otherwise... 
 */ 
 
GLubyte *                          /* O - Bitmap data */ 
LoadDIBitmap(const char *filename, /* I - File to load */ 
             BITMAPINFO **info)    /* O - Bitmap information */ 
    { 
    FILE             *fp;          /* Open file pointer */ 
    GLubyte          *bits;        /* Bitmap pixel bits */ 
    int              bitsize;      /* Size of bitmap */ 
    int              infosize;     /* Size of header information */ 
    BITMAPFILEHEADER header;       /* File header */ 
 
 
    /* Try opening the file; use "rb" mode to read this *binary* file. */ 
    if ((fp = fopen(filename, "rb")) == NULL) 
        return (NULL); 
 
    /* Read the file header and any following bitmap information... */ 
    if (fread(&header, sizeof(BITMAPFILEHEADER), 1, fp) < 1) 
        { 
        /* Couldn't read the file header - return NULL... */ 
	fclose(fp); 
        return (NULL); 
        } 
 
    if (header.bfType != 'MB')	/* Check for BM reversed... */ 
        { 
        /* Not a bitmap file - return NULL... */ 
        fclose(fp); 
        return (NULL); 
        } 
 
    infosize = header.bfOffBits - sizeof(BITMAPFILEHEADER); 
    if ((*info = (BITMAPINFO *)malloc(infosize)) == NULL) 
        { 
        /* Couldn't allocate memory for bitmap info - return NULL... */ 
        fclose(fp); 
        return (NULL); 
        } 
 
    if (fread(*info, 1, infosize, fp) < infosize) 
        { 
        /* Couldn't read the bitmap header - return NULL... */ 
        free(*info); 
        fclose(fp); 
        return (NULL); 
        } 
 
    /* Now that we have all the header info read in, allocate memory for * 
     * the bitmap and read *it* in...                                    */ 
    if ((bitsize = (*info)->bmiHeader.biSizeImage) == 0) 
        bitsize = ((*info)->bmiHeader.biWidth * 
                   (*info)->bmiHeader.biBitCount + 7) / 8 * 
  	           abs((*info)->bmiHeader.biHeight); 
 
    if ((bits = malloc(bitsize)) == NULL) 
        { 
        /* Couldn't allocate memory - return NULL! */ 
        free(*info); 
        fclose(fp); 
        return (NULL); 
        } 
 
    if (fread(bits, 1, bitsize, fp) < bitsize) 
        { 
        /* Couldn't read bitmap - free memory and return NULL! */ 
        free(*info); 
        free(bits); 
        fclose(fp); 
        return (NULL); 
        } 
 
    /* OK, everything went fine - return the allocated bitmap... */ 
    fclose(fp); 
    return (bits); 
    } 
 
 
/* 
 * 'SaveDIBitmap()' - Save a DIB/BMP file to disk. 
 * 
 * Returns 0 on success or -1 on failure... 
 */ 
 
int                                /* O - 0 = success, -1 = failure */ 
SaveDIBitmap(const char *filename, /* I - File to load */ 
             BITMAPINFO *info,     /* I - Bitmap information */ 
	     GLubyte    *bits)     /* I - Bitmap data */ 
    { 
    FILE             *fp;          /* Open file pointer */ 
    int              size,         /* Size of file */ 
                     infosize,     /* Size of bitmap info */ 
                     bitsize;      /* Size of bitmap pixels */ 
    BITMAPFILEHEADER header;       /* File header */ 
 
 
    /* Try opening the file; use "wb" mode to write this *binary* file. */ 
    if ((fp = fopen(filename, "wb")) == NULL) 
        return (-1); 
 
    /* Figure out the bitmap size */ 
    if (info->bmiHeader.biSizeImage == 0) 
	bitsize = (info->bmiHeader.biWidth * 
        	   info->bmiHeader.biBitCount + 7) / 8 * 
		  abs(info->bmiHeader.biHeight); 
    else 
	bitsize = info->bmiHeader.biSizeImage; 
 
    /* Figure out the header size */ 
    infosize = sizeof(BITMAPINFOHEADER); 
    switch (info->bmiHeader.biCompression) 
	{ 
	case BI_BITFIELDS : 
            infosize += 12; /* Add 3 RGB doubleword masks */ 
            if (info->bmiHeader.biClrUsed == 0) 
	      break; 
	case BI_RGB : 
            if (info->bmiHeader.biBitCount > 8 && 
        	info->bmiHeader.biClrUsed == 0) 
	      break; 
	case BI_RLE8 : 
	case BI_RLE4 : 
            if (info->bmiHeader.biClrUsed == 0) 
              infosize += (1 << info->bmiHeader.biBitCount) * 4; 
	    else 
              infosize += info->bmiHeader.biClrUsed * 4; 
	    break; 
	} 
 
    size = sizeof(BITMAPFILEHEADER) + infosize + bitsize; 
 
    /* Write the file header, bitmap information, and bitmap pixel data... */ 
    header.bfType      = 'MB'; /* Non-portable... sigh */ 
    header.bfSize      = size; 
    header.bfReserved1 = 0; 
    header.bfReserved2 = 0; 
    header.bfOffBits   = sizeof(BITMAPFILEHEADER) + infosize; 
 
    if (fwrite(&header, 1, sizeof(BITMAPFILEHEADER), fp) < sizeof(BITMAPFILEHEADER)) 
        { 
        /* Couldn't write the file header - return... */ 
        fclose(fp); 
        return (-1); 
        } 
 
    if (fwrite(info, 1, infosize, fp) < infosize) 
        { 
        /* Couldn't write the bitmap header - return... */ 
        fclose(fp); 
        return (-1); 
        } 
 
    if (fwrite(bits, 1, bitsize, fp) < bitsize) 
        { 
        /* Couldn't write the bitmap - return... */ 
        fclose(fp); 
        return (-1); 
        } 
 
    /* OK, everything went fine - return... */ 
    fclose(fp); 
    return (0); 
    } 
 
 
#else /* !WIN32 */ 
/* 
 * Functions for reading and writing 16- and 32-bit little-endian integers. 
 */ 
 
static unsigned short read_word(FILE *fp); 
static unsigned int   read_dword(FILE *fp); 
static int            read_long(FILE *fp); 
 
static int            write_word(FILE *fp, unsigned short w); 
static int            write_dword(FILE *fp, unsigned int dw); 
static int            write_long(FILE *fp, int l); 
 
 
/* 
 * 'LoadDIBitmap()' - Load a DIB/BMP file from disk. 
 * 
 * Returns a pointer to the bitmap if successful, NULL otherwise... 
 */ 
 
GLubyte *                          /* O - Bitmap data */ 
LoadDIBitmap(const char *filename, /* I - File to load */ 
             BITMAPINFO **info)    /* O - Bitmap information */ 
    { 
    FILE             *fp;          /* Open file pointer */ 
    GLubyte          *bits;        /* Bitmap pixel bits */ 
    GLubyte          *ptr;         /* Pointer into bitmap */ 
    GLubyte          temp;         /* Temporary variable to swap red and blue */ 
    int              x, y;         /* X and Y position in image */ 
    int              length;       /* Line length */ 
    int              bitsize;      /* Size of bitmap */ 
    int              infosize;     /* Size of header information */ 
    BITMAPFILEHEADER header;       /* File header */ 
 
 
    /* Try opening the file; use "rb" mode to read this *binary* file. */ 
    if ((fp = fopen(filename, "rb")) == NULL) 
        return (NULL); 
 
    /* Read the file header and any following bitmap information... */ 
    header.bfType      = read_word(fp); 
    header.bfSize      = read_dword(fp); 
    header.bfReserved1 = read_word(fp); 
    header.bfReserved2 = read_word(fp); 
    header.bfOffBits   = read_dword(fp); 
 
    if (header.bfType != BF_TYPE) /* Check for BM reversed... */ 
        { 
        /* Not a bitmap file - return NULL... */ 
        fclose(fp); 
        return (NULL); 
        } 
 
    infosize = header.bfOffBits - 18; 
    if ((*info = (BITMAPINFO *)malloc(sizeof(BITMAPINFO))) == NULL) 
        { 
        /* Couldn't allocate memory for bitmap info - return NULL... */ 
        fclose(fp); 
        return (NULL); 
        } 
 
    (*info)->bmiHeader.biSize          = read_dword(fp); 
    (*info)->bmiHeader.biWidth         = read_long(fp); 
    (*info)->bmiHeader.biHeight        = read_long(fp); 
    (*info)->bmiHeader.biPlanes        = read_word(fp); 
    (*info)->bmiHeader.biBitCount      = read_word(fp); 
    (*info)->bmiHeader.biCompression   = read_dword(fp); 
    (*info)->bmiHeader.biSizeImage     = read_dword(fp); 
    (*info)->bmiHeader.biXPelsPerMeter = read_long(fp); 
    (*info)->bmiHeader.biYPelsPerMeter = read_long(fp); 
    (*info)->bmiHeader.biClrUsed       = read_dword(fp); 
    (*info)->bmiHeader.biClrImportant  = read_dword(fp); 
 
    if (infosize > 40) 
	if (fread((*info)->bmiColors, infosize - 40, 1, fp) < 1) 
            { 
            /* Couldn't read the bitmap header - return NULL... */ 
            free(*info); 
            fclose(fp); 
            return (NULL); 
            } 
 
    /* Now that we have all the header info read in, allocate memory for * 
     * the bitmap and read *it* in...                                    */ 
    if ((bitsize = (*info)->bmiHeader.biSizeImage) == 0) 
        bitsize = ((*info)->bmiHeader.biWidth * 
                   (*info)->bmiHeader.biBitCount + 7) / 8 * 
  	           abs((*info)->bmiHeader.biHeight); 
 
    if ((bits = malloc(bitsize)) == NULL) 
        { 
        /* Couldn't allocate memory - return NULL! */ 
        free(*info); 
        fclose(fp); 
        return (NULL); 
        } 
 
    if (fread(bits, 1, bitsize, fp) < bitsize) 
        { 
        /* Couldn't read bitmap - free memory and return NULL! */ 
        free(*info); 
        free(bits); 
        fclose(fp); 
        return (NULL); 
        } 
 
    /* Swap red and blue */ 
    length = ((*info)->bmiHeader.biWidth * 3 + 3) & ~3; 
    for (y = 0; y < (*info)->bmiHeader.biHeight; y ++) 
        for (ptr = bits + y * length, x = (*info)->bmiHeader.biWidth; 
             x > 0; 
	     x --, ptr += 3) 
	    { 
	    temp   = ptr[0]; 
	    ptr[0] = ptr[2]; 
	    ptr[2] = temp; 
	    } 
 
    /* OK, everything went fine - return the allocated bitmap... */ 
    fclose(fp); 
    return (bits); 
    } 
 
 
/* 
 * 'SaveDIBitmap()' - Save a DIB/BMP file to disk. 
 * 
 * Returns 0 on success or -1 on failure... 
 */ 
 
int                                /* O - 0 = success, -1 = failure */ 
SaveDIBitmap(const char *filename, /* I - File to load */ 
             BITMAPINFO *info,     /* I - Bitmap information */ 
	     GLubyte    *bits)     /* I - Bitmap data */ 
    { 
    FILE *fp;                      /* Open file pointer */ 
    int  size,                     /* Size of file */ 
         infosize,                 /* Size of bitmap info */ 
         bitsize;                  /* Size of bitmap pixels */ 
 
 
    /* Try opening the file; use "wb" mode to write this *binary* file. */ 
    if ((fp = fopen(filename, "wb")) == NULL) 
        return (-1); 
 
    /* Figure out the bitmap size */ 
    if (info->bmiHeader.biSizeImage == 0) 
	bitsize = (info->bmiHeader.biWidth * 
        	   info->bmiHeader.biBitCount + 7) / 8 * 
		  abs(info->bmiHeader.biHeight); 
    else 
	bitsize = info->bmiHeader.biSizeImage; 
 
    /* Figure out the header size */ 
    infosize = sizeof(BITMAPINFOHEADER); 
    switch (info->bmiHeader.biCompression) 
	{ 
	case BI_BITFIELDS : 
            infosize += 12; /* Add 3 RGB doubleword masks */ 
            if (info->bmiHeader.biClrUsed == 0) 
	      break; 
	case BI_RGB : 
            if (info->bmiHeader.biBitCount > 8 && 
        	info->bmiHeader.biClrUsed == 0) 
	      break; 
	case BI_RLE8 : 
	case BI_RLE4 : 
            if (info->bmiHeader.biClrUsed == 0) 
              infosize += (1 << info->bmiHeader.biBitCount) * 4; 
	    else 
              infosize += info->bmiHeader.biClrUsed * 4; 
	    break; 
	} 
 
    size = sizeof(BITMAPFILEHEADER) + infosize + bitsize; 
 
    /* Write the file header, bitmap information, and bitmap pixel data... */ 
    write_word(fp, BF_TYPE);        /* bfType */ 
    write_dword(fp, size);          /* bfSize */ 
    write_word(fp, 0);              /* bfReserved1 */ 
    write_word(fp, 0);              /* bfReserved2 */ 
    write_dword(fp, 18 + infosize); /* bfOffBits */ 
 
    write_dword(fp, info->bmiHeader.biSize); 
    write_long(fp, info->bmiHeader.biWidth); 
    write_long(fp, info->bmiHeader.biHeight); 
    write_word(fp, info->bmiHeader.biPlanes); 
    write_word(fp, info->bmiHeader.biBitCount); 
    write_dword(fp, info->bmiHeader.biCompression); 
    write_dword(fp, info->bmiHeader.biSizeImage); 
    write_long(fp, info->bmiHeader.biXPelsPerMeter); 
    write_long(fp, info->bmiHeader.biYPelsPerMeter); 
    write_dword(fp, info->bmiHeader.biClrUsed); 
    write_dword(fp, info->bmiHeader.biClrImportant); 
 
    if (infosize > 40) 
	if (fwrite(info->bmiColors, infosize - 40, 1, fp) < 1) 
            { 
            /* Couldn't write the bitmap header - return... */ 
            fclose(fp); 
            return (-1); 
            } 
 
    if (fwrite(bits, 1, bitsize, fp) < bitsize) 
        { 
        /* Couldn't write the bitmap - return... */ 
        fclose(fp); 
        return (-1); 
        } 
 
    /* OK, everything went fine - return... */ 
    fclose(fp); 
    return (0); 
    } 
 
 
/* 
 * 'read_word()' - Read a 16-bit unsigned integer. 
 */ 
 
static unsigned short     /* O - 16-bit unsigned integer */ 
read_word(FILE *fp)       /* I - File to read from */ 
    { 
    unsigned char b0, b1; /* Bytes from file */ 
 
    b0 = getc(fp); 
    b1 = getc(fp); 
 
    return ((b1 << 8) | b0); 
    } 
 
 
/* 
 * 'read_dword()' - Read a 32-bit unsigned integer. 
 */ 
 
static unsigned int               /* O - 32-bit unsigned integer */ 
read_dword(FILE *fp)              /* I - File to read from */ 
    { 
    unsigned char b0, b1, b2, b3; /* Bytes from file */ 
 
    b0 = getc(fp); 
    b1 = getc(fp); 
    b2 = getc(fp); 
    b3 = getc(fp); 
 
    return ((((((b3 << 8) | b2) << 8) | b1) << 8) | b0); 
    } 
 
 
/* 
 * 'read_long()' - Read a 32-bit signed integer. 
 */ 
 
static int                        /* O - 32-bit signed integer */ 
read_long(FILE *fp)               /* I - File to read from */ 
    { 
    unsigned char b0, b1, b2, b3; /* Bytes from file */ 
 
    b0 = getc(fp); 
    b1 = getc(fp); 
    b2 = getc(fp); 
    b3 = getc(fp); 
 
    return ((int)(((((b3 << 8) | b2) << 8) | b1) << 8) | b0); 
    } 
 
 
/* 
 * 'write_word()' - Write a 16-bit unsigned integer. 
 */ 
 
static int                     /* O - 0 on success, -1 on error */ 
write_word(FILE           *fp, /* I - File to write to */ 
           unsigned short w)   /* I - Integer to write */ 
    { 
    putc(w, fp); 
    return (putc(w >> 8, fp)); 
    } 
 
 
/* 
 * 'write_dword()' - Write a 32-bit unsigned integer. 
 */ 
 
static int                    /* O - 0 on success, -1 on error */ 
write_dword(FILE         *fp, /* I - File to write to */ 
            unsigned int dw)  /* I - Integer to write */ 
    { 
    putc(dw, fp); 
    putc(dw >> 8, fp); 
    putc(dw >> 16, fp); 
    return (putc(dw >> 24, fp)); 
    } 
 
 
/* 
 * 'write_long()' - Write a 32-bit signed integer. 
 */ 
 
static int           /* O - 0 on success, -1 on error */ 
write_long(FILE *fp, /* I - File to write to */ 
           int  l)   /* I - Integer to write */ 
    { 
    putc(l, fp); 
    putc(l >> 8, fp); 
    putc(l >> 16, fp); 
    return (putc(l >> 24, fp)); 
    } 
#endif /* WIN32 */