Simplified Doodle Jump game for mbed
Dependencies: 4DGL-uLCD-SE LSM9DS1_Library_cal SDFileSystem mbed-rtos mbed wave_player
Revision 3:141c57be5a2d, committed 2016-03-15
- Comitter:
- bhill42
- Date:
- Tue Mar 15 02:34:14 2016 +0000
- Parent:
- 2:e76f3f3c85c0
- Commit message:
- Final
Changed in this revision
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);