• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.musicvis;
18 
19 import static android.renderscript.Element.RGB_565;
20 import static android.renderscript.ProgramFragment.EnvMode.REPLACE;
21 import static android.renderscript.Sampler.Value.LINEAR;
22 import static android.renderscript.Sampler.Value.WRAP;
23 
24 import android.media.MediaPlayer;
25 import android.os.Handler;
26 import android.os.SystemClock;
27 import android.renderscript.Allocation;
28 import android.renderscript.Element;
29 import android.renderscript.Primitive;
30 import android.renderscript.ProgramFragment;
31 import android.renderscript.ProgramVertex;
32 import android.renderscript.Sampler;
33 import android.renderscript.ScriptC;
34 import android.renderscript.SimpleMesh;
35 import android.renderscript.Type;
36 import android.renderscript.Element.Builder;
37 import android.util.Log;
38 
39 import java.util.TimeZone;
40 
41 public class GenericWaveRS extends RenderScriptScene {
42 
43     private final Handler mHandler = new Handler();
44     private final Runnable mDrawCube = new Runnable() {
45         public void run() {
46             updateWave();
47         }
48     };
49     private boolean mVisible;
50     private int mTexId;
51 
52     protected static class WorldState {
53         public float yRotation;
54         public int idle;
55         public int waveCounter;
56         public int width;
57     }
58     protected WorldState mWorldState = new WorldState();
59     private Type mStateType;
60     protected Allocation mState;
61 
62     private SimpleMesh mCubeMesh;
63 
64     protected Allocation mPointAlloc;
65     // 1024 lines, with 4 points per line (2 space, 2 texture) each consisting of x and y,
66     // so 8 floats per line.
67     protected float [] mPointData = new float[1024*8];
68 
69     private Allocation mLineIdxAlloc;
70     // 2 indices per line
71     private short [] mIndexData = new short[1024*2];
72 
73     private ProgramVertex mPVBackground;
74     private ProgramVertex.MatrixAllocation mPVAlloc;
75 
76     protected short [] mVizData = new short[1024];
77 
78     private ProgramFragment mPfBackground;
79     private Sampler mSampler;
80     private Allocation mTexture;
81 
82     private static final int RSID_STATE = 0;
83     private static final int RSID_POINTS = 1;
84     private static final int RSID_LINES = 2;
85     private static final int RSID_PROGRAMVERTEX = 3;
86 
87 
GenericWaveRS(int width, int height, int texid)88     protected GenericWaveRS(int width, int height, int texid) {
89         super(width, height);
90         mTexId = texid;
91         mWidth = width;
92         mHeight = height;
93         // the x, s and t coordinates don't change, so set those now
94         int outlen = mPointData.length / 8;
95         int half = outlen / 2;
96         for(int i = 0; i < outlen; i++) {
97             mPointData[i*8]   = i - half;          // start point X (Y set later)
98             mPointData[i*8+2] = 0;                 // start point S
99             mPointData[i*8+3] = 0;                 // start point T
100             mPointData[i*8+4]   = i - half;        // end point X (Y set later)
101             mPointData[i*8+6] = 1.0f;                 // end point S
102             mPointData[i*8+7] = 0f;              // end point T
103         }
104     }
105 
106     @Override
resize(int width, int height)107     public void resize(int width, int height) {
108         super.resize(width, height);
109         mWorldState.width = width;
110         if (mPVAlloc != null) {
111             mPVAlloc.setupProjectionNormalized(mWidth, mHeight);
112         }
113     }
114 
115     @Override
createScript()116     protected ScriptC createScript() {
117 
118         // Create a renderscript type from a java class. The specified name doesn't
119         // really matter; the name by which we refer to the object in RenderScript
120         // will be specified later.
121         mStateType = Type.createFromClass(mRS, WorldState.class, 1, "WorldState");
122         // Create an allocation from the type we just created.
123         mState = Allocation.createTyped(mRS, mStateType);
124         // set our java object as the data for the renderscript allocation
125         mWorldState.yRotation = 0.0f;
126         mWorldState.width = mWidth;
127         mState.data(mWorldState);
128 
129         /*
130          *  Now put our model in to a form that renderscript can work with:
131          *  - create a buffer of floats that are the coordinates for the points that define the cube
132          *  - create a buffer of integers that are the indices of the points that form lines
133          *  - combine the two in to a mesh
134          */
135 
136         // First set up the coordinate system and such
137         ProgramVertex.Builder pvb = new ProgramVertex.Builder(mRS, null, null);
138         mPVBackground = pvb.create();
139         mPVBackground.setName("PVBackground");
140         mPVAlloc = new ProgramVertex.MatrixAllocation(mRS);
141         mPVBackground.bindAllocation(mPVAlloc);
142         mPVAlloc.setupProjectionNormalized(mWidth, mHeight);
143 
144         // Start creating the mesh
145         final SimpleMesh.Builder meshBuilder = new SimpleMesh.Builder(mRS);
146 
147         // Create the Element for the points
148         Builder elementBuilder = new Builder(mRS);
149         // By specifying a prefix, even an empty one, the members will be accessible
150         // in the renderscript. If we just called addFloatXYZ(), the members would be
151         // unnamed in the renderscript struct definition.
152         elementBuilder.addFloatXY("");
153         elementBuilder.addFloatST("");
154         final Element vertexElement = elementBuilder.create();
155         final int vertexSlot = meshBuilder.addVertexType(vertexElement, mPointData.length / 4);
156         // Specify the type and number of indices we need. We'll allocate them later.
157         meshBuilder.setIndexType(Element.INDEX_16(mRS), mIndexData.length);
158         // This will be a line mesh
159         meshBuilder.setPrimitive(Primitive.LINE);
160 
161         // Create the Allocation for the vertices
162         mCubeMesh = meshBuilder.create();
163         mCubeMesh.setName("CubeMesh");
164         mPointAlloc = mCubeMesh.createVertexAllocation(vertexSlot);
165         mPointAlloc.setName("PointBuffer");
166 
167         // Create the Allocation for the indices
168         mLineIdxAlloc = mCubeMesh.createIndexAllocation();
169 
170         // Bind the allocations to the mesh
171         mCubeMesh.bindVertexAllocation(mPointAlloc, 0);
172         mCubeMesh.bindIndexAllocation(mLineIdxAlloc);
173 
174         /*
175          *  put the vertex and index data in their respective buffers
176          */
177         updateWave();
178         for(int i = 0; i < mIndexData.length; i ++) {
179             mIndexData[i] = (short) i;
180         }
181 
182         /*
183          *  upload the vertex and index data
184          */
185         mPointAlloc.data(mPointData);
186         mPointAlloc.uploadToBufferObject();
187         mLineIdxAlloc.data(mIndexData);
188         mLineIdxAlloc.uploadToBufferObject();
189 
190         /*
191          * load the texture
192          */
193         mTexture = Allocation.createFromBitmapResourceBoxed(mRS, mResources, mTexId, RGB_565(mRS), false);
194         mTexture.setName("Tlinetexture");
195         mTexture.uploadToTexture(0);
196 
197         /*
198          * create a program fragment to use the texture
199          */
200         Sampler.Builder samplerBuilder = new Sampler.Builder(mRS);
201         samplerBuilder.setMin(LINEAR);
202         samplerBuilder.setMag(LINEAR);
203         samplerBuilder.setWrapS(WRAP);
204         samplerBuilder.setWrapT(WRAP);
205         mSampler = samplerBuilder.create();
206 
207         ProgramFragment.Builder builder = new ProgramFragment.Builder(mRS, null, null);
208         builder.setTexEnable(true, 0);
209         builder.setTexEnvMode(REPLACE, 0);
210         mPfBackground = builder.create();
211         mPfBackground.setName("PFBackground");
212         mPfBackground.bindSampler(mSampler, 0);
213 
214         // Time to create the script
215         ScriptC.Builder sb = new ScriptC.Builder(mRS);
216         // Specify the name by which to refer to the WorldState object in the
217         // renderscript.
218         sb.setType(mStateType, "State", RSID_STATE);
219         sb.setType(mCubeMesh.getVertexType(0), "Points", RSID_POINTS);
220         // this crashes when uncommented
221         //sb.setType(mCubeMesh.getIndexType(), "Lines", RSID_LINES);
222         sb.setScript(mResources, R.raw.waveform);
223         sb.setRoot(true);
224 
225         ScriptC script = sb.create();
226         script.setClearColor(0.0f, 0.0f, 0.0f, 1.0f);
227         script.setTimeZone(TimeZone.getDefault().getID());
228 
229         script.bindAllocation(mState, RSID_STATE);
230         script.bindAllocation(mPointAlloc, RSID_POINTS);
231         script.bindAllocation(mLineIdxAlloc, RSID_LINES);
232         script.bindAllocation(mPVAlloc.mAlloc, RSID_PROGRAMVERTEX);
233 
234         return script;
235     }
236 
237     @Override
setOffset(float xOffset, float yOffset, float xStep, float yStep, int xPixels, int yPixels)238     public void setOffset(float xOffset, float yOffset,
239             float xStep, float yStep, int xPixels, int yPixels) {
240         // update our state, then push it to the renderscript
241 
242         if (xStep <= 0.0f) {
243             xStep = xOffset / 2; // originator didn't set step size, assume we're halfway
244         }
245         mWorldState.yRotation = (xOffset / xStep) * 180; // rotate 180 degrees per screen
246         mState.data(mWorldState);
247     }
248 
249     @Override
start()250     public void start() {
251         super.start();
252         mVisible = true;
253         // Preroll the MediaPlayer so we don't get a spurious 'idle'
254         MediaPlayer.snoop(mVizData, 0);
255         SystemClock.sleep(200);
256         updateWave();
257     }
258 
259     @Override
stop()260     public void stop() {
261         super.stop();
262         mVisible = false;
263         updateWave();
264     }
265 
update()266     public void update() {
267     }
268 
updateWave()269     void updateWave() {
270         mHandler.removeCallbacks(mDrawCube);
271         if (!mVisible) {
272             return;
273         }
274         mHandler.postDelayed(mDrawCube, 20);
275         update();
276         mWorldState.waveCounter++;
277         mState.data(mWorldState);
278     }
279 
280 }
281