Newer
Older
Scratch / objgfx / ogBlit.cpp
#include <string.h>
#include <stdio.h>
#include <iostream>
#include "objgfx30.h"
#include "ogBlit.h"

using namespace std;

static bool
fileExists(const char *file)
{
  FILE *f = fopen(file, "r");
  if (!f)
    return false;
  fclose(f);
  return true;
}

ogBlit::ogBlit(void) {
  blitMask      = NULL;
  blitMaskSize  = 0;
  totalPixCount = 0;
  startX        = 0;
  startY        = 0;
  endX          = 0;
  endY          = 0;
  return;
} // ogBlit::ogBlit

void
ogBlit::blitSize(ogSurface& SrcObject, int32 x1, int32 y1, int32 x2, int32 y2) {
  int32  x,y;
  uInt8 zerocount;
  uInt8 pixcount;
  uInt32 bm;
  bool   inZeros;
  bool   found;

  // first free the image data or the blitMask data if we already have some
  
  free(image);
  delete [] blitMask;
  image = NULL;
  blitMask = NULL;
  imageSize = 0;
  blitMaskSize = 0;
  bm = (bitDepth+7) >> 3;
  tColour = SrcObject.ogGetTransparentColor();

  startX = x1;
  startY = y1;
  endX = x2;
  endY = y2;

  // start by locating the left-most non-transparent pixel in the region defined
  // by (x1,y1) to (x2,y2)
  found = false;
  while ((!found) && (startX<=x2)) {
    for (y=y1; y<=y2; y++)
      found |= (SrcObject.ogGetPixel(startX,y)!=tColour);
    if (!found) startX++;
  } // while
  // now we look for the top-most non-transparent pixel in the regsion defined by
  // (StartX,y1) to (x2,y2)
  found = false;
  while ((!found) && (startY<=y2)) {
    for (x=startX; x<=x2; x++)
      found |= (SrcObject.ogGetPixel(x,startY)!=tColour);
    if (!found) startY++;
  } // while
  found = false;
  while ((!found) && (endX>=startX)) {
    for (y=startY; y<=y2; y++)
      found |= (SrcObject.ogGetPixel(endX,y)!=tColour);
    if (!found) endX--;
  } // while
  found = false;
  while ((!found) && (endY>=startY)) {
    for (x=startX; x<=endX; x++)
      found |= (SrcObject.ogGetPixel(x,endY)!=tColour);
    if (!found) endY--;
  } // while

  for (y = startY; y <= endY; y++) {
    zerocount = 0;
    blitMaskSize++;  // save room for xlcount
    x = startX;
    inZeros = (SrcObject.ogGetPixel(x,y)==tColour);
    while (x<=endX) {
      switch (inZeros) {
        case true:
          zerocount = 0;  // How many zeros?
          while ((x<=endX) && (SrcObject.ogGetPixel(x,y)==tColour)) {
            x++;
            if (zerocount == 255) {
              zerocount = 0;
              blitMaskSize += 2;
            } else zerocount++;
          } // while
          inZeros = false;
          break; // case true
        case false:
          pixcount = 0;
          blitMaskSize += 2;
          do {
            x++;
            if (pixcount == 255) {
              blitMaskSize += 2;
              pixcount = 0;
            } else pixcount++;
            totalPixCount++;
            imageSize += bm;
          } while ((x<=endX) && (SrcObject.ogGetPixel(x,y)!=tColour));
          inZeros = true;
          break; // case false
      } // switch
    } // while
  } // for

  startX -= x1;
  startY -= y1;
  endX -= x1;
  endY -= y1;

  blitMask = new uInt8[blitMaskSize]; //(uInt8 *)malloc(blitMaskSize);
//  memset(blitMask,0,blitMaskSize);
  return;
} // ogBlit::blitSize

