blob: f34a4c08d97a867d4607607d6a1976d2bc0c6057 [file] [log] [blame]
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.musicvis;
import static android.renderscript.Element.RGB_565;
import static android.renderscript.Sampler.Value.LINEAR;
import static android.renderscript.Sampler.Value.WRAP;
import android.os.Handler;
import android.os.SystemClock;
import android.renderscript.Mesh.Primitive;
import android.renderscript.*;
import android.renderscript.Element.Builder;
import android.util.Log;
import java.util.TimeZone;
public class GenericWaveRS extends RenderScriptScene {
private final Handler mHandler = new Handler();
private final Runnable mDrawCube = new Runnable() {
public void run() {
updateWave();
}
};
private boolean mVisible;
private int mTexId;
protected static class WorldState {
public float yRotation;
public int idle;
public int waveCounter;
public int width;
}
protected WorldState mWorldState = new WorldState();
ScriptC_waveform mScript;
private ScriptField_Vertex mVertexBuffer;
private Mesh mCubeMesh;
protected Allocation mPointAlloc;
// 1024 lines, with 4 points per line (2 space, 2 texture) each consisting of x and y,
// so 8 floats per line.
protected float [] mPointData = new float[1024*8];
private Allocation mLineIdxAlloc;
// 2 indices per line
private short [] mIndexData = new short[1024*2];
private ProgramVertex mPVBackground;
private ProgramVertexFixedFunction.Constants mPVAlloc;
protected AudioCapture mAudioCapture = null;
protected int [] mVizData = new int[1024];
private ProgramFragment mPfBackground;
private Sampler mSampler;
private Allocation mTexture;
private static final int RSID_STATE = 0;
private static final int RSID_POINTS = 1;
private static final int RSID_LINES = 2;
private static final int RSID_PROGRAMVERTEX = 3;
protected GenericWaveRS(int width, int height, int texid) {
super(width, height);
mTexId = texid;
mWidth = width;
mHeight = height;
// the x, s and t coordinates don't change, so set those now
int outlen = mPointData.length / 8;
int half = outlen / 2;
for(int i = 0; i < outlen; i++) {
mPointData[i*8] = i - half; // start point X (Y set later)
mPointData[i*8+2] = 0; // start point S
mPointData[i*8+3] = 0; // start point T
mPointData[i*8+4] = i - half; // end point X (Y set later)
mPointData[i*8+6] = 1.0f; // end point S
mPointData[i*8+7] = 0f; // end point T
}
}
@Override
public void resize(int width, int height) {
super.resize(width, height);
mWorldState.width = width;
if (mPVAlloc != null) {
Matrix4f proj = new Matrix4f();
proj.loadProjectionNormalized(mWidth, mHeight);
mPVAlloc.setProjection(proj);
}
}
@Override
protected ScriptC createScript() {
mScript = new ScriptC_waveform(mRS, mResources, R.raw.waveform);
// set our java object as the data for the renderscript allocation
mWorldState.yRotation = 0.0f;
mWorldState.width = mWidth;
updateWorldState();
// Now put our model in to a form that renderscript can work with:
// - create a buffer of floats that are the coordinates for the points that define the cube
// - create a buffer of integers that are the indices of the points that form lines
// - combine the two in to a mesh
// First set up the coordinate system and such
ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS);
mPVBackground = pvb.create();
mPVAlloc = new ProgramVertexFixedFunction.Constants(mRS);
((ProgramVertexFixedFunction)mPVBackground).bindConstants(mPVAlloc);
Matrix4f proj = new Matrix4f();
proj.loadProjectionNormalized(mWidth, mHeight);
mPVAlloc.setProjection(proj);
mScript.set_gPVBackground(mPVBackground);
mVertexBuffer = new ScriptField_Vertex(mRS, mPointData.length / 4);
// Start creating the mesh
final Mesh.AllocationBuilder meshBuilder = new Mesh.AllocationBuilder(mRS);
meshBuilder.addVertexAllocation(mVertexBuffer.getAllocation());
// Create the Allocation for the indices
mLineIdxAlloc = Allocation.createSized(mRS, Element.U16(mRS), mIndexData.length,
Allocation.USAGE_GRAPHICS_VERTEX |
Allocation.USAGE_SCRIPT);
// This will be a line mesh
meshBuilder.addIndexSetAllocation(mLineIdxAlloc, Primitive.LINE);
// Create the Allocation for the vertices
mCubeMesh = meshBuilder.create();
mPointAlloc = mVertexBuffer.getAllocation();
mScript.bind_gPoints(mVertexBuffer);
mScript.set_gPointBuffer(mPointAlloc);
mScript.set_gCubeMesh(mCubeMesh);
// put the vertex and index data in their respective buffers
updateWave();
for(int i = 0; i < mIndexData.length; i ++) {
mIndexData[i] = (short) i;
}
// upload the vertex and index data
mPointAlloc.copyFromUnchecked(mPointData);
mLineIdxAlloc.copyFrom(mIndexData);
mLineIdxAlloc.syncAll(Allocation.USAGE_SCRIPT);
// load the texture
mTexture = Allocation.createFromBitmapResource(mRS, mResources, mTexId);
mScript.set_gTlinetexture(mTexture);
/*
* create a program fragment to use the texture
*/
Sampler.Builder samplerBuilder = new Sampler.Builder(mRS);
samplerBuilder.setMinification(LINEAR);
samplerBuilder.setMagnification(LINEAR);
samplerBuilder.setWrapS(WRAP);
samplerBuilder.setWrapT(WRAP);
mSampler = samplerBuilder.create();
ProgramFragmentFixedFunction.Builder builder = new ProgramFragmentFixedFunction.Builder(mRS);
builder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE,
ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
mPfBackground = builder.create();
mPfBackground.bindSampler(mSampler, 0);
mScript.set_gPFBackground(mPfBackground);
return mScript;
}
@Override
public void setOffset(float xOffset, float yOffset, int xPixels, int yPixels) {
mWorldState.yRotation = (xOffset * 4) * 180;
updateWorldState();
}
@Override
public void start() {
super.start();
mVisible = true;
if (mAudioCapture != null) {
mAudioCapture.start();
}
SystemClock.sleep(200);
updateWave();
}
@Override
public void stop() {
super.stop();
mVisible = false;
if (mAudioCapture != null) {
mAudioCapture.stop();
}
updateWave();
}
public void update() {
}
void updateWave() {
mHandler.removeCallbacks(mDrawCube);
if (!mVisible) {
return;
}
mHandler.postDelayed(mDrawCube, 20);
update();
mWorldState.waveCounter++;
updateWorldState();
}
protected void updateWorldState() {
mScript.set_gYRotation(mWorldState.yRotation);
mScript.set_gIdle(mWorldState.idle);
mScript.set_gWaveCounter(mWorldState.waveCounter);
mScript.set_gWidth(mWorldState.width);
}
}