PokittoLib is the library needed for programming the Pokitto DIY game console (www.pokitto.com)

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?

UserRevisionLine numberNew 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