/**
 *   NeoPixel Fire 2x12 pixel ring
 * Board: Arduino or Arduino Pro Mini
 *
 *      * mod.:  Steve Barth (2022.11.17.)
 *
 *  RAM:   [          ]   2.7% (used   55 bytes from  2048 bytes)
 *  Flash: [=         ]  13.3% (used 4076 bytes from 30720 bytes)
 */

#include <Arduino.h>
#include <Adafruit_NeoPixel.h>
#define PIN 9             // data pin
#define CNT 32            // 24 led count
Adafruit_NeoPixel pix = Adafruit_NeoPixel(CNT, PIN, NEO_GRB + NEO_KHZ800);
uint32_t fire_color = pix.Color(200, 45, 3);            // orig (80, 35, 00); 120 35 0;(110, 33, 00)
uint32_t off_color = pix.Color(0, 0, 0);

//*** Fire simulator

class NeoFire
{
    Adafruit_NeoPixel &pix;

  public:
    NeoFire(Adafruit_NeoPixel &);
    void Draw();
    void Clear();
    void AddColor(uint8_t position, uint32_t color);
    void SubstractColor(uint8_t position, uint32_t color);
    uint32_t Blend(uint32_t color1, uint32_t color2);
    uint32_t Substract(uint32_t color1, uint32_t color2);
};

//*** Constructor

NeoFire::NeoFire(Adafruit_NeoPixel &n_pix) : pix(n_pix)
{
}

//*** Set all colors

void NeoFire::Draw()
{
    Clear();
    for (int i = 0; i < CNT; i++)
    {
        AddColor(i, fire_color);
        int r = random(200);            // 80
        uint32_t diff_color = pix.Color(r, r / 2, r / 2);
        SubstractColor(i, diff_color);
    }
    pix.show();
}

//*** Set color of LED

void NeoFire::AddColor(uint8_t position, uint32_t color)
{
    uint32_t blended_color = Blend(pix.getPixelColor(position), color);
    pix.setPixelColor(position, blended_color);
}

//*** Set color of LED

void NeoFire::SubstractColor(uint8_t position, uint32_t color)
{
    uint32_t blended_color = Substract(pix.getPixelColor(position), color);
    pix.setPixelColor(position, blended_color);
}

//*** Color blending

uint32_t NeoFire::Blend(uint32_t color1, uint32_t color2)
{
    uint8_t r1, g1, b1;
    uint8_t r2, g2, b2;
    // uint8_t r3, g3, b3;

    r1 = (uint8_t)(color1 >> 16), g1 = (uint8_t)(color1 >> 8), b1 = (uint8_t)(color1 >> 0);

    r2 = (uint8_t)(color2 >> 16), g2 = (uint8_t)(color2 >> 8), b2 = (uint8_t)(color2 >> 0);

    return pix.Color(constrain(r1 + r2, 0, 255), constrain(g1 + g2, 0, 255), constrain(b1 + b2, 0, 255));
}

//*** Color blending

uint32_t NeoFire::Substract(uint32_t color1, uint32_t color2)
{
    uint8_t r1, g1, b1;
    uint8_t r2, g2, b2;
    // uint8_t r3, g3, b3;
    int16_t r, g, b;

    r1 = (uint8_t)(color1 >> 16), g1 = (uint8_t)(color1 >> 8), b1 = (uint8_t)(color1 >> 0);

    r2 = (uint8_t)(color2 >> 16), g2 = (uint8_t)(color2 >> 8), b2 = (uint8_t)(color2 >> 0);

    r = (int16_t)r1 - (int16_t)r2;
    g = (int16_t)g1 - (int16_t)g2;
    b = (int16_t)b1 - (int16_t)b2;
    if (r < 0)
        r = 0;
    if (g < 0)
        g = 0;
    if (b < 0)
        b = 0;

    return pix.Color(r, g, b);
}

//*** all led off

void NeoFire::Clear()
{
    for (uint16_t i = 0; i < pix.numPixels(); i++)
        pix.setPixelColor(i, off_color);
}

NeoFire fire(pix);

//******* Setup

void setup()
{
    pix.begin();
    pix.show();            // Initialize all pixels to 'off'
}

//******* loop

void loop()
{
    fire.Draw();
    delay(random(10, 120));            //  orig delay(random(50, 150));
}