Simplified Doodle Jump game for mbed

Dependencies:   4DGL-uLCD-SE LSM9DS1_Library_cal SDFileSystem mbed-rtos mbed wave_player

myBMP/myBMP.cpp

Committer:
bhill42
Date:
2016-03-15
Revision:
3:141c57be5a2d
Parent:
1:bdeb188cb474

File content as of revision 3:141c57be5a2d:

#include "myBMP.h"

int BitDepth = 1;
int Width = 1;
int Height = 1;
RGBApixel *Colors;

bool SafeFread( char* buffer, int size, int number, FILE* fp )
{
 using namespace std;
 int ItemsRead;
 if( feof(fp) )
 { return false; }
 ItemsRead = (int) fread( buffer , size , number , fp );
 if( ItemsRead < number )
 { return false; }
 return true;
}


RGBApixel GetColor( int ColorNumber)
{ 
 RGBApixel Output;
 Output.Red   = 255;
 Output.Green = 255;
 Output.Blue  = 255;
 Output.Alpha = 0;
 
 if( BitDepth != 1 && BitDepth != 4 && BitDepth != 8 )
 {
  return Output;
 }
 if( !Colors )
 {
  return Output; 
 }
 Output = Colors[ColorNumber];
 return Output;
}

bool Read8bitRow(  ebmpBYTE* Buffer, int BufferSize, int Row, uLCD_4DGL *lcd)
{
 int i;
 if( Width > BufferSize )
 { return false; }
 for( i=0 ; i < Width ; i++ )
 {
    int Index = Buffer[i];
     //Blue, Green, Red, Alpha
    RGBApixel colors = GetColor(Index);
    int color = 0x00000000 | (colors.Red<< 16) | (colors.Blue << 8) | (colors.Green);
    (*lcd).pixel((130-Width)/2+i,(130-Height)/2+Row,color);
 }
 return true;
}

bool Read4bitRow(  ebmpBYTE* Buffer, int BufferSize, int Row, uLCD_4DGL *lcd)
{
 int Shifts[2] = {4  ,0 };
 int Masks[2]  = {240,15};
 
 int i=0;
 int j;
 int k=0;
 if( Width > 2*BufferSize )
 { return false; }
 while( i < Width )
 {
  j=0;
  while( j < 2 && i < Width )
  {
   int Index = (int) ( (Buffer[k]&Masks[j]) >> Shifts[j]);
   RGBApixel colors = GetColor(Index);
   int color = 0x00000000 | (colors.Red<< 16) | (colors.Blue << 8) | (colors.Green);
   (*lcd).pixel((130-Width)/2+i,(130-Height)/2+Row,color);
   i++; j++;   
  }
  k++;
 }
 return true;
}









bool Read32bitRow( ebmpBYTE* Buffer, int BufferSize, int Row, uLCD_4DGL *lcd, int x, int y)
{ 
 int i;
 char Colors[4];
 if( Width*4 > BufferSize )
 { return false; }
 for( i=0 ; i < Width ; i++ )
 {
    memcpy( (char*) &(Colors), (char*) Buffer+4*i, 4 );
     //Blue, Green, Red, Alpha
    int color = 0x00000000 | (Colors[2] << 16) | (Colors[1] << 8) | (Colors[0]);
    (*lcd).pixel(x+i,y+Row,color);
 }
 return true;
}


bool Read24bitRow( ebmpBYTE* Buffer, int BufferSize, int Row, uLCD_4DGL *lcd, int x, int y)
{ 
 int i;
 for( i=0 ; i < Width ; i++ )
 {
    int color = 0x00000000 | (Buffer[3*i+2] << 16) | (Buffer[3*i+1] << 8) | (Buffer[3*i+0]);
    (*lcd).pixel(x+i,y+Row,color);
 }
 return true;
}


bool Read8bitRow(  ebmpBYTE* Buffer, int BufferSize, int Row, uLCD_4DGL *lcd, int x, int y)
{
 int i;
 if( Width > BufferSize )
 { return false; }
 for( i=0 ; i < Width ; i++ )
 {
    int Index = Buffer[i];
     //Blue, Green, Red, Alpha
    RGBApixel colors = GetColor(Index);
    int color = 0x00000000 | (colors.Red<< 16) | (colors.Blue << 8) | (colors.Green);
    (*lcd).pixel(x+i,y+Row,color);
 }
 return true;
}


bool Read4bitRow(  ebmpBYTE* Buffer, int BufferSize, int Row, uLCD_4DGL *lcd, int x, int y)
{
 int Shifts[2] = {4  ,0 };
 int Masks[2]  = {240,15};
 
 int i=0;
 int j;
 int k=0;
 if( Width > 2*BufferSize )
 { return false; }
 while( i < Width )
 {
  j=0;
  while( j < 2 && i < Width )
  {
   int Index = (int) ( (Buffer[k]&Masks[j]) >> Shifts[j]);
   RGBApixel colors = GetColor(Index);
   int color = 0x00000000 | (colors.Red<< 16) | (colors.Blue << 8) | (colors.Green);
   (*lcd).pixel(x+i,y+Row,color);
   i++; j++;   
  }
  k++;
 }
 return true;
}


