Simplified Doodle Jump game for mbed

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

Files at this revision

API Documentation at this revision

Comitter:
bhill42
Date:
Tue Mar 15 02:34:14 2016 +0000
Parent:
2:e76f3f3c85c0
Commit message:
Final

Changed in this revision

LSM9DS1_Library_cal.lib Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
myBMP/myBMP.cpp Show annotated file Show diff for this revision Revisions of this file
myBMP/myBMP.h Show annotated file Show diff for this revision Revisions of this file
diff -r e76f3f3c85c0 -r 141c57be5a2d LSM9DS1_Library_cal.lib
--- a/LSM9DS1_Library_cal.lib	Mon Mar 14 20:36:52 2016 +0000
+++ b/LSM9DS1_Library_cal.lib	Tue Mar 15 02:34:14 2016 +0000
@@ -1,1 +1,1 @@
-https://developer.mbed.org/users/4180_1/code/LSM9DS1_Library_cal/#541db6c69ffa
+https://developer.mbed.org/users/bhill42/code/LSM9DS1_Library_cal/#541db6c69ffa
diff -r e76f3f3c85c0 -r 141c57be5a2d main.cpp
--- a/main.cpp	Mon Mar 14 20:36:52 2016 +0000
+++ b/main.cpp	Tue Mar 15 02:34:14 2016 +0000
@@ -1,16 +1,16 @@
-// uLCD-144-G2 demo program for uLCD-4GL LCD driver library
-//
+// Simple game of Doodle Jump with a BMP image, sound, and IMU control.
 #include "mbed.h"
 #include "rtos.h"
-#include "SDFileSystem.h"
-#include "uLCD_4DGL.h"
-#include "LSM9DS1.h"
-#include "wave_player.h"
-#include "myBMP.h"
+#include "SDFileSystem.h" /* SD card library */
+#include "uLCD_4DGL.h" /* LCD library */
+#include "LSM9DS1.h" /* IMU library */
+#include "wave_player.h" /* wav file playing */
+#include "myBMP.h" /* BMP image handling */
 #include <stdlib.h>     /* srand, rand */
 #include <time.h>       /* time */
-#define PI 3.14159
-#define DECLINATION -4.94 // Declination (degrees) in Atlanta,GA.
+
+//#define PI 3.14159
+//#define DECLINATION -4.94 // Declination (degrees) in Atlanta,GA.
 #define GRAVITY 3 /* acceleration per frame */
 #define MAX_PLATFORMS 5
 #define MAX_ENEMIES 2
@@ -24,21 +24,17 @@
 #define INIT_PLAYER_VELOCITY -15
 
 
-uLCD_4DGL uLCD(p28,p27,p30); // serial tx, serial rx, reset pin;
+uLCD_4DGL uLCD(p28,p27,p30); // serial tx, serial rx, reset pin
 LSM9DS1 IMU(p9, p10, 0xD6, 0x3C);
-
 SDFileSystem sd(p5, p6, p7, p8, "sd");
+AnalogOut DACout(p18); //analog out for speaker
+wave_player waver(&DACout);     
 
 DigitalOut myled1(LED1);
-DigitalOut myled2(LED2);
-DigitalOut myled3(LED3);
-DigitalOut myled4(LED4);
-AnalogOut DACout(p18); //analog out for speaker
-wave_player waver(&DACout);                    
-FILE *wave_file;
+DigitalOut myled2(LED2);               
 
 Mutex sound_mutex;
-Thread * t1 = NULL;
+Thread * t1 = NULL; // must set to null for initial delete, calling delete on a null pointer is safe
 
 typedef struct xycoord {
     int x;
@@ -46,15 +42,225 @@
 } xycoord; 
 
 xycoord platforms[MAX_PLATFORMS];
