Subversion Repositories ipe_artfile_utils

Rev

Blame | Last modification | View Log | RSS feed

  1. /**
  2.  * Bitmap Export for Imagination Pilots Entertainment 16-bit games (IPE16)
  3.  * - Blown Away - The Interactive Game by Imagination Pilots (BA)
  4.  * - Panic in the Park - The Interactive Game by Imagination Pilots (PiP)
  5.  * - Where's Waldo? At the Circus (Waldo1)
  6.  * ART file packer and unpacker by Daniel Marschall, ViaThinkSoft (C) 2014-2018
  7.  * Revision: 2018-02-15
  8.  **/
  9.  
  10. #include <stdio.h>
  11. #include <stdint.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <assert.h>
  15.  
  16. #include "ipe16_bmpexport.h"
  17.  
  18. #define BMP_LINE_PADDING 4
  19.  
  20. // Windows 98 does not support top-down bitmaps, so we need to flip everything
  21. #define USE_BOTTOMUP
  22.  
  23. RGBQUAD ipe16_rgb_to_rgbquad(Ipe16ColorTableEntry cte) {
  24.         RGBQUAD ret;
  25.         ret.rgbRed   = cte.r;
  26.         ret.rgbGreen = cte.g;
  27.         ret.rgbBlue  = cte.b;
  28.         ret.rgbReserved = 0;
  29.         return ret;
  30. }
  31.  
  32. void ipe16_write_bmp(FILE* output, unsigned int width, unsigned int height, unsigned char* imagedata, size_t imagedata_len, Ipe16ColorTable ct) {
  33.  
  34.         #ifdef USE_BOTTOMUP
  35.         const size_t bmpDataSize = width*height;
  36.         unsigned char* bmpData = (unsigned char*)malloc(bmpDataSize);
  37.         assert(bmpData != NULL);
  38.         int h;
  39.         for (h=0; h<height; ++h) {
  40.                 int idx_dest = (height-1)-h;
  41.                 int idx_src  = h;
  42.                 assert(idx_src*width >= 0);
  43.                 assert(idx_dest*width >= 0);
  44.                 memcpy(bmpData+idx_dest*width, imagedata+idx_src*width, width);
  45.         }
  46.         imagedata = bmpData;
  47.         #endif
  48.  
  49.         // Each line must be padded to a multiple of 4
  50.         int pad = (BMP_LINE_PADDING - (width % BMP_LINE_PADDING)) % BMP_LINE_PADDING;
  51.         int newwidth = width+pad;
  52.         int newsize = newwidth * height;
  53.         unsigned char* padded_imagedata = (unsigned char*)malloc(newsize);
  54.         int i;
  55.         for (i=0; i<height; ++i) {
  56.                 int offset = newwidth*i;
  57.                 memcpy(&padded_imagedata[offset], imagedata, width);
  58.                 memset(&padded_imagedata[offset+width], 0, pad);
  59.                 imagedata += width;
  60.         }
  61.  
  62.         // Color table in a bitmap is BGR0, while Blown Away uses RGB
  63.         const unsigned int NUM_COLORS = sizeof(ct.colors)/sizeof(ct.colors[0]);
  64.         RGBQUAD rgba_colortable[NUM_COLORS];
  65.         for (i=0; i<NUM_COLORS; ++i) {
  66.                 rgba_colortable[i] = ipe16_rgb_to_rgbquad(ct.colors[i]);
  67.         }
  68.  
  69.         BITMAPFILEHEADER bfh;
  70.         bfh.bfType = BI_SIGNATURE;
  71.         bfh.bfSize = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+sizeof(rgba_colortable)+newsize;
  72.         bfh.bfReserved1 = 0;
  73.         bfh.bfReserved2 = 0;
  74.         bfh.bfOffBits = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+sizeof(rgba_colortable);
  75.         fwrite(&bfh, sizeof(bfh), 1, output);
  76.  
  77.         BITMAPINFOHEADER bih;
  78.         bih.biSize = sizeof(BITMAPINFOHEADER);
  79.         bih.biWidth = width;
  80.         #ifdef USE_BOTTOMUP
  81.         bih.biHeight = height; // (positive = "bottom-up"-Bitmap)
  82.         #else
  83.         bih.biHeight = -height; // (negative = "top-down"-Bitmap)
  84.         #endif
  85.         bih.biPlanes = 1;
  86.         bih.biBitCount = 8;
  87.         bih.biCompression = BI_RGB;
  88.         bih.biSizeImage = 0;
  89.         bih.biXPelsPerMeter = 0;
  90.         bih.biYPelsPerMeter = 0;
  91.         bih.biClrUsed = 0;
  92.         bih.biClrImportant = 0;
  93.         fwrite(&bih, sizeof(bih), 1, output);
  94.  
  95.         // Color table
  96.         fwrite(rgba_colortable, sizeof(rgba_colortable), 1, output);
  97.  
  98.         // Image data
  99.         fwrite(padded_imagedata, newsize, 1, output);
  100.  
  101.         free(padded_imagedata);
  102.         #ifdef USE_BOTTOMUP
  103.         free(bmpData);
  104.         #endif
  105. }
  106.  
  107.