home *** CD-ROM | disk | FTP | other *** search
/ PC PowerPlay 58 / pcpp58a.iso / extras / quake 3 source / Q3A_ToolSource.exe / Main / Bmp.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-02  |  8.3 KB  |  397 lines

  1.  
  2. #include "stdafx.h"
  3. #include <stdio.h>
  4. #include <malloc.h>
  5. #include <string.h>
  6.  
  7. #include "bmp.h"
  8.  
  9.  
  10. void Error(char *fmt, ...);
  11.  
  12.  
  13. static int GetColorCount(int nbits)
  14. {
  15.     int ncolors = 0;
  16.  
  17.     if (nbits < 24)
  18.     {
  19.          ncolors = 1 << nbits;
  20.     }
  21.  
  22.     return(ncolors);
  23. }
  24.  
  25.  
  26. static void BMPLineNone(FILE *f, char *sline, int pixbytes, int width)
  27. {
  28.     int nbytes, i, k, j;
  29.  
  30.     switch (pixbytes)
  31.     {
  32.         case 1 :
  33.             nbytes = (width + 3) / 4;
  34.             nbytes *= 4;
  35.  
  36.             fread(sline, width, 1, f);
  37.             nbytes -= width;
  38.  
  39.             while (nbytes-- > 0) fgetc(f);
  40.             return;
  41.  
  42.         case 3 :
  43.             nbytes = ((width * 3) + 3) / 4;
  44.             nbytes *= 4;
  45.  
  46.             fread(sline, width, 3, f);
  47.             nbytes -= width * 3;
  48.  
  49.             while (nbytes-- > 0) fgetc(f);
  50.  
  51.             // reorder bgr to rgb
  52.             for (i = 0, j = 0; i < width; i++, j += 3)
  53.             {
  54.                 k = sline[j];
  55.                 sline[j] = sline[j+2];
  56.                 sline[j+2] = k;
  57.             }
  58.  
  59.             return;
  60.     }
  61.  
  62.     Error("BMPLineNone failed.");
  63. }
  64.  
  65.  
  66. static void BMPLineRLE8(FILE *f, char *sline, int pixbytes, int width)
  67. {
  68.     Error("RLE8 not yet supported.");
  69. }
  70.  
  71.  
  72. static void BMPLineRLE4(FILE *f, char *sline, int pixbytes, int width)
  73. {
  74.     Error("RLE4 not yet supported.");
  75. }
  76.  
  77.  
  78. static void BMPLine(FILE *f, char *scanline, int pixbytes, int width, int rle)
  79. {
  80.     switch (rle)
  81.     {
  82.         case xBI_NONE : BMPLineNone(f, scanline, pixbytes, width); return;
  83.         case xBI_RLE8 : BMPLineRLE8(f, scanline, pixbytes, width); return;
  84.         case xBI_RLE4 : BMPLineRLE4(f, scanline, pixbytes, width); return;
  85.     }
  86.  
  87.     Error("Unknown compression type.");
  88. }
  89.  
  90.  
  91.  
  92. static void PrintHeader(binfo_t *b)
  93. {
  94.     printf("biSize         : %ld\n", b->biSize);
  95.     printf("biWidth        : %ld\n", b->biWidth);
  96.     printf("biHeight       : %ld\n", b->biHeight);
  97.     printf("biPlanes       : %d\n", b->biPlanes);
  98.     printf("biBitCount     : %d\n", b->biBitCount);
  99.     printf("biCompression  : %ld\n", b->biCompression);
  100.     printf("biSizeImage    : %ld\n", b->biSizeImage);
  101.     printf("biXPelsPerMeter: %ld\n", b->biXPelsPerMeter);
  102.     printf("biYPelsPerMeter: %ld\n", b->biYPelsPerMeter);
  103.     printf("biClrUsed      : %ld\n", b->biClrUsed);
  104.     printf("biClrImportant : %ld\n", b->biClrImportant);
  105. }
  106.  
  107.  
  108. void LoadBMP(char *filename, bitmap_t *bit)
  109. {
  110.     FILE    *f;
  111.     bmphd_t  bhd;
  112.     binfo_t  info;
  113.     int      pxlsize = 1;
  114.     int      rowbytes, i, pixbytes;
  115.     char    *scanline;
  116.  
  117.     // open file
  118.     if ((f = fopen(filename, "rb")) == NULL)
  119.     {
  120.         Error("Unable to open %s.", filename);
  121.     }
  122.  
  123.     // read in bitmap header
  124.     if (fread(&bhd, sizeof(bhd), 1, f) != 1)
  125.     {
  126.         fclose(f);
  127.         Error("Unable to read in bitmap header.");
  128.     }
  129.  
  130.     // make sure we have a valid bitmap file
  131.     if (bhd.bfType != BMP_SIGNATURE_WORD)
  132.     {
  133.         fclose(f);
  134.         Error("Invalid BMP file: %s", filename);
  135.     }
  136.  
  137.     // load in info header
  138.     if (fread(&info, sizeof(info), 1, f) != 1)
  139.     {
  140.         fclose(f);
  141.         Error("Unable to read bitmap info header.");
  142.     }
  143.  
  144.     // make sure this is an info type of bitmap
  145.     if (info.biSize != sizeof(binfo_t))
  146.     {
  147.         fclose(f);
  148.         Error("We only support the info bitmap type.");
  149.     }
  150.  
  151.     // PrintHeader(&info);
  152.  
  153.     bit->bpp      = info.biBitCount;
  154.     bit->width    = info.biWidth;
  155.     bit->height   = info.biHeight;
  156.     bit->data     = NULL;
  157.     bit->palette  = NULL;
  158.  
  159.     //currently we only read in 8 and 24 bit bmp files
  160.     if      (info.biBitCount == 8)  pixbytes = 1;
  161.     else if (info.biBitCount == 24) pixbytes = 3;
  162.     else
  163.     {
  164.         Error("BPP %d not supported.", info.biBitCount);
  165.     }
  166.  
  167.     // if this is an eight bit image load palette
  168.     if (pixbytes == 1)
  169.     {
  170.         drgb_t q;
  171.  
  172.         bit->palette = reinterpret_cast<rgb_t*>(malloc(sizeof(rgb_t) * 256));
  173.  
  174.         for (i = 0; i < 256; i++)
  175.         {
  176.             if (fread(&q, sizeof(drgb_t), 1, f) != 1)
  177.             {
  178.                 fclose(f); free(bit->palette);
  179.                 Error("Unable to read palette.");
  180.             }
  181.  
  182.             bit->palette[i].r   = q.red;
  183.             bit->palette[i].g   = q.green;
  184.             bit->palette[i].b   = q.blue;
  185.         }
  186.     }
  187.  
  188.     // position to start of bitmap
  189.     fseek(f, bhd.bfOffBits, SEEK_SET);
  190.  
  191.     // create scanline to read data into
  192.     rowbytes = ((info.biWidth * pixbytes) + 3) / 4;
  193.     rowbytes *= 4;
  194.  
  195.     scanline = reinterpret_cast<char*>(malloc(rowbytes));
  196.  
  197.     // alloc space for new bitmap
  198.     bit->data = reinterpret_cast<unsigned char*>(malloc(info.biWidth * pixbytes * info.biHeight));
  199.  
  200.     // read in image
  201.     for (i = 0; i < info.biHeight; i++)
  202.     {
  203.         BMPLine(f, scanline, pixbytes, info.biWidth, info.biCompression);
  204.  
  205.         // store line
  206.         memcpy(&bit->data[info.biWidth * pixbytes * (info.biHeight - i - 1)], scanline, info.biWidth * pixbytes);
  207.     }
  208.  
  209.     free(scanline);
  210.     fclose(f);
  211. }
  212.  
  213.  
  214.  
  215. static void BMPEncodeLine(FILE *f, unsigned char *data, int npxls, int pixbytes)
  216. {
  217.     int nbytes, i, j, k;
  218.  
  219.     switch (pixbytes)
  220.     {
  221.         case 1 :
  222.             nbytes = (npxls + 3) / 4;
  223.             nbytes *= 4;
  224.  
  225.             fwrite(data, npxls, 1, f);
  226.             nbytes -= npxls;
  227.  
  228.             while (nbytes-- > 0) fputc(0, f);
  229.             return;
  230.  
  231.         case 3 :
  232.             // reorder rgb to bgr
  233.             for (i = 0, j = 0; i < npxls; i++, j+= 3)
  234.             {
  235.                 k = data[j];
  236.                 data[j] = data[j + 2];
  237.                 data[j + 2] = k;
  238.             }
  239.  
  240.             nbytes = ((npxls * 3) + 3) / 4;
  241.             nbytes *= 4;
  242.  
  243.             fwrite(data, npxls, 3, f);
  244.             nbytes -= npxls * 3;
  245.  
  246.             while (nbytes-- > 0) fputc(0, f);
  247.             return;
  248.     }
  249.  
  250.     Error("BMPEncodeLine Failed.");
  251. }
  252.  
  253.  
  254.  
  255. void WriteBMP(char *filename, bitmap_t *bit)
  256. {
  257.     FILE    *f;
  258.     bmphd_t  header;
  259.     binfo_t  info;
  260.     drgb_t   q;        // palette that gets written
  261.     long     bmofs;
  262.     int      w, h, i;
  263.     int      pixbytes;
  264.  
  265.     if      (bit->bpp == 8)  pixbytes = 1;
  266.     else if (bit->bpp == 24) pixbytes = 3;
  267.  
  268.     else
  269.     {
  270.         Error("BPP %d not supported.", bit->bpp);
  271.     }
  272.  
  273.  
  274.     if ((f = fopen(filename, "wb")) == NULL)
  275.     {
  276.         Error("Unable to open %s.", filename);
  277.     }
  278.  
  279.     // write out an empty header as a place holder
  280.     if (fwrite(&header, sizeof(header), 1, f) != 1)
  281.     {
  282.         Error("Unable to fwrite.");
  283.     }
  284.  
  285.     // init and write info header
  286.     info.biSize          = sizeof(binfo_t);
  287.     info.biWidth         = bit->width;
  288.     info.biHeight        = bit->height;
  289.     info.biPlanes        = 1;
  290.     info.biBitCount      = bit->bpp;
  291.     info.biCompression   = xBI_NONE;
  292.     info.biSizeImage     = bit->width * bit->height;
  293.     info.biXPelsPerMeter = 0;
  294.     info.biYPelsPerMeter = 0;
  295.     info.biClrUsed       = 256;
  296.     info.biClrImportant  = 256;
  297.  
  298.     if (fwrite(&info, sizeof(binfo_t), 1, f) != 1)
  299.     {
  300.         Error("fwrite failed.");
  301.     }
  302.  
  303.     // write out palette if we need to
  304.     if (bit->bpp == 8)
  305.     {
  306.         for (i = 0; i < 256; i++)
  307.         {
  308.             q.red   = bit->palette[i].r;
  309.             q.green = bit->palette[i].g;
  310.             q.blue  = bit->palette[i].b;
  311.  
  312.             fwrite(&q, sizeof(q), 1, f);
  313.         }
  314.     }
  315.  
  316.     // save offset to start of bitmap
  317.     bmofs = ftell(f);
  318.  
  319.     // output bitmap
  320.     w = bit->width;
  321.     h = bit->height;
  322.  
  323.     for (i = h - 1; i >= 0; i--)
  324.     {
  325.         BMPEncodeLine(f, &bit->data[w * pixbytes * i], w, pixbytes);
  326.     }
  327.  
  328.     // update and rewrite file header
  329.     header.bfType    = BMP_SIGNATURE_WORD;
  330.     header.bfSize    = ftell(f);
  331.     header.bfOffBits = bmofs;
  332.  
  333.     fseek(f, 0L, SEEK_SET);
  334.     fwrite(&header, sizeof(header), 1, f);
  335.  
  336.     fclose(f);
  337. }
  338.  
  339.  
  340. void NewBMP(int width, int height, int bpp, bitmap_t *bit)
  341. {
  342.     int pixbytes;
  343.  
  344.     if      (bpp == 8)  pixbytes = 1;
  345.     else if (bpp == 24) pixbytes = 3;
  346.  
  347.     else
  348.     {
  349.         Error("NewBMP: 8 or 24 bit only.");
  350.     }
  351.  
  352.     bit->bpp    = bpp;
  353.     bit->width  = width;
  354.     bit->height = height;
  355.  
  356.     bit->data = reinterpret_cast<unsigned char*>(malloc(width * height * pixbytes));
  357.  
  358.     if (bit->data == NULL)
  359.     {
  360.         Error("NewBMP: malloc failed.");
  361.     }
  362.  
  363.     // see if we need to create a palette
  364.     if (pixbytes == 1)
  365.     {
  366.         bit->palette = (rgb_t *) malloc(768);
  367.  
  368.         if (bit->palette == NULL)
  369.         {
  370.             Error("NewBMP: unable to malloc palette.");
  371.         }
  372.     }
  373.     else
  374.     {
  375.         bit->palette = NULL;
  376.     }
  377. }
  378.  
  379.  
  380.  
  381. void FreeBMP(bitmap_t *bitmap)
  382. {
  383.     if (bitmap->palette)
  384.     {
  385.         free(bitmap->palette);
  386.         bitmap->palette = NULL;
  387.     }
  388.  
  389.     if (bitmap->data)
  390.     {
  391.         free(bitmap->data);
  392.         bitmap->data = NULL;
  393.     }
  394. }
  395.  
  396.  
  397.