• 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.wallpaper.fall;
18 
19 import android.os.Bundle;
20 import android.renderscript.Element;
21 import android.renderscript.ScriptC;
22 import android.renderscript.ProgramFragment;
23 import android.renderscript.ProgramStore;
24 import android.renderscript.ProgramVertex;
25 import android.renderscript.Allocation;
26 import android.renderscript.Sampler;
27 import android.renderscript.Type;
28 import android.renderscript.SimpleMesh;
29 import android.renderscript.Script;
30 import static android.renderscript.Sampler.Value.LINEAR;
31 import static android.renderscript.Sampler.Value.CLAMP;
32 import static android.renderscript.ProgramStore.DepthFunc.*;
33 import static android.renderscript.ProgramStore.BlendDstFunc;
34 import static android.renderscript.ProgramStore.BlendSrcFunc;
35 import static android.renderscript.Element.*;
36 
37 import android.app.WallpaperManager;
38 import android.graphics.BitmapFactory;
39 import android.graphics.Bitmap;
40 import static android.util.MathUtils.*;
41 
42 import java.util.TimeZone;
43 
44 import com.android.wallpaper.R;
45 import com.android.wallpaper.RenderScriptScene;
46 
47 class FallRS extends RenderScriptScene {
48     private static final int MESH_RESOLUTION = 48;
49 
50     private static final int RSID_STATE = 0;
51     private static final int RSID_CONSTANTS = 1;
52     private static final int RSID_DROP = 2;
53 
54     private static final int TEXTURES_COUNT = 2;
55     private static final int RSID_TEXTURE_RIVERBED = 0;
56     private static final int RSID_TEXTURE_LEAVES = 1;
57 
58     private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options();
59 
60     @SuppressWarnings({"FieldCanBeLocal"})
61     private ProgramFragment mPfBackground;
62     @SuppressWarnings({"FieldCanBeLocal"})
63     private ProgramFragment mPfSky;
64     @SuppressWarnings({"FieldCanBeLocal"})
65     private ProgramStore mPfsBackground;
66     @SuppressWarnings({"FieldCanBeLocal"})
67     private ProgramStore mPfsLeaf;
68     @SuppressWarnings({"FieldCanBeLocal"})
69     private ProgramVertex mPvSky;
70     @SuppressWarnings({"FieldCanBeLocal"})
71     private ProgramVertex mPvWater;
72     private ProgramVertex.MatrixAllocation mPvOrthoAlloc;
73     @SuppressWarnings({"FieldCanBeLocal"})
74     private Sampler mSampler;
75 
76     private Allocation mState;
77     private Allocation mDropState;
78     private DropState mDrop;
79     private Type mStateType;
80     private Type mDropType;
81     private int mMeshWidth;
82     private Allocation mUniformAlloc;
83 
84     private int mMeshHeight;
85     @SuppressWarnings({"FieldCanBeLocal"})
86     private SimpleMesh mMesh;
87     private WorldState mWorldState;
88 
89     private float mGlHeight;
90 
FallRS(int width, int height)91     public FallRS(int width, int height) {
92         super(width, height);
93 
94         mOptionsARGB.inScaled = false;
95         mOptionsARGB.inPreferredConfig = Bitmap.Config.ARGB_8888;
96     }
97 
98     @Override
setOffset(float xOffset, float yOffset, int xPixels, int yPixels)99     public void setOffset(float xOffset, float yOffset, int xPixels, int yPixels) {
100         mWorldState.xOffset = xOffset;
101         mState.data(mWorldState);
102     }
103 
104     @Override
onCommand(String action, int x, int y, int z, Bundle extras, boolean resultRequested)105     public Bundle onCommand(String action, int x, int y, int z, Bundle extras,
106             boolean resultRequested) {
107         if (WallpaperManager.COMMAND_TAP.equals(action)) {
108             addDrop(x + (mWorldState.rotate == 0 ? (mWorldState.width * mWorldState.xOffset) : 0), y);
109         } else if (WallpaperManager.COMMAND_DROP.equals(action)) {
110             addDrop(x + (mWorldState.rotate == 0 ? (mWorldState.width * mWorldState.xOffset) : 0), y);
111         }
112         return null;
113     }
114 
115     @Override
start()116     public void start() {
117         super.start();
118         final WorldState worldState = mWorldState;
119         final int width = worldState.width;
120         final int x = width / 4 + (int)(Math.random() * (width / 2));
121         final int y = worldState.height / 4 + (int)(Math.random() * (worldState.height / 2));
122         addDrop(x + (mWorldState.rotate == 0 ? (width * worldState.xOffset) : 0), y);
123     }
124 
125     @Override
resize(int width, int height)126     public void resize(int width, int height) {
127         super.resize(width, height);
128 
129         mWorldState.width = width;
130         mWorldState.height = height;
131         mWorldState.rotate = width > height ? 1 : 0;
132         mState.data(mWorldState);
133 
134         mPvOrthoAlloc.setupProjectionNormalized(mWidth, mHeight);
135     }
136 
137     @Override
createScript()138     protected ScriptC createScript() {
139         createMesh();
140         createState();
141         createProgramVertex();
142         createProgramFragmentStore();
143         createProgramFragment();
144         loadTextures();
145 
146         ScriptC.Builder sb = new ScriptC.Builder(mRS);
147         sb.setType(mStateType, "State", RSID_STATE);
148         sb.setType(mDropType, "Drop", RSID_DROP);
149         sb.setType(mUniformAlloc.getType(), "Constants", RSID_CONSTANTS);
150         sb.setScript(mResources, R.raw.fall);
151         Script.Invokable invokable = sb.addInvokable("initLeaves");
152         sb.setRoot(true);
153 
154         ScriptC script = sb.create();
155         script.setClearColor(0.0f, 0.0f, 0.0f, 1.0f);
156         script.setTimeZone(TimeZone.getDefault().getID());
157 
158         script.bindAllocation(mState, RSID_STATE);
159         script.bindAllocation(mUniformAlloc, RSID_CONSTANTS);
160         script.bindAllocation(mDropState, RSID_DROP);
161 
162         invokable.execute();
163 
164         return script;
165     }
166 
createMesh()167     private void createMesh() {
168         SimpleMesh.TriangleMeshBuilder tmb = new SimpleMesh.TriangleMeshBuilder(mRS, 2, 0);
169 
170         final int width = mWidth > mHeight ? mHeight : mWidth;
171         final int height = mWidth > mHeight ? mWidth : mHeight;
172 
173         int wResolution = MESH_RESOLUTION;
174         int hResolution = (int) (MESH_RESOLUTION * height / (float) width);
175 
176         mGlHeight = 2.0f * height / (float) width;
177 
178         wResolution += 2;
179         hResolution += 2;
180 
181         for (int y = 0; y <= hResolution; y++) {
182             final float yOffset = (((float)y / hResolution) * 2.f - 1.f) * height / width;
183             for (int x = 0; x <= wResolution; x++) {
184                 tmb.addVertex(((float)x / wResolution) * 2.f - 1.f, yOffset);
185             }
186         }
187 
188         for (int y = 0; y < hResolution; y++) {
189             final boolean shift = (y & 0x1) == 0;
190             final int yOffset = y * (wResolution + 1);
191             for (int x = 0; x < wResolution; x++) {
192                 final int index = yOffset + x;
193                 final int iWR1 = index + wResolution + 1;
194                 if (shift) {
195                     tmb.addTriangle(index, index + 1, iWR1);
196                     tmb.addTriangle(index + 1, iWR1 + 1, iWR1);
197                 } else {
198                     tmb.addTriangle(index, iWR1 + 1, iWR1);
199                     tmb.addTriangle(index, index + 1, iWR1 + 1);
200                 }
201             }
202         }
203 
204         mMesh = tmb.create();
205         mMesh.setName("WaterMesh");
206 
207         mMeshWidth = wResolution + 1;
208         mMeshHeight = hResolution + 1;
209     }
210 
211     static class WorldState {
212         public int frameCount;
213         public int width;
214         public int height;
215         public int meshWidth;
216         public int meshHeight;
217         public int rippleIndex;
218         public float glWidth;
219         public float glHeight;
220         public float skySpeedX;
221         public float skySpeedY;
222         public int rotate;
223         public int isPreview;
224         public float xOffset;
225     }
226 
227     static class DropState {
228         public int dropX;
229         public int dropY;
230     }
231 
createState()232     private void createState() {
233         mWorldState = new WorldState();
234         mWorldState.width = mWidth;
235         mWorldState.height = mHeight;
236         mWorldState.meshWidth = mMeshWidth;
237         mWorldState.meshHeight = mMeshHeight;
238         mWorldState.rippleIndex = 0;
239         mWorldState.glWidth = 2.0f;
240         mWorldState.glHeight = mGlHeight;
241         mWorldState.skySpeedX = random(-0.001f, 0.001f);
242         mWorldState.skySpeedY = random(0.00008f, 0.0002f);
243         mWorldState.rotate = mWidth > mHeight ? 1 : 0;
244         mWorldState.isPreview = isPreview() ? 1 : 0;
245 
246         mStateType = Type.createFromClass(mRS, WorldState.class, 1, "WorldState");
247         mState = Allocation.createTyped(mRS, mStateType);
248         mState.data(mWorldState);
249 
250         mDrop = new DropState();
251         mDrop.dropX = -1;
252         mDrop.dropY = -1;
253 
254         mDropType = Type.createFromClass(mRS, DropState.class, 1, "DropState");
255         mDropState = Allocation.createTyped(mRS, mDropType);
256         mDropState.data(mDrop);
257     }
258 
loadTextures()259     private void loadTextures() {
260         final Allocation[] textures = new Allocation[TEXTURES_COUNT];
261         textures[RSID_TEXTURE_RIVERBED] = loadTexture(R.drawable.pond, "TRiverbed");
262         textures[RSID_TEXTURE_LEAVES] = loadTextureARGB(R.drawable.leaves, "TLeaves");
263 
264         final int count = textures.length;
265         for (int i = 0; i < count; i++) {
266             textures[i].uploadToTexture(0);
267         }
268     }
269 
loadTexture(int id, String name)270     private Allocation loadTexture(int id, String name) {
271         final Allocation allocation = Allocation.createFromBitmapResource(mRS, mResources,
272                 id, RGB_565(mRS), false);
273         allocation.setName(name);
274         return allocation;
275     }
276 
loadTextureARGB(int id, String name)277     private Allocation loadTextureARGB(int id, String name) {
278         Bitmap b = BitmapFactory.decodeResource(mResources, id, mOptionsARGB);
279         final Allocation allocation = Allocation.createFromBitmap(mRS, b, RGBA_8888(mRS), false);
280         allocation.setName(name);
281         return allocation;
282     }
283 
createProgramFragment()284     private void createProgramFragment() {
285         Sampler.Builder sampleBuilder = new Sampler.Builder(mRS);
286         sampleBuilder.setMin(LINEAR);
287         sampleBuilder.setMag(LINEAR);
288         sampleBuilder.setWrapS(CLAMP);
289         sampleBuilder.setWrapT(CLAMP);
290         mSampler = sampleBuilder.create();
291 
292         ProgramFragment.Builder builder = new ProgramFragment.Builder(mRS);
293         builder.setTexture(ProgramFragment.Builder.EnvMode.REPLACE,
294                            ProgramFragment.Builder.Format.RGBA, 0);
295         mPfBackground = builder.create();
296         mPfBackground.setName("PFBackground");
297         mPfBackground.bindSampler(mSampler, 0);
298 
299         builder = new ProgramFragment.Builder(mRS);
300         builder.setTexture(ProgramFragment.Builder.EnvMode.MODULATE,
301                            ProgramFragment.Builder.Format.RGBA, 0);
302         mPfSky = builder.create();
303         mPfSky.setName("PFSky");
304         mPfSky.bindSampler(mSampler, 0);
305     }
306 
createProgramFragmentStore()307     private void createProgramFragmentStore() {
308         ProgramStore.Builder builder = new ProgramStore.Builder(mRS, null, null);
309         builder.setDepthFunc(ALWAYS);
310         builder.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ONE);
311         builder.setDitherEnable(false);
312         builder.setDepthMask(true);
313         mPfsBackground = builder.create();
314         mPfsBackground.setName("PFSBackground");
315 
316         builder = new ProgramStore.Builder(mRS, null, null);
317         builder.setDepthFunc(ALWAYS);
318         builder.setBlendFunc(BlendSrcFunc.SRC_ALPHA, BlendDstFunc.ONE_MINUS_SRC_ALPHA);
319         builder.setDitherEnable(false);
320         builder.setDepthMask(true);
321         mPfsLeaf = builder.create();
322         mPfsLeaf.setName("PFSLeaf");
323     }
324 
createProgramVertex()325     private void createProgramVertex() {
326         mPvOrthoAlloc = new ProgramVertex.MatrixAllocation(mRS);
327         mPvOrthoAlloc.setupProjectionNormalized(mWidth, mHeight);
328 
329         ProgramVertex.Builder builder = new ProgramVertex.Builder(mRS, null, null);
330         mPvSky = builder.create();
331         mPvSky.bindAllocation(mPvOrthoAlloc);
332         mPvSky.setName("PVSky");
333 
334         Element.Builder eb = new Element.Builder(mRS);
335         // Make this an array when we can.
336         eb.add(Element.createVector(mRS, Element.DataType.FLOAT_32, 4), "Drop01");
337         eb.add(Element.createVector(mRS, Element.DataType.FLOAT_32, 4), "Drop02");
338         eb.add(Element.createVector(mRS, Element.DataType.FLOAT_32, 4), "Drop03");
339         eb.add(Element.createVector(mRS, Element.DataType.FLOAT_32, 4), "Drop04");
340         eb.add(Element.createVector(mRS, Element.DataType.FLOAT_32, 4), "Drop05");
341         eb.add(Element.createVector(mRS, Element.DataType.FLOAT_32, 4), "Drop06");
342         eb.add(Element.createVector(mRS, Element.DataType.FLOAT_32, 4), "Drop07");
343         eb.add(Element.createVector(mRS, Element.DataType.FLOAT_32, 4), "Drop08");
344         eb.add(Element.createVector(mRS, Element.DataType.FLOAT_32, 4), "Drop09");
345         eb.add(Element.createVector(mRS, Element.DataType.FLOAT_32, 4), "Drop10");
346         eb.add(Element.createVector(mRS, Element.DataType.FLOAT_32, 4), "Offset");
347         eb.add(Element.USER_F32(mRS), "Rotate");
348         Element e = eb.create();
349 
350         mUniformAlloc = Allocation.createSized(mRS, e, 1);
351 
352         ProgramVertex.ShaderBuilder sb = new ProgramVertex.ShaderBuilder(mRS);
353 
354         String t = "\n" +
355                 "vec2 addDrop(vec4 d, vec2 pos, float dxMul) {\n" +
356                 "  vec2 ret = vec2(0.0, 0.0);\n" +
357                 "  vec2 delta = d.xy - pos;\n" +
358                 "  delta.x *= dxMul;\n" +
359                 "  float dist = length(delta);\n" +
360                 "  if (dist < d.w) { \n" +
361                 "    float amp = d.z * dist;\n" +
362                 "    amp /= d.w * d.w;\n" +
363                 "    amp *= sin(d.w - dist);\n" +
364                 "    ret = delta * amp;\n" +
365                 "  }\n" +
366                 "  return ret;\n" +
367                 "}\n" +
368 
369                 "void main() {\n" +
370                 "  vec2 pos = ATTRIB_position.xy;\n" +
371                 "  gl_Position = vec4(pos.x, pos.y, 0.0, 1.0);\n" +
372                 "  float dxMul = 1.0;\n" +
373 
374                 "  varTex0 = vec4((pos.x + 1.0), (pos.y + 1.6666), 0.0, 0.0);\n" +
375 
376                 "  if (UNI_Rotate < 0.9) {\n" +
377                 "    varTex0.xy *= vec2(0.25, 0.33);\n" +
378                 "    varTex0.x += UNI_Offset.x * 0.5;\n" +
379                 "    pos.x += UNI_Offset.x * 2.0;\n" +
380                 "  } else {\n" +
381                 "    varTex0.xy *= vec2(0.5, 0.3125);\n" +
382                 "    dxMul = 2.5;\n" +
383                 "  }\n" +
384 
385                 "  varColor = vec4(1.0, 1.0, 1.0, 1.0);\n" +
386                 "  pos.xy += vec2(1.0, 1.0);\n" +
387                 "  pos.xy *= vec2(25.0, 42.0);\n" +
388 
389                 "  varTex0.xy += addDrop(UNI_Drop01, pos, dxMul);\n" +
390                 "  varTex0.xy += addDrop(UNI_Drop02, pos, dxMul);\n" +
391                 "  varTex0.xy += addDrop(UNI_Drop03, pos, dxMul);\n" +
392                 "  varTex0.xy += addDrop(UNI_Drop04, pos, dxMul);\n" +
393                 "  varTex0.xy += addDrop(UNI_Drop05, pos, dxMul);\n" +
394                 "  varTex0.xy += addDrop(UNI_Drop06, pos, dxMul);\n" +
395                 "  varTex0.xy += addDrop(UNI_Drop07, pos, dxMul);\n" +
396                 "  varTex0.xy += addDrop(UNI_Drop08, pos, dxMul);\n" +
397                 "  varTex0.xy += addDrop(UNI_Drop09, pos, dxMul);\n" +
398                 "  varTex0.xy += addDrop(UNI_Drop10, pos, dxMul);\n" +
399                 "}\n";
400         sb.setShader(t);
401         sb.addConstant(mUniformAlloc.getType());
402         sb.addInput(mMesh.getVertexType(0).getElement());
403         mPvWater = sb.create();
404         mPvWater.bindAllocation(mPvOrthoAlloc);
405         mPvWater.setName("PVWater");
406         mPvWater.bindConstants(mUniformAlloc, 1);
407 
408     }
409 
addDrop(float x, float y)410     void addDrop(float x, float y) {
411         mDrop.dropX = (int) ((x / mWidth) * mMeshWidth);
412         mDrop.dropY = (int) ((y / mHeight) * mMeshHeight);
413         mDropState.data(mDrop);
414     }
415 }