package com.ihunda.android.binauralbeat.viz; /* * @author Giorgio Regni * @contact @GiorgioRegni on Twitter * http://twitter.com/GiorgioRegni * * This file is part of Binaural Beats Therapy or BBT. * * BBT 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. * * BBT 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 BBT. If not, see <http://www.gnu.org/licenses/>. * * BBT project home is at https://github.com/GiorgioRegni/Binaural-Beats */ import java.nio.ByteBuffer; import javax.microedition.khronos.opengles.GL10; import javax.microedition.khronos.opengles.GL11; import javax.microedition.khronos.opengles.GL11Ext; import android.graphics.Color; import com.ihunda.android.binauralbeat.GLVisualization; public class Plasma implements GLVisualization { private static final int PALETTE_SIZE = 257; private static final int COS_TABLE_SIZE = 256; /** * Beat frequency in Hz */ float freq; float period; private int palette[] = new int[PALETTE_SIZE]; private int cosTbl[] = new int[COS_TABLE_SIZE]; byte p1,p2,p3,p4; byte t1,t2,t3,t4; private int textureWidth; private int textureHeight; private ByteBuffer pixelBuffer; private static final int bytesPerPixel = 3; private int glTextureId = -1; private int[] textureCrop = new int[4]; private boolean glInited = false; public Plasma() { for (int x=0; x<64; x++) { int a = x*3; // Black -> yellow palette[x] = Color.rgb(a, a, 0); // Yellow -> red palette[x+64] = Color.rgb(192, 192-a, 0); // Red -> Blue palette[x+128] = Color.rgb(192-a, 0, a); // Blue -> Green palette[x+192] = Color.rgb(0, a, 192-a); } palette[256] = palette[255]; int i; double step = 2 * Math.PI / COS_TABLE_SIZE; for (i=0; i<COS_TABLE_SIZE; i++) cosTbl[i] = (int) (Math.cos(i*step)*32)+32; } public void setFrequency(float beat_frequency) { freq = beat_frequency; period = 1f / beat_frequency; } @Override public void setup(GL11 gl, int width, int height) { // TODO: choose values smarter // but remember they have to be powers of 2 if (width < height) { textureWidth = 196; textureHeight = 256; } else { textureWidth = 256; textureHeight = 196; } textureCrop[0] = 0; textureCrop[1] = 0; textureCrop[2] = textureWidth; textureCrop[3] = textureHeight; // init the pixel buffer pixelBuffer = ByteBuffer.allocate(textureWidth * textureHeight * bytesPerPixel); // init the GL settings if (glInited) { resetGl(gl); } initGl(gl, width, height); // init the GL texture initGlTexture(gl); } private void resetGl(GL11 gl) { gl.glMatrixMode(GL10.GL_PROJECTION); gl.glPopMatrix(); gl.glMatrixMode(GL10.GL_MODELVIEW); gl.glPopMatrix(); } private void initGl(GL11 gl, int surfaceWidth, int surfaceHeight) { gl.glShadeModel(GL10.GL_FLAT); gl.glFrontFace(GL10.GL_CCW); gl.glEnable(GL10.GL_TEXTURE_2D); gl.glMatrixMode(GL10.GL_PROJECTION); gl.glPushMatrix(); gl.glLoadIdentity(); gl.glOrthof(0.0f, surfaceWidth, 0.0f, surfaceHeight, 0.0f, 1.0f); gl.glMatrixMode(GL10.GL_MODELVIEW); gl.glPushMatrix(); gl.glLoadIdentity(); glInited = true; } private void releaseTexture(GL11 gl) { if (glTextureId != -1) { gl.glDeleteTextures(1, new int[] { glTextureId }, 0); } } private void initGlTexture(GL11 gl) { releaseTexture(gl); int[] textures = new int[1]; gl.glGenTextures(1, textures, 0); glTextureId = textures[0]; // we want to modify this texture so bind it gl.glBindTexture(GL10.GL_TEXTURE_2D, glTextureId); // GL_LINEAR gives us smoothing since the texture is larger than the screen gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR); // repeat the edge pixels if a surface is larger than the texture gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT); gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT); pixelBuffer.rewind(); // we need to output the pixels upside down due to glDrawTex peculiarities for (int y = textureWidth*textureHeight - textureWidth; y > 0; y -= textureWidth) { for (int x = 0; x < textureWidth; ++x) { int pixel = 0; pixelBuffer.put((byte) (pixel >> 16)); pixelBuffer.put((byte) ((pixel >> 8) & 0xff)); pixelBuffer.put((byte) (pixel & 0xff)); } } // and init the GL texture with the pixels gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_RGB, textureWidth, textureHeight, 0, GL10.GL_RGB, GL10.GL_UNSIGNED_BYTE, pixelBuffer); // at this point, we are OK to further modify the texture // using glTexSubImage2D } @Override public void dispose(GL11 gl) { releaseTexture(gl); } @Override public void redraw(GL11 gl, int width, int height, float now, float totalTime) { // window [-2.0, 1.0, -1.5, 1.5] float dperiod = period * 2; float ratio = (now % dperiod) / dperiod; //int img[] = new int[textureHeight*textureWidth]; int x,y,col,pos; pixelBuffer.rewind(); pos = 0; // position dans le buffer t1 = p1; // on sauvegarde les positions des "pointeurs" de colonne t2 = p2; for (y=0; y<textureHeight; y++) { t3 = p3; // on sauvegarde les positions des "pointeurs" de ligne t4 = p4; for (x=0; x<textureWidth; x++) { col = cosTbl[t1&0XFF] + cosTbl[t2&0XFF]+ cosTbl[t3&0XFF] + cosTbl[t4&0XFF]; int pixel = palette[col]; pixelBuffer.put((byte) (pixel >> 16)); pixelBuffer.put((byte) ((pixel >> 8) & 0xff)); pixelBuffer.put((byte) (pixel & 0xff)); pos++; t3 -= 1; // on incr�mente les "pointeurs" de ligne. t4 += 4; // ceci fait bouger la courbe du plasma sur l'axe horizontal } t1 -= 4; // on incr�mente les "pointeurs" de colonne. t2 += 2; // ceci fait bouger la courbe du plasma sur l'axe vertical } p1 += 1; // on incr�mente les positions des diff�rents pointeurs p2 += 4; // pour faire bouger le plasma sur les 2 axes1 p3 += 1; p4 -= (int) Math.ceil((8*ratio)); // Clear the surface gl.glClearColorx(0, 0, 0, 0); gl.glClear(GL10.GL_COLOR_BUFFER_BIT); // Choose the texture gl.glBindTexture(GL10.GL_TEXTURE_2D, glTextureId); // Update the texture gl.glTexSubImage2D(GL10.GL_TEXTURE_2D, 0, 0, 0, textureWidth, textureHeight, GL10.GL_RGB, GL10.GL_UNSIGNED_BYTE, pixelBuffer); // Draw the texture on the surface gl.glTexParameteriv(GL10.GL_TEXTURE_2D, GL11Ext.GL_TEXTURE_CROP_RECT_OES, textureCrop, 0); ((GL11Ext) gl).glDrawTexiOES(0, 0, 0, width, height); } }