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

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?

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