-xycoord enemies[MAX_ENEMIES];
-xycoord player;
-int player_velocity = INIT_PLAYER_VELOCITY;
-int absolute_y = 0;
+
+// play a song of given filename, void const * input for use with threads
+// thread safe, will not try to play more than one sound at once
+void playSound(void const * args);
+
+// return index of platform with lowest y coordinates (highest on screen)
+int getHighestPlatform();
+
+// return index of platform with highest y coordinates (lowst on screen)
+int getLowestPlatform();
+
+// if a generate x, y coordinates above highest platform
+void getNextPlatform(int &x, int &y);
+
+// create all platforms
+void initPlatforms();
 
-void playSound(void const * args) //play a song of given filename
+// try to play a sound, do nothing if mutex locked
+void trySound(const char * file);
+    
+int main()
+{
+    wait(2.0f); // wait a bit for initialization
+    uLCD.cls();
+    // jack up LCD baud rate to max for fast display
+    uLCD.baudrate(3000000); 
+    trySound("/sd/DMX.wav"); // play init sound
+  
+    // set up IMU
+    uLCD.printf("Calibrating IMU, place on flat surface. Please wait...");
+    IMU.begin();
+    if (!IMU.begin()) {
+        uLCD.printf("Failed to communicate with LSM9DS1.\n");
+        wait(5.0f);
+        return -1;
+    }
+    IMU.calibrate(1);
+    IMU.calibrateMag(0);
+    
+    //start countdown timer for player to start playing
+    
+    uLCD.cls();
+    uLCD.locate(0,8);
+    uLCD.printf("Starting in: 3");
+    wait(1.0f);
+    uLCD.cls();
+    uLCD.locate(0,8);
+    uLCD.printf("Starting in: 2");
+    wait(1.0f);
+    uLCD.cls();
+    uLCD.locate(0,8);
+    uLCD.printf("Starting in: 1");
+    wait(0.6f);
+    uLCD.cls();
+    uLCD.locate(0,15);
+    uLCD.printf("TA SAYS WHAT");
+    
+    
+    
+    //float fx=63.0,fy=63.0,vx=1.0,vy=0.4;
+    // x, y is player x and y, player_velocity is player movement in pixels/frame, absolute_y is the y pixels the camera has "moved" up, old_x old_y for drawing over old player image
+    int x = 64+(PLAYER_WIDTH + 1)/2, y = 127-PLAYER_HEIGHT; //,radius=4;
+    int player_velocity = INIT_PLAYER_VELOCITY;
+    int absolute_y = 0;
+    int old_x = x, old_y = y;
+    uLCD.background_color(BLACK);
+    
+    
+    
+    float ax; // accelerometer reading
+    
+    RGBApixel *Colors = new RGBApixel [2];
+    
+    // init random number generator, remove text from IMU
+    srand(time(0));
+    uLCD.cls();
+    
+    // initialize platforms and prepare them for drawing
+    initPlatforms();
+    int lowestPlatformIndex;
+    int platx;
+    int platy;
+    
+    // store the pixel values of player in memory to reduce the drawing time per frame
+    // note that this image should be small, mbed's memory is not very large
+    int * color_array = new int[PLAYER_WIDTH*PLAYER_HEIGHT];
+    ReadColorsFromFile("/sd/stardesu.bmp", Colors, color_array, x, y);
+    
+    // make score color white
+    uLCD.color(WHITE);
+    
+    // enter main game loop
+    while (1) 
+    {
+        // read from IMU
+        while(!IMU.accelAvailable());
+        IMU.readAccel();
+        ax = IMU.calcAccel(IMU.ax);
+        
+        // get lowest platform
+        lowestPlatformIndex = getLowestPlatform();
+        platx = platforms[lowestPlatformIndex].x;
+        platy = platforms[lowestPlatformIndex].y;
+        
+        // platform is off screen, create a new one
+        if (platy > 127)
+        {
+            getNextPlatform(platx, platy);
+            platforms[lowestPlatformIndex].y = platy;
+            platforms[lowestPlatformIndex].x = platx;
+        }
+        
+        // check collisions of player with platforms
+        for (int i = 0; i < MAX_PLATFORMS; i++)
+        {
+            if (player_velocity > 0 && (x+PLAYER_WIDTH) > platforms[i].x && x < (platforms[i].x + PLATFORM_WIDTH) && (y+PLAYER_HEIGHT) >= (platforms[i].y) && (y+PLAYER_HEIGHT) <= (platforms[i].y + PLATFORM_HEIGHT+7))
+            {
+                 player_velocity = INIT_PLAYER_VELOCITY;   
+                 y = platforms[i].y-(PLAYER_HEIGHT-1);
+                 // bounce sound
+                 trySound("/sd/DMX3.wav");
+                 break;
+            }
+        }
+        
+        
+        
+        //erase old player location by drawing over it
+        uLCD.filled_rectangle(old_x, old_y, old_x+PLAYER_WIDTH, old_y+PLAYER_HEIGHT, BLACK);
+        
+        // if player is at middle of screen, stop moving player and start moving platforms relative to player
+        // "halfway point" is at pixal 64 = 63, force player to be unable to go above 63
+        if (y < 63)
+        {
+               int difference = 63 - y;
+               y = 63;
+               absolute_y+=difference;
+               for (int i = 0; i < MAX_PLATFORMS; i++)
+               {
+                   platx = platforms[i].x;
+                   platy = platforms[i].y;
+                   // draw over old location
+                   uLCD.filled_rectangle(platx, platy, platx+PLATFORM_WIDTH, platy+PLATFORM_HEIGHT, BLACK);
+                   platforms[i].y+=difference;
+               }           
+        }
+        // draw platforms
+        for (int i = 0; i < MAX_PLATFORMS; i++)
+        {
+            uLCD.filled_rectangle(platforms[i].x, platforms[i].y, platforms[i].x + PLATFORM_WIDTH - 1, platforms[i].y + PLATFORM_HEIGHT - 1, GREEN);
+        }
+        // draw new player location
+        //ReadBMPFromFile("/sd/stardesu.bmp", Colors, &uLCD, x,y);
+        DrawColorstoLCD(color_array, &uLCD, x, y, PLAYER_WIDTH, PLAYER_HEIGHT);
+        wait(.05f);
+        // print absolute y as player score
+        uLCD.locate(0, 0);
+        uLCD.printf("Score: %i", absolute_y);
+        
+        // save previous player coordinates, update player coordinates
+        old_x = x;
+        old_y = y;
+        x = 64-PLAYER_WIDTH/2 + (int)(64.0f * ax);
+        y += player_velocity;
+        // apply "gravity" and "terminal velocity" to current player velocity
+        player_velocity += GRAVITY;
+        if (player_velocity > -1*INIT_PLAYER_VELOCITY)
+        {
+            player_velocity = -1*INIT_PLAYER_VELOCITY;
+        }
+        
+        
+        
+        
+        
+        
+        // check game over condition
+        if ( y >= 127-PLAYER_HEIGHT && player_velocity > 0)
+        {
+            // kill player, game over
+            wait(.1f);
+            trySound("/sd/RR.wav");
+            trySound("/sd/RR.wav");
+            wait(.1f);
+            while(1)
+            {
+                uLCD.cls();
+                for (int i = 0; i < 20; i++)
+                {
+                    uLCD.color(RED);
+                    uLCD.printf("GET REKT");
+                    uLCD.color(GREEN);
+                    uLCD.printf("GET REKT");
+                }
+                wait(.1f);
+                uLCD.cls();
+                for (int i = 0; i < 80; i++)
+                {
+                    uLCD.color(RED);
+                    uLCD.printf("(=");
+                    uLCD.color(GREEN);
+                    uLCD.printf("(=");
+                }
+                wait(.1f);
+            }
+            //player_velocity = INIT_PLAYER_VELOCITY;
+            //y = 127-PLAYER_HEIGHT;
+        } 
+    } // end of main loop
+} // end of main
+
+// function implementations
+
+void playSound(void const * args) 
 {
     sound_mutex.lock();
-    wave_file = fopen("/sd/DMX.wav","r"); // change to whatever sound
+    FILE *wave_file;
+    char const * actual_args = (char const *)args;
+    wave_file = fopen(actual_args,"r"); // change to whatever sound
     if (wave_file == NULL)
     {
         myled1 = 1;
@@ -63,12 +269,12 @@
     {
         myled2 = 1;
     }
-        
     waver.play(wave_file);
     fclose(wave_file);
     sound_mutex.unlock();
 }
 
+
 int getHighestPlatform()
 {
     int highest_index = 0;
@@ -80,12 +286,26 @@
     return highest_index;
 }
 
+
+int getLowestPlatform()
+{
+    int lowest_index = 0;
+    for (int i = 1; i < MAX_PLATFORMS; i++)
+    {  
+        if (platforms[i].y > platforms[lowest_index].y)
+            lowest_index = i;
+    }
+    return lowest_index;
+}
+
+
 void getNextPlatform(int &x, int &y)
 {  
     x = rand()%(128-PLATFORM_WIDTH+1);
     y = platforms[getHighestPlatform()].y - (rand()%(MAX_PLATFORM_INTERVAL-MIN_PLATFORM_INTERVAL+1) + MIN_PLATFORM_INTERVAL);
 }
 
+
 void initPlatforms()
 {
     // first set all to 0
@@ -103,111 +323,14 @@
         platforms[i].y = y;
     }
 }
