COOLDOWN_FACTOR = 0.9998 MAX_ENERGY_PROPAGATION = 0.3 RM_ENERGY=0.0100 EXPONENT=1.5 W_EXPONENT=2.2 OVERDRIVE=1.5 num_modules = 1 num_strips = 1 max_new_energy_per_strip = 2.00*RM_ENERGY * num_modules -- warning: these must also be updated in init() max_target_energy = num_strips * num_modules -- maximum energy values for each band maxRedEnergy = 1 maxGreenEnergy = 1 maxBlueEnergy = 1 maxWhiteEnergy = 1 redMomentum = 0 greenMomentum = 0 blueMomentum = 0 whiteMomentum = 0 -- array storing the flameā€™s energy for each pixel fireRedEnergy = {} fireGreenEnergy = {} fireBlueEnergy = {} fireWhiteEnergy = {} -- output color buffers red = {} green = {} blue = {} white = {} function limit(val) if val > 1 then return 1 elseif val < 0 then return 0 else return val end end function updateFire(targetEnergy, energyArray, momentum) local totalEnergy = 0 local avgEnergyPerStrip for s = 1,num_strips do for m = 1,num_modules do totalEnergy = totalEnergy + energyArray[idx(s,m)] end end if targetEnergy > totalEnergy then avgEnergyPerStrip = (targetEnergy - totalEnergy) / num_strips avgEnergyPerStrip = base_new_energy_per_strip * momentum if avgEnergyPerStrip > max_new_energy_per_strip then avgEnergyPerStrip = max_new_energy_per_strip end momentum = momentum + 1 else avgEnergyPerStrip = 0 momentum = momentum - 1 if momentum < 0 then momentum = 0 end end for s = 1,num_strips do -- Add new energy in the center rows i = idx(s, num_modules/2) energyArray[i] = energyArray[i] + math.random() * avgEnergyPerStrip i = idx(s, num_modules/2+1) energyArray[i] = energyArray[i] + math.random() * avgEnergyPerStrip -- remove energy at the top and the bottom i = idx(s, num_modules) energyArray[i] = energyArray[i] * (1.0 - math.random() * MAX_ENERGY_PROPAGATION) i = idx(s, 1) energyArray[i] = energyArray[i] * (1.0 - math.random() * MAX_ENERGY_PROPAGATION) -- move energy upwards for m_out = num_modules,num_modules/2+2,-1 do i_out = idx(s, m_out) i_in = idx(s, m_out - 1) energyMoved = energyArray[i_in] * math.random() * MAX_ENERGY_PROPAGATION energyArray[i_in] = energyArray[i_in] - energyMoved energyArray[i_out] = energyArray[i_out] + energyMoved end -- move energy downwards for m_out = 1,num_modules/2-1,1 do i_out = idx(s, m_out) i_in = idx(s, m_out + 1) energyMoved = energyArray[i_in] * math.random() * MAX_ENERGY_PROPAGATION energyArray[i_in] = energyArray[i_in] - energyMoved energyArray[i_out] = energyArray[i_out] + energyMoved end -- globally remove energy for m = 1,num_modules do i = idx(s, m) if energyArray[i] > RM_ENERGY then energyArray[i] = energyArray[i] - RM_ENERGY else energyArray[i] = 0 end end end return momentum end function fractionToEnergy(fract, max) return math.sqrt(fract) * max --dB = 20*math.log(fract)/math.log(10) --result = max * (dB + 40) / 40 --if result > 0 then -- return result --else -- return 0 --end end function periodic() local redEnergy = get_energy_in_band(0, 400); local greenEnergy = get_energy_in_band(400, 4000); local blueEnergy = get_energy_in_band(4000, 12000); local whiteEnergy = get_energy_in_band(12000, 22000); maxRedEnergy = maxRedEnergy * COOLDOWN_FACTOR if redEnergy > maxRedEnergy then maxRedEnergy = redEnergy end maxGreenEnergy = maxGreenEnergy * COOLDOWN_FACTOR if greenEnergy > maxGreenEnergy then maxGreenEnergy = greenEnergy end maxBlueEnergy = maxBlueEnergy * COOLDOWN_FACTOR if blueEnergy > maxBlueEnergy then maxBlueEnergy = blueEnergy end maxWhiteEnergy = maxWhiteEnergy * COOLDOWN_FACTOR if whiteEnergy > maxWhiteEnergy then maxWhiteEnergy = whiteEnergy end redMomentum = updateFire(fractionToEnergy(redEnergy / maxRedEnergy, max_target_energy), fireRedEnergy, redMomentum) greenMomentum = updateFire(fractionToEnergy(greenEnergy / maxGreenEnergy, max_target_energy), fireGreenEnergy, greenMomentum) blueMomentum = updateFire(fractionToEnergy(blueEnergy / maxBlueEnergy, max_target_energy), fireBlueEnergy, blueMomentum) whiteMomentum = updateFire(fractionToEnergy((whiteEnergy / maxWhiteEnergy)^W_EXPONENT, max_target_energy), fireWhiteEnergy, whiteMomentum) --updateFire(2 * max_target_energy, fireRedEnergy) --updateFire(0 * max_target_energy, fireGreenEnergy) --updateFire(0 * max_target_energy, fireBlueEnergy) --updateFire(0 * max_target_energy, fireWhiteEnergy) -- make colors more exciting + remove the first (flickering) mass for m = 1,num_modules do for s = 1,num_strips do i = idx(s, m) rval = limit(OVERDRIVE * (fireRedEnergy[i])) gval = limit(OVERDRIVE * (fireGreenEnergy[i])) bval = limit(OVERDRIVE * (fireBlueEnergy[i])) wval = limit(OVERDRIVE * (fireWhiteEnergy[i])) red[i] = rval green[i] = gval blue[i] = bval white[i] = wval end end -- return the 4 color arrays return red, green, blue, white end function init(nstrip, nmod, cmod) num_strips = nstrip num_modules = nmod max_new_energy_per_strip = num_modules * RM_ENERGY * 2 base_new_energy_per_strip = num_modules * RM_ENERGY * 0.1 max_target_energy = 0.2 * num_strips * num_modules for i = 1,(nmod*nstrip) do red[i] = 0 green[i] = 0 blue[i] = 0 white[i] = 0 fireRedEnergy[i] = 0 fireGreenEnergy[i] = 0 fireBlueEnergy[i] = 0 fireWhiteEnergy[i] = 0 end -- don't use fading return 0 end