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@23:f88837b8f914, 2017-12-29 (annotated)
- Committer:
- Pokitto
- Date:
- Fri Dec 29 05:17:10 2017 +0000
- Revision:
- 23:f88837b8f914
- Child:
- 45:bbfc6002118c
PokittoLib mbed and Github are back in sync with all contributions from Hanski and Spinal included
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 | 23:f88837b8f914 | 53 | #if POK_ENABLE_SD > 0 |
Pokitto | 23:f88837b8f914 | 54 | |
Pokitto | 23:f88837b8f914 | 55 | |
Pokitto | 23:f88837b8f914 | 56 | #include "PokittoDisplay.h" |
Pokitto | 23:f88837b8f914 | 57 | #include "ImageFormat.h" |
Pokitto | 23:f88837b8f914 | 58 | |
Pokitto | 23:f88837b8f914 | 59 | Pokitto::Core _game; |
Pokitto | 23:f88837b8f914 | 60 | Pokitto::Display pokdisp; |
Pokitto | 23:f88837b8f914 | 61 | |
Pokitto | 23:f88837b8f914 | 62 | int openImageFileFromSD(char* filepath, uint16_t **palette_out, uint8_t **bitmap_out) { |
Pokitto | 23:f88837b8f914 | 63 | |
Pokitto | 23:f88837b8f914 | 64 | // Reset the out pointers. |
Pokitto | 23:f88837b8f914 | 65 | *palette_out = 0; |
Pokitto | 23:f88837b8f914 | 66 | *bitmap_out = 0; |
Pokitto | 23:f88837b8f914 | 67 | |
Pokitto | 23:f88837b8f914 | 68 | BITMAPFILEHEADER bf; |
Pokitto | 23:f88837b8f914 | 69 | BITMAPINFO bmi; |
Pokitto | 23:f88837b8f914 | 70 | |
Pokitto | 23:f88837b8f914 | 71 | uint32_t bytes_read=0, bmpsize=0; |
Pokitto | 23:f88837b8f914 | 72 | |
Pokitto | 23:f88837b8f914 | 73 | /** numcol is the number of colors for output */ |
Pokitto | 23:f88837b8f914 | 74 | unsigned int numcol = 0; |
Pokitto | 23:f88837b8f914 | 75 | |
Pokitto | 23:f88837b8f914 | 76 | if (POK_COLORDEPTH == 8) numcol=256; |
Pokitto | 23:f88837b8f914 | 77 | else if (POK_COLORDEPTH == 4) numcol=16; |
Pokitto | 23:f88837b8f914 | 78 | else if (POK_COLORDEPTH == 2) numcol=4; |
Pokitto | 23:f88837b8f914 | 79 | else if (POK_COLORDEPTH == 1) numcol=1; |
Pokitto | 23:f88837b8f914 | 80 | |
Pokitto | 23:f88837b8f914 | 81 | if (!isThisFileOpen(filepath)) { |
Pokitto | 23:f88837b8f914 | 82 | fileClose(); // close any open files |
Pokitto | 23:f88837b8f914 | 83 | fileOpen(filepath, FILE_MODE_READONLY | FILE_MODE_BINARY); |
Pokitto | 23:f88837b8f914 | 84 | } |
Pokitto | 23:f88837b8f914 | 85 | else |
Pokitto | 23:f88837b8f914 | 86 | return -1; // Already open, not good. |
Pokitto | 23:f88837b8f914 | 87 | |
Pokitto | 23:f88837b8f914 | 88 | if (fileOK() && fileReadBytes((uint8_t*)&bf, sizeof(bf)) == sizeof(bf) ) { |
Pokitto | 23:f88837b8f914 | 89 | bytes_read += sizeof(bf); |
Pokitto | 23:f88837b8f914 | 90 | } |
Pokitto | 23:f88837b8f914 | 91 | else |
Pokitto | 23:f88837b8f914 | 92 | { |
Pokitto | 23:f88837b8f914 | 93 | POK_TRACE("Error reading BMP header\n"); |
Pokitto | 23:f88837b8f914 | 94 | fileClose(); |
Pokitto | 23:f88837b8f914 | 95 | return(-1); |
Pokitto | 23:f88837b8f914 | 96 | } |
Pokitto | 23:f88837b8f914 | 97 | |
Pokitto | 23:f88837b8f914 | 98 | if (fileReadBytes((uint8_t*)&bmi,sizeof(bmi.bmiHeader)) != sizeof(bmi.bmiHeader)) { |
Pokitto | 23:f88837b8f914 | 99 | POK_TRACE("Error reading BMP info\n"); |
Pokitto | 23:f88837b8f914 | 100 | fileClose(); |
Pokitto | 23:f88837b8f914 | 101 | return(-1); |
Pokitto | 23:f88837b8f914 | 102 | } |
Pokitto | 23:f88837b8f914 | 103 | bytes_read += sizeof(bmi.bmiHeader); |
Pokitto | 23:f88837b8f914 | 104 | |
Pokitto | 23:f88837b8f914 | 105 | /** Check image validity */ |
Pokitto | 23:f88837b8f914 | 106 | |
Pokitto | 23:f88837b8f914 | 107 | if (bf.bfType != 0x4D42) { |
Pokitto | 23:f88837b8f914 | 108 | POK_TRACE("Bitmap file has an unrecognized format (4D42 id missing from beginning).\n"); |
Pokitto | 23:f88837b8f914 | 109 | POK_TRACE("BMP2POK accepts .BMP files that have an indexed (1,-bit, 4-bit or 8-bit) color palette.\n"); |
Pokitto | 23:f88837b8f914 | 110 | fileClose(); |
Pokitto | 23:f88837b8f914 | 111 | return(-1); |
Pokitto | 23:f88837b8f914 | 112 | } |
Pokitto | 23:f88837b8f914 | 113 | if (bmi.bmiHeader.biBitCount != POK_COLORDEPTH ) { |
Pokitto | 23:f88837b8f914 | 114 | POK_TRACE("ERROR!\nThe image color depth should be the same as screen color depth!\n"); |
Pokitto | 23:f88837b8f914 | 115 | } |
Pokitto | 23:f88837b8f914 | 116 | if (bmi.bmiHeader.biWidth%32 && bmi.bmiHeader.biBitCount == 1) { |
Pokitto | 23:f88837b8f914 | 117 | POK_TRACE("ERROR!\nPadding of 1-bit (monochrome) images is not yet supported\n"); |
Pokitto | 23:f88837b8f914 | 118 | POK_TRACE("1-bit images need to have width that is divisible by 32!\n"); |
Pokitto | 23:f88837b8f914 | 119 | POK_TRACE("Adjust size of source image.\n"); |
Pokitto | 23:f88837b8f914 | 120 | fileClose(); |
Pokitto | 23:f88837b8f914 | 121 | return(-1); |
Pokitto | 23:f88837b8f914 | 122 | } |
Pokitto | 23:f88837b8f914 | 123 | if (bmi.bmiHeader.biWidth%4) { |
Pokitto | 23:f88837b8f914 | 124 | POK_TRACE("Width is not divisible by 4\n"); |
Pokitto | 23:f88837b8f914 | 125 | fileClose(); |
Pokitto | 23:f88837b8f914 | 126 | return(-1); |
Pokitto | 23:f88837b8f914 | 127 | } |
Pokitto | 23:f88837b8f914 | 128 | if (bmi.bmiHeader.biWidth%8 && bmi.bmiHeader.biBitCount==4) { |
Pokitto | 23:f88837b8f914 | 129 | if (bmi.bmiHeader.biWidth%4) { |
Pokitto | 23:f88837b8f914 | 130 | POK_TRACE("ERROR!\n4-bit source images have to have a width that is divisible by 4\n"); |
Pokitto | 23:f88837b8f914 | 131 | fileClose(); |
Pokitto | 23:f88837b8f914 | 132 | return(-1); |
Pokitto | 23:f88837b8f914 | 133 | } |
Pokitto | 23:f88837b8f914 | 134 | } |
Pokitto | 23:f88837b8f914 | 135 | if (bmi.bmiHeader.biBitCount != 8 && bmi.bmiHeader.biBitCount != 4 && bmi.bmiHeader.biBitCount != 1) |
Pokitto | 23:f88837b8f914 | 136 | { |
Pokitto | 23:f88837b8f914 | 137 | POK_TRACE("Only 8bpp, 4bpp & 1bpp BMP files are supported\n"); |
Pokitto | 23:f88837b8f914 | 138 | fileClose(); |
Pokitto | 23:f88837b8f914 | 139 | return(-1); |
Pokitto | 23:f88837b8f914 | 140 | } |
Pokitto | 23:f88837b8f914 | 141 | if (bmi.bmiHeader.biCompression != 0 && |
Pokitto | 23:f88837b8f914 | 142 | !(bmi.bmiHeader.biCompression == BI_RLE4 && bmi.bmiHeader.biBitCount == 4)) |
Pokitto | 23:f88837b8f914 | 143 | { |
Pokitto | 23:f88837b8f914 | 144 | POK_TRACE("Only RLE compression for bitmaps with 4 bpp is supported\n"); |
Pokitto | 23:f88837b8f914 | 145 | fileClose(); |
Pokitto | 23:f88837b8f914 | 146 | return(-1); |
Pokitto | 23:f88837b8f914 | 147 | } |
Pokitto | 23:f88837b8f914 | 148 | |
Pokitto | 23:f88837b8f914 | 149 | /* If the height is negative the bmp image is in the correct way. |
Pokitto | 23:f88837b8f914 | 150 | If the heigh is positive the bmp image is vertically mirrored |
Pokitto | 23:f88837b8f914 | 151 | */ |
Pokitto | 23:f88837b8f914 | 152 | int biAbsHeight = bmi.bmiHeader.biHeight; |
Pokitto | 23:f88837b8f914 | 153 | if (bmi.bmiHeader.biHeight < 0 ) |
Pokitto | 23:f88837b8f914 | 154 | biAbsHeight = - bmi.bmiHeader.biHeight; |
Pokitto | 23:f88837b8f914 | 155 | |
Pokitto | 23:f88837b8f914 | 156 | /** Read and copy palette **/ |
Pokitto | 23:f88837b8f914 | 157 | |
Pokitto | 23:f88837b8f914 | 158 | int c = bmi.bmiHeader.biClrUsed; |
Pokitto | 23:f88837b8f914 | 159 | if (c==0) c = 1 << bmi.bmiHeader.biBitCount; // from MS BMP specs. 0 means 2^n colors |
Pokitto | 23:f88837b8f914 | 160 | bmi.bmiHeader.biClrUsed = c; |
Pokitto | 23:f88837b8f914 | 161 | |
Pokitto | 23:f88837b8f914 | 162 | /* Allocate memory for the output parameter */ |
Pokitto | 23:f88837b8f914 | 163 | if (numcol>bmi.bmiHeader.biClrUsed) numcol = bmi.bmiHeader.biClrUsed; |
Pokitto | 23:f88837b8f914 | 164 | *palette_out = (uint16_t*) malloc(numcol*2); |
Pokitto | 23:f88837b8f914 | 165 | if (*palette_out == NULL) |
Pokitto | 23:f88837b8f914 | 166 | { |
Pokitto | 23:f88837b8f914 | 167 | POK_TRACE("Error allocating temporary palette buffer.\n"); |
Pokitto | 23:f88837b8f914 | 168 | free(*palette_out); |
Pokitto | 23:f88837b8f914 | 169 | return(-1); |
Pokitto | 23:f88837b8f914 | 170 | } |
Pokitto | 23:f88837b8f914 | 171 | |
Pokitto | 23:f88837b8f914 | 172 | /* seek to the beginning of the color table - because of gimp */ |
Pokitto | 23:f88837b8f914 | 173 | fileSeekAbsolute(bf.bfOffBits-c*4); //gfx data star minus color table |
Pokitto | 23:f88837b8f914 | 174 | |
Pokitto | 23:f88837b8f914 | 175 | for (unsigned int c=0;c<numcol;c++) { |
Pokitto | 23:f88837b8f914 | 176 | |
Pokitto | 23:f88837b8f914 | 177 | RGBQUAD rgbValue; |
Pokitto | 23:f88837b8f914 | 178 | fileReadBytes((uint8_t*)&rgbValue, sizeof(RGBQUAD)); |
Pokitto | 23:f88837b8f914 | 179 | bytes_read += sizeof(RGBQUAD); |
Pokitto | 23:f88837b8f914 | 180 | |
Pokitto | 23:f88837b8f914 | 181 | unsigned int r,g,b,o; |
Pokitto | 23:f88837b8f914 | 182 | r = rgbValue.rgbRed >> 3; // 5 bit |
Pokitto | 23:f88837b8f914 | 183 | g = rgbValue.rgbGreen >> 2; // 6 bits |
Pokitto | 23:f88837b8f914 | 184 | b = rgbValue.rgbBlue >> 3; // 5 bits |
Pokitto | 23:f88837b8f914 | 185 | o = (r<<11)|(g<<5)|b; |
Pokitto | 23:f88837b8f914 | 186 | |
Pokitto | 23:f88837b8f914 | 187 | (*palette_out)[c] = o; |
Pokitto | 23:f88837b8f914 | 188 | } |
Pokitto | 23:f88837b8f914 | 189 | |
Pokitto | 23:f88837b8f914 | 190 | /** Read and copy image data **/ |
Pokitto | 23:f88837b8f914 | 191 | |
Pokitto | 23:f88837b8f914 | 192 | /* Get image data size. If the biSizeImage is given (>0) for RLE image, use that to reduce memory usage. */ |
Pokitto | 23:f88837b8f914 | 193 | bmpsize = bmi.bmiHeader.biWidth * biAbsHeight*bmi.bmiHeader.biBitCount/8; |
Pokitto | 23:f88837b8f914 | 194 | if (bmi.bmiHeader.biCompression == BI_RLE4) |
Pokitto | 23:f88837b8f914 | 195 | bmpsize = (bmi.bmiHeader.biSizeImage > 0) ? bmi.bmiHeader.biSizeImage : bmpsize; |
Pokitto | 23:f88837b8f914 | 196 | |
Pokitto | 23:f88837b8f914 | 197 | // SEEK to the beginning of the data |
Pokitto | 23:f88837b8f914 | 198 | fileSeekAbsolute(bf.bfOffBits); |
Pokitto | 23:f88837b8f914 | 199 | |
Pokitto | 23:f88837b8f914 | 200 | /* Allocate output data buffer */ |
Pokitto | 23:f88837b8f914 | 201 | *bitmap_out = (uint8_t *) malloc(bmpsize + 2); // header takes 2 bytes |
Pokitto | 23:f88837b8f914 | 202 | if (*bitmap_out == NULL) |
Pokitto | 23:f88837b8f914 | 203 | { |
Pokitto | 23:f88837b8f914 | 204 | POK_TRACE("Error allocating temporary data buffer, is image too big?\n"); |
Pokitto | 23:f88837b8f914 | 205 | free(*palette_out); |
Pokitto | 23:f88837b8f914 | 206 | return(-1); |
Pokitto | 23:f88837b8f914 | 207 | } |
Pokitto | 23:f88837b8f914 | 208 | |
Pokitto | 23:f88837b8f914 | 209 | /* Store image size to the pokitto bitmap header */ |
Pokitto | 23:f88837b8f914 | 210 | uint32_t outindex = 0; |
Pokitto | 23:f88837b8f914 | 211 | (*bitmap_out)[outindex++] = bmi.bmiHeader.biWidth; |
Pokitto | 23:f88837b8f914 | 212 | (*bitmap_out)[outindex++] = biAbsHeight; |
Pokitto | 23:f88837b8f914 | 213 | |
Pokitto | 23:f88837b8f914 | 214 | if (bmi.bmiHeader.biCompression == BI_RLE4) { |
Pokitto | 23:f88837b8f914 | 215 | bool eofReached = false; |
Pokitto | 23:f88837b8f914 | 216 | while (outindex < bmpsize && !eofReached ) { |
Pokitto | 23:f88837b8f914 | 217 | /* Read byte from the file. */ |
Pokitto | 23:f88837b8f914 | 218 | unsigned char rleByte; |
Pokitto | 23:f88837b8f914 | 219 | if (fileReadBytes(&rleByte, sizeof(rleByte)) != sizeof(rleByte)) |
Pokitto | 23:f88837b8f914 | 220 | { |
Pokitto | 23:f88837b8f914 | 221 | /* End of file reached. Allocate a new bitmap which is of the exact size of the data */ |
Pokitto | 23:f88837b8f914 | 222 | eofReached = true; |
Pokitto | 23:f88837b8f914 | 223 | |
Pokitto | 23:f88837b8f914 | 224 | /* Allocate output data buffer */ |
Pokitto | 23:f88837b8f914 | 225 | uint8_t* old_bitmap = *bitmap_out; |
Pokitto | 23:f88837b8f914 | 226 | *bitmap_out = NULL; |
Pokitto | 23:f88837b8f914 | 227 | *bitmap_out = (uint8_t *) malloc(outindex); // header takes 2 bytes |
Pokitto | 23:f88837b8f914 | 228 | if (*bitmap_out == NULL) |
Pokitto | 23:f88837b8f914 | 229 | { |
Pokitto | 23:f88837b8f914 | 230 | POK_TRACE("Error allocating temporary data buffer, is image too big?\n"); |
Pokitto | 23:f88837b8f914 | 231 | free(old_bitmap); |
Pokitto | 23:f88837b8f914 | 232 | free(*palette_out); |
Pokitto | 23:f88837b8f914 | 233 | return(-1); |
Pokitto | 23:f88837b8f914 | 234 | } |
Pokitto | 23:f88837b8f914 | 235 | |
Pokitto | 23:f88837b8f914 | 236 | /* Copy data */ |
Pokitto | 23:f88837b8f914 | 237 | for (int i=0; i<outindex;i++) |
Pokitto | 23:f88837b8f914 | 238 | (*bitmap_out)[i] = old_bitmap[i]; |
Pokitto | 23:f88837b8f914 | 239 | |
Pokitto | 23:f88837b8f914 | 240 | /* Free original bitmap */ |
Pokitto | 23:f88837b8f914 | 241 | free(old_bitmap); |
Pokitto | 23:f88837b8f914 | 242 | } |
Pokitto | 23:f88837b8f914 | 243 | else { |
Pokitto | 23:f88837b8f914 | 244 | /* Store byte */ |
Pokitto | 23:f88837b8f914 | 245 | (*bitmap_out)[outindex++] = rleByte; |
Pokitto | 23:f88837b8f914 | 246 | } |
Pokitto | 23:f88837b8f914 | 247 | } // end while |
Pokitto | 23:f88837b8f914 | 248 | } |
Pokitto | 23:f88837b8f914 | 249 | else { |
Pokitto | 23:f88837b8f914 | 250 | /* Do vertical mirroring only for uncompressed data. |
Pokitto | 23:f88837b8f914 | 251 | Note the compressed RLE data above could not be mirrored. |
Pokitto | 23:f88837b8f914 | 252 | */ |
Pokitto | 23:f88837b8f914 | 253 | int widthInBytes = bmi.bmiHeader.biWidth * bmi.bmiHeader.biBitCount/8; |
Pokitto | 23:f88837b8f914 | 254 | int widthInBytesInc, incY, startY, endY; |
Pokitto | 23:f88837b8f914 | 255 | if (bmi.bmiHeader.biHeight > 0 ) { |
Pokitto | 23:f88837b8f914 | 256 | /* Mirror vertically */ |
Pokitto | 23:f88837b8f914 | 257 | widthInBytesInc = - widthInBytes; |
Pokitto | 23:f88837b8f914 | 258 | incY = -1; |
Pokitto | 23:f88837b8f914 | 259 | startY = biAbsHeight - 1; |
Pokitto | 23:f88837b8f914 | 260 | endY = -1; |
Pokitto | 23:f88837b8f914 | 261 | } |
Pokitto | 23:f88837b8f914 | 262 | else { |
Pokitto | 23:f88837b8f914 | 263 | /* Do not mirror */ |
Pokitto | 23:f88837b8f914 | 264 | widthInBytesInc = widthInBytes; |
Pokitto | 23:f88837b8f914 | 265 | incY = 1; |
Pokitto | 23:f88837b8f914 | 266 | startY = 0; |
Pokitto | 23:f88837b8f914 | 267 | endY = biAbsHeight; |
Pokitto | 23:f88837b8f914 | 268 | } |
Pokitto | 23:f88837b8f914 | 269 | |
Pokitto | 23:f88837b8f914 | 270 | /* Copy all bytes to the output bitmap */ |
Pokitto | 23:f88837b8f914 | 271 | for ( int y = startY, beginLine=startY*widthInBytes; y != endY; y += incY, beginLine += widthInBytesInc) { |
Pokitto | 23:f88837b8f914 | 272 | |
Pokitto | 23:f88837b8f914 | 273 | /* Go to the beginning of the previous or next line */ |
Pokitto | 23:f88837b8f914 | 274 | outindex = beginLine; |
Pokitto | 23:f88837b8f914 | 275 | |
Pokitto | 23:f88837b8f914 | 276 | for ( int xbyte = 0; xbyte < widthInBytes; xbyte++) { |
Pokitto | 23:f88837b8f914 | 277 | |
Pokitto | 23:f88837b8f914 | 278 | /* Read byte from the file. */ |
Pokitto | 23:f88837b8f914 | 279 | unsigned char byteOfPixels; |
Pokitto | 23:f88837b8f914 | 280 | if (fileReadBytes(&byteOfPixels, sizeof(byteOfPixels)) != sizeof(byteOfPixels)) |
Pokitto | 23:f88837b8f914 | 281 | { |
Pokitto | 23:f88837b8f914 | 282 | POK_TRACE("Error reading BMP data\n"); |
Pokitto | 23:f88837b8f914 | 283 | fileClose(); |
Pokitto | 23:f88837b8f914 | 284 | free(*bitmap_out); |
Pokitto | 23:f88837b8f914 | 285 | free(*palette_out); |
Pokitto | 23:f88837b8f914 | 286 | return(-1); |
Pokitto | 23:f88837b8f914 | 287 | } |
Pokitto | 23:f88837b8f914 | 288 | |
Pokitto | 23:f88837b8f914 | 289 | /* Copy a byte from the file to the bitmap */ |
Pokitto | 23:f88837b8f914 | 290 | (*bitmap_out)[2 + outindex] = byteOfPixels; |
Pokitto | 23:f88837b8f914 | 291 | outindex++; |
Pokitto | 23:f88837b8f914 | 292 | } // end for |
Pokitto | 23:f88837b8f914 | 293 | } // end for |
Pokitto | 23:f88837b8f914 | 294 | } // end if |
Pokitto | 23:f88837b8f914 | 295 | |
Pokitto | 23:f88837b8f914 | 296 | // Done with the file reading. |
Pokitto | 23:f88837b8f914 | 297 | fileClose(); |
Pokitto | 23:f88837b8f914 | 298 | |
Pokitto | 23:f88837b8f914 | 299 | return 0; |
Pokitto | 23:f88837b8f914 | 300 | } |
Pokitto | 23:f88837b8f914 | 301 | |
Pokitto | 23:f88837b8f914 | 302 | int directDrawImageFileFromSD(int16_t sx, int16_t sy, char* filepath) { |
Pokitto | 23:f88837b8f914 | 303 | |
Pokitto | 23:f88837b8f914 | 304 | return(directDrawImageFileFromSD(0, 0, 0/* full width */, 0/* full height */, sx, sy, filepath)); |
Pokitto | 23:f88837b8f914 | 305 | } |
Pokitto | 23:f88837b8f914 | 306 | |
Pokitto | 23:f88837b8f914 | 307 | 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 | 308 | |
Pokitto | 23:f88837b8f914 | 309 | BITMAPFILEHEADER bf; |
Pokitto | 23:f88837b8f914 | 310 | BITMAPINFO bmi; |
Pokitto | 23:f88837b8f914 | 311 | |
Pokitto | 23:f88837b8f914 | 312 | uint32_t bytes_read=0; |
Pokitto | 23:f88837b8f914 | 313 | |
Pokitto | 23:f88837b8f914 | 314 | if (!isThisFileOpen(filepath)) { |
Pokitto | 23:f88837b8f914 | 315 | fileClose(); // close any open files |
Pokitto | 23:f88837b8f914 | 316 | fileOpen(filepath, FILE_MODE_READONLY | FILE_MODE_BINARY); |
Pokitto | 23:f88837b8f914 | 317 | } |
Pokitto | 23:f88837b8f914 | 318 | else { |
Pokitto | 23:f88837b8f914 | 319 | POK_TRACE("Error! Already open\n"); |
Pokitto | 23:f88837b8f914 | 320 | return -1; // Already open, not good. |
Pokitto | 23:f88837b8f914 | 321 | } |
Pokitto | 23:f88837b8f914 | 322 | |
Pokitto | 23:f88837b8f914 | 323 | if (fileOK() && fileReadBytes((uint8_t*)&bf, sizeof(bf)) == sizeof(bf) ) { //!HV why we have to check fileOK()? |
Pokitto | 23:f88837b8f914 | 324 | bytes_read += sizeof(bf); |
Pokitto | 23:f88837b8f914 | 325 | } |
Pokitto | 23:f88837b8f914 | 326 | else |
Pokitto | 23:f88837b8f914 | 327 | { |
Pokitto | 23:f88837b8f914 | 328 | POK_TRACE("Error reading BMP header\n"); |
Pokitto | 23:f88837b8f914 | 329 | fileClose(); |
Pokitto | 23:f88837b8f914 | 330 | return(-1); |
Pokitto | 23:f88837b8f914 | 331 | } |
Pokitto | 23:f88837b8f914 | 332 | |
Pokitto | 23:f88837b8f914 | 333 | if (fileReadBytes((uint8_t*)&bmi,sizeof(bmi.bmiHeader)) != sizeof(bmi.bmiHeader)) { |
Pokitto | 23:f88837b8f914 | 334 | POK_TRACE("Error reading BMP info\n"); |
Pokitto | 23:f88837b8f914 | 335 | fileClose(); |
Pokitto | 23:f88837b8f914 | 336 | return(-1); |
Pokitto | 23:f88837b8f914 | 337 | } |
Pokitto | 23:f88837b8f914 | 338 | bytes_read += sizeof(bmi.bmiHeader); |
Pokitto | 23:f88837b8f914 | 339 | |
Pokitto | 23:f88837b8f914 | 340 | /** Check image validity */ |
Pokitto | 23:f88837b8f914 | 341 | |
Pokitto | 23:f88837b8f914 | 342 | if (bf.bfType != 0x4D42) { |
Pokitto | 23:f88837b8f914 | 343 | POK_TRACE("Bitmap file has an unrecognized format (4D42 id missing from beginning).\n"); |
Pokitto | 23:f88837b8f914 | 344 | POK_TRACE("BMP2POK accepts .BMP files that have an indexed (1,-bit, 4-bit or 8-bit) color palette.\n"); |
Pokitto | 23:f88837b8f914 | 345 | fileClose(); |
Pokitto | 23:f88837b8f914 | 346 | return(-1); |
Pokitto | 23:f88837b8f914 | 347 | } |
Pokitto | 23:f88837b8f914 | 348 | if (bmi.bmiHeader.biBitCount != 24 ) { |
Pokitto | 23:f88837b8f914 | 349 | POK_TRACE("ERROR!\nThe image color depth should be the same as screen color depth (%d)!\n"); |
Pokitto | 23:f88837b8f914 | 350 | fileClose(); |
Pokitto | 23:f88837b8f914 | 351 | return(-1); |
Pokitto | 23:f88837b8f914 | 352 | } |
Pokitto | 23:f88837b8f914 | 353 | if (bmi.bmiHeader.biCompression != 0 ) |
Pokitto | 23:f88837b8f914 | 354 | { |
Pokitto | 23:f88837b8f914 | 355 | POK_TRACE("Compression is not supported.\n"); |
Pokitto | 23:f88837b8f914 | 356 | fileClose(); |
Pokitto | 23:f88837b8f914 | 357 | return(-1); |
Pokitto | 23:f88837b8f914 | 358 | } |
Pokitto | 23:f88837b8f914 | 359 | |
Pokitto | 23:f88837b8f914 | 360 | /* If the height is negative the bmp image is in the correct way. |
Pokitto | 23:f88837b8f914 | 361 | If the heigh is positive the bmp image is vertically mirrored |
Pokitto | 23:f88837b8f914 | 362 | */ |
Pokitto | 23:f88837b8f914 | 363 | int biAbsHeight = bmi.bmiHeader.biHeight; |
Pokitto | 23:f88837b8f914 | 364 | if (bmi.bmiHeader.biHeight < 0 ) |
Pokitto | 23:f88837b8f914 | 365 | biAbsHeight = - bmi.bmiHeader.biHeight; |
Pokitto | 23:f88837b8f914 | 366 | |
Pokitto | 23:f88837b8f914 | 367 | /** Zero size parameter means full image size */ |
Pokitto | 23:f88837b8f914 | 368 | if(iw==0) iw = bmi.bmiHeader.biWidth; // 0 means full image width |
Pokitto | 23:f88837b8f914 | 369 | if(ih==0) ih = biAbsHeight; // 0 means full image width |
Pokitto | 23:f88837b8f914 | 370 | |
Pokitto | 23:f88837b8f914 | 371 | /** Check parameters */ |
Pokitto | 23:f88837b8f914 | 372 | if( ix + iw > bmi.bmiHeader.biWidth ) { |
Pokitto | 23:f88837b8f914 | 373 | POK_TRACE("Error! Invalid parameter\n"); |
Pokitto | 23:f88837b8f914 | 374 | fileClose(); |
Pokitto | 23:f88837b8f914 | 375 | return(-1); |
Pokitto | 23:f88837b8f914 | 376 | } |
Pokitto | 23:f88837b8f914 | 377 | if( iy + ih > biAbsHeight ) { |
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( sx > pokdisp.getWidth()-1 || sx<-iw) { |
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( sy > pokdisp.getHeight()-1 || sy<-ih) { |
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 | |
Pokitto | 23:f88837b8f914 | 393 | /** Zero size parameter means full image size */ |
Pokitto | 23:f88837b8f914 | 394 | if(iw==0) iw = bmi.bmiHeader.biWidth; // 0 means full image width |
Pokitto | 23:f88837b8f914 | 395 | if(ih==0) ih = biAbsHeight; // 0 means full image width |
Pokitto | 23:f88837b8f914 | 396 | |
Pokitto | 23:f88837b8f914 | 397 | /** Clip image to screen dimensions */ |
Pokitto | 23:f88837b8f914 | 398 | |
Pokitto | 23:f88837b8f914 | 399 | int16_t clipX1OnScreen = max( 0, sx); |
Pokitto | 23:f88837b8f914 | 400 | int16_t clipX2OnScreen = min( pokdisp.getWidth()-1, sx+iw-1); |
Pokitto | 23:f88837b8f914 | 401 | int16_t clipWidthOnScreen = clipX2OnScreen-clipX1OnScreen+1; |
Pokitto | 23:f88837b8f914 | 402 | int16_t clipY1OnScreen = max( 0, sy); |
Pokitto | 23:f88837b8f914 | 403 | int16_t clipY2OnScreen = min( pokdisp.getHeight()-1, sy+ih-1); |
Pokitto | 23:f88837b8f914 | 404 | int16_t clipHeightOnScreen = clipY2OnScreen-clipY1OnScreen+1; |
Pokitto | 23:f88837b8f914 | 405 | |
Pokitto | 23:f88837b8f914 | 406 | uint16_t skipImagePixelsAtLineStart = ix+(clipX1OnScreen-sx); |
Pokitto | 23:f88837b8f914 | 407 | uint16_t skipImagePixelsAtLineStartAsBytes = skipImagePixelsAtLineStart*3; // 3 bytes per pixel |
Pokitto | 23:f88837b8f914 | 408 | uint16_t skipImagePixelsAtLineEndAsBytes = (bmi.bmiHeader.biWidth-(skipImagePixelsAtLineStart+clipWidthOnScreen))*3; // 3 bytes per pixel |
Pokitto | 23:f88837b8f914 | 409 | |
Pokitto | 23:f88837b8f914 | 410 | uint16_t skipImageRowsAtImageStart = iy+(clipY1OnScreen-sy); |
Pokitto | 23:f88837b8f914 | 411 | uint16_t skipImageRowsAtImageEnd = biAbsHeight-(skipImageRowsAtImageStart+clipHeightOnScreen); |
Pokitto | 23:f88837b8f914 | 412 | |
Pokitto | 23:f88837b8f914 | 413 | /* Vertical loop parameters */ |
Pokitto | 23:f88837b8f914 | 414 | int incY, startY, pastEndY; |
Pokitto | 23:f88837b8f914 | 415 | uint32_t skipImageRowsAsBytes = 0; |
Pokitto | 23:f88837b8f914 | 416 | if (bmi.bmiHeader.biHeight > 0 ) { |
Pokitto | 23:f88837b8f914 | 417 | /* Mirror vertically */ |
Pokitto | 23:f88837b8f914 | 418 | incY = -1; |
Pokitto | 23:f88837b8f914 | 419 | startY = clipY2OnScreen; |
Pokitto | 23:f88837b8f914 | 420 | pastEndY = clipY1OnScreen-1; |
Pokitto | 23:f88837b8f914 | 421 | skipImageRowsAsBytes = skipImageRowsAtImageEnd*bmi.bmiHeader.biWidth*3; // 3 bytes per pixel |
Pokitto | 23:f88837b8f914 | 422 | } |
Pokitto | 23:f88837b8f914 | 423 | else { |
Pokitto | 23:f88837b8f914 | 424 | /* Do not mirror */ |
Pokitto | 23:f88837b8f914 | 425 | incY = 1; |
Pokitto | 23:f88837b8f914 | 426 | startY = clipY1OnScreen ; |
Pokitto | 23:f88837b8f914 | 427 | pastEndY = clipY2OnScreen+1; |
Pokitto | 23:f88837b8f914 | 428 | skipImageRowsAsBytes = skipImageRowsAtImageStart*bmi.bmiHeader.biWidth*3; // 3 bytes per pixel |
Pokitto | 23:f88837b8f914 | 429 | } |
Pokitto | 23:f88837b8f914 | 430 | |
Pokitto | 23:f88837b8f914 | 431 | /** Read and copy image data directly to the screen **/ |
Pokitto | 23:f88837b8f914 | 432 | |
Pokitto | 23:f88837b8f914 | 433 | /* Seek to the beginning of the data */ |
Pokitto | 23:f88837b8f914 | 434 | fileSeekAbsolute(bf.bfOffBits); |
Pokitto | 23:f88837b8f914 | 435 | |
Pokitto | 23:f88837b8f914 | 436 | /* Seek until the image rect starts */ |
Pokitto | 23:f88837b8f914 | 437 | if (skipImageRowsAsBytes>0) fileSeekRelative( skipImageRowsAsBytes ); |
Pokitto | 23:f88837b8f914 | 438 | |
Pokitto | 23:f88837b8f914 | 439 | /* Copy all bytes to the output bitmap */ |
Pokitto | 23:f88837b8f914 | 440 | for ( int y = startY; y != pastEndY; y += incY) { |
Pokitto | 23:f88837b8f914 | 441 | |
Pokitto | 23:f88837b8f914 | 442 | /* Seek until the image rect starts */ |
Pokitto | 23:f88837b8f914 | 443 | if (skipImagePixelsAtLineStartAsBytes>0) fileSeekRelative( skipImagePixelsAtLineStartAsBytes ); |
Pokitto | 23:f88837b8f914 | 444 | |
Pokitto | 23:f88837b8f914 | 445 | for ( int x = clipX1OnScreen; x <= clipX2OnScreen; x++) { |
Pokitto | 23:f88837b8f914 | 446 | |
Pokitto | 23:f88837b8f914 | 447 | /* Read RGB pixel from the file. For 24 bpp the pixel is stored to 3 bytes*/ |
Pokitto | 23:f88837b8f914 | 448 | uint32_t rgb24; |
Pokitto | 23:f88837b8f914 | 449 | if (fileReadBytes((uint8_t*)&rgb24, 3) != 3) |
Pokitto | 23:f88837b8f914 | 450 | { |
Pokitto | 23:f88837b8f914 | 451 | POK_TRACE("Error reading BMP data\n"); |
Pokitto | 23:f88837b8f914 | 452 | fileClose(); |
Pokitto | 23:f88837b8f914 | 453 | return(-1); |
Pokitto | 23:f88837b8f914 | 454 | } |
Pokitto | 23:f88837b8f914 | 455 | |
Pokitto | 23:f88837b8f914 | 456 | /* Copy a pixel from the file directly to the screen */ |
Pokitto | 23:f88837b8f914 | 457 | // uint8_t r,g,b; |
Pokitto | 23:f88837b8f914 | 458 | // r = (xrgb >> (3 + 16)) & 0x1f; // 5 bit |
Pokitto | 23:f88837b8f914 | 459 | // g = (xrgb >> (2 + 8)) & 0x3f; // 6 bits |
Pokitto | 23:f88837b8f914 | 460 | // b = (xrgb >> 3) & 0x1f; // 5 bits |
Pokitto | 23:f88837b8f914 | 461 | // uint16_t targetpixel = (r<<11) | (g<<5) | b; |
Pokitto | 23:f88837b8f914 | 462 | |
Pokitto | 23:f88837b8f914 | 463 | uint16_t targetpixel = |
Pokitto | 23:f88837b8f914 | 464 | ((rgb24 >> 8) & 0x0000F800) | // red (bits 15-11) |
Pokitto | 23:f88837b8f914 | 465 | ((rgb24 >> 5) & 0x000007E0) | // green (bits 10-5) |
Pokitto | 23:f88837b8f914 | 466 | ((rgb24 >> 3) & 0x0000001F); // blue (bits 4-0) |
Pokitto | 23:f88837b8f914 | 467 | _game.display.directPixel(x, y, targetpixel); |
Pokitto | 23:f88837b8f914 | 468 | } // end for |
Pokitto | 23:f88837b8f914 | 469 | |
Pokitto | 23:f88837b8f914 | 470 | /* Skip pixels at line end */ |
Pokitto | 23:f88837b8f914 | 471 | if (skipImagePixelsAtLineEndAsBytes>0) fileSeekRelative( skipImagePixelsAtLineEndAsBytes ); |
Pokitto | 23:f88837b8f914 | 472 | |
Pokitto | 23:f88837b8f914 | 473 | } // end for |
Pokitto | 23:f88837b8f914 | 474 | |
Pokitto | 23:f88837b8f914 | 475 | // Done with the file reading. |
Pokitto | 23:f88837b8f914 | 476 | fileClose(); |
Pokitto | 23:f88837b8f914 | 477 | |
Pokitto | 23:f88837b8f914 | 478 | return 0; |
Pokitto | 23:f88837b8f914 | 479 | } |
Pokitto | 23:f88837b8f914 | 480 | |
Pokitto | 23:f88837b8f914 | 481 | #endif |
Pokitto | 23:f88837b8f914 | 482 |