-    
-int main()
+
+
+void trySound(const char * file)
 {
-    wait(2);
-    uLCD.cls();
-    //Thread t1(playSound);
     if (sound_mutex.trylock())
     {   
         delete t1;
-        t1 = new Thread(playSound);
+        t1 = new Thread(playSound, (void*)file);
         sound_mutex.unlock();
     }
-  
-       
-    uLCD.printf("Calibrating IMU, place on flat surface. Please wait...");
-    IMU.begin();
-    if (!IMU.begin()) {
-        uLCD.printf("Failed to communicate with LSM9DS1.\n");
-        wait(5);
-        return -1;
-    }
-    IMU.calibrate(1);
-    IMU.calibrateMag(0);
-    
-    uLCD.baudrate(3000000); //jack up baud rate to max for fast display
-    
-    //float fx=63.0,fy=63.0,vx=1.0,vy=0.4;
-    int x=64+(PLAYER_WIDTH + 1)/2,y=127-PLAYER_HEIGHT,radius=4;
-    uLCD.background_color(BLACK);
-    
-    
-    
-    float ax;
-    
-    RGBApixel *Colors = new RGBApixel [2];
-    
-    srand(time(0));
-    uLCD.cls();
-    
-    initPlatforms();
-    int highestPlatformIndex;
-    int platx;
-    int platy;
-    
-    while (1) {
-        
-        while(!IMU.accelAvailable());
-        IMU.readAccel();
-        ax = IMU.calcAccel(IMU.ax);
-        
-        
-        highestPlatformIndex = getHighestPlatform();
-        platy = platforms[highestPlatformIndex].y;
-        if (platy > 127)
-        {
-            getNextPlatform(platx, platy);
-            platforms[highestPlatformIndex].y = platy;
-            platforms[highestPlatformIndex].x = platx;
-        }
-        
-        
-        
-        
-        for (int i = 0; i < MAX_PLATFORMS; i++)
-        {
-            uLCD.filled_rectangle(platforms[i].x, platforms[i].y, platforms[i].x + PLATFORM_WIDTH - 1, platforms[i].y + PLATFORM_HEIGHT - 1, GREEN);
-        }
-        
-        
-        //draw ball
-        //uLCD.filled_circle(x, y, radius, RED);
-        
-        for (int i = 0; i < MAX_PLATFORMS; i++)
-        {
-            if (player_velocity > 0 && (x+PLAYER_WIDTH) > platforms[i].x && x < (platforms[i].x + PLATFORM_WIDTH) && (y+PLAYER_HEIGHT) >= (platforms[i].y-3) && (y+PLAYER_HEIGHT) <= (platforms[i].y + 6))
-            {
-                
-                 player_velocity = INIT_PLAYER_VELOCITY;   
-                       
-                  
-            }
-            
-        }
-        
-        
-        
-        ReadBMPFromFile("/sd/stardesu.bmp", Colors, &uLCD, x,y);
-        uLCD.locate(0, 0);
-        uLCD.printf("(%i, %i)", x, y);
-        //bounce off edge walls and slow down a bit?
-        //erase old ball location
-        uLCD.filled_rectangle(x, y, x+PLAYER_WIDTH, y+PLAYER_HEIGHT, BLACK);
-
-        
-        x = 64-PLAYER_WIDTH/2 + (int)(64.0f * ax);
-        y += player_velocity;
-        player_velocity += GRAVITY;
-        if ( y >= 127-PLAYER_HEIGHT)
-        {
-            player_velocity = INIT_PLAYER_VELOCITY;
-            y = 127-PLAYER_HEIGHT;
-        }
-        
-        
-        wait(.05);
-    }
-
 }
