/* * Copyright (C) 2011 Michael Vogt <michu@neophob.com> * Copyright (C) 2012 Gyver * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.gyver.matrixmover.generator; import com.gyver.matrixmover.core.MatrixData; import com.gyver.matrixmover.generator.enums.GeneratorName; import java.awt.Color; import java.util.List; import java.util.Random; import java.util.concurrent.CopyOnWriteArrayList; /** * The Class Fire. Computes a fire of flame like effect. * * Code-parts copied from http://github.com/neophob/PixelController * * @author Gyver */ public class Fire extends ColorMapAwareGenerator { /* paletter */ /** The colors. */ private int[] colors; /** The r. */ private Random r; /* fire buffer, contains 0..255 */ /** The buffer. */ private int[] buffer; private int[] thisFirePicture; private int[] nextFirePicture; private float step = 0; private float speed = 0; private int decay = 0; private int intensity = 0; /** * Instantiates a new fire. * * @param md The MatrixData of the matrix. */ public Fire(MatrixData md) { super(GeneratorName.FIRE, md, null); intensity = 6; decay = 2; speed = 0.2F; //Setup palette colors = new int[256]; buffer = new int[internalBufferWidth * (internalBufferHeight + 2)]; thisFirePicture = new int[internalBufferHeight * internalBufferWidth]; nextFirePicture = new int[internalBufferHeight * internalBufferWidth]; CopyOnWriteArrayList<Color> localColorMap = new CopyOnWriteArrayList<Color>(); localColorMap.add(new Color(0, 0, 0)); localColorMap.add(new Color(0, 0, 64)); localColorMap.add(new Color(255, 0, 0)); localColorMap.add(new Color(255, 255, 0)); localColorMap.add(new Color(255, 255, 64)); localColorMap.add(new Color(255, 255, 128)); localColorMap.add(new Color(255, 255, 192)); localColorMap.add(new Color(255, 255, 224)); localColorMap.add(new Color(255, 255, 255)); super.setColorMap(localColorMap); updateColorArray(); r = new Random(); } @Override public void update() { step += speed; if (step >= 1) { thisFirePicture = nextFirePicture; nextFirePicture = calcNewImage(); step -= 1; } combineBuffers(thisFirePicture, nextFirePicture, step); } @Override public void init() { buffer = new int[internalBufferWidth * (internalBufferHeight + 2)]; thisFirePicture = new int[internalBufferHeight * internalBufferWidth]; nextFirePicture = new int[internalBufferHeight * internalBufferWidth]; } /** * Update the color map * * @param colorMap */ @Override public void setColorMap(List<Color> colorMap) { super.setColorMap(colorMap); updateColorArray(); } /** * @return the decay */ public int getDecay() { return decay; } /** * @param decay the decay to set */ public void setDecay(int decay) { this.decay = decay; } /** * @return the intensity */ public int getIntensity() { return intensity; } /** * @param intensity the intensity to set */ public void setIntensity(int intensity) { this.intensity = intensity; } /** * @return the speed */ public float getSpeed() { return speed; } /** * @param speed the speed to set */ public void setSpeed(float speed) { this.speed = speed; } private int[] calcNewImage() { int j = internalBufferWidth * (internalBufferHeight); int[] tmpBuffer = new int[j]; int random; for (int i = 0; i < internalBufferWidth; i++) { random = r.nextInt(16); /* the lower the value, the intense the fire, compensate a lower value with a higher decay value*/ if (random > 16 - getIntensity()) { /*maximum heat*/ this.buffer[j + i] = 255; } else { this.buffer[j + i] = 0; } } /* move fire upwards, start at bottom*/ int temp; for (int index = 0; index < internalBufferHeight; index++) { for (int i = 0; i < internalBufferWidth; i++) { if (i == 0) { /* at the left border*/ temp = buffer[j]; temp += buffer[j + 1]; temp += buffer[j - internalBufferWidth]; temp /= 3; } else if (i == internalBufferWidth - 1) { /* at the right border*/ temp = buffer[j + i]; temp += buffer[j - internalBufferWidth + i]; temp += buffer[j + i - 1]; temp /= 3; } else { temp = buffer[j + i]; temp += buffer[j + i + 1]; temp += buffer[j + i - 1]; temp += buffer[j - internalBufferWidth + i]; temp >>= 2; } /* decay */ temp -= getDecay(); if (temp < 0) { temp = 0; } this.buffer[j - internalBufferWidth + i] = temp; tmpBuffer[j - internalBufferWidth + i] = colors[temp]; } j -= internalBufferWidth; } return tmpBuffer; } private void combineBuffers(int[] thisFirePicture, int[] nextFirePicture, float step) { short r1, g1, b1, r2, g2, b2; int col_s, col_d; for (int i = 0; i < Math.max(internalBuffer.length, Math.max(thisFirePicture.length, nextFirePicture.length)); i++) { col_s = thisFirePicture[i]; r1 = (short) ((col_s >> 16) & 255); g1 = (short) ((col_s >> 8) & 255); b1 = (short) (col_s & 255); col_d = nextFirePicture[i]; r2 = (short) ((col_d >> 16) & 255); g2 = (short) ((col_d >> 8) & 255); b2 = (short) (col_d & 255); r1 = (short) (r1 - (short) Math.round((r1 - r2) * step)); g1 = (short) (g1 - (short) Math.round((g1 - g2) * step)); b1 = (short) (b1 - (short) Math.round((b1 - b2) * step)); internalBuffer[i] = (int) (r1 << 16) | (g1 << 8) | b1; } } private void updateColorArray() { float index = 0; float indicesPerColorChange = 256 / (float) (colorMap.size() - 1); int thisColor = 0; int nextColor = 1; for (int i = 0; i < colors.length; i++) { colors[i] = super.getColor(thisColor, nextColor, index / indicesPerColorChange); index++; if (index > indicesPerColorChange) { index = index - indicesPerColorChange; thisColor++; nextColor++; } } } }