Emulate the "Flame effect" of the game DOOM. Based on: https://github.com/filipedeschamps/doom-fire-algorithm
Dependencies: LCD_DISCO_F429ZI mbed BSP_DISCO_F429ZI STM32F4_RNG
main.cpp@0:5d90a43149b1, 2019-01-24 (annotated)
- Committer:
- agaelema
- Date:
- Thu Jan 24 01:30:04 2019 +0000
- Revision:
- 0:5d90a43149b1
- Child:
- 1:739609be634c
Emulate in realtime the "Flame effect" of the game DOOM.; ; Based on: https://github.com/filipedeschamps/doom-fire-algorithm
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
agaelema | 0:5d90a43149b1 | 1 | /********************************************************************* |
agaelema | 0:5d90a43149b1 | 2 | * Based on: https://github.com/filipedeschamps/doom-fire-algorithm |
agaelema | 0:5d90a43149b1 | 3 | * modified by: Haroldo Amaral - http://bit.ly/haroldo_github |
agaelema | 0:5d90a43149b1 | 4 | *********************************************************************/ |
agaelema | 0:5d90a43149b1 | 5 | |
agaelema | 0:5d90a43149b1 | 6 | #include "mbed.h" |
agaelema | 0:5d90a43149b1 | 7 | #include "LCD_DISCO_F429ZI.h" |
agaelema | 0:5d90a43149b1 | 8 | #include "STM32F4_RNG.h" |
agaelema | 0:5d90a43149b1 | 9 | |
agaelema | 0:5d90a43149b1 | 10 | LCD_DISCO_F429ZI lcd; // declare lcd class |
agaelema | 0:5d90a43149b1 | 11 | |
agaelema | 0:5d90a43149b1 | 12 | STM32F4_RNG rnd; // declare random number class (use internal HW) |
agaelema | 0:5d90a43149b1 | 13 | |
agaelema | 0:5d90a43149b1 | 14 | DigitalOut led1(LED1); // declare GPIO class (output) |
agaelema | 0:5d90a43149b1 | 15 | |
agaelema | 0:5d90a43149b1 | 16 | Serial pc(USBTX, USBRX); // declare serial class (UART) |
agaelema | 0:5d90a43149b1 | 17 | |
agaelema | 0:5d90a43149b1 | 18 | //#define ENABLE_DEBUGMATRIX // uncomment to enable matrix debug via UART |
agaelema | 0:5d90a43149b1 | 19 | |
agaelema | 0:5d90a43149b1 | 20 | |
agaelema | 0:5d90a43149b1 | 21 | #define PALETTESIZE (sizeof(ColorPalette)/sizeof(uint32_t)) |
agaelema | 0:5d90a43149b1 | 22 | |
agaelema | 0:5d90a43149b1 | 23 | #define ROWS 40 // numeber of lines |
agaelema | 0:5d90a43149b1 | 24 | #define COLS 40 // number of columns |
agaelema | 0:5d90a43149b1 | 25 | #define MATRIXSIZE (ROWS*COLS) // number os vector (cells) |
agaelema | 0:5d90a43149b1 | 26 | |
agaelema | 0:5d90a43149b1 | 27 | #define PIXELSIZE 4 // size of pixel |
agaelema | 0:5d90a43149b1 | 28 | |
agaelema | 0:5d90a43149b1 | 29 | uint8_t FlameMatrix[ROWS*COLS]; |
agaelema | 0:5d90a43149b1 | 30 | |
agaelema | 0:5d90a43149b1 | 31 | uint32_t ColorPalette[] = |
agaelema | 0:5d90a43149b1 | 32 | { |
agaelema | 0:5d90a43149b1 | 33 | 0xFF070707, //{"r":7,"g":7,"b":7} |
agaelema | 0:5d90a43149b1 | 34 | 0xFF1F0707, //{"r":31,"g":7,"b":7} |
agaelema | 0:5d90a43149b1 | 35 | 0xFF2F0F07, //{"r":47,"g":15,"b":7} |
agaelema | 0:5d90a43149b1 | 36 | 0xFF470F07, //{"r":71,"g":15,"b":7} |
agaelema | 0:5d90a43149b1 | 37 | 0xFF571707, //{"r":87,"g":23,"b":7} |
agaelema | 0:5d90a43149b1 | 38 | 0xFF671F07, //{"r":103,"g":31,"b":7} |
agaelema | 0:5d90a43149b1 | 39 | 0xFF771F07, //{"r":119,"g":31,"b":7} |
agaelema | 0:5d90a43149b1 | 40 | 0xFF8F2707, //{"r":143,"g":39,"b":7} |
agaelema | 0:5d90a43149b1 | 41 | 0xFF9F2F07, //{"r":159,"g":47,"b":7} |
agaelema | 0:5d90a43149b1 | 42 | 0xFFAF3F07, //{"r":175,"g":63,"b":7} |
agaelema | 0:5d90a43149b1 | 43 | 0xFFBF4707, //{"r":191,"g":71,"b":7} |
agaelema | 0:5d90a43149b1 | 44 | 0xFFC74707, //{"r":199,"g":71,"b":7} |
agaelema | 0:5d90a43149b1 | 45 | 0xFFDF4707, //{"r":223,"g":79,"b":7} |
agaelema | 0:5d90a43149b1 | 46 | 0xFFDF5707, //{"r":223,"g":87,"b":7} |
agaelema | 0:5d90a43149b1 | 47 | 0xFFDF5707, //{"r":223,"g":87,"b":7} |
agaelema | 0:5d90a43149b1 | 48 | 0xFFD75F07, //{"r":215,"g":95,"b":7} |
agaelema | 0:5d90a43149b1 | 49 | 0xFFD75F07, //{"r":215,"g":95,"b":7} |
agaelema | 0:5d90a43149b1 | 50 | 0xFFD7670F, //{"r":215,"g":103,"b":15} |
agaelema | 0:5d90a43149b1 | 51 | 0xFFCF6F0F, //{"r":207,"g":111,"b":15} |
agaelema | 0:5d90a43149b1 | 52 | 0xFFCF770F, //{"r":207,"g":119,"b":15} |
agaelema | 0:5d90a43149b1 | 53 | 0xFFCF7F0F, //{"r":207,"g":127,"b":15} |
agaelema | 0:5d90a43149b1 | 54 | 0xFFCF8717, //{"r":207,"g":135,"b":23} |
agaelema | 0:5d90a43149b1 | 55 | 0xFFC78717, //{"r":199,"g":135,"b":23} |
agaelema | 0:5d90a43149b1 | 56 | 0xFFC78F17, //{"r":199,"g":143,"b":23} |
agaelema | 0:5d90a43149b1 | 57 | 0xFFC7971F, //{"r":199,"g":151,"b":31} |
agaelema | 0:5d90a43149b1 | 58 | 0xFFBF9F1F, //{"r":191,"g":159,"b":31} |
agaelema | 0:5d90a43149b1 | 59 | 0xFFBF9F1F, //{"r":191,"g":159,"b":31} |
agaelema | 0:5d90a43149b1 | 60 | 0xFFBFA727, //{"r":191,"g":167,"b":39} |
agaelema | 0:5d90a43149b1 | 61 | 0xFFBFA727, //{"r":191,"g":167,"b":39} |
agaelema | 0:5d90a43149b1 | 62 | 0xFFBFAF2F, //{"r":191,"g":175,"b":47} |
agaelema | 0:5d90a43149b1 | 63 | 0xFFB7AF2F, //{"r":183,"g":175,"b":47} |
agaelema | 0:5d90a43149b1 | 64 | 0xFFB7B72F, //{"r":183,"g":183,"b":47} |
agaelema | 0:5d90a43149b1 | 65 | 0xFFB7B737, //{"r":183,"g":183,"b":55} |
agaelema | 0:5d90a43149b1 | 66 | 0xFFCFCF6F, //{"r":207,"g":207,"b":111} |
agaelema | 0:5d90a43149b1 | 67 | 0xFFDFDF9F, //{"r":223,"g":223,"b":159} |
agaelema | 0:5d90a43149b1 | 68 | 0xFFEFEFC7, //{"r":239,"g":239,"b":199} |
agaelema | 0:5d90a43149b1 | 69 | 0xFFFFFFFF, //{"r":255,"g":255,"b":255} |
agaelema | 0:5d90a43149b1 | 70 | }; |
agaelema | 0:5d90a43149b1 | 71 | |
agaelema | 0:5d90a43149b1 | 72 | |
agaelema | 0:5d90a43149b1 | 73 | /********************************************************************* |
agaelema | 0:5d90a43149b1 | 74 | * Prototype of functions |
agaelema | 0:5d90a43149b1 | 75 | *********************************************************************/ |
agaelema | 0:5d90a43149b1 | 76 | void fillWithZeros(uint8_t *ptrMatrix, uint32_t size); |
agaelema | 0:5d90a43149b1 | 77 | void createFireSource(uint8_t *ptrMatrix, uint32_t rows, uint32_t cols, uint32_t fireIntensity); |
agaelema | 0:5d90a43149b1 | 78 | void drawFlames(uint8_t *ptrMatrix, uint32_t rows, uint32_t cols, uint32_t pixelSize); |
agaelema | 0:5d90a43149b1 | 79 | void calculateFirePropagation(uint8_t *ptrMatrix, uint32_t rows, uint32_t cols, int32_t randAtt, int32_t wind); |
agaelema | 0:5d90a43149b1 | 80 | |
agaelema | 0:5d90a43149b1 | 81 | void debugMatrix(uint8_t *ptrMatrix, uint32_t rows, uint32_t cols); |
agaelema | 0:5d90a43149b1 | 82 | |
agaelema | 0:5d90a43149b1 | 83 | |
agaelema | 0:5d90a43149b1 | 84 | int main() |
agaelema | 0:5d90a43149b1 | 85 | { |
agaelema | 0:5d90a43149b1 | 86 | led1 = 1; // set LED |
agaelema | 0:5d90a43149b1 | 87 | |
agaelema | 0:5d90a43149b1 | 88 | uint8_t *matrixPtr; // pointer to matrix |
agaelema | 0:5d90a43149b1 | 89 | matrixPtr = FlameMatrix; |
agaelema | 0:5d90a43149b1 | 90 | |
agaelema | 0:5d90a43149b1 | 91 | lcd.Clear(LCD_COLOR_BLACK); // fill lcd with black color |
agaelema | 0:5d90a43149b1 | 92 | |
agaelema | 0:5d90a43149b1 | 93 | fillWithZeros(matrixPtr, MATRIXSIZE); // fill matrix with zeros |
agaelema | 0:5d90a43149b1 | 94 | #if defined (ENABLE_DEBUGMATRIX) |
agaelema | 0:5d90a43149b1 | 95 | debugMatrix(matrixPtr, ROWS, COLS); |
agaelema | 0:5d90a43149b1 | 96 | #endif |
agaelema | 0:5d90a43149b1 | 97 | |
agaelema | 0:5d90a43149b1 | 98 | /* |
agaelema | 0:5d90a43149b1 | 99 | * create firesource |
agaelema | 0:5d90a43149b1 | 100 | * - matrix -> pointer to fire matrix |
agaelema | 0:5d90a43149b1 | 101 | * - rows -> number of lines |
agaelema | 0:5d90a43149b1 | 102 | * - cols -> number of columns |
agaelema | 0:5d90a43149b1 | 103 | * - fireIntensity -> intensity of source |
agaelema | 0:5d90a43149b1 | 104 | */ |
agaelema | 0:5d90a43149b1 | 105 | createFireSource(matrixPtr, ROWS, COLS, 36); |
agaelema | 0:5d90a43149b1 | 106 | #if defined (ENABLE_DEBUGMATRIX) |
agaelema | 0:5d90a43149b1 | 107 | debugMatrix(matrixPtr, ROWS, COLS); |
agaelema | 0:5d90a43149b1 | 108 | #endif |
agaelema | 0:5d90a43149b1 | 109 | |
agaelema | 0:5d90a43149b1 | 110 | while(1) |
agaelema | 0:5d90a43149b1 | 111 | { |
agaelema | 0:5d90a43149b1 | 112 | /* |
agaelema | 0:5d90a43149b1 | 113 | * merge functions "calculateFirePropagation" and "updateFireIntensityPerPixel" |
agaelema | 0:5d90a43149b1 | 114 | * - matrix -> pointer to fire matrix |
agaelema | 0:5d90a43149b1 | 115 | * - rows -> number of lines |
agaelema | 0:5d90a43149b1 | 116 | * - cols -> number of columns |
agaelema | 0:5d90a43149b1 | 117 | * - randAtt -> attenuation of randomness |
agaelema | 0:5d90a43149b1 | 118 | * - wind -> negative number (left), positive (right), zero (no wind) |
agaelema | 0:5d90a43149b1 | 119 | */ |
agaelema | 0:5d90a43149b1 | 120 | calculateFirePropagation(matrixPtr, ROWS, COLS, 3 , -3); |
agaelema | 0:5d90a43149b1 | 121 | |
agaelema | 0:5d90a43149b1 | 122 | drawFlames(matrixPtr, ROWS, COLS, PIXELSIZE); |
agaelema | 0:5d90a43149b1 | 123 | |
agaelema | 0:5d90a43149b1 | 124 | wait(0.05); |
agaelema | 0:5d90a43149b1 | 125 | led1 = (led1 ^ 1); |
agaelema | 0:5d90a43149b1 | 126 | } |
agaelema | 0:5d90a43149b1 | 127 | } |
agaelema | 0:5d90a43149b1 | 128 | |
agaelema | 0:5d90a43149b1 | 129 | |
agaelema | 0:5d90a43149b1 | 130 | |
agaelema | 0:5d90a43149b1 | 131 | |
agaelema | 0:5d90a43149b1 | 132 | void fillWithZeros(uint8_t *ptrMatrix, uint32_t size) |
agaelema | 0:5d90a43149b1 | 133 | { |
agaelema | 0:5d90a43149b1 | 134 | uint32_t counter; |
agaelema | 0:5d90a43149b1 | 135 | |
agaelema | 0:5d90a43149b1 | 136 | for (counter = 0; counter < size; counter++) |
agaelema | 0:5d90a43149b1 | 137 | { |
agaelema | 0:5d90a43149b1 | 138 | *(ptrMatrix+counter) = 0; |
agaelema | 0:5d90a43149b1 | 139 | // pc.printf("Cl = %u \r\n", counter); |
agaelema | 0:5d90a43149b1 | 140 | } |
agaelema | 0:5d90a43149b1 | 141 | } |
agaelema | 0:5d90a43149b1 | 142 | |
agaelema | 0:5d90a43149b1 | 143 | void createFireSource(uint8_t *ptrMatrix, uint32_t rows, uint32_t cols, uint32_t fireIntensity) |
agaelema | 0:5d90a43149b1 | 144 | { |
agaelema | 0:5d90a43149b1 | 145 | uint32_t lasRow = rows*cols - cols; |
agaelema | 0:5d90a43149b1 | 146 | uint32_t counter; |
agaelema | 0:5d90a43149b1 | 147 | |
agaelema | 0:5d90a43149b1 | 148 | if (fireIntensity > 36) fireIntensity = 36; |
agaelema | 0:5d90a43149b1 | 149 | |
agaelema | 0:5d90a43149b1 | 150 | for (counter = 0; counter < cols; counter++) // in each cell |
agaelema | 0:5d90a43149b1 | 151 | { |
agaelema | 0:5d90a43149b1 | 152 | ptrMatrix[lasRow + counter] = fireIntensity; |
agaelema | 0:5d90a43149b1 | 153 | // pc.printf("Fs %u = %u \r\n", lasRow + counter, fireIntensity); |
agaelema | 0:5d90a43149b1 | 154 | } |
agaelema | 0:5d90a43149b1 | 155 | } |
agaelema | 0:5d90a43149b1 | 156 | |
agaelema | 0:5d90a43149b1 | 157 | void drawFlames(uint8_t *ptrMatrix, uint32_t rows, uint32_t cols, uint32_t pixelSize) |
agaelema | 0:5d90a43149b1 | 158 | { |
agaelema | 0:5d90a43149b1 | 159 | uint32_t rowCounter = 0; |
agaelema | 0:5d90a43149b1 | 160 | uint32_t colCounter = 0; |
agaelema | 0:5d90a43149b1 | 161 | |
agaelema | 0:5d90a43149b1 | 162 | for (rowCounter = 0; rowCounter < rows; rowCounter++) // in each line |
agaelema | 0:5d90a43149b1 | 163 | { |
agaelema | 0:5d90a43149b1 | 164 | for (colCounter = 0; colCounter < cols; colCounter++) // in each column |
agaelema | 0:5d90a43149b1 | 165 | { |
agaelema | 0:5d90a43149b1 | 166 | lcd.SetTextColor( ColorPalette[*(ptrMatrix + rowCounter*cols + colCounter)] ); |
agaelema | 0:5d90a43149b1 | 167 | lcd.FillRect(pixelSize*colCounter, pixelSize*rowCounter, pixelSize, pixelSize); |
agaelema | 0:5d90a43149b1 | 168 | } |
agaelema | 0:5d90a43149b1 | 169 | } |
agaelema | 0:5d90a43149b1 | 170 | } |
agaelema | 0:5d90a43149b1 | 171 | |
agaelema | 0:5d90a43149b1 | 172 | void calculateFirePropagation(uint8_t *ptrMatrix, uint32_t rows, uint32_t cols, int32_t randAtt, int32_t wind) |
agaelema | 0:5d90a43149b1 | 173 | { |
agaelema | 0:5d90a43149b1 | 174 | uint32_t rowCounter = 0; |
agaelema | 0:5d90a43149b1 | 175 | uint32_t colCounter = 0; |
agaelema | 0:5d90a43149b1 | 176 | int32_t currentIndex; |
agaelema | 0:5d90a43149b1 | 177 | |
agaelema | 0:5d90a43149b1 | 178 | for (colCounter = 0; colCounter < cols; colCounter++) // in each column |
agaelema | 0:5d90a43149b1 | 179 | { |
agaelema | 0:5d90a43149b1 | 180 | for (rowCounter = 0; rowCounter < rows - 1; rowCounter++) // in each line |
agaelema | 0:5d90a43149b1 | 181 | { |
agaelema | 0:5d90a43149b1 | 182 | float random = (float)rnd.Get()/0xFFFFFFFF; // calculate a random number between 0-1 |
agaelema | 0:5d90a43149b1 | 183 | int32_t decay = (int32_t)(random * randAtt); // calculate decay |
agaelema | 0:5d90a43149b1 | 184 | |
agaelema | 0:5d90a43149b1 | 185 | /* |
agaelema | 0:5d90a43149b1 | 186 | * calculate the current index considering the randomness |
agaelema | 0:5d90a43149b1 | 187 | */ |
agaelema | 0:5d90a43149b1 | 188 | currentIndex = rowCounter*cols + colCounter + (int32_t)(random * wind); |
agaelema | 0:5d90a43149b1 | 189 | if (currentIndex < 0) currentIndex = 0; // avoid exit the matrix |
agaelema | 0:5d90a43149b1 | 190 | |
agaelema | 0:5d90a43149b1 | 191 | int32_t temp = *(ptrMatrix + (rowCounter+1)*cols + colCounter) - decay; |
agaelema | 0:5d90a43149b1 | 192 | *(ptrMatrix + currentIndex) = (temp <=0) ? 0 : temp; // avoid nonexistent palette color |
agaelema | 0:5d90a43149b1 | 193 | } |
agaelema | 0:5d90a43149b1 | 194 | } |
agaelema | 0:5d90a43149b1 | 195 | } |
agaelema | 0:5d90a43149b1 | 196 | |
agaelema | 0:5d90a43149b1 | 197 | |
agaelema | 0:5d90a43149b1 | 198 | void debugMatrix(uint8_t *ptrMatrix, uint32_t rows, uint32_t cols) |
agaelema | 0:5d90a43149b1 | 199 | { |
agaelema | 0:5d90a43149b1 | 200 | uint32_t rowCounter = 0; |
agaelema | 0:5d90a43149b1 | 201 | uint32_t colCounter = 0; |
agaelema | 0:5d90a43149b1 | 202 | |
agaelema | 0:5d90a43149b1 | 203 | pc.printf("\r\n debug matrix linear \r\n"); |
agaelema | 0:5d90a43149b1 | 204 | |
agaelema | 0:5d90a43149b1 | 205 | for (colCounter = 0; colCounter < cols*rows; colCounter++) |
agaelema | 0:5d90a43149b1 | 206 | { |
agaelema | 0:5d90a43149b1 | 207 | pc.printf("%02d ", *(ptrMatrix + colCounter)); |
agaelema | 0:5d90a43149b1 | 208 | } |
agaelema | 0:5d90a43149b1 | 209 | pc.printf("\r\n"); |
agaelema | 0:5d90a43149b1 | 210 | |
agaelema | 0:5d90a43149b1 | 211 | pc.printf("\r\n debug matrix form \r\n"); |
agaelema | 0:5d90a43149b1 | 212 | for (rowCounter = 0; rowCounter < rows; rowCounter++) |
agaelema | 0:5d90a43149b1 | 213 | { |
agaelema | 0:5d90a43149b1 | 214 | for (colCounter = 0; colCounter < cols; colCounter++) |
agaelema | 0:5d90a43149b1 | 215 | { |
agaelema | 0:5d90a43149b1 | 216 | pc.printf("%02d-%02d-%02d ", *(ptrMatrix + rowCounter*cols + colCounter), rowCounter*cols, colCounter); |
agaelema | 0:5d90a43149b1 | 217 | } |
agaelema | 0:5d90a43149b1 | 218 | pc.printf("\r\n"); |
agaelema | 0:5d90a43149b1 | 219 | } |
agaelema | 0:5d90a43149b1 | 220 | } |