PokittoLib is the library needed for programming the Pokitto DIY game console (www.pokitto.com)
Dependents: YATTT sd_map_test cPong SnowDemo ... more
PokittoLib
Library for programming Pokitto hardware
How to Use
- Import this library to online compiler (see button "import" on the right hand side
- DO NOT import mbed-src anymore, a better version is now included inside PokittoLib
- Change My_settings.h according to your project
- Start coding!
POKITTO_LIBS/ImageFormat/BmpImage.cpp@45:bbfc6002118c, 2018-05-21 (annotated)
- Committer:
- Pokitto
- Date:
- Mon May 21 18:03:03 2018 +0000
- Revision:
- 45:bbfc6002118c
- Parent:
- 23:f88837b8f914
Fixes to sound etc
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Pokitto | 23:f88837b8f914 | 1 | /**************************************************************************/ |
Pokitto | 23:f88837b8f914 | 2 | /*! |
Pokitto | 23:f88837b8f914 | 3 | @file BmpImage.cpp |
Pokitto | 23:f88837b8f914 | 4 | @author Hannu Viitala. Original BMP decoder code by Jonne Valola. |
Pokitto | 23:f88837b8f914 | 5 | |
Pokitto | 23:f88837b8f914 | 6 | @section LICENSE |
Pokitto | 23:f88837b8f914 | 7 | |
Pokitto | 23:f88837b8f914 | 8 | Software License Agreement (BSD License) |
Pokitto | 23:f88837b8f914 | 9 | |
Pokitto | 23:f88837b8f914 | 10 | Copyright (c) 2016, Jonne Valola |
Pokitto | 23:f88837b8f914 | 11 | All rights reserved. |
Pokitto | 23:f88837b8f914 | 12 | |
Pokitto | 23:f88837b8f914 | 13 | Redistribution and use in source and binary forms, with or without |
Pokitto | 23:f88837b8f914 | 14 | modification, are permitted provided that the following conditions are met: |
Pokitto | 23:f88837b8f914 | 15 | 1. Redistributions of source code must retain the above copyright |
Pokitto | 23:f88837b8f914 | 16 | notice, this list of conditions and the following disclaimer. |
Pokitto | 23:f88837b8f914 | 17 | 2. Redistributions in binary form must reproduce the above copyright |
Pokitto | 23:f88837b8f914 | 18 | notice, this list of conditions and the following disclaimer in the |
Pokitto | 23:f88837b8f914 | 19 | documentation and/or other materials provided with the distribution. |
Pokitto | 23:f88837b8f914 | 20 | 3. Neither the name of the copyright holders nor the |
Pokitto | 23:f88837b8f914 | 21 | names of its contributors may be used to endorse or promote products |
Pokitto | 23:f88837b8f914 | 22 | derived from this software without specific prior written permission. |
Pokitto | 23:f88837b8f914 | 23 | |
Pokitto | 23:f88837b8f914 | 24 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY |
Pokitto | 23:f88837b8f914 | 25 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
Pokitto | 23:f88837b8f914 | 26 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
Pokitto | 23:f88837b8f914 | 27 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY |
Pokitto | 23:f88837b8f914 | 28 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
Pokitto | 23:f88837b8f914 | 29 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
Pokitto | 23:f88837b8f914 | 30 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
Pokitto | 23:f88837b8f914 | 31 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
Pokitto | 23:f88837b8f914 | 32 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
Pokitto | 23:f88837b8f914 | 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
Pokitto | 23:f88837b8f914 | 34 | */ |
Pokitto | 23:f88837b8f914 | 35 | /**************************************************************************/ |
Pokitto | 23:f88837b8f914 | 36 | |
Pokitto | 23:f88837b8f914 | 37 | #if POKITTO_USE_WIN_SIMULATOR |
Pokitto | 23:f88837b8f914 | 38 | #include "defines_win_SIM.h" |
Pokitto | 23:f88837b8f914 | 39 | #endif |
Pokitto | 23:f88837b8f914 | 40 | |
Pokitto | 23:f88837b8f914 | 41 | #define PROJ_MBED 1 |
Pokitto | 23:f88837b8f914 | 42 | |
Pokitto | 23:f88837b8f914 | 43 | #if PROJ_LINUX || PROJ_MBED |
Pokitto | 23:f88837b8f914 | 44 | #include "defines_linux_SIM.h" |
Pokitto | 23:f88837b8f914 | 45 | #endif |
Pokitto | 23:f88837b8f914 | 46 | |
Pokitto | 23:f88837b8f914 | 47 | #include "Pokitto.h" |
Pokitto | 23:f88837b8f914 | 48 | #include "PokittoDisk.h" |
Pokitto | 23:f88837b8f914 | 49 | #ifdef POK_SIM |
Pokitto | 23:f88837b8f914 | 50 | #include "FileIO.h" |
Pokitto | 23:f88837b8f914 | 51 | #endif |
Pokitto | 23:f88837b8f914 | 52 | |
Pokitto | 45:bbfc6002118c | 53 | |
Pokitto | 45:bbfc6002118c | 54 | #define max(a,b) ((a)>(b)?(a):(b)) |
Pokitto | 45:bbfc6002118c | 55 | #define min(a,b) ((a)<(b)?(a):(b)) |
Pokitto | 45:bbfc6002118c | 56 | |
Pokitto | 45:bbfc6002118c | 57 | |
Pokitto | 23:f88837b8f914 | 58 | #if POK_ENABLE_SD > 0 |
Pokitto | 23:f88837b8f914 | 59 | |
Pokitto | 23:f88837b8f914 | 60 | |
Pokitto | 23:f88837b8f914 | 61 | #include "PokittoDisplay.h" |
Pokitto | 23:f88837b8f914 | 62 | #include "ImageFormat.h" |
Pokitto | 23:f88837b8f914 | 63 | |
Pokitto | 23:f88837b8f914 | 64 | Pokitto::Core _game; |
Pokitto | 23:f88837b8f914 | 65 | Pokitto::Display pokdisp; |
Pokitto | 23:f88837b8f914 | 66 | |
Pokitto | 23:f88837b8f914 | 67 | int openImageFileFromSD(char* filepath, uint16_t **palette_out, uint8_t **bitmap_out) { |
Pokitto | 23:f88837b8f914 | 68 | |
Pokitto | 23:f88837b8f914 | 69 | // Reset the out pointers. |
Pokitto | 23:f88837b8f914 | 70 | *palette_out = 0; |
Pokitto | 23:f88837b8f914 | 71 | *bitmap_out = 0; |
Pokitto | 23:f88837b8f914 | 72 | |
Pokitto | 23:f88837b8f914 | 73 | BITMAPFILEHEADER bf; |
Pokitto | 23:f88837b8f914 | 74 | BITMAPINFO bmi; |
Pokitto | 23:f88837b8f914 | 75 | |
Pokitto | 23:f88837b8f914 | 76 | uint32_t bytes_read=0, bmpsize=0; |
Pokitto | 23:f88837b8f914 | 77 | |
Pokitto | 23:f88837b8f914 | 78 | /** numcol is the number of colors for output */ |
Pokitto | 23:f88837b8f914 | 79 | unsigned int numcol = 0; |
Pokitto | 23:f88837b8f914 | 80 | |
Pokitto | 23:f88837b8f914 | 81 | if (POK_COLORDEPTH == 8) numcol=256; |
Pokitto | 23:f88837b8f914 | 82 | else if (POK_COLORDEPTH == 4) numcol=16; |
Pokitto | 23:f88837b8f914 | 83 | else if (POK_COLORDEPTH == 2) numcol=4; |
Pokitto | 23:f88837b8f914 | 84 | else if (POK_COLORDEPTH == 1) numcol=1; |
Pokitto | 23:f88837b8f914 | 85 | |
Pokitto | 23:f88837b8f914 | 86 | if (!isThisFileOpen(filepath)) { |
Pokitto | 23:f88837b8f914 | 87 | fileClose(); // close any open files |
Pokitto | 23:f88837b8f914 | 88 | fileOpen(filepath, FILE_MODE_READONLY | FILE_MODE_BINARY); |
Pokitto | 23:f88837b8f914 | 89 | } |
Pokitto | 23:f88837b8f914 | 90 | else |
Pokitto | 23:f88837b8f914 | 91 | return -1; // Already open, not good. |
Pokitto | 23:f88837b8f914 | 92 | |
Pokitto | 23:f88837b8f914 | 93 | if (fileOK() && fileReadBytes((uint8_t*)&bf, sizeof(bf)) == sizeof(bf) ) { |
Pokitto | 23:f88837b8f914 | 94 | bytes_read += sizeof(bf); |
Pokitto | 23:f88837b8f914 | 95 | } |
Pokitto | 23:f88837b8f914 | 96 | else |
Pokitto | 23:f88837b8f914 | 97 | { |
Pokitto | 23:f88837b8f914 | 98 | POK_TRACE("Error reading BMP header\n"); |
Pokitto | 23:f88837b8f914 | 99 | fileClose(); |
Pokitto | 23:f88837b8f914 | 100 | return(-1); |
Pokitto | 23:f88837b8f914 | 101 | } |
Pokitto | 23:f88837b8f914 | 102 | |
Pokitto | 23:f88837b8f914 | 103 | if (fileReadBytes((uint8_t*)&bmi,sizeof(bmi.bmiHeader)) != sizeof(bmi.bmiHeader)) { |
Pokitto | 23:f88837b8f914 | 104 | POK_TRACE("Error reading BMP info\n"); |
Pokitto | 23:f88837b8f914 | 105 | fileClose(); |
Pokitto | 23:f88837b8f914 | 106 | return(-1); |
Pokitto | 23:f88837b8f914 | 107 | } |
Pokitto | 23:f88837b8f914 | 108 | bytes_read += sizeof(bmi.bmiHeader); |
Pokitto | 23:f88837b8f914 | 109 | |
Pokitto | 23:f88837b8f914 | 110 | /** Check image validity */ |
Pokitto | 23:f88837b8f914 | 111 | |
Pokitto | 23:f88837b8f914 | 112 | if (bf.bfType != 0x4D42) { |
Pokitto | 23:f88837b8f914 | 113 | POK_TRACE("Bitmap file has an unrecognized format (4D42 id missing from beginning).\n"); |
Pokitto | 23:f88837b8f914 | 114 | POK_TRACE("BMP2POK accepts .BMP files that have an indexed (1,-bit, 4-bit or 8-bit) color palette.\n"); |
Pokitto | 23:f88837b8f914 | 115 | fileClose(); |
Pokitto | 23:f88837b8f914 | 116 | return(-1); |
Pokitto | 23:f88837b8f914 | 117 | } |
Pokitto | 23:f88837b8f914 | 118 | if (bmi.bmiHeader.biBitCount != POK_COLORDEPTH ) { |
Pokitto | 23:f88837b8f914 | 119 | POK_TRACE("ERROR!\nThe image color depth should be the same as screen color depth!\n"); |
Pokitto | 23:f88837b8f914 | 120 | } |
Pokitto | 23:f88837b8f914 | 121 | if (bmi.bmiHeader.biWidth%32 && bmi.bmiHeader.biBitCount == 1) { |
Pokitto | 23:f88837b8f914 | 122 | POK_TRACE("ERROR!\nPadding of 1-bit (monochrome) images is not yet supported\n"); |
Pokitto | 23:f88837b8f914 | 123 | POK_TRACE("1-bit images need to have width that is divisible by 32!\n"); |
Pokitto | 23:f88837b8f914 | 124 | POK_TRACE("Adjust size of source image.\n"); |
Pokitto | 23:f88837b8f914 | 125 | fileClose(); |
Pokitto | 23:f88837b8f914 | 126 | return(-1); |
Pokitto | 23:f88837b8f914 | 127 | } |
Pokitto | 23:f88837b8f914 | 128 | if (bmi.bmiHeader.biWidth%4) { |
Pokitto | 23:f88837b8f914 | 129 | POK_TRACE("Width is not divisible by 4\n"); |
Pokitto | 23:f88837b8f914 | 130 | fileClose(); |
Pokitto | 23:f88837b8f914 | 131 | return(-1); |
Pokitto | 23:f88837b8f914 | 132 | } |
Pokitto | 23:f88837b8f914 | 133 | if (bmi.bmiHeader.biWidth%8 && bmi.bmiHeader.biBitCount==4) { |
Pokitto | 23:f88837b8f914 | 134 | if (bmi.bmiHeader.biWidth%4) { |
Pokitto | 23:f88837b8f914 | 135 | POK_TRACE("ERROR!\n4-bit source images have to have a width that is divisible by 4\n"); |
Pokitto | 23:f88837b8f914 | 136 | fileClose(); |
Pokitto | 23:f88837b8f914 | 137 | return(-1); |
Pokitto | 23:f88837b8f914 | 138 | } |
Pokitto | 23:f88837b8f914 | 139 | } |
Pokitto | 23:f88837b8f914 | 140 | if (bmi.bmiHeader.biBitCount != 8 && bmi.bmiHeader.biBitCount != 4 && bmi.bmiHeader.biBitCount != 1) |
Pokitto | 23:f88837b8f914 | 141 | { |
Pokitto | 23:f88837b8f914 | 142 | POK_TRACE("Only 8bpp, 4bpp & 1bpp BMP files are supported\n"); |
Pokitto | 23:f88837b8f914 | 143 | fileClose(); |
Pokitto | 23:f88837b8f914 | 144 | return(-1); |
Pokitto | 23:f88837b8f914 | 145 | } |
Pokitto | 23:f88837b8f914 | 146 | if (bmi.bmiHeader.biCompression != 0 && |
Pokitto | 23:f88837b8f914 | 147 | !(bmi.bmiHeader.biCompression == BI_RLE4 && bmi.bmiHeader.biBitCount == 4)) |
Pokitto | 23:f88837b8f914 | 148 | { |
Pokitto | 23:f88837b8f914 | 149 | POK_TRACE("Only RLE compression for bitmaps with 4 bpp is supported\n"); |
Pokitto | 23:f88837b8f914 | 150 | fileClose(); |
Pokitto | 23:f88837b8f914 | 151 | return(-1); |
Pokitto | 23:f88837b8f914 | 152 | } |
Pokitto | 23:f88837b8f914 | 153 | |
Pokitto | 23:f88837b8f914 | 154 | /* If the height is negative the bmp image is in the correct way. |
Pokitto | 23:f88837b8f914 | 155 | If the heigh is positive the bmp image is vertically mirrored |
Pokitto | 23:f88837b8f914 | 156 | */ |
Pokitto | 23:f88837b8f914 | 157 | int biAbsHeight = bmi.bmiHeader.biHeight; |
Pokitto | 23:f88837b8f914 | 158 | if (bmi.bmiHeader.biHeight < 0 ) |
Pokitto | 23:f88837b8f914 | 159 | biAbsHeight = - bmi.bmiHeader.biHeight; |
Pokitto | 23:f88837b8f914 | 160 | |
Pokitto | 23:f88837b8f914 | 161 | /** Read and copy palette **/ |
Pokitto | 23:f88837b8f914 | 162 | |
Pokitto | 23:f88837b8f914 | 163 | int c = bmi.bmiHeader.biClrUsed; |
Pokitto | 23:f88837b8f914 | 164 | if (c==0) c = 1 << bmi.bmiHeader.biBitCount; // from MS BMP specs. 0 means 2^n colors |
Pokitto | 23:f88837b8f914 | 165 | bmi.bmiHeader.biClrUsed = c; |
Pokitto | 23:f88837b8f914 | 166 | |
Pokitto | 23:f88837b8f914 | 167 | /* Allocate memory for the output parameter */ |
Pokitto | 23:f88837b8f914 | 168 | if (numcol>bmi.bmiHeader.biClrUsed) numcol = bmi.bmiHeader.biClrUsed; |
Pokitto | 23:f88837b8f914 | 169 | *palette_out = (uint16_t*) malloc(numcol*2); |
Pokitto | 23:f88837b8f914 | 170 | if (*palette_out == NULL) |
Pokitto | 23:f88837b8f914 | 171 | { |
Pokitto | 23:f88837b8f914 | 172 | POK_TRACE("Error allocating temporary palette buffer.\n"); |
Pokitto | 23:f88837b8f914 | 173 | free(*palette_out); |
Pokitto | 23:f88837b8f914 | 174 | return(-1); |
Pokitto | 23:f88837b8f914 | 175 | } |
Pokitto | 23:f88837b8f914 | 176 | |
Pokitto | 23:f88837b8f914 | 177 | /* seek to the beginning of the color table - because of gimp */ |
Pokitto | 23:f88837b8f914 | 178 | fileSeekAbsolute(bf.bfOffBits-c*4); //gfx data star minus color table |
Pokitto | 23:f88837b8f914 | 179 | |
Pokitto | 23:f88837b8f914 | 180 | for (unsigned int c=0;c<numcol;c++) { |
Pokitto | 23:f88837b8f914 | 181 | |
Pokitto | 23:f88837b8f914 | 182 | RGBQUAD rgbValue; |
Pokitto | 23:f88837b8f914 | 183 | fileReadBytes((uint8_t*)&rgbValue, sizeof(RGBQUAD)); |
Pokitto | 23:f88837b8f914 | 184 | bytes_read += sizeof(RGBQUAD); |
Pokitto | 23:f88837b8f914 | 185 | |
Pokitto | 23:f88837b8f914 | 186 | unsigned int r,g,b,o; |
Pokitto | 23:f88837b8f914 | 187 | r = rgbValue.rgbRed >> 3; // 5 bit |
Pokitto | 23:f88837b8f914 | 188 | g = rgbValue.rgbGreen >> 2; // 6 bits |
Pokitto | 23:f88837b8f914 | 189 | b = rgbValue.rgbBlue >> 3; // 5 bits |
Pokitto | 23:f88837b8f914 | 190 | o = (r<<11)|(g<<5)|b; |
Pokitto | 23:f88837b8f914 | 191 | |
Pokitto | 23:f88837b8f914 | 192 | (*palette_out)[c] = o; |
Pokitto | 23:f88837b8f914 | 193 | } |
Pokitto | 23:f88837b8f914 | 194 | |
Pokitto | 23:f88837b8f914 | 195 | /** Read and copy image data **/ |
Pokitto | 23:f88837b8f914 | 196 | |
Pokitto | 23:f88837b8f914 | 197 | /* Get image data size. If the biSizeImage is given (>0) for RLE image, use that to reduce memory usage. */ |
Pokitto | 23:f88837b8f914 | 198 | bmpsize = bmi.bmiHeader.biWidth * biAbsHeight*bmi.bmiHeader.biBitCount/8; |
Pokitto | 23:f88837b8f914 | 199 | if (bmi.bmiHeader.biCompression == BI_RLE4) |
Pokitto | 23:f88837b8f914 | 200 | bmpsize = (bmi.bmiHeader.biSizeImage > 0) ? bmi.bmiHeader.biSizeImage : bmpsize; |
Pokitto | 23:f88837b8f914 | 201 | |
Pokitto | 23:f88837b8f914 | 202 | // SEEK to the beginning of the data |
Pokitto | 23:f88837b8f914 | 203 | fileSeekAbsolute(bf.bfOffBits); |
Pokitto | 23:f88837b8f914 | 204 | |
Pokitto | 23:f88837b8f914 | 205 | /* Allocate output data buffer */ |
Pokitto | 23:f88837b8f914 | 206 | *bitmap_out = (uint8_t *) malloc(bmpsize + 2); // header takes 2 bytes |
Pokitto | 23:f88837b8f914 | 207 | if (*bitmap_out == NULL) |
Pokitto | 23:f88837b8f914 | 208 | { |
Pokitto | 23:f88837b8f914 | 209 | POK_TRACE("Error allocating temporary data buffer, is image too big?\n"); |
Pokitto | 23:f88837b8f914 | 210 | free(*palette_out); |
Pokitto | 23:f88837b8f914 | 211 | return(-1); |
Pokitto | 23:f88837b8f914 | 212 | } |
Pokitto | 23:f88837b8f914 | 213 | |
Pokitto | 23:f88837b8f914 | 214 | /* Store image size to the pokitto bitmap header */ |
Pokitto | 23:f88837b8f914 | 215 | uint32_t outindex = 0; |
Pokitto | 23:f88837b8f914 | 216 | (*bitmap_out)[outindex++] = bmi.bmiHeader.biWidth; |
Pokitto | 23:f88837b8f914 | 217 | (*bitmap_out)[outindex++] = biAbsHeight; |
Pokitto | 23:f88837b8f914 | 218 | |
Pokitto | 23:f88837b8f914 | 219 | if (bmi.bmiHeader.biCompression == BI_RLE4) { |
Pokitto | 23:f88837b8f914 | 220 | bool eofReached = false; |
Pokitto | 23:f88837b8f914 | 221 | while (outindex < bmpsize && !eofReached ) { |
Pokitto | 23:f88837b8f914 | 222 | /* Read byte from the file. */ |
Pokitto | 23:f88837b8f914 | 223 | unsigned char rleByte; |
Pokitto | 23:f88837b8f914 | 224 | if (fileReadBytes(&rleByte, sizeof(rleByte)) != sizeof(rleByte)) |
Pokitto | 23:f88837b8f914 | 225 | { |
Pokitto | 23:f88837b8f914 | 226 | /* End of file reached. Allocate a new bitmap which is of the exact size of the data */ |
Pokitto | 23:f88837b8f914 | 227 | eofReached = true; |
Pokitto | 23:f88837b8f914 | 228 | |
Pokitto | 23:f88837b8f914 | 229 | /* Allocate output data buffer */ |
Pokitto | 23:f88837b8f914 | 230 | uint8_t* old_bitmap = *bitmap_out; |
Pokitto | 23:f88837b8f914 | 231 | *bitmap_out = NULL; |
Pokitto | 23:f88837b8f914 | 232 | *bitmap_out = (uint8_t *) malloc(outindex); // header takes 2 bytes |
Pokitto | 23:f88837b8f914 | 233 | if (*bitmap_out == NULL) |
Pokitto | 23:f88837b8f914 | 234 | { |
Pokitto | 23:f88837b8f914 | 235 | POK_TRACE("Error allocating temporary data buffer, is image too big?\n"); |
Pokitto | 23:f88837b8f914 | 236 | free(old_bitmap); |
Pokitto | 23:f88837b8f914 | 237 | free(*palette_out); |
Pokitto | 23:f88837b8f914 | 238 | return(-1); |
Pokitto | 23:f88837b8f914 | 239 | } |
Pokitto | 23:f88837b8f914 | 240 | |
Pokitto | 23:f88837b8f914 | 241 | /* Copy data */ |
Pokitto | 23:f88837b8f914 | 242 | for (int i=0; i<outindex;i++) |
Pokitto | 23:f88837b8f914 | 243 | (*bitmap_out)[i] = old_bitmap[i]; |
Pokitto | 23:f88837b8f914 | 244 | |
Pokitto | 23:f88837b8f914 | 245 | /* Free original bitmap */ |
Pokitto | 23:f88837b8f914 | 246 | free(old_bitmap); |
Pokitto | 23:f88837b8f914 | 247 | } |
Pokitto | 23:f88837b8f914 | 248 | else { |
Pokitto | 23:f88837b8f914 | 249 | /* Store byte */ |
Pokitto | 23:f88837b8f914 | 250 | (*bitmap_out)[outindex++] = rleByte; |
Pokitto | 23:f88837b8f914 | 251 | } |
Pokitto | 23:f88837b8f914 | 252 | } // end while |
Pokitto | 23:f88837b8f914 | 253 | } |
Pokitto | 23:f88837b8f914 | 254 | else { |
Pokitto | 23:f88837b8f914 | 255 | /* Do vertical mirroring only for uncompressed data. |
Pokitto | 23:f88837b8f914 | 256 | Note the compressed RLE data above could not be mirrored. |
Pokitto | 23:f88837b8f914 | 257 | */ |
Pokitto | 23:f88837b8f914 | 258 | int widthInBytes = bmi.bmiHeader.biWidth * bmi.bmiHeader.biBitCount/8; |
Pokitto | 23:f88837b8f914 | 259 | int widthInBytesInc, incY, startY, endY; |
Pokitto | 23:f88837b8f914 | 260 | if (bmi.bmiHeader.biHeight > 0 ) { |
Pokitto | 23:f88837b8f914 | 261 | /* Mirror vertically */ |
Pokitto | 23:f88837b8f914 | 262 | widthInBytesInc = - widthInBytes; |
Pokitto | 23:f88837b8f914 | 263 | incY = -1; |
Pokitto | 23:f88837b8f914 | 264 | startY = biAbsHeight - 1; |
Pokitto | 23:f88837b8f914 | 265 | endY = -1; |
Pokitto | 23:f88837b8f914 | 266 | } |
Pokitto | 23:f88837b8f914 | 267 | else { |
Pokitto | 23:f88837b8f914 | 268 | /* Do not mirror */ |
Pokitto | 23:f88837b8f914 | 269 | widthInBytesInc = widthInBytes; |
Pokitto | 23:f88837b8f914 | 270 | incY = 1; |
Pokitto | 23:f88837b8f914 | 271 | startY = 0; |
Pokitto | 23:f88837b8f914 | 272 | endY = biAbsHeight; |
Pokitto | 23:f88837b8f914 | 273 | } |
Pokitto | 23:f88837b8f914 | 274 | |
Pokitto | 23:f88837b8f914 | 275 | /* Copy all bytes to the output bitmap */ |
Pokitto | 23:f88837b8f914 | 276 | for ( int y = startY, beginLine=startY*widthInBytes; y != endY; y += incY, beginLine += widthInBytesInc) { |
Pokitto | 23:f88837b8f914 | 277 | |
Pokitto | 23:f88837b8f914 | 278 | /* Go to the beginning of the previous or next line */ |
Pokitto | 23:f88837b8f914 | 279 | outindex = beginLine; |
Pokitto | 23:f88837b8f914 | 280 | |
Pokitto | 23:f88837b8f914 | 281 | for ( int xbyte = 0; xbyte < widthInBytes; xbyte++) { |
Pokitto | 23:f88837b8f914 | 282 | |
Pokitto | 23:f88837b8f914 | 283 | /* Read byte from the file. */ |
Pokitto | 23:f88837b8f914 | 284 | unsigned char byteOfPixels; |
Pokitto | 23:f88837b8f914 | 285 | if (fileReadBytes(&byteOfPixels, sizeof(byteOfPixels)) != sizeof(byteOfPixels)) |
Pokitto | 23:f88837b8f914 | 286 | { |
Pokitto | 23:f88837b8f914 | 287 | POK_TRACE("Error reading BMP data\n"); |
Pokitto | 23:f88837b8f914 | 288 | fileClose(); |
Pokitto | 23:f88837b8f914 | 289 | free(*bitmap_out); |
Pokitto | 23:f88837b8f914 | 290 | free(*palette_out); |
Pokitto | 23:f88837b8f914 | 291 | return(-1); |
Pokitto | 23:f88837b8f914 | 292 | } |
Pokitto | 23:f88837b8f914 | 293 | |
Pokitto | 23:f88837b8f914 | 294 | /* Copy a byte from the file to the bitmap */ |
Pokitto | 23:f88837b8f914 | 295 | (*bitmap_out)[2 + outindex] = byteOfPixels; |
Pokitto | 23:f88837b8f914 | 296 | outindex++; |
Pokitto | 23:f88837b8f914 | 297 | } // end for |
Pokitto | 23:f88837b8f914 | 298 | } // end for |
Pokitto | 23:f88837b8f914 | 299 | } // end if |
Pokitto | 23:f88837b8f914 | 300 | |
Pokitto | 23:f88837b8f914 | 301 | // Done with the file reading. |
Pokitto | 23:f88837b8f914 | 302 | fileClose(); |
Pokitto | 23:f88837b8f914 | 303 | |
Pokitto | 23:f88837b8f914 | 304 | return 0; |
Pokitto | 23:f88837b8f914 | 305 | } |
Pokitto | 23:f88837b8f914 | 306 | |
Pokitto | 23:f88837b8f914 | 307 | int directDrawImageFileFromSD(int16_t sx, int16_t sy, char* filepath) { |
Pokitto | 23:f88837b8f914 | 308 | |
Pokitto | 23:f88837b8f914 | 309 | return(directDrawImageFileFromSD(0, 0, 0/* full width */, 0/* full height */, sx, sy, filepath)); |
Pokitto | 23:f88837b8f914 | 310 | } |
Pokitto | 23:f88837b8f914 | 311 | |
Pokitto | 23:f88837b8f914 | 312 | int directDrawImageFileFromSD(uint16_t ix, uint16_t iy, uint16_t iw, uint16_t ih, int16_t sx, int16_t sy, char* filepath) { |
Pokitto | 23:f88837b8f914 | 313 | |
Pokitto | 23:f88837b8f914 | 314 | BITMAPFILEHEADER bf; |
Pokitto | 23:f88837b8f914 | 315 | BITMAPINFO bmi; |
Pokitto | 23:f88837b8f914 | 316 | |
Pokitto | 23:f88837b8f914 | 317 | uint32_t bytes_read=0; |
Pokitto | 23:f88837b8f914 | 318 | |
Pokitto | 23:f88837b8f914 | 319 | if (!isThisFileOpen(filepath)) { |
Pokitto | 23:f88837b8f914 | 320 | fileClose(); // close any open files |
Pokitto | 23:f88837b8f914 | 321 | fileOpen(filepath, FILE_MODE_READONLY | FILE_MODE_BINARY); |
Pokitto | 23:f88837b8f914 | 322 | } |
Pokitto | 23:f88837b8f914 | 323 | else { |
Pokitto | 23:f88837b8f914 | 324 | POK_TRACE("Error! Already open\n"); |
Pokitto | 23:f88837b8f914 | 325 | return -1; // Already open, not good. |
Pokitto | 23:f88837b8f914 | 326 | } |
Pokitto | 23:f88837b8f914 | 327 | |
Pokitto | 23:f88837b8f914 | 328 | if (fileOK() && fileReadBytes((uint8_t*)&bf, sizeof(bf)) == sizeof(bf) ) { //!HV why we have to check fileOK()? |
Pokitto | 23:f88837b8f914 | 329 | bytes_read += sizeof(bf); |
Pokitto | 23:f88837b8f914 | 330 | } |
Pokitto | 23:f88837b8f914 | 331 | else |
Pokitto | 23:f88837b8f914 | 332 | { |
Pokitto | 23:f88837b8f914 | 333 | POK_TRACE("Error reading BMP header\n"); |
Pokitto | 23:f88837b8f914 | 334 | fileClose(); |
Pokitto | 23:f88837b8f914 | 335 | return(-1); |
Pokitto | 23:f88837b8f914 | 336 | } |
Pokitto | 23:f88837b8f914 | 337 | |
Pokitto | 23:f88837b8f914 | 338 | if (fileReadBytes((uint8_t*)&bmi,sizeof(bmi.bmiHeader)) != sizeof(bmi.bmiHeader)) { |
Pokitto | 23:f88837b8f914 | 339 | POK_TRACE("Error reading BMP info\n"); |
Pokitto | 23:f88837b8f914 | 340 | fileClose(); |
Pokitto | 23:f88837b8f914 | 341 | return(-1); |
Pokitto | 23:f88837b8f914 | 342 | } |
Pokitto | 23:f88837b8f914 | 343 | bytes_read += sizeof(bmi.bmiHeader); |
Pokitto | 23:f88837b8f914 | 344 | |
Pokitto | 23:f88837b8f914 | 345 | /** Check image validity */ |
Pokitto | 23:f88837b8f914 | 346 | |
Pokitto | 23:f88837b8f914 | 347 | if (bf.bfType != 0x4D42) { |
Pokitto | 23:f88837b8f914 | 348 | POK_TRACE("Bitmap file has an unrecognized format (4D42 id missing from beginning).\n"); |
Pokitto | 23:f88837b8f914 | 349 | POK_TRACE("BMP2POK accepts .BMP files that have an indexed (1,-bit, 4-bit or 8-bit) color palette.\n"); |
Pokitto | 23:f88837b8f914 | 350 | fileClose(); |
Pokitto | 23:f88837b8f914 | 351 | return(-1); |
Pokitto | 23:f88837b8f914 | 352 | } |
Pokitto | 23:f88837b8f914 | 353 | if (bmi.bmiHeader.biBitCount != 24 ) { |
Pokitto | 23:f88837b8f914 | 354 | POK_TRACE("ERROR!\nThe image color depth should be the same as screen color depth (%d)!\n"); |
Pokitto | 23:f88837b8f914 | 355 | fileClose(); |
Pokitto | 23:f88837b8f914 | 356 | return(-1); |
Pokitto | 23:f88837b8f914 | 357 | } |
Pokitto | 23:f88837b8f914 | 358 | if (bmi.bmiHeader.biCompression != 0 ) |
Pokitto | 23:f88837b8f914 | 359 | { |
Pokitto | 23:f88837b8f914 | 360 | POK_TRACE("Compression is not supported.\n"); |
Pokitto | 23:f88837b8f914 | 361 | fileClose(); |
Pokitto | 23:f88837b8f914 | 362 | return(-1); |
Pokitto | 23:f88837b8f914 | 363 | } |
Pokitto | 23:f88837b8f914 | 364 | |
Pokitto | 23:f88837b8f914 | 365 | /* If the height is negative the bmp image is in the correct way. |
Pokitto | 23:f88837b8f914 | 366 | If the heigh is positive the bmp image is vertically mirrored |
Pokitto | 23:f88837b8f914 | 367 | */ |
Pokitto | 23:f88837b8f914 | 368 | int biAbsHeight = bmi.bmiHeader.biHeight; |
Pokitto | 23:f88837b8f914 | 369 | if (bmi.bmiHeader.biHeight < 0 ) |
Pokitto | 23:f88837b8f914 | 370 | biAbsHeight = - bmi.bmiHeader.biHeight; |
Pokitto | 23:f88837b8f914 | 371 | |
Pokitto | 23:f88837b8f914 | 372 | /** Zero size parameter means full image size */ |
Pokitto | 23:f88837b8f914 | 373 | if(iw==0) iw = bmi.bmiHeader.biWidth; // 0 means full image width |
Pokitto | 23:f88837b8f914 | 374 | if(ih==0) ih = biAbsHeight; // 0 means full image width |
Pokitto | 23:f88837b8f914 | 375 | |
Pokitto | 23:f88837b8f914 | 376 | /** Check parameters */ |
Pokitto | 23:f88837b8f914 | 377 | if( ix + iw > bmi.bmiHeader.biWidth ) { |
Pokitto | 23:f88837b8f914 | 378 | POK_TRACE("Error! Invalid parameter\n"); |
Pokitto | 23:f88837b8f914 | 379 | fileClose(); |
Pokitto | 23:f88837b8f914 | 380 | return(-1); |
Pokitto | 23:f88837b8f914 | 381 | } |
Pokitto | 23:f88837b8f914 | 382 | if( iy + ih > biAbsHeight ) { |
Pokitto | 23:f88837b8f914 | 383 | POK_TRACE("Error! Invalid parameter\n"); |
Pokitto | 23:f88837b8f914 | 384 | fileClose(); |
Pokitto | 23:f88837b8f914 | 385 | return(-1); |
Pokitto | 23:f88837b8f914 | 386 | } |
Pokitto | 23:f88837b8f914 | 387 | if( sx > pokdisp.getWidth()-1 || sx<-iw) { |
Pokitto | 23:f88837b8f914 | 388 | POK_TRACE("Error! Invalid parameter\n"); |
Pokitto | 23:f88837b8f914 | 389 | fileClose(); |
Pokitto | 23:f88837b8f914 | 390 | return(-1); |
Pokitto | 23:f88837b8f914 | 391 | } |
Pokitto | 23:f88837b8f914 | 392 | if( sy > pokdisp.getHeight()-1 || sy<-ih) { |
Pokitto | 23:f88837b8f914 | 393 | POK_TRACE("Error! Invalid parameter\n"); |
Pokitto | 23:f88837b8f914 | 394 | fileClose(); |
Pokitto | 23:f88837b8f914 | 395 | return(-1); |
Pokitto | 23:f88837b8f914 | 396 | } |
Pokitto | 23:f88837b8f914 | 397 | |
Pokitto | 23:f88837b8f914 | 398 | /** Zero size parameter means full image size */ |
Pokitto | 23:f88837b8f914 | 399 | if(iw==0) iw = bmi.bmiHeader.biWidth; // 0 means full image width |
Pokitto | 23:f88837b8f914 | 400 | if(ih==0) ih = biAbsHeight; // 0 means full image width |
Pokitto | 23:f88837b8f914 | 401 | |
Pokitto | 23:f88837b8f914 | 402 | /** Clip image to screen dimensions */ |
Pokitto | 23:f88837b8f914 | 403 | |
Pokitto | 23:f88837b8f914 | 404 | int16_t clipX1OnScreen = max( 0, sx); |
Pokitto | 23:f88837b8f914 | 405 | int16_t clipX2OnScreen = min( pokdisp.getWidth()-1, sx+iw-1); |
Pokitto | 23:f88837b8f914 | 406 | int16_t clipWidthOnScreen = clipX2OnScreen-clipX1OnScreen+1; |
Pokitto | 23:f88837b8f914 | 407 | int16_t clipY1OnScreen = max( 0, sy); |
Pokitto | 23:f88837b8f914 | 408 | int16_t clipY2OnScreen = min( pokdisp.getHeight()-1, sy+ih-1); |
Pokitto | 23:f88837b8f914 | 409 | int16_t clipHeightOnScreen = clipY2OnScreen-clipY1OnScreen+1; |
Pokitto | 23:f88837b8f914 | 410 | |
Pokitto | 23:f88837b8f914 | 411 | uint16_t skipImagePixelsAtLineStart = ix+(clipX1OnScreen-sx); |
Pokitto | 23:f88837b8f914 | 412 | uint16_t skipImagePixelsAtLineStartAsBytes = skipImagePixelsAtLineStart*3; // 3 bytes per pixel |
Pokitto | 23:f88837b8f914 | 413 | uint16_t skipImagePixelsAtLineEndAsBytes = (bmi.bmiHeader.biWidth-(skipImagePixelsAtLineStart+clipWidthOnScreen))*3; // 3 bytes per pixel |
Pokitto | 23:f88837b8f914 | 414 | |
Pokitto | 23:f88837b8f914 | 415 | uint16_t skipImageRowsAtImageStart = iy+(clipY1OnScreen-sy); |
Pokitto | 23:f88837b8f914 | 416 | uint16_t skipImageRowsAtImageEnd = biAbsHeight-(skipImageRowsAtImageStart+clipHeightOnScreen); |
Pokitto | 23:f88837b8f914 | 417 | |
Pokitto | 23:f88837b8f914 | 418 | /* Vertical loop parameters */ |
Pokitto | 23:f88837b8f914 | 419 | int incY, startY, pastEndY; |
Pokitto | 23:f88837b8f914 | 420 | uint32_t skipImageRowsAsBytes = 0; |
Pokitto | 23:f88837b8f914 | 421 | if (bmi.bmiHeader.biHeight > 0 ) { |
Pokitto | 23:f88837b8f914 | 422 | /* Mirror vertically */ |
Pokitto | 23:f88837b8f914 | 423 | incY = -1; |
Pokitto | 23:f88837b8f914 | 424 | startY = clipY2OnScreen; |
Pokitto | 23:f88837b8f914 | 425 | pastEndY = clipY1OnScreen-1; |
Pokitto | 23:f88837b8f914 | 426 | skipImageRowsAsBytes = skipImageRowsAtImageEnd*bmi.bmiHeader.biWidth*3; // 3 bytes per pixel |
Pokitto | 23:f88837b8f914 | 427 | } |
Pokitto | 23:f88837b8f914 | 428 | else { |
Pokitto | 23:f88837b8f914 | 429 | /* Do not mirror */ |
Pokitto | 23:f88837b8f914 | 430 | incY = 1; |
Pokitto | 23:f88837b8f914 | 431 | startY = clipY1OnScreen ; |
Pokitto | 23:f88837b8f914 | 432 | pastEndY = clipY2OnScreen+1; |
Pokitto | 23:f88837b8f914 | 433 | skipImageRowsAsBytes = skipImageRowsAtImageStart*bmi.bmiHeader.biWidth*3; // 3 bytes per pixel |
Pokitto | 23:f88837b8f914 | 434 | } |
Pokitto | 23:f88837b8f914 | 435 | |
Pokitto | 23:f88837b8f914 | 436 | /** Read and copy image data directly to the screen **/ |
Pokitto | 23:f88837b8f914 | 437 | |
Pokitto | 23:f88837b8f914 | 438 | /* Seek to the beginning of the data */ |
Pokitto | 23:f88837b8f914 | 439 | fileSeekAbsolute(bf.bfOffBits); |
Pokitto | 23:f88837b8f914 | 440 | |
Pokitto | 23:f88837b8f914 | 441 | /* Seek until the image rect starts */ |
Pokitto | 23:f88837b8f914 | 442 | if (skipImageRowsAsBytes>0) fileSeekRelative( skipImageRowsAsBytes ); |
Pokitto | 23:f88837b8f914 | 443 | |
Pokitto | 23:f88837b8f914 | 444 | /* Copy all bytes to the output bitmap */ |
Pokitto | 23:f88837b8f914 | 445 | for ( int y = startY; y != pastEndY; y += incY) { |
Pokitto | 23:f88837b8f914 | 446 | |
Pokitto | 23:f88837b8f914 | 447 | /* Seek until the image rect starts */ |
Pokitto | 23:f88837b8f914 | 448 | if (skipImagePixelsAtLineStartAsBytes>0) fileSeekRelative( skipImagePixelsAtLineStartAsBytes ); |
Pokitto | 23:f88837b8f914 | 449 | |
Pokitto | 23:f88837b8f914 | 450 | for ( int x = clipX1OnScreen; x <= clipX2OnScreen; x++) { |
Pokitto | 23:f88837b8f914 | 451 | |
Pokitto | 23:f88837b8f914 | 452 | /* Read RGB pixel from the file. For 24 bpp the pixel is stored to 3 bytes*/ |
Pokitto | 23:f88837b8f914 | 453 | uint32_t rgb24; |
Pokitto | 23:f88837b8f914 | 454 | if (fileReadBytes((uint8_t*)&rgb24, 3) != 3) |
Pokitto | 23:f88837b8f914 | 455 | { |
Pokitto | 23:f88837b8f914 | 456 | POK_TRACE("Error reading BMP data\n"); |
Pokitto | 23:f88837b8f914 | 457 | fileClose(); |
Pokitto | 23:f88837b8f914 | 458 | return(-1); |
Pokitto | 23:f88837b8f914 | 459 | } |
Pokitto | 23:f88837b8f914 | 460 | |
Pokitto | 23:f88837b8f914 | 461 | /* Copy a pixel from the file directly to the screen */ |
Pokitto | 23:f88837b8f914 | 462 | // uint8_t r,g,b; |
Pokitto | 23:f88837b8f914 | 463 | // r = (xrgb >> (3 + 16)) & 0x1f; // 5 bit |
Pokitto | 23:f88837b8f914 | 464 | // g = (xrgb >> (2 + 8)) & 0x3f; // 6 bits |
Pokitto | 23:f88837b8f914 | 465 | // b = (xrgb >> 3) & 0x1f; // 5 bits |
Pokitto | 23:f88837b8f914 | 466 | // uint16_t targetpixel = (r<<11) | (g<<5) | b; |
Pokitto | 23:f88837b8f914 | 467 | |
Pokitto | 23:f88837b8f914 | 468 | uint16_t targetpixel = |
Pokitto | 23:f88837b8f914 | 469 | ((rgb24 >> 8) & 0x0000F800) | // red (bits 15-11) |
Pokitto | 23:f88837b8f914 | 470 | ((rgb24 >> 5) & 0x000007E0) | // green (bits 10-5) |
Pokitto | 23:f88837b8f914 | 471 | ((rgb24 >> 3) & 0x0000001F); // blue (bits 4-0) |
Pokitto | 23:f88837b8f914 | 472 | _game.display.directPixel(x, y, targetpixel); |
Pokitto | 23:f88837b8f914 | 473 | } // end for |
Pokitto | 23:f88837b8f914 | 474 | |
Pokitto | 23:f88837b8f914 | 475 | /* Skip pixels at line end */ |
Pokitto | 23:f88837b8f914 | 476 | if (skipImagePixelsAtLineEndAsBytes>0) fileSeekRelative( skipImagePixelsAtLineEndAsBytes ); |
Pokitto | 23:f88837b8f914 | 477 | |
Pokitto | 23:f88837b8f914 | 478 | } // end for |
Pokitto | 23:f88837b8f914 | 479 | |
Pokitto | 23:f88837b8f914 | 480 | // Done with the file reading. |
Pokitto | 23:f88837b8f914 | 481 | fileClose(); |
Pokitto | 23:f88837b8f914 | 482 | |
Pokitto | 23:f88837b8f914 | 483 | return 0; |
Pokitto | 23:f88837b8f914 | 484 | } |
Pokitto | 23:f88837b8f914 | 485 | |
Pokitto | 23:f88837b8f914 | 486 | #endif |
Pokitto | 23:f88837b8f914 | 487 |