bool Read1bitRow(  ebmpBYTE* Buffer, int BufferSize, int Row, uLCD_4DGL *lcd, int x, int y)
{
 int Shifts[8] = {7  ,6 ,5 ,4 ,3,2,1,0};
 int Masks[8]  = {128,64,32,16,8,4,2,1};
 
 int i=0;
 int j;
 int k=0;
 
 if( Width > 8*BufferSize )
 { return false; }
 while( i < Width )
 {
  j=0;
  while( j < 8 && i < Width )
  {
   int Index = (int) ( (Buffer[k]&Masks[j]) >> Shifts[j]);
   RGBApixel colors = GetColor(Index);
   int color = 0x00000000 | (colors.Red<< 16) | (colors.Blue << 8) | (colors.Green);
   (*lcd).pixel(x+i,y+Row,color);
   i++; j++;   
  }
  k++;
 }
 return true;
}






bool Read32bitRow( ebmpBYTE* Buffer, int BufferSize, int Row, uLCD_4DGL *lcd)
{ 
 int i;
 char Colors[4];
 if( Width*4 > BufferSize )
 { return false; }
 for( i=0 ; i < Width ; i++ )
 {
    memcpy( (char*) &(Colors), (char*) Buffer+4*i, 4 );
     //Blue, Green, Red, Alpha
    int color = 0x00000000 | (Colors[2] << 16) | (Colors[1] << 8) | (Colors[0]);
    (*lcd).pixel((130-Width)/2+i,(130-Height)/2+Row,color);
 }
 return true;
}

bool Read24bitRow( ebmpBYTE* Buffer, int BufferSize, int Row, uLCD_4DGL *lcd)
{ 
 int i;
 char Colors[4];
 if( Width*3 > BufferSize )
 { return false; }
 for( i=0 ; i < Width ; i++ )
 {
    memcpy( (char*) &(Colors), (char*) Buffer+3*i, 3 );
     //Blue, Green, Red, Alpha
    int color = 0x00000000 | (Colors[2] << 16) | (Colors[1] << 8) | (Colors[0]);
    (*lcd).pixel((130-Width)/2+i,(130-Height)/2+Row,color);
 }
 return true;
}


bool Read1bitRow(  ebmpBYTE* Buffer, int BufferSize, int Row, uLCD_4DGL *lcd)
{
 int Shifts[8] = {7  ,6 ,5 ,4 ,3,2,1,0};
 int Masks[8]  = {128,64,32,16,8,4,2,1};
 
 int i=0;
 int j;
 int k=0;
 
 if( Width > 8*BufferSize )
 { return false; }
 while( i < Width )
 {
  j=0;
  while( j < 8 && i < Width )
  {
   int Index = (int) ( (Buffer[k]&Masks[j]) >> Shifts[j]);
   RGBApixel colors = GetColor(Index);
   int color = 0x00000000 | (colors.Red<< 16) | (colors.Blue << 8) | (colors.Green);
   (*lcd).pixel((130-Width)/2+i,(130-Height)/2+Row,color);
   i++; j++;   
  }
  k++;
 }
 return true;
}

int TellNumberOfColors( int BitDepth )
{
 int output = 1 << BitDepth;
 if( BitDepth == 32 )
 { output = 1 << 24; }
 return output;
}