void
ogBlit::getBlitMask(ogSurface& SrcObject, int32 x1, int32 y1) {
  uInt8 * blitMaskPtr;
  uInt8 * lineCountPtr;
  uInt32 bm;
  int32 x,y;
  bool inZeros;
  uInt8 pixCount, zeroCount;

  if (blitMask==NULL) return;
  blitMaskPtr = blitMask;
  bm = (bitDepth+7) >> 3;
// This is done elsewhere  tColour = SrcObject.ogGetTransparentColor();

  for (y = y1+startY; y <= y1+endY; y++) {
    zeroCount = 0;
    lineCountPtr = blitMaskPtr;
    *lineCountPtr = 0;
    blitMaskPtr++;
    x = x1+startX;
    inZeros = (SrcObject.ogGetPixel(x,y)==tColour);
    while (x<=x1+endX) {
      switch (inZeros) {
        case true:
          zeroCount = 0;
          while ((x<=x1+endX) && (SrcObject.ogGetPixel(x,y)==tColour)) {
            x++;
            if (zeroCount == 255) {
              (*lineCountPtr)++;
              *blitMaskPtr = 255;     // offset
              blitMaskPtr++;          // increment to next byte
              *blitMaskPtr = 0;       // runcount
              blitMaskPtr++;          // increment to next byte
              *blitMaskPtr = 0;       // offset
              zeroCount = 0;
            } else zeroCount++;
          } // while
          inZeros = false;  // we are no longer in zeros}
          break; // case true
        case false:
          (*lineCountPtr)++;
          *blitMaskPtr = zeroCount;
          blitMaskPtr++;
          *blitMaskPtr = 0;
          pixCount = 0;
          do {
            x++;
            if (pixCount == 255) {
              (*lineCountPtr)++;
              *blitMaskPtr = 255;     // runcount
              blitMaskPtr++;          // advance pointer
              *blitMaskPtr = 0;       // offset to next run
              blitMaskPtr++;          // advance pointer
              *blitMaskPtr = 0;       // next run count (incremented below)
              pixCount = 0;
            } else pixCount++;
            (*blitMaskPtr)++;
         } while ((x<=(x1+endX)) &&
                   (SrcObject.ogGetPixel(x,y)!=tColour));
          blitMaskPtr++;
          inZeros = true;      // set inZeros to true to toggle
          break; // case false
      } // switch
    } // while
  } // for
  return;
} // ogBlit::getBlitMask

void
ogBlit::get(ogSurface& SrcObject, int32 x1, int32 y1, int32 x2, int32 y2) {
  int32 tmp;
  ogPixelFmt pixfmt;
  
  if (x1 > x2) {
    tmp = x1;
    x1  = x2;
    x2  = tmp;
  } // if

  if (y1 > y2) {
    tmp = y1;
    y1  = y2;
    y2  = tmp;
  } // if

  width = (x2-x1)+1;
  height = (y2-y1)+1;
  
  SrcObject.ogGetPixFmt(pixfmt);

  bitDepth = pixfmt.BPP;
  RFP = pixfmt.redFieldPosition;
  GFP = pixfmt.greenFieldPosition;
  BFP = pixfmt.blueFieldPosition;
  AFP = pixfmt.alphaFieldPosition;
  RShift = 8-pixfmt.redMaskSize;
  GShift = 8-pixfmt.greenMaskSize;
  BShift = 8-pixfmt.blueMaskSize;
  AShift = 8-pixfmt.alphaMaskSize;

  if (bitDepth == 8) {
    if (pal==NULL) pal = new ogRGBA[256];
    for (tmp=0; tmp<256; tmp++)
      SrcObject.ogUnpackRGB(tmp,pal[tmp].red, pal[tmp].green, pal[tmp].blue);
//    memcpy(pal, SrcObject.pal, sizeof(ogRGBA)*256);
  } // if

  blitSize(SrcObject, x1, y1, x2, y2);
  getBlitMask(SrcObject, x1, y1);
  getBlitWithMask(SrcObject, x1, y1);
  return;
} // ogBlit::get()

