1/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.musicvis;
18
19import static android.renderscript.Element.RGB_565;
20import static android.renderscript.Sampler.Value.LINEAR;
21import static android.renderscript.Sampler.Value.WRAP;
22
23import android.os.Handler;
24import android.os.SystemClock;
25import android.renderscript.Mesh.Primitive;
26import android.renderscript.*;
27import android.renderscript.Element.Builder;
28import android.util.Log;
29
30import java.util.TimeZone;
31
32public class GenericWaveRS extends RenderScriptScene {
33
34    private final Handler mHandler = new Handler();
35    private final Runnable mDrawCube = new Runnable() {
36        public void run() {
37            updateWave();
38        }
39    };
40    private boolean mVisible;
41    private int mTexId;
42
43    protected static class WorldState {
44        public float yRotation;
45        public int idle;
46        public int waveCounter;
47        public int width;
48    }
49    protected WorldState mWorldState = new WorldState();
50
51    ScriptC_waveform mScript;
52
53    private ScriptField_Vertex mVertexBuffer;
54
55    private Mesh mCubeMesh;
56
57    protected Allocation mPointAlloc;
58    // 1024 lines, with 4 points per line (2 space, 2 texture) each consisting of x and y,
59    // so 8 floats per line.
60    protected float [] mPointData = new float[1024*8];
61
62    private ProgramVertex mPVBackground;
63    private ProgramVertexFixedFunction.Constants mPVAlloc;
64
65    protected AudioCapture mAudioCapture = null;
66    protected int [] mVizData = new int[1024];
67
68    private ProgramFragment mPfBackground;
69    private Sampler mSampler;
70    private Allocation mTexture;
71
72    private static final int RSID_STATE = 0;
73    private static final int RSID_POINTS = 1;
74    private static final int RSID_LINES = 2;
75    private static final int RSID_PROGRAMVERTEX = 3;
76
77    protected GenericWaveRS(int width, int height, int texid) {
78        super(width, height);
79        mTexId = texid;
80        mWidth = width;
81        mHeight = height;
82        // the x, s and t coordinates don't change, so set those now
83        int outlen = mPointData.length / 8;
84        int half = outlen / 2;
85        for(int i = 0; i < outlen; i++) {
86            mPointData[i*8]   = i - half;          // start point X (Y set later)
87            mPointData[i*8+2] = 0;                 // start point S
88            mPointData[i*8+3] = 0;                 // start point T
89            mPointData[i*8+4]   = i - half;        // end point X (Y set later)
90            mPointData[i*8+6] = 1.0f;                 // end point S
91            mPointData[i*8+7] = 0f;              // end point T
92        }
93    }
94
95    @Override
96    public void resize(int width, int height) {
97        super.resize(width, height);
98        mWorldState.width = width;
99        if (mPVAlloc != null) {
100            Matrix4f proj = new Matrix4f();
101            proj.loadProjectionNormalized(mWidth, mHeight);
102            mPVAlloc.setProjection(proj);
103        }
104    }
105
106    @Override
107    protected ScriptC createScript() {
108
109        mScript = new ScriptC_waveform(mRS, mResources, R.raw.waveform);
110
111        // set our java object as the data for the renderscript allocation
112        mWorldState.yRotation = 0.0f;
113        mWorldState.width = mWidth;
114        updateWorldState();
115
116        //  Now put our model in to a form that renderscript can work with:
117        //  - create a buffer of floats that are the coordinates for the points that define the cube
118        //  - create a buffer of integers that are the indices of the points that form lines
119        //  - combine the two in to a mesh
120
121        // First set up the coordinate system and such
122        ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS);
123        mPVBackground = pvb.create();
124        mPVAlloc = new ProgramVertexFixedFunction.Constants(mRS);
125        ((ProgramVertexFixedFunction)mPVBackground).bindConstants(mPVAlloc);
126        Matrix4f proj = new Matrix4f();
127        proj.loadProjectionNormalized(mWidth, mHeight);
128        mPVAlloc.setProjection(proj);
129
130        mScript.set_gPVBackground(mPVBackground);
131
132        mVertexBuffer = new ScriptField_Vertex(mRS, mPointData.length / 4);
133
134        // Start creating the mesh
135        final Mesh.AllocationBuilder meshBuilder = new Mesh.AllocationBuilder(mRS);
136        meshBuilder.addVertexAllocation(mVertexBuffer.getAllocation());
137        // This will be a triangle strip mesh
138        meshBuilder.addIndexSetType(Primitive.TRIANGLE_STRIP);
139
140        // Create the Allocation for the vertices
141        mCubeMesh = meshBuilder.create();
142
143        mPointAlloc = mVertexBuffer.getAllocation();
144
145        mScript.bind_gPoints(mVertexBuffer);
146        mScript.set_gPointBuffer(mPointAlloc);
147        mScript.set_gCubeMesh(mCubeMesh);
148
149        //  upload the vertex data
150        mPointAlloc.copyFromUnchecked(mPointData);
151
152        // load the texture
153        mTexture = Allocation.createFromBitmapResource(mRS, mResources, mTexId,
154                                           Allocation.MipmapControl.MIPMAP_NONE,
155                                           Allocation.USAGE_GRAPHICS_TEXTURE);
156
157        mScript.set_gTlinetexture(mTexture);
158
159        /*
160         * create a program fragment to use the texture
161         */
162        Sampler.Builder samplerBuilder = new Sampler.Builder(mRS);
163        samplerBuilder.setMinification(LINEAR);
164        samplerBuilder.setMagnification(LINEAR);
165        samplerBuilder.setWrapS(WRAP);
166        samplerBuilder.setWrapT(WRAP);
167        mSampler = samplerBuilder.create();
168
169        ProgramFragmentFixedFunction.Builder builder = new ProgramFragmentFixedFunction.Builder(mRS);
170        builder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE,
171                           ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
172        mPfBackground = builder.create();
173        mPfBackground.bindSampler(mSampler, 0);
174
175        mScript.set_gPFBackground(mPfBackground);
176
177        return mScript;
178    }
179
180    @Override
181    public void setOffset(float xOffset, float yOffset, int xPixels, int yPixels) {
182        mWorldState.yRotation = (xOffset * 4) * 180;
183        updateWorldState();
184    }
185
186    @Override
187    public void start() {
188        super.start();
189        mVisible = true;
190        if (mAudioCapture != null) {
191            mAudioCapture.start();
192        }
193        SystemClock.sleep(200);
194        updateWave();
195    }
196
197    @Override
198    public void stop() {
199        super.stop();
200        mVisible = false;
201        if (mAudioCapture != null) {
202            mAudioCapture.stop();
203        }
204        updateWave();
205    }
206
207    public void update() {
208    }
209
210    void updateWave() {
211        mHandler.removeCallbacks(mDrawCube);
212        if (!mVisible) {
213            return;
214        }
215        mHandler.postDelayed(mDrawCube, 20);
216        update();
217        mWorldState.waveCounter++;
218        updateWorldState();
219    }
220
221    protected void updateWorldState() {
222        mScript.set_gYRotation(mWorldState.yRotation);
223        mScript.set_gIdle(mWorldState.idle);
224        mScript.set_gWaveCounter(mWorldState.waveCounter);
225        mScript.set_gWidth(mWorldState.width);
226    }
227}
228