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

Committer:
agaelema
Date:
2019-01-24
Revision:
1:739609be634c
Parent:
0:5d90a43149b1

File content as of revision 1:739609be634c:

/*********************************************************************
 * available in: https://os.mbed.com/users/agaelema/code/Doom_Flame-F429ZI_v02/
 * 
 * Based on: https://github.com/filipedeschamps/doom-fire-algorithm
 * modified by: Haroldo Amaral - http://bit.ly/haroldo_github
 *********************************************************************/

#include "mbed.h"
#include "LCD_DISCO_F429ZI.h"
#include "STM32F4_RNG.h"

LCD_DISCO_F429ZI lcd;               // declare lcd class

STM32F4_RNG rnd;                    // declare random number class (use internal HW)

DigitalOut led1(LED1);              // declare GPIO class (output)

Serial pc(USBTX, USBRX);            // declare serial class (UART)

//#define     ENABLE_DEBUGMATRIX      // uncomment to enable matrix debug via UART


#define     PALETTESIZE     (sizeof(ColorPalette)/sizeof(uint32_t))

#define     ROWS            40          // numeber of lines
#define     COLS            40          // number of columns
#define     MATRIXSIZE      (ROWS*COLS) // number os vector (cells)

#define     PIXELSIZE       4           // size of pixel

uint8_t     FlameMatrix[ROWS*COLS];

uint32_t ColorPalette[] = 
{
    0xFF070707, //{"r":7,"g":7,"b":7}
    0xFF1F0707, //{"r":31,"g":7,"b":7}
    0xFF2F0F07, //{"r":47,"g":15,"b":7}
    0xFF470F07, //{"r":71,"g":15,"b":7}
    0xFF571707, //{"r":87,"g":23,"b":7}
    0xFF671F07, //{"r":103,"g":31,"b":7}
    0xFF771F07, //{"r":119,"g":31,"b":7}
    0xFF8F2707, //{"r":143,"g":39,"b":7}
    0xFF9F2F07, //{"r":159,"g":47,"b":7}
    0xFFAF3F07, //{"r":175,"g":63,"b":7}
    0xFFBF4707, //{"r":191,"g":71,"b":7}
    0xFFC74707, //{"r":199,"g":71,"b":7}
    0xFFDF4707, //{"r":223,"g":79,"b":7}
    0xFFDF5707, //{"r":223,"g":87,"b":7}
    0xFFDF5707, //{"r":223,"g":87,"b":7}
    0xFFD75F07, //{"r":215,"g":95,"b":7}
    0xFFD75F07, //{"r":215,"g":95,"b":7}
    0xFFD7670F, //{"r":215,"g":103,"b":15}
    0xFFCF6F0F, //{"r":207,"g":111,"b":15}
    0xFFCF770F, //{"r":207,"g":119,"b":15}
    0xFFCF7F0F, //{"r":207,"g":127,"b":15}
    0xFFCF8717, //{"r":207,"g":135,"b":23}
    0xFFC78717, //{"r":199,"g":135,"b":23}
    0xFFC78F17, //{"r":199,"g":143,"b":23}
    0xFFC7971F, //{"r":199,"g":151,"b":31}
    0xFFBF9F1F, //{"r":191,"g":159,"b":31}
    0xFFBF9F1F, //{"r":191,"g":159,"b":31}
    0xFFBFA727, //{"r":191,"g":167,"b":39}
    0xFFBFA727, //{"r":191,"g":167,"b":39}
    0xFFBFAF2F, //{"r":191,"g":175,"b":47}
    0xFFB7AF2F, //{"r":183,"g":175,"b":47}
    0xFFB7B72F, //{"r":183,"g":183,"b":47}
    0xFFB7B737, //{"r":183,"g":183,"b":55}
    0xFFCFCF6F, //{"r":207,"g":207,"b":111}
    0xFFDFDF9F, //{"r":223,"g":223,"b":159}
    0xFFEFEFC7, //{"r":239,"g":239,"b":199}
    0xFFFFFFFF, //{"r":255,"g":255,"b":255}
};


/*********************************************************************
 * Prototype of functions
 *********************************************************************/
void fillWithZeros(uint8_t *ptrMatrix, uint32_t size);
void createFireSource(uint8_t *ptrMatrix, uint32_t rows, uint32_t cols, uint32_t fireIntensity);
void drawFlames(uint8_t *ptrMatrix, uint32_t rows, uint32_t cols, uint32_t pixelSize);
void calculateFirePropagation(uint8_t *ptrMatrix, uint32_t rows, uint32_t cols, int32_t randAtt, int32_t wind);

void debugMatrix(uint8_t *ptrMatrix, uint32_t rows, uint32_t cols);