diff -r e76f3f3c85c0 -r 141c57be5a2d myBMP/myBMP.cpp
--- a/myBMP/myBMP.cpp	Mon Mar 14 20:36:52 2016 +0000
+++ b/myBMP/myBMP.cpp	Tue Mar 15 02:34:14 2016 +0000
@@ -108,13 +108,8 @@
 bool Read24bitRow( ebmpBYTE* Buffer, int BufferSize, int Row, uLCD_4DGL *lcd, int x, int y)
 { 
  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 | (Buffer[3*i+2] << 16) | (Buffer[3*i+1] << 8) | (Buffer[3*i+0]);
     (*lcd).pixel(x+i,y+Row,color);
  }
@@ -558,296 +553,231 @@
  return true;
 }
 
-bool ReadBMPFromFile(const char * FileName, RGBApixel *Colors, uLCD_4DGL *lcd, int x, int y)
+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;
- }
+    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
+    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; 
 
- 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.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
 
- 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; 
- }
+    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
+    // 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( (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.
+    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 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 )
+    int n;
+    for( n=0; n < NumberOfColorsToRead ; n++ )
+    {
+    SafeFread( (char*) &(Colors[n]) , 4 , 1 , fp);     
+    }
+    for( n=NumberOfColorsToRead ; n < TellNumberOfColors(BitDepth) ; n++ )
     {
-     j = -1;
+        RGBApixel HWITE; 
+        HWITE.Red = 255;
+        HWITE.Green = 255;
+        HWITE.Blue = 255;
+        HWITE.Alpha = 0;
+        Colors[n] = HWITE;
+    }
     }
