/* * 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.Controller; import com.gyver.matrixmover.core.MatrixData; import com.gyver.matrixmover.generator.enums.GeneratorName; import com.gyver.matrixmover.generator.enums.RainDirection; /** * Generator generating rain drop kind of a effect. Drops are * traveling over the screen in an direkction. * * @author Gyver */ public class Rain extends ObjectsContainingGenerator { private RainDirection dropDirection = null; private int dropsPerScreen = 2; private int lengthDrops = 5; private double updatesToNextDrop = 0; private double updatesToNextShift = 0; private double dropUpdatesDone = 0; private double shiftUpdatesDone = 0; private int nextColor = 0; private int bpm = 120; /** * Instantiates a new rain generator. * * @param md the MatrixData of the matrix */ public Rain(MatrixData md){ super(GeneratorName.RAIN, md, null); dropDirection = RainDirection.TOP_TO_BOTTOM; calculateUpdateRates(); } @Override public void update() { dropUpdatesDone++; shiftUpdatesDone++; switch (dropDirection) { case LEFT_TO_RIGHT: leftToRight(); break; case RIGHT_TO_LEFT: rightToLeft(); break; case TOP_TO_BOTTOM: topToBottom(); break; case BOTTOM_TO_TOP: bottomToTop(); break; } } @Override public void init() { calculateUpdateRates(); } /** * Sets the speed as bpm * @param bpm the speed */ public void setBpm(int bpm){ this.bpm = bpm; calculateUpdateRates(); } /** * Returns the speet as bpm * @return the speed */ public int getBpm(){ return bpm; } /** * Returns the number of drops per screen * @param nrDrops the number of drops */ public void setDrosPerScreen(int nrDrops){ this.dropsPerScreen = nrDrops; calculateUpdateRates(); } /** * Gets the number of drops per screen * @return the number of drops */ public int getDropsPerScreen(){ return dropsPerScreen; } /** * Sets the drops tail length * @param lengthDrops the length */ public void setRainLength(int lengthDrops){ this.lengthDrops = lengthDrops; } /** * Returns the drops tail length * @return the length */ public int getRainLength(){ return lengthDrops; } /** * Returns the RainDirection * @return the RainDirection */ public RainDirection getMode(){ return dropDirection; } /** * Sets the RainDirection mode * @param dir the RainDirection */ public void setMode(RainDirection dir){ this.dropDirection = dir; } private void leftToRight() { while(dropUpdatesDone >= updatesToNextDrop){ dropUpdatesDone = dropUpdatesDone - updatesToNextDrop; //paint a new drop int position = (int) Math.floor(Math.random()*internalBufferHeight); nextColor = ((nextColor+1) % colorMap.size()); internalBuffer[position * internalBufferWidth] = this.getColor(nextColor); } while(shiftUpdatesDone >= updatesToNextShift){ shiftUpdatesDone = shiftUpdatesDone - updatesToNextShift; //shift the buffer down, keep first line for(int i = internalBufferWidth-1; i >= 1; i--){ for(int n = 0; n < internalBufferHeight; n++){ internalBuffer[n*internalBufferWidth+i] = internalBuffer[n*internalBufferWidth+i-1]; } } //then dimm fist line for(int n = 0; n < internalBufferHeight; n++){ int col = internalBuffer[n * internalBufferWidth]; if(col == 0){ continue; } short red = (short) ((col >> 16) & 255); short green = (short) ((col >> 8) & 255); short blue = (short) (col & 255); red = (short) (red - (256 / lengthDrops)); if(red < 0){ red = 0; } green = (short) (green - (256 / lengthDrops)); if(green < 0){ green = 0; } blue = (short) (blue - (256 / lengthDrops)); if(blue < 0){ blue = 0; } internalBuffer[n * internalBufferWidth] = (int) ((red << 16) | (green << 8) | blue); } } } private void rightToLeft() { while(dropUpdatesDone >= updatesToNextDrop){ dropUpdatesDone = dropUpdatesDone - updatesToNextDrop; //paint a new drop int position = (int) Math.floor(Math.random()*internalBufferHeight); nextColor = ((nextColor+1) % colorMap.size()); internalBuffer[((position+1) * internalBufferWidth)-1] = this.getColor(nextColor); } while(shiftUpdatesDone >= updatesToNextShift){ shiftUpdatesDone = shiftUpdatesDone - updatesToNextShift; for(int i = 1; i < internalBufferWidth; i++){ for(int n = 0; n < internalBufferHeight; n++){ internalBuffer[(n*internalBufferWidth)+i-1] = internalBuffer[(n*internalBufferWidth)+i]; } } //then dimm fist line for(int n = 0; n < internalBufferHeight; n++){ int col = internalBuffer[((n+1) * internalBufferWidth)-1]; if(col == 0){ continue; } short red = (short) ((col >> 16) & 255); short green = (short) ((col >> 8) & 255); short blue = (short) (col & 255); red = (short) (red - (256 / lengthDrops)); if(red < 0){ red = 0; } green = (short) (green - (256 / lengthDrops)); if(green < 0){ green = 0; } blue = (short) (blue - (256 / lengthDrops)); if(blue < 0){ blue = 0; } internalBuffer[((n+1) * internalBufferWidth)-1] = (int) ((red << 16) | (green << 8) | blue); } } } private void topToBottom() { while(dropUpdatesDone >= updatesToNextDrop){ dropUpdatesDone = dropUpdatesDone - updatesToNextDrop; //paint a new drop int position = (int) Math.floor(Math.random()*internalBufferWidth); nextColor = ((nextColor+1) % colorMap.size()); internalBuffer[position] = this.getColor(nextColor); } while(shiftUpdatesDone >= updatesToNextShift){ shiftUpdatesDone = shiftUpdatesDone - updatesToNextShift; //shift the buffer down, keep first line for(int i = internalBufferHeight-1; i >= 1; i--){ for(int n = 0; n < internalBufferWidth; n++){ internalBuffer[i*internalBufferWidth+n] = internalBuffer[(i-1)*internalBufferWidth+n]; } } //then dimm fist line for(int n = 0; n < internalBufferWidth; n++){ int col = internalBuffer[n]; if(col == 0){ continue; } short red = (short) ((col >> 16) & 255); short green = (short) ((col >> 8) & 255); short blue = (short) (col & 255); red = (short) (red - (256 / lengthDrops)); if(red < 0){ red = 0; } green = (short) (green - (256 / lengthDrops)); if(green < 0){ green = 0; } blue = (short) (blue - (256 / lengthDrops)); if(blue < 0){ blue = 0; } internalBuffer[n] = (int) ((red << 16) | (green << 8) | blue); } } } private void bottomToTop() { while(dropUpdatesDone >= updatesToNextDrop){ dropUpdatesDone = dropUpdatesDone - updatesToNextDrop; //paint a new drop int position = (int) Math.floor(Math.random()*internalBufferWidth); nextColor = ((nextColor+1) % colorMap.size()); internalBuffer[internalBuffer.length - internalBufferWidth + position] = this.getColor(nextColor); } while(shiftUpdatesDone >= updatesToNextShift){ shiftUpdatesDone = shiftUpdatesDone - updatesToNextShift; //shift the buffer up, keep first line for(int i = 0; i < internalBufferHeight-1; i++){ for(int n = 0; n < internalBufferWidth; n++){ internalBuffer[i*internalBufferWidth+n] = internalBuffer[(i+1)*internalBufferWidth+n]; } } //then dimm fist line for(int n = 0; n < internalBufferWidth; n++){ int col = internalBuffer[internalBuffer.length - internalBufferWidth + n]; if(col == 0){ continue; } short red = (short) ((col >> 16) & 255); short green = (short) ((col >> 8) & 255); short blue = (short) (col & 255); red = (short) (red - (256 / lengthDrops)); if(red < 0){ red = 0; } green = (short) (green - (256 / lengthDrops)); if(green < 0){ green = 0; } blue = (short) (blue - (256 / lengthDrops)); if(blue < 0){ blue = 0; } internalBuffer[internalBuffer.length - internalBufferWidth + n] = (int) ((red << 16) | (green << 8) | blue); } } } private void calculateUpdateRates() { int fps = Controller.getControllerInstance().getFps(); updatesToNextDrop = ((fps / (bpm / 60F)) / (float) dropsPerScreen); switch (dropDirection) { case LEFT_TO_RIGHT: case RIGHT_TO_LEFT: updatesToNextShift = (fps / (float)internalBufferWidth) / (bpm / 60F); break; case TOP_TO_BOTTOM: case BOTTOM_TO_TOP: updatesToNextShift = (fps / (float)internalBufferHeight) / (bpm / 60F); break; } } }