image.cpp
上传用户:center1979
上传日期:2022-07-26
资源大小:50633k
文件大小:23k
源码类别:

OpenGL

开发平台:

Visual C++

  1. // image.cpp
  2. //
  3. // Copyright (C) 2001, Chris Laurel
  4. //
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the GNU General Public License
  7. // as published by the Free Software Foundation; either version 2
  8. // of the License, or (at your option) any later version.
  9. #include <fstream>
  10. #ifndef TARGET_OS_MAC
  11. #define JPEG_SUPPORT
  12. #define PNG_SUPPORT
  13. #endif
  14. #ifdef TARGET_OS_MAC
  15. #include <unistd.h>
  16. #include "CGBuffer.h"
  17. #ifndef PNG_SUPPORT
  18. #include <Quicktime/ImageCompression.h>
  19. #include <QuickTime/QuickTimeComponents.h>
  20. #endif
  21. #endif
  22. #ifndef _WIN32
  23. #ifndef TARGET_OS_MAC
  24. #include <config.h>
  25. #endif /* ! TARGET_OS_MAC */
  26. #endif /* ! _WIN32 */
  27. #include "image.h"
  28. #ifdef JPEG_SUPPORT
  29. #ifndef PNG_SUPPORT
  30. #include "setjmp.h"
  31. #endif // PNG_SUPPORT
  32. extern "C" {
  33. #ifdef _WIN32
  34. #include "jpeglib.h"
  35. #else
  36. #include <cstdio>
  37. #include <jpeglib.h>
  38. #endif
  39. }
  40. #endif // JPEG_SUPPORT
  41. #ifdef PNG_SUPPORT // PNG_SUPPORT
  42. #ifdef TARGET_OS_MAC
  43. #include "../../macosx/png.h"
  44. #else
  45. #include "png.h"
  46. #endif // TARGET_OS_MAC
  47. #include <celutil/debug.h>
  48. #include <celutil/util.h>
  49. #include <celutil/filetype.h>
  50. #include "gl.h"
  51. #include "glext.h"
  52. #include "celestia.h"
  53. #include <cassert>
  54. #include <iostream>
  55. #include <algorithm>
  56. #include <cmath>
  57. using namespace std;
  58. // Define png_jmpbuf() in case we are using a pre-1.0.6 version of libpng
  59. #ifndef png_jmpbuf
  60. #define png_jmpbuf(png_ptr) png_ptr->jmpbuf
  61. #endif // PNG_SUPPORT
  62. // Define various expansion transformations for old versions of libpng
  63. #if PNG_LIBPNG_VER < 10004
  64. #define png_set_palette_to_rgb(p)  png_set_expand(p)
  65. #define png_set_gray_1_2_4_to_8(p) png_set_expand(p)
  66. #define png_set_tRNS_to_alpha(p)   png_set_expand(p)
  67. #endif // PNG_LIBPNG_VER < 10004
  68. #endif // PNG_SUPPORT
  69. // All rows are padded to a size that's a multiple of 4 bytes
  70. static int pad(int n)
  71. {
  72.     return (n + 3) & ~0x3;
  73. }
  74. static int formatComponents(int fmt)
  75. {
  76.     switch (fmt)
  77.     {
  78.     case GL_RGBA:
  79.     case GL_BGRA_EXT:
  80.         return 4;
  81.     case GL_RGB:
  82.     case GL_BGR_EXT:
  83.         return 3;
  84.     case GL_LUMINANCE_ALPHA:
  85.     case GL_DSDT_NV:
  86.         return 2;
  87.     case GL_ALPHA:
  88.     case GL_LUMINANCE:
  89.         return 1;
  90.     // Compressed formats
  91.     case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
  92.         return 3;
  93.     case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
  94.     case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
  95.         return 4;
  96.     // Unknown format
  97.     default:
  98.         return 0;
  99.     }
  100. }
  101. static int calcMipLevelSize(int fmt, int w, int h, int mip)
  102. {
  103.     w = max(w >> mip, 1);
  104.     h = max(h >> mip, 1);
  105.     switch (fmt)
  106.     {
  107.     case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
  108.         // 4x4 blocks, 8 bytes per block
  109.         return ((w + 3) / 4) * ((h + 3) / 4) * 8;
  110.     case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
  111.     case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
  112.         // 4x4 blocks, 16 bytes per block
  113.         return ((w + 3) / 4) * ((h + 3) / 4) * 16;
  114.     default:
  115.         return h * pad(w * formatComponents(fmt));
  116.     }
  117. }
  118. Image::Image(int fmt, int w, int h, int mips) :
  119.     width(w),
  120.     height(h),
  121.     mipLevels(mips),
  122.     format(fmt),
  123.     pixels(NULL)
  124. {
  125.     components = formatComponents(fmt);
  126.     assert(components != 0);
  127.     pitch = pad(w * components);
  128.     size = 1;
  129.     for (int i = 0; i < mipLevels; i++)
  130.         size += calcMipLevelSize(fmt, w, h, i);
  131.     pixels = new unsigned char[size];
  132. }
  133. Image::~Image()
  134. {
  135.     if (pixels != NULL)
  136.         delete[] pixels;
  137. }
  138. int Image::getWidth() const
  139. {
  140.     return width;
  141. }
  142. int Image::getHeight() const
  143. {
  144.     return height;
  145. }
  146. int Image::getPitch() const
  147. {
  148.     return pitch;
  149. }
  150. int Image::getMipLevelCount() const
  151. {
  152.     return mipLevels;
  153. }
  154. int Image::getSize() const
  155. {
  156.     return size;
  157. }
  158. int Image::getFormat() const
  159. {
  160.     return format;
  161. }
  162. int Image::getComponents() const
  163. {
  164.     return components;
  165. }
  166. unsigned char* Image::getPixels()
  167. {
  168.     return pixels;
  169. }
  170. unsigned char* Image::getPixelRow(int mip, int row)
  171. {
  172.     /*int w = max(width >> mip, 1); Unused*/
  173.     int h = max(height >> mip, 1);
  174.     if (mip >= mipLevels || row >= h)
  175.         return NULL;
  176.     // Row addressing of compressed textures is not allowed
  177.     if (isCompressed())
  178.         return NULL;
  179.     return getMipLevel(mip) + row * pitch;
  180. }
  181. unsigned char* Image::getPixelRow(int row)
  182. {
  183.     return getPixelRow(0, row);
  184. }
  185. unsigned char* Image::getMipLevel(int mip)
  186. {
  187.     if (mip >= mipLevels)
  188.         return NULL;
  189.     int offset = 0;
  190.     for (int i = 0; i < mip; i++)
  191.         offset += calcMipLevelSize(format, width, height, i);
  192.     return pixels + offset;
  193. }
  194. int Image::getMipLevelSize(int mip) const
  195. {
  196.     if (mip >= mipLevels)
  197.         return 0;
  198.     else
  199.         return calcMipLevelSize(format, width, height, mip);
  200. }
  201. bool Image::isCompressed() const
  202. {
  203.     switch (format)
  204.     {
  205.     case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
  206.     case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
  207.     case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
  208.         return true;
  209.     default:
  210.         return false;
  211.     }
  212. }
  213. bool Image::hasAlpha() const
  214. {
  215.     switch (format)
  216.     {
  217.     case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
  218.     case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
  219.     case GL_RGBA:
  220.     case GL_BGRA_EXT:
  221.     case GL_LUMINANCE_ALPHA:
  222.     case GL_ALPHA:
  223.         return true;
  224.     default:
  225.         return false;
  226.     }
  227. }
  228. // Convert an input height map to a normal map.  Ideally, a single channel
  229. // input should be used.  If not, the first color channel of the input image
  230. // is the one only one used when generating normals.  This produces the
  231. // expected results for grayscale values in RGB images.
  232. Image* Image::computeNormalMap(float scale, bool wrap) const
  233. {
  234.     // Can't do anything with compressed input; there are probably some other
  235.     // formats that should be rejected as well . . .
  236.     if (isCompressed())
  237.         return NULL;
  238.     Image* normalMap = new Image(GL_RGBA, width, height);
  239.     if (normalMap == NULL)
  240.         return NULL;
  241.     unsigned char* nmPixels = normalMap->getPixels();
  242.     int nmPitch = normalMap->getPitch();
  243.     // Compute normals using differences between adjacent texels.
  244.     for (int i = 0; i < height; i++)
  245.     {
  246.         for (int j = 0; j < width; j++)
  247.         {
  248.             int i0 = i;
  249.             int j0 = j;
  250.             int i1 = i - 1;
  251.             int j1 = j - 1;
  252.             if (i1 < 0)
  253.             {
  254.                 if (wrap)
  255.                 {
  256.                     i1 = height - 1;
  257.                 }
  258.                 else
  259.                 {
  260.                     i0++;
  261.                     i1++;
  262.                 }
  263.             }
  264.             if (j1 < 0)
  265.             {
  266.                 if (wrap)
  267.                 {
  268.                     j1 = width - 1;
  269.                 }
  270.                 else
  271.                 {
  272.                     j0++;
  273.                     j1++;
  274.                 }
  275.             }
  276.             int h00 = (int) pixels[i0 * pitch + j0 * components];
  277.             int h10 = (int) pixels[i0 * pitch + j1 * components];
  278.             int h01 = (int) pixels[i1 * pitch + j0 * components];
  279.             float dx = (float) (h10 - h00) * (1.0f / 255.0f) * scale;
  280.             float dy = (float) (h01 - h00) * (1.0f / 255.0f) * scale;
  281.             float mag = (float) sqrt(dx * dx + dy * dy + 1.0f);
  282.             float rmag = 1.0f / mag;
  283.             int n = i * nmPitch + j * 4;
  284.             nmPixels[n]     = (unsigned char) (128 + 127 * dx * rmag);
  285.             nmPixels[n + 1] = (unsigned char) (128 + 127 * dy * rmag);
  286.             nmPixels[n + 2] = (unsigned char) (128 + 127 * rmag);
  287.             nmPixels[n + 3] = 255;
  288.         }
  289.     }
  290.     return normalMap;
  291. }
  292. Image* LoadImageFromFile(const string& filename)
  293. {
  294.     ContentType type = DetermineFileType(filename);
  295.     Image* img = NULL;
  296.     clog << _("Loading image from file ") << filename << 'n';
  297.     switch (type)
  298.     {
  299.     case Content_JPEG:
  300.         img = LoadJPEGImage(filename);
  301.         break;
  302.     case Content_BMP:
  303.         img = LoadBMPImage(filename);
  304.         break;
  305.     case Content_PNG:
  306.         img = LoadPNGImage(filename);
  307.         break;
  308.     case Content_DDS:
  309.     case Content_DXT5NormalMap:
  310.         img = LoadDDSImage(filename);
  311.         break;
  312.     default:
  313.         clog << filename << _(": unrecognized or unsupported image file type.n");
  314.         break;
  315.     }
  316.     return img;
  317. }
  318. #ifdef JPEG_SUPPORT
  319. struct my_error_mgr
  320. {
  321.     struct jpeg_error_mgr pub; // "public" fields
  322.     jmp_buf setjmp_buffer;      // for return to caller
  323. };
  324. typedef struct my_error_mgr *my_error_ptr;
  325. METHODDEF(void) my_error_exit(j_common_ptr cinfo)
  326. {
  327.     // cinfo->err really points to a my_error_mgr struct, so coerce pointer
  328.     my_error_ptr myerr = (my_error_ptr) cinfo->err;
  329.     // Always display the message.
  330.     // We could postpone this until after returning, if we chose.
  331.     (*cinfo->err->output_message) (cinfo);
  332.     // Return control to the setjmp point
  333.     longjmp(myerr->setjmp_buffer, 1);
  334. }
  335. #endif // JPEG_SUPPORT
  336. Image* LoadJPEGImage(const string& filename, int)
  337. {
  338. #ifdef JPEG_SUPPORT
  339.     Image* img = NULL;
  340.     // This struct contains the JPEG decompression parameters and pointers to
  341.     // working space (which is allocated as needed by the JPEG library).
  342.     struct jpeg_decompress_struct cinfo;
  343.     // We use our private extension JPEG error handler.
  344.     // Note that this struct must live as long as the main JPEG parameter
  345.     // struct, to avoid dangling-pointer problems.
  346.     struct my_error_mgr jerr;
  347.     // More stuff
  348.     JSAMPARRAY buffer; // Output row buffer
  349.     int row_stride; // physical row width in output buffer
  350.     long cont;
  351.     // In this example we want to open the input file before doing anything else,
  352.     // so that the setjmp() error recovery below can assume the file is open.
  353.     // VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
  354.     // requires it in order to read binary files.
  355.     FILE *in;
  356.     in = fopen(filename.c_str(), "rb");
  357.     if (in == NULL)
  358.         return NULL;
  359.     // Step 1: allocate and initialize JPEG decompression object
  360.     // We set up the normal JPEG error routines, then override error_exit.
  361.     cinfo.err = jpeg_std_error(&jerr.pub);
  362.     jerr.pub.error_exit = my_error_exit;
  363.     // Establish the setjmp return context for my_error_exit to use.
  364.     if (setjmp(jerr.setjmp_buffer))
  365.     {
  366.         // If we get here, the JPEG code has signaled an error.
  367.         // We need to clean up the JPEG object, close the input file, and return.
  368.         jpeg_destroy_decompress(&cinfo);
  369.         fclose(in);
  370.         if (img != NULL)
  371.             delete img;
  372.         return NULL;
  373.     }
  374.     // Now we can initialize the JPEG decompression object.
  375.     jpeg_create_decompress(&cinfo);
  376.     // Step 2: specify data source (eg, a file)
  377.     jpeg_stdio_src(&cinfo, in);
  378.     // Step 3: read file parameters with jpeg_read_header()
  379.     (void) jpeg_read_header(&cinfo, TRUE);
  380.     // We can ignore the return value from jpeg_read_header since
  381.     //  (a) suspension is not possible with the stdio data source, and
  382.     //  (b) we passed TRUE to reject a tables-only JPEG file as an error.
  383.     // Step 4: set parameters for decompression
  384.     // In this example, we don't need to change any of the defaults set by
  385.     // jpeg_read_header(), so we do nothing here.
  386.     // Step 5: Start decompressor
  387.     (void) jpeg_start_decompress(&cinfo);
  388.     // We can ignore the return value since suspension is not possible
  389.     // with the stdio data source.
  390.     // We may need to do some setup of our own at this point before reading
  391.     // the data.  After jpeg_start_decompress() we have the correct scaled
  392.     // output image dimensions available, as well as the output colormap
  393.     // if we asked for color quantization.
  394.     // In this example, we need to make an output work buffer of the right size.
  395.     // JSAMPLEs per row in output buffer
  396.     row_stride = cinfo.output_width * cinfo.output_components;
  397.     // Make a one-row-high sample array that will go away when done with image
  398.     buffer = (*cinfo.mem->alloc_sarray)
  399.         ((j_common_ptr) & cinfo, JPOOL_IMAGE, row_stride, 1);
  400.     // Step 6: while (scan lines remain to be read)
  401.     //             jpeg_read_scanlines(...);
  402.     // Here we use the library's state variable cinfo.output_scanline as the
  403.     // loop counter, so that we don't have to keep track ourselves.
  404.     int format = GL_RGB;
  405.     if (cinfo.output_components == 1)
  406.         format = GL_LUMINANCE;
  407.     img = new Image(format, cinfo.image_width, cinfo.image_height);
  408.     // cont = cinfo.output_height - 1;
  409.     cont = 0;
  410.     while (cinfo.output_scanline < cinfo.output_height)
  411.     {
  412.         // jpeg_read_scanlines expects an array of pointers to scanlines.
  413.         // Here the array is only one element long, but you could ask for
  414.         // more than one scanline at a time if that's more convenient.
  415.         (void) jpeg_read_scanlines(&cinfo, buffer, 1);
  416.         // Assume put_scanline_someplace wants a pointer and sample count.
  417.         // put_scanline_someplace(buffer[0], row_stride);
  418.         memcpy(img->getPixelRow(cont), buffer[0], row_stride);
  419.         cont++;
  420.     }
  421.     // Step 7: Finish decompression
  422.     (void) jpeg_finish_decompress(&cinfo);
  423.     // We can ignore the return value since suspension is not possible
  424.     // with the stdio data source.
  425.     // Step 8: Release JPEG decompression object
  426.     // This is an important step since it will release a good deal of memory.
  427.     jpeg_destroy_decompress(&cinfo);
  428.     // After finish_decompress, we can close the input file.
  429.     // Here we postpone it until after no more JPEG errors are possible,
  430.     // so as to simplify the setjmp error logic above.  (Actually, I don't
  431.     // think that jpeg_destroy can do an error exit, but why assume anything...
  432.     fclose(in);
  433.     // At this point you may want to check to see whether any corrupt-data
  434.     // warnings occurred (test whether jerr.pub.num_warnings is nonzero).
  435.     return img;
  436. #elif TARGET_OS_MAC
  437.     Image* img = NULL;
  438.     CGBuffer* cgJpegImage;
  439.     size_t img_w, img_h, img_d;
  440.     cgJpegImage = new CGBuffer(filename.c_str());
  441.     if (cgJpegImage == NULL) {
  442.         char tempcwd[2048];
  443.         getcwd(tempcwd, sizeof(tempcwd));
  444.         DPRINTF(0, "CGBuffer :: Error opening JPEG image file %s/%sn", tempcwd, filename.c_str());
  445.         delete cgJpegImage;
  446.         return NULL;
  447.     }
  448.     if (!cgJpegImage->LoadJPEG()) {
  449.         char tempcwd[2048];
  450.         getcwd(tempcwd, sizeof(tempcwd));
  451.         DPRINTF(0, "CGBuffer :: Error loading JPEG image file %s/%sn", tempcwd, filename.c_str());
  452.         delete cgJpegImage;
  453.         return NULL;
  454.     }
  455.     cgJpegImage->Render();
  456.     img_w = (size_t) cgJpegImage->image_size.width;
  457.     img_h = (size_t) cgJpegImage->image_size.height;
  458.     img_d = (size_t) ((cgJpegImage->image_depth == 8) ? 1 : 4);
  459.     // DPRINTF(0,"cgJpegImage :: %d x %d x %d [%d] bppn", img_w, img_h, (size_t)cgJpegImage->image_depth, img_d);
  460. #ifdef MACOSX_ALPHA_JPEGS
  461.     int format = (img_d == 1) ? GL_LUMINANCE : GL_RGBA;
  462. #else
  463.     int format = (img_d == 1) ? GL_LUMINANCE : GL_RGB;
  464. #endif
  465.     img = new Image(format, img_w, img_h);
  466.     if (img == NULL || img->getPixels() == NULL) {
  467.         DPRINTF(0, "Could not create imagen");
  468.         delete cgJpegImage;
  469.         return NULL;
  470.     }
  471.     // following code flips image and skips alpha byte if no alpha support
  472.     unsigned char* bout = (unsigned char*) img->getPixels();
  473.     unsigned char* bin  = (unsigned char*) cgJpegImage->buffer->data;
  474.     unsigned int bcount = img_w * img_h * img_d;
  475.     unsigned int i = 0;
  476.     bin += bcount+(img_w*img_d); // start one row past end
  477.     for (i=0; i<bcount; ++i)
  478.     {
  479.          // at end of row, move back two rows
  480.         if ( (i % (img_w * img_d)) == 0 ) bin -= 2*(img_w * img_d);
  481. #ifndef MACOSX_ALPHA_JPEGS
  482.         if (( (img_d != 1) && !((i&3)^3) )) // skip extra byte
  483.         {
  484.             ++bin;
  485.         } else
  486. #endif // !MACOSX_ALPHA_JPEGS
  487.         *bout++ = *bin++;
  488.     }
  489.     delete cgJpegImage;
  490.     return img;
  491. #else
  492.     return NULL;
  493. #endif // JPEG_SUPPORT
  494. }
  495. #ifdef PNG_SUPPORT
  496. void PNGReadData(png_structp png_ptr, png_bytep data, png_size_t length)
  497. {
  498.     FILE* fp = (FILE*) png_get_io_ptr(png_ptr);
  499.     fread((void*) data, 1, length, fp);
  500. }
  501. #endif
  502. Image* LoadPNGImage(const string& filename)
  503. {
  504. #ifndef PNG_SUPPORT
  505.     return NULL;
  506. #else
  507.     char header[8];
  508.     png_structp png_ptr;
  509.     png_infop info_ptr;
  510.     png_uint_32 width, height;
  511.     int bit_depth, color_type, interlace_type;
  512.     FILE* fp = NULL;
  513.     Image* img = NULL;
  514.     png_bytep* row_pointers = NULL;
  515.     fp = fopen(filename.c_str(), "rb");
  516.     if (fp == NULL)
  517.     {
  518.         clog << _("Error opening image file ") << filename << 'n';
  519.         return NULL;
  520.     }
  521.     fread(header, 1, sizeof(header), fp);
  522.     if (png_sig_cmp((unsigned char*) header, 0, sizeof(header)))
  523.     {
  524.         clog << _("Error: ") << filename << _(" is not a PNG file.n");
  525.         fclose(fp);
  526.         return NULL;
  527.     }
  528.     png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
  529.                                      NULL, NULL, NULL);
  530.     if (png_ptr == NULL)
  531.     {
  532.         fclose(fp);
  533.         return NULL;
  534.     }
  535.     info_ptr = png_create_info_struct(png_ptr);
  536.     if (info_ptr == NULL)
  537.     {
  538.         fclose(fp);
  539.         png_destroy_read_struct(&png_ptr, (png_infopp) NULL, (png_infopp) NULL);
  540.         return NULL;
  541.     }
  542.     if (setjmp(png_jmpbuf(png_ptr)))
  543.     {
  544.         fclose(fp);
  545.         if (img != NULL)
  546.             delete img;
  547.         png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);
  548.         clog << _("Error reading PNG image file ") << filename << 'n';
  549.         return NULL;
  550.     }
  551.     // png_init_io(png_ptr, fp);
  552.     png_set_read_fn(png_ptr, (void*) fp, PNGReadData);
  553.     png_set_sig_bytes(png_ptr, sizeof(header));
  554.     png_read_info(png_ptr, info_ptr);
  555.     png_get_IHDR(png_ptr, info_ptr,
  556.                  &width, &height, &bit_depth,
  557.                  &color_type, &interlace_type,
  558.                  NULL, NULL);
  559.     GLenum glformat = GL_RGB;
  560.     switch (color_type)
  561.     {
  562.     case PNG_COLOR_TYPE_GRAY:
  563.         glformat = GL_LUMINANCE;
  564.         break;
  565.     case PNG_COLOR_TYPE_GRAY_ALPHA:
  566.         glformat = GL_LUMINANCE_ALPHA;
  567.         break;
  568.     case PNG_COLOR_TYPE_RGB:
  569.         glformat = GL_RGB;
  570.         break;
  571.     case PNG_COLOR_TYPE_PALETTE:
  572.     case PNG_COLOR_TYPE_RGB_ALPHA:
  573.         glformat = GL_RGBA;
  574.         break;
  575.     default:
  576.         // badness
  577.         break;
  578.     }
  579.     img = new Image(glformat, width, height);
  580.     if (img == NULL)
  581.     {
  582.         fclose(fp);
  583.         png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);
  584.         return NULL;
  585.     }
  586.     // TODO: consider using paletted textures if they're available
  587.     if (color_type == PNG_COLOR_TYPE_PALETTE)
  588.     {
  589.         png_set_palette_to_rgb(png_ptr);
  590.     }
  591.     if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
  592.     {
  593.         png_set_gray_1_2_4_to_8(png_ptr);
  594.     }
  595.     if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
  596.     {
  597.         png_set_tRNS_to_alpha(png_ptr);
  598.     }
  599.     // TODO: consider passing images with < 8 bits/component to
  600.     // GL without expanding
  601.     if (bit_depth == 16)
  602.         png_set_strip_16(png_ptr);
  603.     else if (bit_depth < 8)
  604.         png_set_packing(png_ptr);
  605.     row_pointers = new png_bytep[height];
  606.     for (unsigned int i = 0; i < height; i++)
  607.         row_pointers[i] = (png_bytep) img->getPixelRow(i);
  608.     png_read_image(png_ptr, row_pointers);
  609.     delete[] row_pointers;
  610.     png_read_end(png_ptr, NULL);
  611.     png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
  612.     fclose(fp);
  613.     return img;
  614. #endif
  615. }
  616. // BMP file definitions--can't use windows.h because we might not be
  617. // built on Windows!
  618. typedef struct
  619. {
  620.     unsigned char b;
  621.     unsigned char m;
  622.     unsigned int size;
  623.     unsigned int reserved;
  624.     unsigned int offset;
  625. } BMPFileHeader;
  626. typedef struct
  627. {
  628.     unsigned int size;
  629.     int width;
  630.     int height;
  631.     unsigned short planes;
  632.     unsigned short bpp;
  633.     unsigned int compression;
  634.     unsigned int imageSize;
  635.     int widthPPM;
  636.     int heightPPM;
  637.     unsigned int colorsUsed;
  638.     unsigned int colorsImportant;
  639. } BMPImageHeader;
  640. static int readInt(ifstream& in)
  641. {
  642.     unsigned char b[4];
  643.     in.read(reinterpret_cast<char*>(b), 4);
  644.     return ((int) b[3] << 24) + ((int) b[2] << 16)
  645.         + ((int) b[1] << 8) + (int) b[0];
  646. }
  647. static short readShort(ifstream& in)
  648. {
  649.     unsigned char b[2];
  650.     in.read(reinterpret_cast<char*>(b), 2);
  651.     return ((short) b[1] << 8) + (short) b[0];
  652. }
  653. static Image* LoadBMPImage(ifstream& in)
  654. {
  655.     BMPFileHeader fileHeader;
  656.     BMPImageHeader imageHeader;
  657.     unsigned char* pixels;
  658.     in >> fileHeader.b;
  659.     in >> fileHeader.m;
  660.     fileHeader.size = readInt(in);
  661.     fileHeader.reserved = readInt(in);
  662.     fileHeader.offset = readInt(in);
  663.     if (fileHeader.b != 'B' || fileHeader.m != 'M')
  664.         return NULL;
  665.     imageHeader.size = readInt(in);
  666.     imageHeader.width = readInt(in);
  667.     imageHeader.height = readInt(in);
  668.     imageHeader.planes = readShort(in);
  669.     imageHeader.bpp = readShort(in);
  670.     imageHeader.compression = readInt(in);
  671.     imageHeader.imageSize = readInt(in);
  672.     imageHeader.widthPPM = readInt(in);
  673.     imageHeader.heightPPM = readInt(in);
  674.     imageHeader.colorsUsed = readInt(in);
  675.     imageHeader.colorsImportant = readInt(in);
  676.     if (imageHeader.width <= 0 || imageHeader.height <= 0)
  677.         return NULL;
  678.     // We currently don't support compressed BMPs
  679.     if (imageHeader.compression != 0)
  680.         return NULL;
  681.     // We don't handle 1-, 2-, or 4-bpp images
  682.     if (imageHeader.bpp != 8 && imageHeader.bpp != 24 && imageHeader.bpp != 32)
  683.         return NULL;
  684.     unsigned char* palette = NULL;
  685.     if (imageHeader.bpp == 8)
  686.     {
  687.         printf("Reading %d color paletten", imageHeader.colorsUsed);
  688.         palette = new unsigned char[imageHeader.colorsUsed * 4];
  689.         in.read(reinterpret_cast<char*>(palette), imageHeader.colorsUsed * 4);
  690.     }
  691.     in.seekg(fileHeader.offset, ios::beg);
  692.     unsigned int bytesPerRow =
  693.         (imageHeader.width * imageHeader.bpp / 8 + 1) & ~1;
  694.     unsigned int imageBytes = bytesPerRow * imageHeader.height;
  695.     // slurp the image data
  696.     pixels = new unsigned char[imageBytes];
  697.     in.read(reinterpret_cast<char*>(pixels), imageBytes);
  698.     // check for truncated file
  699.     Image* img = new Image(GL_RGB, imageHeader.width, imageHeader.height);
  700.     if (img == NULL)
  701.     {
  702.         delete[] pixels;
  703.         return NULL;
  704.     }
  705.     // Copy the image and perform any necessary conversions
  706.     for (int y = 0; y < imageHeader.height; y++)
  707.     {
  708.         unsigned char* src = &pixels[y * bytesPerRow];
  709.         unsigned char* dst = img->getPixelRow(y);
  710.         switch (imageHeader.bpp)
  711.         {
  712.         case 8:
  713.             {
  714.                 for (int x = 0; x < imageHeader.width; x++)
  715.                 {
  716.                     unsigned char* color = palette + (*src << 2);
  717.                     dst[0] = color[2];
  718.                     dst[1] = color[1];
  719.                     dst[2] = color[0];
  720.                     src++;
  721.                     dst += 3;
  722.                 }
  723.             }
  724.             break;
  725.         case 24:
  726.             {
  727.                 for (int x = 0; x < imageHeader.width; x++)
  728.                 {
  729.                     dst[0] = src[2];
  730.                     dst[1] = src[1];
  731.                     dst[2] = src[0];
  732.                     src += 3;
  733.                     dst += 3;
  734.                 }
  735.             }
  736.             break;
  737.         case 32:
  738.             {
  739.                 for (int x = 0; x < imageHeader.width; x++)
  740.                 {
  741.                     dst[0] = src[2];
  742.                     dst[1] = src[1];
  743.                     dst[2] = src[0];
  744.                     src += 4;
  745.                     dst += 3;
  746.                 }
  747.             }
  748.             break;
  749.         }
  750.     }
  751.     delete[] pixels;
  752.     return img;
  753. }
  754. Image* LoadBMPImage(const string& filename)
  755. {
  756.     ifstream bmpFile(filename.c_str(), ios::in | ios::binary);
  757.     if (bmpFile.good())
  758.     {
  759.         Image* img = LoadBMPImage(bmpFile);
  760.         bmpFile.close();
  761.         return img;
  762.     }
  763.     else
  764.     {
  765.         return NULL;
  766.     }
  767. }