-   }   
-   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
+    // skip blank data if bfOffBits so indicates
 
-  // read the bit fields, if necessary, to 
-  // override the default 5-5-5 mask
-  
-  if( bmih.biCompression != 0 )
-  {
-   // read the three bit masks
+    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;
+    } 
 
-   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
+    // This code reads 1, 4, 8, 24, and 32-bpp files 
+    // with a more-efficient buffered technique.
 
-  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++;
-   }
-  }
+    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; 
+    }
 
- }
- 
- fclose(fp);
- return true;
+    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]);
+        }
+    }
 }
 
 
@@ -866,4 +796,297 @@
  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;
 }
\ No newline at end of file
diff -r e76f3f3c85c0 -r 141c57be5a2d myBMP/myBMP.h
--- a/myBMP/myBMP.h	Mon Mar 14 20:36:52 2016 +0000
+++ b/myBMP/myBMP.h	Tue Mar 15 02:34:14 2016 +0000
@@ -53,3 +53,8 @@
 };
 bool ReadBMPFromFile( const char* FileName , RGBApixel *Colors, uLCD_4DGL *lcd);
 bool ReadBMPFromFile(const char* FileName , RGBApixel *Colors, uLCD_4DGL *lcd, int x, int y);
+// need to allocate width*height ints for color_array
+// colors go from color_array[0] to color_array[width*height-1] going from i,j coord values
+// accessed with color_array[width*j + i]
+bool ReadColorsFromFile(const char* FileName , RGBApixel *Colors, int * color_array, int x, int y);
+void DrawColorstoLCD(int * color_array, uLCD_4DGL *lcd, int x, int y, int w, int h);