bool ReadBMPFromFile( const char* FileName, RGBApixel *Colors, uLCD_4DGL *lcd)
{ 
 FILE* fp = fopen( FileName, "rb" );
 if( fp == NULL )
 {
  return false;
 }
 
 // read the file header 
 
 BMFH bmfh;
 bool NotCorrupted = true;
 
 NotCorrupted &= SafeFread( (char*) &(bmfh.bfType) , sizeof(ebmpWORD), 1, fp);
 
 bool IsBitmap = false;
 
 if( bmfh.bfType == 19778 )
 { IsBitmap = true; }
 
 if( !IsBitmap ) 
 {
  fclose( fp ); 
  return false;
 }

 NotCorrupted &= SafeFread( (char*) &(bmfh.bfSize) , sizeof(ebmpDWORD) , 1, fp); 
 NotCorrupted &= SafeFread( (char*) &(bmfh.bfReserved1) , sizeof(ebmpWORD) , 1, fp);
 NotCorrupted &= SafeFread( (char*) &(bmfh.bfReserved2) , sizeof(ebmpWORD) , 1, fp);
 NotCorrupted &= SafeFread( (char*) &(bmfh.bfOffBits) , sizeof(ebmpDWORD) , 1 , fp);
 
 // read the info header

 BMIH bmih; 
 
 NotCorrupted &= SafeFread( (char*) &(bmih.biSize) , sizeof(ebmpDWORD) , 1 , fp);
 NotCorrupted &= SafeFread( (char*) &(bmih.biWidth) , sizeof(ebmpDWORD) , 1 , fp); 
 NotCorrupted &= SafeFread( (char*) &(bmih.biHeight) , sizeof(ebmpDWORD) , 1 , fp);
 NotCorrupted &= SafeFread( (char*) &(bmih.biPlanes) , sizeof(ebmpWORD) , 1, fp); 
 NotCorrupted &= SafeFread( (char*) &(bmih.biBitCount) , sizeof(ebmpWORD) , 1, fp);

 NotCorrupted &= SafeFread( (char*) &(bmih.biCompression) , sizeof(ebmpDWORD) , 1 , fp);
 NotCorrupted &= SafeFread( (char*) &(bmih.biSizeImage) , sizeof(ebmpDWORD) , 1 , fp);
 NotCorrupted &= SafeFread( (char*) &(bmih.biXPelsPerMeter) , sizeof(ebmpDWORD) , 1 , fp);
 NotCorrupted &= SafeFread( (char*) &(bmih.biYPelsPerMeter) , sizeof(ebmpDWORD) , 1 , fp);
 NotCorrupted &= SafeFread( (char*) &(bmih.biClrUsed) , sizeof(ebmpDWORD) , 1 , fp);
 NotCorrupted &= SafeFread( (char*) &(bmih.biClrImportant) , sizeof(ebmpDWORD) , 1 , fp);
 
 // a safety catch: if any of the header information didn't read properly, abort
 // future idea: check to see if at least most is self-consistent
  
 if( !NotCorrupted )
 {
  fclose(fp);
  return false;
 } 
 
 // if bmih.biCompression 1 or 2, then the file is RLE compressed
 
 if( bmih.biCompression == 1 || bmih.biCompression == 2 )
 {
  fclose(fp);
  return false; 
 }
 
 // if bmih.biCompression > 3, then something strange is going on 
 // it's probably an OS2 bitmap file.
 
 if( bmih.biCompression > 3 )
 {
  fclose(fp);
  return false; 
 }
 
 if( bmih.biCompression == 3 && bmih.biBitCount != 16 )
 {
  fclose(fp);
  return false; 
 }

 // set the bit depth
 
 int TempBitDepth = (int) bmih.biBitCount;
 if(    TempBitDepth != 1  && TempBitDepth != 4 
     && TempBitDepth != 8  && TempBitDepth != 16
     && TempBitDepth != 24 && TempBitDepth != 32 )
 {
  fclose(fp);
  return false;
 }
 BitDepth = (int)bmih.biBitCount;
 // set the size

 if( (int) bmih.biWidth <= 0 || (int) bmih.biHeight <= 0 ) 
 {
  fclose(fp);
  return false;
 } 
 Width = (int) bmih.biWidth;
 Height = (int) bmih.biHeight;
 // some preliminaries
 
 double dBytesPerPixel = ( (double) BitDepth ) / 8.0;
 double dBytesPerRow = dBytesPerPixel * (Width+0.0);
 dBytesPerRow = ceil(dBytesPerRow);
  
 int BytePaddingPerRow = 4 - ( (int) (dBytesPerRow) )% 4;
 if( BytePaddingPerRow == 4 )
 { BytePaddingPerRow = 0; }  
 
 // if < 16 bits, read the palette
 
 if( BitDepth < 16 )
 {
  // determine the number of colors specified in the 
  // color table
  
  int NumberOfColorsToRead = ((int) bmfh.bfOffBits - 54 )/4;  
  if( NumberOfColorsToRead > (1 << BitDepth) )
  { NumberOfColorsToRead = (1 << BitDepth); }
 
  int n;
  for( n=0; n < NumberOfColorsToRead ; n++ )
  {
   SafeFread( (char*) &(Colors[n]) , 4 , 1 , fp);     
  }
  for( n=NumberOfColorsToRead ; n < TellNumberOfColors(BitDepth) ; n++ )
  {
   RGBApixel HWITE; 
   HWITE.Red = 255;
   HWITE.Green = 255;
   HWITE.Blue = 255;
   HWITE.Alpha = 0;
   Colors[n] = HWITE;
  }
 }
 
 // skip blank data if bfOffBits so indicates
 
 int BytesToSkip = bmfh.bfOffBits - 54;;
 if( BitDepth < 16 )
 { BytesToSkip -= 4*(1 << BitDepth); }
 if( BitDepth == 16 && bmih.biCompression == 3 )
 { BytesToSkip -= 3*4; }
 if( BytesToSkip < 0 )
 { BytesToSkip = 0; }
 if( BytesToSkip > 0 && BitDepth != 16 )
 {
  ebmpBYTE* TempSkipBYTE;
  TempSkipBYTE = new ebmpBYTE [BytesToSkip];
  SafeFread( (char*) TempSkipBYTE , BytesToSkip , 1 , fp);   
  delete [] TempSkipBYTE;
 } 
  
 // This code reads 1, 4, 8, 24, and 32-bpp files 
 // with a more-efficient buffered technique.

 int i,j;
 if( BitDepth != 16 )
 {
  int BufferSize = (int) ( (Width*BitDepth) / 8.0 );
  while( 8*BufferSize < Width*BitDepth )
  { BufferSize++; }
  while( BufferSize % 4 )
  { BufferSize++; }
  ebmpBYTE* Buffer;
  Buffer = new ebmpBYTE [BufferSize];
  j= Height-1;
  while( j > -1 )
  {
   int BytesRead = (int) fread( (char*) Buffer, 1, BufferSize, fp );
   if( BytesRead < BufferSize )
   {
    j = -1; 
   }
   else
   {
    bool Success = false;
    if( BitDepth == 1  )
    { Success = Read1bitRow(  Buffer, BufferSize, j , lcd); }
    if( BitDepth == 4  )
    { Success = Read4bitRow(  Buffer, BufferSize, j , lcd); }
    if( BitDepth == 8  )
    { Success = Read8bitRow(  Buffer, BufferSize, j , lcd); }
    if( BitDepth == 24 )
    { Success = Read24bitRow( Buffer, BufferSize, j , lcd); }
    if( BitDepth == 32 )
    { Success = Read32bitRow( Buffer, BufferSize, j , lcd); }
    if( !Success )
    {
     j = -1;
    }
   }   
   j--;
  }
  delete [] Buffer; 
 }

 if( BitDepth == 16 )
 {
  int DataBytes = Width*2;
  int PaddingBytes = ( 4 - DataBytes % 4 ) % 4;

  // set the default mask
  
  ebmpWORD BlueMask = 31; // bits 12-16
  ebmpWORD GreenMask = 992; // bits 7-11
  ebmpWORD RedMask = 31744; // bits 2-6

  // read the bit fields, if necessary, to 
  // override the default 5-5-5 mask
  
  if( bmih.biCompression != 0 )
  {
   // read the three bit masks

   ebmpWORD TempMaskWORD;
  
   SafeFread( (char*) &RedMask , 2 , 1 , fp );
   SafeFread( (char*) &TempMaskWORD , 2, 1, fp );
  
   SafeFread( (char*) &GreenMask , 2 , 1 , fp );
   SafeFread( (char*) &TempMaskWORD , 2, 1, fp );

   SafeFread( (char*) &BlueMask , 2 , 1 , fp );
   SafeFread( (char*) &TempMaskWORD , 2, 1, fp );
  }
  
  // read and skip any meta data

  if( BytesToSkip > 0 )
  {
   ebmpBYTE* TempSkipBYTE;
   TempSkipBYTE = new ebmpBYTE [BytesToSkip];
   SafeFread( (char*) TempSkipBYTE , BytesToSkip , 1 , fp);
   delete [] TempSkipBYTE;   
  } 
  
  // determine the red, green and blue shifts
  
  int GreenShift = 0; 
  ebmpWORD TempShiftWORD = GreenMask;
  while( TempShiftWORD > 31 )
  { TempShiftWORD = TempShiftWORD>>1; GreenShift++; }  
  int BlueShift = 0;
  TempShiftWORD = BlueMask;
  while( TempShiftWORD > 31 )
  { TempShiftWORD = TempShiftWORD>>1; BlueShift++; }  
  int RedShift = 0;  
  TempShiftWORD = RedMask;
  while( TempShiftWORD > 31 )
  { TempShiftWORD = TempShiftWORD>>1; RedShift++; }  
  
  // read the actual pixels
  
  for( j=Height-1 ; j >= 0 ; j-- )
  {
   i=0;
   int ReadNumber = 0;
   while( ReadNumber < DataBytes )
   {
    ebmpWORD TempWORD;
    SafeFread( (char*) &TempWORD , 2 , 1 , fp );
    ReadNumber += 2;
  
    ebmpWORD Red = RedMask & TempWORD;
    ebmpWORD Green = GreenMask & TempWORD;
    ebmpWORD Blue = BlueMask & TempWORD;
                
    ebmpBYTE BlueBYTE = (ebmpBYTE) 8*(Blue>>BlueShift);
    ebmpBYTE GreenBYTE = (ebmpBYTE) 8*(Green>>GreenShift);
    ebmpBYTE RedBYTE = (ebmpBYTE) 8*(Red>>RedShift);
        
    int color = 0x00000000 | (RedBYTE << 16) | (GreenBYTE << 8) | (BlueBYTE);
    (*lcd).pixel((130-Width)/2+i,(130-Height)/2+j,color);
    i++;
   }
   ReadNumber = 0;
   while( ReadNumber < PaddingBytes )
   {
    ebmpBYTE TempBYTE;
    SafeFread( (char*) &TempBYTE , 1, 1, fp);
    ReadNumber++;
   }
  }

 }
 
 fclose(fp);
 return true;
}