void
ogBlit::getBlitWithMask(ogSurface& SrcObject, int32 x, int32 y) {
 /*
  * getBlitWithMask
  *
  * Retrieves the data portion of a blit using a predefined mask and
  * stores the data in the Image pointer.  If the source buffer is
  * a different pixel format, we will adjust the image pointer
  * to accommodate the new data and update the pixel format.  The put()
  * function will adjust the pixels to the dest buffer as needed.
  * Before calling this routine, you must call getBlitMask.
  */

  int32   sx, sy;
  uInt8   lineCount, offset, pixCount;
  uInt32  nsy, ney;    // new start y, new end y
  uInt8 * blitMaskPtr;
  void *  imagePtr;
  uInt32  distToEdge, bm, xRight, count;
  ogPixelFmt pixfmt;
  
  // can we draw anything?
  if (blitMask==NULL) return;
  // see if the blit is outside the buffer
  if ( (x+startX > (int32)SrcObject.ogGetMaxX()) || (x+endX<0) ||
       (y+startY > (int32)SrcObject.ogGetMaxY()) || (y+endY<0)) return;
  blitMaskPtr = blitMask;

  // first check to see if the pixel format we get the blitmask from is
  // different than what we're dealing with now.
  SrcObject.ogGetPixFmt(pixfmt);
  if ( (bitDepth!=pixfmt.BPP) ||
       (RFP!=pixfmt.redFieldPosition) ||
       (GFP!=pixfmt.greenFieldPosition) ||
       (BFP!=pixfmt.blueFieldPosition) ) {
    if (image!=NULL) free(image);
    image     = NULL;
    imageSize = 0;
    bitDepth  = pixfmt.BPP;
    RFP       = pixfmt.redFieldPosition;
    GFP       = pixfmt.greenFieldPosition;
    BFP       = pixfmt.blueFieldPosition;
    AFP       = pixfmt.alphaFieldPosition;
    RShift    = 8-pixfmt.redMaskSize;
    GShift    = 8-pixfmt.greenMaskSize;
    BShift    = 8-pixfmt.blueMaskSize;
    AShift    = 8-pixfmt.alphaMaskSize;
  } // if

  bm = (bitDepth+7) >> 3; // bit multiplier

  if (image==NULL) {
    imageSize = totalPixCount*bm;
    image = malloc(imageSize);
  } // if
  imagePtr = image;

  // If any part of the blit data is out of bounds, we need to fill it with the
  // transparent colour
  if ((x+startX<0) || (x+endX>(int32)SrcObject.ogGetMaxX()) ||
      (y+startY<0) || (y+endY>(int32)SrcObject.ogGetMaxY())) {
    for (count=0; count<totalPixCount; count++) {
      setPixel(imagePtr,tColour);
      (uInt8 *)imagePtr+=bm;
    } // for
    imagePtr = image;  // reset the image ptr
  } // if
  
  // first do clipping on the top edge
  nsy = startY;
  if (y+startY<0) {
    /*
     *  If we're here then part of the blit is above the top edge of the
     *  buffer.  The distance to the top of the buffer is abs(y+startY).
     *  So, we need to loop through the blit geometry and advance the
     *  relative pointers (BlitMaskPtr and ImagePtr)
     */
    for (sy = (y+startY); sy<0; sy++) {
      nsy++;
      lineCount = *blitMaskPtr;
      blitMaskPtr++;
      while (lineCount>0) {
        blitMaskPtr++;
        pixCount = *blitMaskPtr;
        blitMaskPtr++;
        if (pixCount>0) (uInt8 *)imagePtr+=pixCount*bm;
        lineCount--;
      } // while
    } // for sy
  } // if

  // Now do clipping on the bottom edge. This is easy.
  if (y+endY>(int32)SrcObject.ogGetMaxY())
    ney = (SrcObject.ogGetMaxY()-y);
  else
    ney = endY;

  for (sy = nsy; (uInt32)sy <= ney; sy++) {
    sx = x+startX;
    lineCount = *blitMaskPtr;
    blitMaskPtr++;
    while (lineCount>0) {
      offset = *blitMaskPtr;
      blitMaskPtr++;
      sx += offset;
      pixCount = *blitMaskPtr;
      blitMaskPtr++;
      if (pixCount>0) {
        if (sx<=(int32)SrcObject.ogGetMaxX()) {
          if ((sx<0) && (sx+pixCount>0)) {
            pixCount += sx;              // remember, sx is negative
            (uInt8*)imagePtr -= sx*bm;   // remember, sx is negative
            sx=0;
          } // if sx<0 && sx+pixcount>0

          if (sx+pixCount>(int32)SrcObject.ogGetMaxX()+1) {
            distToEdge = (SrcObject.ogGetMaxX()-sx)+1;
            xRight = (pixCount - distToEdge)*bm;
            pixCount = distToEdge;
          } else xRight = 0; // if sx+pixCount>MaxX

          if (sx>=0)
            SrcObject.ogCopyLineFrom(sx,y+sy,imagePtr,pixCount*bm);
//            memcpy(imagePtr,                                // dest
//                   ((uInt8*)SrcObject.Buffer+SrcObject.LineOfs[y+sy]+sx*bm),
//                   pixCount*bm);
          (uInt8*)imagePtr += xRight;
        } // if sx <= MaxX
        sx += pixCount;
        (uInt8*)imagePtr += pixCount*bm;
      } // if pixCount>0
      lineCount--;
    } // while
  } // for

  return;
} // ogBlit::getBlitWithMask