int main()
{      
    led1 = 1;                                       // set LED
    
    uint8_t *matrixPtr;                             // pointer to matrix
    matrixPtr = FlameMatrix;
    
    lcd.Clear(LCD_COLOR_BLACK);                     // fill lcd with black color
    
    fillWithZeros(matrixPtr, MATRIXSIZE);           // fill matrix with zeros
#if defined (ENABLE_DEBUGMATRIX)
    debugMatrix(matrixPtr, ROWS, COLS);
#endif
    
    /*
     * create firesource 
     * - matrix     -> pointer to fire matrix
     * - rows       -> number of lines
     * - cols       -> number of columns
     * - fireIntensity -> intensity of source
     */
    createFireSource(matrixPtr, ROWS, COLS, 36);
#if defined (ENABLE_DEBUGMATRIX)
    debugMatrix(matrixPtr, ROWS, COLS);
#endif
    
    while(1)
    {
        /*
         * merge functions "calculateFirePropagation" and "updateFireIntensityPerPixel"
         * - matrix     -> pointer to fire matrix
         * - rows       -> number of lines
         * - cols       -> number of columns
         * - randAtt    -> attenuation of randomness
         * - wind       -> negative number (left), positive (right), zero (no wind)
         */
        calculateFirePropagation(matrixPtr, ROWS, COLS, 3 , -3);
    
        drawFlames(matrixPtr, ROWS, COLS, PIXELSIZE);
        
        wait(0.05);
        led1 = (led1 ^ 1);
    }
}




void fillWithZeros(uint8_t *ptrMatrix, uint32_t size)
{
    uint32_t counter;
    
    for (counter = 0; counter < size; counter++)
    {
        *(ptrMatrix+counter) = 0;
//        pc.printf("Cl = %u \r\n", counter);
    }
}

void createFireSource(uint8_t *ptrMatrix, uint32_t rows, uint32_t cols, uint32_t fireIntensity)
{
    uint32_t lasRow = rows*cols - cols;
    uint32_t counter;
    
    if (fireIntensity > 36) fireIntensity = 36;
    
    for (counter = 0; counter < cols; counter++)                // in each cell
    {
        ptrMatrix[lasRow + counter] = fireIntensity;
//        pc.printf("Fs %u = %u \r\n", lasRow + counter, fireIntensity);
    }
}

void drawFlames(uint8_t *ptrMatrix, uint32_t rows, uint32_t cols, uint32_t pixelSize)
{
    uint32_t rowCounter = 0;
    uint32_t colCounter = 0;
    
    for (rowCounter = 0; rowCounter < rows; rowCounter++)       // in each line
    {
        for (colCounter = 0; colCounter < cols; colCounter++)   // in each column
        {
            lcd.SetTextColor( ColorPalette[*(ptrMatrix + rowCounter*cols + colCounter)] );
            lcd.FillRect(pixelSize*colCounter, pixelSize*rowCounter, pixelSize, pixelSize);
        }
    }
}

void calculateFirePropagation(uint8_t *ptrMatrix, uint32_t rows, uint32_t cols, int32_t randAtt, int32_t wind)
{
    uint32_t rowCounter = 0;
    uint32_t colCounter = 0;
    int32_t currentIndex;
    
    for (colCounter = 0; colCounter < cols; colCounter++)           // in each column
    {
        for (rowCounter = 0; rowCounter < rows - 1; rowCounter++)   // in each line
        {
            float random = (float)rnd.Get()/0xFFFFFFFF;             // calculate a random number  between 0-1
            int32_t decay = (int32_t)(random * randAtt);            // calculate decay

            /*
             * calculate the current index considering the randomness
             */
            currentIndex = rowCounter*cols + colCounter + (int32_t)(random * wind);
            if (currentIndex < 0) currentIndex = 0;                 // avoid exit the matrix
            
            int32_t temp = *(ptrMatrix + (rowCounter+1)*cols + colCounter) - decay;
            *(ptrMatrix + currentIndex) = (temp <=0) ? 0 : temp;    // avoid nonexistent palette color
        }
    }
}


void debugMatrix(uint8_t *ptrMatrix, uint32_t rows, uint32_t cols)
{
    uint32_t rowCounter = 0;
    uint32_t colCounter = 0;
    
    pc.printf("\r\n debug matrix linear \r\n");
    
    for (colCounter = 0; colCounter < cols*rows; colCounter++)
    {
        pc.printf("%02d ", *(ptrMatrix + colCounter));
    }
    pc.printf("\r\n");
    
    pc.printf("\r\n debug matrix form \r\n");
    for (rowCounter = 0; rowCounter < rows; rowCounter++)
    {
        for (colCounter = 0; colCounter < cols; colCounter++)
        {
            pc.printf("%02d-%02d-%02d ", *(ptrMatrix + rowCounter*cols + colCounter), rowCounter*cols, colCounter);
        }
        pc.printf("\r\n");
    }
}