bool ReadColorsFromFile(const char * FileName, RGBApixel *Colors, int * color_array, int x, int y)
{ 
    FILE* fp = fopen( FileName, "rb" );
    if( fp == NULL )
    {
        return false;
    }

    // read the file header 

    BMFH bmfh;
    bool NotCorrupted = true;

    NotCorrupted &= SafeFread( (char*) &(bmfh.bfType) , sizeof(ebmpWORD), 1, fp);

    bool IsBitmap = false;

    if( bmfh.bfType == 19778 )
    { IsBitmap = true; }

    if( !IsBitmap ) 
    {
        fclose( fp ); 
        return false;
    }

    NotCorrupted &= SafeFread( (char*) &(bmfh.bfSize) , sizeof(ebmpDWORD) , 1, fp); 
    NotCorrupted &= SafeFread( (char*) &(bmfh.bfReserved1) , sizeof(ebmpWORD) , 1, fp);
    NotCorrupted &= SafeFread( (char*) &(bmfh.bfReserved2) , sizeof(ebmpWORD) , 1, fp);
    NotCorrupted &= SafeFread( (char*) &(bmfh.bfOffBits) , sizeof(ebmpDWORD) , 1 , fp);

    // read the info header

    BMIH bmih; 

    NotCorrupted &= SafeFread( (char*) &(bmih.biSize) , sizeof(ebmpDWORD) , 1 , fp);
    NotCorrupted &= SafeFread( (char*) &(bmih.biWidth) , sizeof(ebmpDWORD) , 1 , fp); 
    NotCorrupted &= SafeFread( (char*) &(bmih.biHeight) , sizeof(ebmpDWORD) , 1 , fp);
    NotCorrupted &= SafeFread( (char*) &(bmih.biPlanes) , sizeof(ebmpWORD) , 1, fp); 
    NotCorrupted &= SafeFread( (char*) &(bmih.biBitCount) , sizeof(ebmpWORD) , 1, fp);

    NotCorrupted &= SafeFread( (char*) &(bmih.biCompression) , sizeof(ebmpDWORD) , 1 , fp);
    NotCorrupted &= SafeFread( (char*) &(bmih.biSizeImage) , sizeof(ebmpDWORD) , 1 , fp);
    NotCorrupted &= SafeFread( (char*) &(bmih.biXPelsPerMeter) , sizeof(ebmpDWORD) , 1 , fp);
    NotCorrupted &= SafeFread( (char*) &(bmih.biYPelsPerMeter) , sizeof(ebmpDWORD) , 1 , fp);
    NotCorrupted &= SafeFread( (char*) &(bmih.biClrUsed) , sizeof(ebmpDWORD) , 1 , fp);
    NotCorrupted &= SafeFread( (char*) &(bmih.biClrImportant) , sizeof(ebmpDWORD) , 1 , fp);

    // a safety catch: if any of the header information didn't read properly, abort
    // future idea: check to see if at least most is self-consistent

    if( !NotCorrupted )
    {
        fclose(fp);
        return false;
    } 

    // if bmih.biCompression 1 or 2, then the file is RLE compressed

    if( bmih.biCompression == 1 || bmih.biCompression == 2 )
    {
        fclose(fp);
        return false; 
    }

    // if bmih.biCompression > 3, then something strange is going on 
    // it's probably an OS2 bitmap file.

    if( bmih.biCompression > 3 )
    {
        fclose(fp);
        return false; 
    }

    if( bmih.biCompression == 3 && bmih.biBitCount != 16 )
    {
        fclose(fp);
        return false; 
    }

    // set the bit depth

    int TempBitDepth = (int) bmih.biBitCount;
    if(    TempBitDepth != 1  && TempBitDepth != 4 
    && TempBitDepth != 8  && TempBitDepth != 16
    && TempBitDepth != 24 && TempBitDepth != 32 )
    {
        fclose(fp);
        return false;
    }
    BitDepth = (int)bmih.biBitCount;
    // set the size

    if( (int) bmih.biWidth <= 0 || (int) bmih.biHeight <= 0 ) 
    {
        fclose(fp);
        return false;
    } 
    Width = (int) bmih.biWidth;
    Height = (int) bmih.biHeight;
    // some preliminaries

    double dBytesPerPixel = ( (double) BitDepth ) / 8.0;
    double dBytesPerRow = dBytesPerPixel * (Width+0.0);
    dBytesPerRow = ceil(dBytesPerRow);

    int BytePaddingPerRow = 4 - ( (int) (dBytesPerRow) )% 4;
    if( BytePaddingPerRow == 4 )
    { BytePaddingPerRow = 0; }  

    // if < 16 bits, read the palette

    if( BitDepth < 16 )
    {
    // determine the number of colors specified in the 
    // color table

    int NumberOfColorsToRead = ((int) bmfh.bfOffBits - 54 )/4;  
    if( NumberOfColorsToRead > (1 << BitDepth) )
    { NumberOfColorsToRead = (1 << BitDepth); }

    int n;
    for( n=0; n < NumberOfColorsToRead ; n++ )
    {
    SafeFread( (char*) &(Colors[n]) , 4 , 1 , fp);     
    }
    for( n=NumberOfColorsToRead ; n < TellNumberOfColors(BitDepth) ; n++ )
    {
        RGBApixel HWITE; 
        HWITE.Red = 255;
        HWITE.Green = 255;
        HWITE.Blue = 255;
        HWITE.Alpha = 0;
        Colors[n] = HWITE;
    }
    }

    // skip blank data if bfOffBits so indicates

    int BytesToSkip = bmfh.bfOffBits - 54;;
    if( BitDepth < 16 )
    { BytesToSkip -= 4*(1 << BitDepth); }
    if( BitDepth == 16 && bmih.biCompression == 3 )
    { BytesToSkip -= 3*4; }
    if( BytesToSkip < 0 )
    { BytesToSkip = 0; }
    if( BytesToSkip > 0 && BitDepth != 16 )
    {
        ebmpBYTE* TempSkipBYTE;
        TempSkipBYTE = new ebmpBYTE [BytesToSkip];
        SafeFread( (char*) TempSkipBYTE , BytesToSkip , 1 , fp);   
        delete [] TempSkipBYTE;
    } 

    // This code reads 1, 4, 8, 24, and 32-bpp files 
    // with a more-efficient buffered technique.

    int i,j;
    if( BitDepth != 16 )
    {
        int BufferSize = (int) ( (Width*BitDepth) / 8.0 );
        while( 8*BufferSize < Width*BitDepth )
        { BufferSize++; }
        while( BufferSize % 4 )
        { BufferSize++; }
        ebmpBYTE* Buffer;
        Buffer = new ebmpBYTE [BufferSize];
        j= Height-1;
        while( j > -1 )
        {
            int BytesRead = (int) fread( (char*) Buffer, 1, BufferSize, fp );
            if( BytesRead < BufferSize )
            {
                j = -1; 
            }
            else
            {
                bool Success = false;
                if( BitDepth == 1  )
                { return -1; }
                if( BitDepth == 4  )
                { return -1; }
                if( BitDepth == 8  )
                { return -1; }
                if( BitDepth == 24 )
                {
                    // don't do BufferSize bounds checking, also NOTE: only bothering for 24 because that is what our image uses
                    Success = true;
                    for(int i=0 ; i < Width ; i++ )
                    {
                        int color = 0x00000000 | (Buffer[3*i+2] << 16) | (Buffer[3*i+1] << 8) | (Buffer[3*i+0]);
                        color_array[Width*j + i] = color; // width * row + col
                        //(*lcd).pixel(x+i,y+j,color);
                    }
                }
                if( BitDepth == 32 )
                { return -1; }
                if( !Success )
                {
                    j = -1;
                }
            }   
            j--;
        }
        delete [] Buffer; 
    }

    if( BitDepth == 16 )
    {
        return -1;
    }

    fclose(fp);
    return true;
}