uInt32
ogBlit::getSize(void) {
  return ogSprite::getSize() +
           sizeof(totalPixCount) +
           sizeof(blitMaskSize) +
           blitMaskSize +
           sizeof(startX) +
           sizeof(startY) +
           sizeof(endX) +
           sizeof(endY);
} // ogBlit::getSize

bool
ogBlit::loadFrom(const char * filename, uInt32 offset) {
  FILE * infile;
  uInt32 lresult, tresult, totSize;
  uInt32 tmpSize;
  char header_ident[4];

  if (fileExists(filename)==false) return false;
  if ((infile = fopen(filename,"rb"))==NULL) return false;
  fseek(infile, offset, SEEK_SET);

  // for now just free up the previous image.  This will be changed
  // later so it doesn't affect the current image (if any) if there
  // is a failure loading

  free(image);
  delete [] pal;
  delete [] blitMask;
  imageSize = 0;
  blitMaskSize = 0;

  tresult = 0;   // total bytes we've read in so far
  
  lresult = fread(header_ident, sizeof(header_ident), 1, infile);
  tresult += lresult*sizeof(header_ident);
  if ((header_ident[0]!='B') ||
      (header_ident[1]!='L') ||
      (header_ident[2]!='T') ||
      (header_ident[3]!=(char)0x1A)) {
    fclose(infile);
    return false;
  }
  lresult = fread(&totSize, sizeof(totSize), 1, infile);
  tresult += lresult*sizeof(totSize);

  lresult = fread(&width, sizeof(width), 1, infile);
  tresult += lresult*sizeof(width);

  lresult = fread(&height, sizeof(height), 1, infile);
  tresult += lresult*sizeof(height);

  lresult = fread(&bitDepth, sizeof(bitDepth), 1, infile);
  tresult += lresult*sizeof(bitDepth);

  lresult = fread(&RFP, sizeof(RFP), 1, infile);
  tresult += lresult*sizeof(RFP);

  lresult = fread(&GFP, sizeof(GFP), 1, infile);
  tresult += lresult*sizeof(GFP);

  lresult = fread(&BFP, sizeof(BFP), 1, infile);
  tresult += lresult*sizeof(BFP);

  lresult = fread(&AFP, sizeof(AFP), 1, infile);
  tresult += lresult*sizeof(AFP);

  lresult = fread(&RShift, sizeof(RShift), 1, infile);
  tresult += lresult*sizeof(RShift);
  
  lresult = fread(&GShift, sizeof(GShift), 1, infile);
  tresult += lresult*sizeof(GShift);
  
  lresult = fread(&BShift, sizeof(BShift), 1, infile);
  tresult += lresult*sizeof(BShift);
  
  lresult = fread(&AShift, sizeof(AShift), 1, infile);
  tresult += lresult*sizeof(AShift);

  lresult = fread(&tColour, sizeof(tColour), 1, infile);
  tresult += lresult*sizeof(tColour);

  lresult = fread(&totalPixCount, sizeof(totalPixCount), 1, infile);
  tresult += lresult*sizeof(totalPixCount);
  
  lresult = fread(&startX, sizeof(startX), 1, infile);
  tresult += lresult*sizeof(startX);

  lresult = fread(&startY, sizeof(startY), 1, infile);
  tresult += lresult*sizeof(startY);

  lresult = fread(&endX, sizeof(endX), 1, infile);
  tresult += lresult*sizeof(endX);

  lresult = fread(&endY, sizeof(endY), 1, infile);
  tresult += lresult*sizeof(endY);

  lresult = fread(&blitMaskSize, sizeof(blitMaskSize), 1, infile);
  tresult += lresult*sizeof(blitMaskSize);

  lresult = fread(&imageSize, sizeof(imageSize), 1, infile);
  tresult += lresult*sizeof(imageSize);
  
  blitMask = new uInt8[blitMaskSize];
  if (blitMask == NULL) {
    fclose(infile);
    return false;
  }
  
  image = malloc(imageSize);
  if (image == NULL) {
    fclose(infile);
    return false;
  }

  // read in the blit mask
  lresult = fread(blitMask, blitMaskSize, 1, infile);
  tresult += lresult*blitMaskSize;

  // read in the image data
  // it's possible that if we start saving only blit masks this section will be
  // blank
  lresult = fread(image, 1, imageSize, infile);
  tresult += lresult;

  if (bitDepth==8) {
    // 8bpp sprites have palettes
    if (pal==NULL) pal = new ogRGBA[256];
    if (pal==NULL) {
      fclose(infile);
      return false;
    } // if pal==NULL
    lresult = fread(&tmpSize, sizeof(tmpSize), 1, infile);
    tresult += lresult*sizeof(tmpSize);
    if (tmpSize>sizeof(ogRGBA)*256) {
      fclose(infile);
      return false;
    }
    lresult = fread(pal, tmpSize, 1, infile);
    tresult += lresult*tmpSize;
  } // if bitDepth == 8

  fclose(infile);
  return (tresult == totSize);
} // ogBlit::loadFrom