void DrawColorstoLCD(int * color_array, uLCD_4DGL *lcd, int x, int y, int w, int h) 
{
    for (int i = 0; i < w; i++)
    {
        for (int j = 0; j < h; j++)
        {
            (*lcd).pixel(x+i,y+j,color_array[w*j + i]);
        }
    }
}


BMIH::BMIH()
{
 biPlanes = 1;
 biCompression = 0;
 biXPelsPerMeter = DefaultXPelsPerMeter;  
 biYPelsPerMeter = DefaultYPelsPerMeter;
 biClrUsed = 0;
 biClrImportant = 0;
}

BMFH::BMFH()
{
 bfType = 19778;
 bfReserved1 = 0;
 bfReserved2 = 0;
}


bool ReadBMPFromFile(const char * FileName, RGBApixel *Colors, uLCD_4DGL *lcd, int x, int y)
{ 
    FILE* fp = fopen( FileName, "rb" );
    if( fp == NULL )
    {
        return false;
    }

    // read the file header 

    BMFH bmfh;
    bool NotCorrupted = true;

    NotCorrupted &= SafeFread( (char*) &(bmfh.bfType) , sizeof(ebmpWORD), 1, fp);

    bool IsBitmap = false;

    if( bmfh.bfType == 19778 )
    { IsBitmap = true; }

    if( !IsBitmap ) 
    {
        fclose( fp ); 
        return false;
    }

    NotCorrupted &= SafeFread( (char*) &(bmfh.bfSize) , sizeof(ebmpDWORD) , 1, fp); 
    NotCorrupted &= SafeFread( (char*) &(bmfh.bfReserved1) , sizeof(ebmpWORD) , 1, fp);
    NotCorrupted &= SafeFread( (char*) &(bmfh.bfReserved2) , sizeof(ebmpWORD) , 1, fp);
    NotCorrupted &= SafeFread( (char*) &(bmfh.bfOffBits) , sizeof(ebmpDWORD) , 1 , fp);

    // read the info header

    BMIH bmih; 

    NotCorrupted &= SafeFread( (char*) &(bmih.biSize) , sizeof(ebmpDWORD) , 1 , fp);
    NotCorrupted &= SafeFread( (char*) &(bmih.biWidth) , sizeof(ebmpDWORD) , 1 , fp); 
    NotCorrupted &= SafeFread( (char*) &(bmih.biHeight) , sizeof(ebmpDWORD) , 1 , fp);
    NotCorrupted &= SafeFread( (char*) &(bmih.biPlanes) , sizeof(ebmpWORD) , 1, fp); 
    NotCorrupted &= SafeFread( (char*) &(bmih.biBitCount) , sizeof(ebmpWORD) , 1, fp);

    NotCorrupted &= SafeFread( (char*) &(bmih.biCompression) , sizeof(ebmpDWORD) , 1 , fp);
    NotCorrupted &= SafeFread( (char*) &(bmih.biSizeImage) , sizeof(ebmpDWORD) , 1 , fp);
    NotCorrupted &= SafeFread( (char*) &(bmih.biXPelsPerMeter) , sizeof(ebmpDWORD) , 1 , fp);
    NotCorrupted &= SafeFread( (char*) &(bmih.biYPelsPerMeter) , sizeof(ebmpDWORD) , 1 , fp);
    NotCorrupted &= SafeFread( (char*) &(bmih.biClrUsed) , sizeof(ebmpDWORD) , 1 , fp);
    NotCorrupted &= SafeFread( (char*) &(bmih.biClrImportant) , sizeof(ebmpDWORD) , 1 , fp);

    // a safety catch: if any of the header information didn't read properly, abort
    // future idea: check to see if at least most is self-consistent

    if( !NotCorrupted )
    {
        fclose(fp);
        return false;
    } 

    // if bmih.biCompression 1 or 2, then the file is RLE compressed

    if( bmih.biCompression == 1 || bmih.biCompression == 2 )
    {
        fclose(fp);
        return false; 
    }

    // if bmih.biCompression > 3, then something strange is going on 
    // it's probably an OS2 bitmap file.

    if( bmih.biCompression > 3 )
    {
        fclose(fp);
        return false; 
    }

    if( bmih.biCompression == 3 && bmih.biBitCount != 16 )
    {
        fclose(fp);
        return false; 
    }

    // set the bit depth

    int TempBitDepth = (int) bmih.biBitCount;
    if(    TempBitDepth != 1  && TempBitDepth != 4 
     && TempBitDepth != 8  && TempBitDepth != 16
     && TempBitDepth != 24 && TempBitDepth != 32 )
    {
        fclose(fp);
        return false;
    }
    BitDepth = (int)bmih.biBitCount;
    // set the size

    if( (int) bmih.biWidth <= 0 || (int) bmih.biHeight <= 0 ) 
    {
        fclose(fp);
        return false;
    } 
    Width = (int) bmih.biWidth;
    Height = (int) bmih.biHeight;
    // some preliminaries

    double dBytesPerPixel = ( (double) BitDepth ) / 8.0;
    double dBytesPerRow = dBytesPerPixel * (Width+0.0);
    dBytesPerRow = ceil(dBytesPerRow);

    int BytePaddingPerRow = 4 - ( (int) (dBytesPerRow) )% 4;
    if( BytePaddingPerRow == 4 )
    { BytePaddingPerRow = 0; }  

    // if < 16 bits, read the palette

    if( BitDepth < 16 )
    {
    // determine the number of colors specified in the 
    // color table

    int NumberOfColorsToRead = ((int) bmfh.bfOffBits - 54 )/4;  
    if( NumberOfColorsToRead > (1 << BitDepth) )
    { NumberOfColorsToRead = (1 << BitDepth); }

    int n;
    for( n=0; n < NumberOfColorsToRead ; n++ )
    {
    SafeFread( (char*) &(Colors[n]) , 4 , 1 , fp);     
    }
    for( n=NumberOfColorsToRead ; n < TellNumberOfColors(BitDepth) ; n++ )
    {
    RGBApixel HWITE; 
    HWITE.Red = 255;
    HWITE.Green = 255;
    HWITE.Blue = 255;
    HWITE.Alpha = 0;
    Colors[n] = HWITE;
    }
    }

    // skip blank data if bfOffBits so indicates

    int BytesToSkip = bmfh.bfOffBits - 54;;
    if( BitDepth < 16 )
    { BytesToSkip -= 4*(1 << BitDepth); }
    if( BitDepth == 16 && bmih.biCompression == 3 )
    { BytesToSkip -= 3*4; }
    if( BytesToSkip < 0 )
    { BytesToSkip = 0; }
    if( BytesToSkip > 0 && BitDepth != 16 )
    {
    ebmpBYTE* TempSkipBYTE;
    TempSkipBYTE = new ebmpBYTE [BytesToSkip];
    SafeFread( (char*) TempSkipBYTE , BytesToSkip , 1 , fp);   
    delete [] TempSkipBYTE;
    } 

    // This code reads 1, 4, 8, 24, and 32-bpp files 
    // with a more-efficient buffered technique.

    int i,j;
    if( BitDepth != 16 )
    {
    int BufferSize = (int) ( (Width*BitDepth) / 8.0 );
    while( 8*BufferSize < Width*BitDepth )
    { BufferSize++; }
    while( BufferSize % 4 )
    { BufferSize++; }
    ebmpBYTE* Buffer;
    Buffer = new ebmpBYTE [BufferSize];
    j= Height-1;
    while( j > -1 )
    {
    int BytesRead = (int) fread( (char*) Buffer, 1, BufferSize, fp );
    if( BytesRead < BufferSize )
    {
    j = -1; 
    }
    else
    {
    bool Success = false;
    if( BitDepth == 1  )
    { Success = Read1bitRow(  Buffer, BufferSize, j , lcd, x, y); }
    if( BitDepth == 4  )
    { Success = Read4bitRow(  Buffer, BufferSize, j , lcd, x, y); }
    if( BitDepth == 8  )
    { Success = Read8bitRow(  Buffer, BufferSize, j , lcd, x, y); }
    if( BitDepth == 24 )
    { Success = Read24bitRow( Buffer, BufferSize, j , lcd, x, y); }
    if( BitDepth == 32 )
    { Success = Read32bitRow( Buffer, BufferSize, j , lcd, x, y); }
    if( !Success )
    {
     j = -1;
    }
    }   
    j--;
    }
    delete [] Buffer; 
    }

    if( BitDepth == 16 )
    {
    int DataBytes = Width*2;
    int PaddingBytes = ( 4 - DataBytes % 4 ) % 4;

    // set the default mask

    ebmpWORD BlueMask = 31; // bits 12-16
    ebmpWORD GreenMask = 992; // bits 7-11
    ebmpWORD RedMask = 31744; // bits 2-6

    // read the bit fields, if necessary, to 
    // override the default 5-5-5 mask

    if( bmih.biCompression != 0 )
    {
    // read the three bit masks

    ebmpWORD TempMaskWORD;

    SafeFread( (char*) &RedMask , 2 , 1 , fp );
    SafeFread( (char*) &TempMaskWORD , 2, 1, fp );

    SafeFread( (char*) &GreenMask , 2 , 1 , fp );
    SafeFread( (char*) &TempMaskWORD , 2, 1, fp );

    SafeFread( (char*) &BlueMask , 2 , 1 , fp );
    SafeFread( (char*) &TempMaskWORD , 2, 1, fp );
    }

    // read and skip any meta data

    if( BytesToSkip > 0 )
    {
    ebmpBYTE* TempSkipBYTE;
    TempSkipBYTE = new ebmpBYTE [BytesToSkip];
    SafeFread( (char*) TempSkipBYTE , BytesToSkip , 1 , fp);
    delete [] TempSkipBYTE;   
    } 

    // determine the red, green and blue shifts

    int GreenShift = 0; 
    ebmpWORD TempShiftWORD = GreenMask;
    while( TempShiftWORD > 31 )
    { TempShiftWORD = TempShiftWORD>>1; GreenShift++; }  
    int BlueShift = 0;
    TempShiftWORD = BlueMask;
    while( TempShiftWORD > 31 )
    { TempShiftWORD = TempShiftWORD>>1; BlueShift++; }  
    int RedShift = 0;  
    TempShiftWORD = RedMask;
    while( TempShiftWORD > 31 )
    { TempShiftWORD = TempShiftWORD>>1; RedShift++; }  

    // read the actual pixels

    for( j=Height-1 ; j >= 0 ; j-- )
    {
    i=0;
    int ReadNumber = 0;
    while( ReadNumber < DataBytes )
    {
    ebmpWORD TempWORD;
    SafeFread( (char*) &TempWORD , 2 , 1 , fp );
    ReadNumber += 2;

    ebmpWORD Red = RedMask & TempWORD;
    ebmpWORD Green = GreenMask & TempWORD;
    ebmpWORD Blue = BlueMask & TempWORD;
                
    ebmpBYTE BlueBYTE = (ebmpBYTE) 8*(Blue>>BlueShift);
    ebmpBYTE GreenBYTE = (ebmpBYTE) 8*(Green>>GreenShift);
    ebmpBYTE RedBYTE = (ebmpBYTE) 8*(Red>>RedShift);
        
    int color = 0x00000000 | (RedBYTE << 16) | (GreenBYTE << 8) | (BlueBYTE);
    (*lcd).pixel(x+i,y+j,color);
    i++;
    }
    ReadNumber = 0;
    while( ReadNumber < PaddingBytes )
    {
    ebmpBYTE TempBYTE;
    SafeFread( (char*) &TempBYTE , 1, 1, fp);
    ReadNumber++;
    }
    }

    }

    fclose(fp);
    return true;
}