void
ogBlit::put(ogSurface& DestObject, int32 x, int32 y) {
  int32  sx, sy;
  uInt32 nsy, ney;
  uInt8  lineCount, offset, pixCount;
  uInt8* blitMaskPtr;
  void * imagePtr;
  uInt32 distToEdge, bm, xRight, xx;
  uInt8  r, g, b;
  ogPixelFmt pixfmt;
  
  // can we draw anything?
  if ((blitMask==NULL) || (image==NULL)) return;
  if (DestObject.ogAvail()==false) return;
  // see if the blit is oustide the buffer
  if ( ((x+startX)>(int32)DestObject.ogGetMaxX()) ||
       ((y+startY)>(int32)DestObject.ogGetMaxY()) ||
       ((x+endX)<0) || ((y+endY)<0) ) return;

  blitMaskPtr = blitMask;
  imagePtr = image;

  bm = (bitDepth+7) >> 3;

  // first do clipping on the top edge
  nsy = startY;
  if (y+startY<0) {
    /*
     *  If we're here then part of the blit is above the top edge of the
     *  buffer.  The distance to the top of the buffer is abs(y+startY).
     *  So, we need to loop through the blit geometry and advance the
     *  relative pointers (BlitMaskPtr and ImagePtr)
     */
    for (sy = (y+startY); sy<0; sy++) {
      nsy++;
      lineCount = *blitMaskPtr;
      blitMaskPtr++;
      while (lineCount>0) {
        blitMaskPtr++;
        pixCount = *blitMaskPtr;
        blitMaskPtr++;
        if (pixCount>0) (uInt8 *)imagePtr+=pixCount*bm;
        lineCount--;
      } // while
    } // for sy
  } // if

  // Now do clipping on the bottom edge. This is easy
  // y is guaranteed to be >=0
  if (y+endY>(int32)DestObject.ogGetMaxY())
    ney = (DestObject.ogGetMaxY()-y);
  else
    ney = endY;

  DestObject.ogGetPixFmt(pixfmt);

  if ( (pixfmt.BPP != bitDepth) ||
       (pixfmt.redFieldPosition != RFP) ||
       (pixfmt.greenFieldPosition != GFP) ||
       (pixfmt.blueFieldPosition != BFP)) {
    for (sy = nsy; (uInt32)sy <= ney; sy++) {
      sx = x+startX;
      lineCount = *blitMaskPtr;
      blitMaskPtr++;
      while (lineCount>0) {
        offset = *blitMaskPtr;
        blitMaskPtr++;
        sx += offset;
        pixCount = *blitMaskPtr;
        blitMaskPtr++;
        if (pixCount>0) {
          if (sx<=(int32)DestObject.ogGetMaxX()) {
            if ((sx<0) && (sx+(int32)pixCount>0)) {
              pixCount += sx;             // remember, sx is negative
              (uInt8*)imagePtr -= sx*bm;  // remember, sx is negative
              sx = 0;
            } // if sx<0 && sx+pixCount>0
            if (sx+pixCount>(int32)DestObject.ogGetMaxX()) {
              distToEdge = (DestObject.ogGetMaxX()-sx)+1;
              xRight = (pixCount-distToEdge)*bm;
              pixCount = distToEdge;
            } else xRight = 0; // if sx+pixCount>MaxX
            if (sx>=0)
              for (xx=0; xx<pixCount; xx++) {
                unpackRGB(getPixel((uInt8*)imagePtr+(xx*bm)),r,g,b);
                DestObject.ogSetPixel(sx+xx,sy+y,DestObject.ogRGB(r,g,b));
              } // for
            (uInt8*)imagePtr+=xRight;
          } // if sx <= MaxX
          sx += pixCount;
          (uInt8*)imagePtr += pixCount*bm;
        } // if pixCount != 0
        lineCount--;
      } // while
    } // for
  } else {
    for (sy = nsy; (uInt32)sy <= ney; sy++) {
      sx = x+startX;
      lineCount = *blitMaskPtr;
      blitMaskPtr++;
      while (lineCount>0) {
        offset = *blitMaskPtr;
        blitMaskPtr++;
        sx += offset;
        pixCount = *blitMaskPtr;
        blitMaskPtr++;
        if (pixCount>0) {
          if (sx<=(int32)DestObject.ogGetMaxX()) {
            if ((sx<0) && (sx+pixCount>0)) {
              pixCount += sx;             // remember, sx is negative
              (uInt8*)imagePtr -= sx*bm;  // remember, sx is negative
              sx = 0;
            } // if sx<0 && sx+pixCount>0

            if (sx+pixCount>(int32)DestObject.ogGetMaxX()+1) {
              distToEdge = (DestObject.ogGetMaxX()-sx)+1;
              xRight = (pixCount - distToEdge)*bm;
              pixCount = distToEdge;
            } else xRight = 0; // if sx+pixCount>MaxX

            if (sx>=0)
              DestObject.ogCopyLineTo(sx,y+sy,imagePtr,pixCount*bm);
//              memcpy( ((uInt8*)DestObject.Buffer+DestObject.LineOfs[y+sy]+sx*bm),
//                      imagePtr,
//                      pixCount*bm);
            (uInt8*)imagePtr += xRight;
          } // if sx <= MaxX
          sx += pixCount;
          (uInt8*)imagePtr += pixCount*bm;
        } // if pixCount>0
        lineCount--;
      } // while
    } // for
  } // else

  return;
} // ogBlit::put
bool
ogBlit::saveTo(const char * filename, int32 offset) {
  /*
   * saveTo
   *
   * saves a blit to disk.  If the file doesn't exit then we will create
   * a new one (doing this will ignore any specified offset).  If the file
   * exists, we will seek to the specified offset and place the bitmap there.
   * If offset is -1, then we seek to the end of the file.
   *
   * This function will fail on files larger than 2GB.
   *
   */
  FILE * outfile = NULL;
  char header_ident[4];
  uInt32 tmpSize;
  
  if (image==NULL) return false;
  if ((bitDepth==8) && (pal==NULL)) return false;

  if (fileExists(filename)==false) {        // file doesn't exist
    if ((outfile = fopen(filename,"wb")) == NULL) return false;
  } else {
    // file exists. Now we check to see where we put it
    if (offset==-1) {
      if ((outfile = fopen(filename, "ab")) == NULL) return false;
    } else {
      // we have an existing file and an offset to place the data
      if ((outfile = fopen(filename, "wb")) == NULL) return false;
      if (offset!=0) fseek(outfile, offset, SEEK_SET);
    } // else
  } // else

  tmpSize = getSize();
  
  header_ident[0] = 'B';
  header_ident[1] = 'L';
  header_ident[2] = 'T';
  header_ident[3] = (char)0x1A;  // EOF marker

  // we store exactly how bit this sucker is inside the header. This includes
  // the header information before it, and the size itself
  fwrite(header_ident, sizeof(header_ident), 1, outfile);

  fwrite(&tmpSize, sizeof(tmpSize), 1, outfile);
  fwrite(&width, sizeof(width), 1, outfile);
  fwrite(&height, sizeof(height), 1, outfile);
  fwrite(&bitDepth, sizeof(bitDepth), 1, outfile);

  fwrite(&RFP, sizeof(RFP), 1, outfile);
  fwrite(&GFP, sizeof(GFP), 1, outfile);
  fwrite(&BFP, sizeof(BFP), 1, outfile);
  fwrite(&AFP, sizeof(AFP), 1, outfile);

  fwrite(&RShift, sizeof(RShift), 1, outfile);
  fwrite(&GShift, sizeof(GShift), 1, outfile);
  fwrite(&BShift, sizeof(BShift), 1, outfile);
  fwrite(&AShift, sizeof(AShift), 1, outfile);

  fwrite(&tColour, sizeof(tColour), 1, outfile);
  fwrite(&totalPixCount, sizeof(totalPixCount), 1, outfile);

  fwrite(&startX, sizeof(startX), 1, outfile);
  fwrite(&startY, sizeof(startY), 1, outfile);
  fwrite(&endX, sizeof(endX), 1, outfile);
  fwrite(&endY, sizeof(endY), 1, outfile);

  fwrite(&blitMaskSize, sizeof(blitMaskSize), 1, outfile);
  fwrite(&imageSize, sizeof(imageSize), 1, outfile);

  fwrite(blitMask, blitMaskSize, 1, outfile);
  fwrite(image, 1, imageSize, outfile);

  if (bitDepth == 8) {
    tmpSize = sizeof(ogRGBA)*256;
    fwrite(&tmpSize, sizeof(tmpSize), 1, outfile);
    fwrite(pal, sizeof(ogRGBA), 256, outfile);
  } // if bitDepth == 8

  fclose(outfile);
  return true;
} // ogBlit::saveTo

ogBlit::~ogBlit(void) {
  delete [] blitMask;
  blitMask = NULL;
  blitMaskSize = 0;
  return;
} // ogBlit::~ogBlit