• 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.ScriptC;
21 import android.renderscript.ProgramFragment;
22 import android.renderscript.ProgramStore;
23 import android.renderscript.ProgramVertex;
24 import android.renderscript.Allocation;
25 import android.renderscript.Sampler;
26 import android.renderscript.Light;
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.WRAP;
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.ProgramFragment.EnvMode.*;
36 import static android.renderscript.Element.*;
37 import android.graphics.BitmapFactory;
38 import android.graphics.Bitmap;
39 import static android.util.MathUtils.*;
40 
41 import java.util.TimeZone;
42 
43 import com.android.wallpaper.R;
44 import com.android.wallpaper.RenderScriptScene;
45 
46 class FallRS extends RenderScriptScene {
47     private static final int MESH_RESOLUTION = 48;
48 
49     private static final int RSID_STATE = 0;
50 
51     private static final int TEXTURES_COUNT = 2;
52     private static final int RSID_TEXTURE_RIVERBED = 0;
53     private static final int RSID_TEXTURE_LEAVES = 1;
54     private static final int RSID_TEXTURE_SKY = 2;
55 
56     private static final int RSID_RIPPLE_MAP = 1;
57     private static final int RSID_LEAVES = 3;
58     private static final int RSID_DROP = 4;
59 
60     private static final int LEAVES_COUNT = 14;
61 
62     private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options();
63 
64     @SuppressWarnings({"FieldCanBeLocal"})
65     private ProgramFragment mPfBackground;
66     @SuppressWarnings({"FieldCanBeLocal"})
67     private ProgramFragment mPfSky;
68     @SuppressWarnings({"FieldCanBeLocal"})
69     private ProgramStore mPfsBackground;
70     @SuppressWarnings({"FieldCanBeLocal"})
71     private ProgramStore mPfsLeaf;
72     @SuppressWarnings({"FieldCanBeLocal"})
73     private ProgramVertex mPvSky;
74     private ProgramVertex.MatrixAllocation mPvOrthoAlloc;
75     @SuppressWarnings({"FieldCanBeLocal"})
76     private Sampler mSampler;
77 
78     private Allocation mState;
79     private Allocation mDropState;
80     private DropState mDrop;
81     private Type mStateType;
82     private Type mDropType;
83     private int mMeshWidth;
84 
85     private int mMeshHeight;
86     @SuppressWarnings({"FieldCanBeLocal"})
87     private SimpleMesh mMesh;
88     private WorldState mWorldState;
89 
90     private Allocation mRippleMap;
91 
92     private Allocation mLeaves;
93     private Type mLeavesType;
94 
95     private float mGlHeight;
96 
FallRS(int width, int height)97     public FallRS(int width, int height) {
98         super(width, height);
99 
100         mOptionsARGB.inScaled = false;
101         mOptionsARGB.inPreferredConfig = Bitmap.Config.ARGB_8888;
102     }
103 
104     @Override
setOffset(float xOffset, float yOffset, int xPixels, int yPixels)105     public void setOffset(float xOffset, float yOffset, int xPixels, int yPixels) {
106         mWorldState.xOffset = xOffset;
107         mState.data(mWorldState);
108     }
109 
110     @Override
onCommand(String action, int x, int y, int z, Bundle extras, boolean resultRequested)111     public Bundle onCommand(String action, int x, int y, int z, Bundle extras,
112             boolean resultRequested) {
113         if ("android.wallpaper.tap".equals(action)) {
114             addDrop(x + (mWorldState.width * mWorldState.xOffset), y);
115         } else if ("android.home.drop".equals(action)) {
116             addDrop(x + (mWorldState.width * mWorldState.xOffset), y);
117         }
118         return null;
119     }
120 
121     @Override
start()122     public void start() {
123         super.start();
124         final WorldState worldState = mWorldState;
125         final int width = worldState.width;
126         final int x = width / 4 + (int)(Math.random() * (width / 2));
127         final int y = worldState.height / 4 + (int)(Math.random() * (worldState.height / 2));
128         addDrop(x + (width * worldState.xOffset), y);
129     }
130 
131     @Override
resize(int width, int height)132     public void resize(int width, int height) {
133         super.resize(width, height);
134 
135         mWorldState.width = width;
136         mWorldState.height = height;
137         mWorldState.rotate = width > height ? 1 : 0;
138         mState.data(mWorldState);
139 
140         mPvOrthoAlloc.setupProjectionNormalized(mWidth, mHeight);
141     }
142 
143     @Override
createScript()144     protected ScriptC createScript() {
145         createProgramVertex();
146         createProgramFragmentStore();
147         createProgramFragment();
148         createMesh();
149         createScriptStructures();
150         loadTextures();
151 
152         ScriptC.Builder sb = new ScriptC.Builder(mRS);
153         sb.setType(mStateType, "State", RSID_STATE);
154         sb.setType(mDropType, "Drop", RSID_DROP);
155         sb.setType(mLeavesType, "Leaves", RSID_LEAVES);
156         sb.setScript(mResources, R.raw.fall);
157         Script.Invokable invokable = sb.addInvokable("initLeaves");
158         sb.setRoot(true);
159 
160         ScriptC script = sb.create();
161         script.setClearColor(0.0f, 0.0f, 0.0f, 1.0f);
162         script.setTimeZone(TimeZone.getDefault().getID());
163 
164         script.bindAllocation(mState, RSID_STATE);
165         script.bindAllocation(mRippleMap, RSID_RIPPLE_MAP);
166         script.bindAllocation(mLeaves, RSID_LEAVES);
167         script.bindAllocation(mDropState, RSID_DROP);
168 
169         invokable.execute();
170 
171         return script;
172     }
173 
createMesh()174     private void createMesh() {
175         SimpleMesh.TriangleMeshBuilder tmb = new SimpleMesh.TriangleMeshBuilder(mRS, 3,
176                 SimpleMesh.TriangleMeshBuilder.TEXTURE_0);
177 
178         final int width = mWidth > mHeight ? mHeight : mWidth;
179         final int height = mWidth > mHeight ? mWidth : mHeight;
180 
181         int wResolution = MESH_RESOLUTION;
182         int hResolution = (int) (MESH_RESOLUTION * height / (float) width);
183 
184         mGlHeight = 2.0f * height / (float) width;
185         final float glHeight = mGlHeight;
186 
187         float quadWidth = 2.0f / (float) wResolution;
188         float quadHeight = glHeight / (float) hResolution;
189 
190         wResolution += 2;
191         hResolution += 2;
192 
193         for (int y = 0; y <= hResolution; y++) {
194             final float yOffset = y * quadHeight - glHeight / 2.0f - quadHeight;
195             final float t = 1.0f - y / (float) hResolution;
196             for (int x = 0; x <= wResolution; x++) {
197                 tmb.setTexture(x / (float) wResolution, t);
198                 tmb.addVertex(-1.0f + x * quadWidth - quadWidth, yOffset, 0.0f);
199             }
200         }
201 
202         for (int y = 0; y < hResolution; y++) {
203             final boolean shift = (y & 0x1) == 0;
204             final int yOffset = y * (wResolution + 1);
205             for (int x = 0; x < wResolution; x++) {
206                 final int index = yOffset + x;
207                 final int iWR1 = index + wResolution + 1;
208                 if (shift) {
209                     tmb.addTriangle(index, index + 1, iWR1);
210                     tmb.addTriangle(index + 1, iWR1 + 1, iWR1);
211                 } else {
212                     tmb.addTriangle(index, iWR1 + 1, iWR1);
213                     tmb.addTriangle(index, index + 1, iWR1 + 1);
214                 }
215             }
216         }
217 
218         mMesh = tmb.create();
219         mMesh.setName("WaterMesh");
220 
221         mMeshWidth = wResolution + 1;
222         mMeshHeight = hResolution + 1;
223     }
224 
createScriptStructures()225     private void createScriptStructures() {
226         final int rippleMapSize = (mMeshWidth + 2) * (mMeshHeight + 2);
227 
228         createState(rippleMapSize);
229         createRippleMap(rippleMapSize);
230         createLeaves();
231     }
232 
createLeaves()233     private void createLeaves() {
234         mLeavesType = Type.createFromClass(mRS, Leaf.class, LEAVES_COUNT, "Leaf");
235         mLeaves = Allocation.createTyped(mRS, mLeavesType);
236     }
237 
createRippleMap(int rippleMapSize)238     private void createRippleMap(int rippleMapSize) {
239         final int[] rippleMap = new int[rippleMapSize * 2];
240         mRippleMap = Allocation.createSized(mRS, USER_I32(mRS), rippleMap.length);
241         mRippleMap.data(rippleMap);
242     }
243 
244     static class WorldState {
245         public int frameCount;
246         public int width;
247         public int height;
248         public int meshWidth;
249         public int meshHeight;
250         public int rippleMapSize;
251         public int rippleIndex;
252         public int leavesCount;
253         public float glWidth;
254         public float glHeight;
255         public float skySpeedX;
256         public float skySpeedY;
257         public int rotate;
258         public int isPreview;
259         public float xOffset;
260     }
261 
262     static class DropState {
263         public int dropX;
264         public int dropY;
265     }
266 
createState(int rippleMapSize)267     private void createState(int rippleMapSize) {
268         mWorldState = new WorldState();
269         mWorldState.width = mWidth;
270         mWorldState.height = mHeight;
271         mWorldState.meshWidth = mMeshWidth;
272         mWorldState.meshHeight = mMeshHeight;
273         mWorldState.rippleMapSize = rippleMapSize;
274         mWorldState.rippleIndex = 0;
275         mWorldState.leavesCount = LEAVES_COUNT;
276         mWorldState.glWidth = 2.0f;
277         mWorldState.glHeight = mGlHeight;
278         mWorldState.skySpeedX = random(-0.001f, 0.001f);
279         mWorldState.skySpeedY = random(0.00008f, 0.0002f);
280         mWorldState.rotate = mWidth > mHeight ? 1 : 0;
281         mWorldState.isPreview = isPreview() ? 1 : 0;
282 
283         mStateType = Type.createFromClass(mRS, WorldState.class, 1, "WorldState");
284         mState = Allocation.createTyped(mRS, mStateType);
285         mState.data(mWorldState);
286 
287         mDrop = new DropState();
288         mDrop.dropX = -1;
289         mDrop.dropY = -1;
290 
291         mDropType = Type.createFromClass(mRS, DropState.class, 1, "DropState");
292         mDropState = Allocation.createTyped(mRS, mDropType);
293         mDropState.data(mDrop);
294     }
295 
296     static class Leaf {
297         public float x;
298         public float y;
299         public float scale;
300         public float angle;
301         public float spin;
302         public float u1;
303         public float u2;
304         public float altitude;
305         public float rippled;
306         public float deltaX;
307         public float deltaY;
308     }
309 
loadTextures()310     private void loadTextures() {
311         final Allocation[] textures = new Allocation[TEXTURES_COUNT];
312         textures[RSID_TEXTURE_RIVERBED] = loadTexture(R.drawable.pond, "TRiverbed");
313         textures[RSID_TEXTURE_LEAVES] = loadTextureARGB(R.drawable.leaves, "TLeaves");
314         // textures[RSID_TEXTURE_SKY] = loadTextureARGB(R.drawable.clouds, "TSky");
315 
316         final int count = textures.length;
317         for (int i = 0; i < count; i++) {
318             textures[i].uploadToTexture(0);
319         }
320     }
321 
loadTexture(int id, String name)322     private Allocation loadTexture(int id, String name) {
323         final Allocation allocation = Allocation.createFromBitmapResource(mRS, mResources,
324                 id, RGB_565(mRS), false);
325         allocation.setName(name);
326         return allocation;
327     }
328 
loadTextureARGB(int id, String name)329     private Allocation loadTextureARGB(int id, String name) {
330         Bitmap b = BitmapFactory.decodeResource(mResources, id, mOptionsARGB);
331         final Allocation allocation = Allocation.createFromBitmap(mRS, b, RGBA_8888(mRS), false);
332         allocation.setName(name);
333         return allocation;
334     }
335 
createProgramFragment()336     private void createProgramFragment() {
337         Sampler.Builder sampleBuilder = new Sampler.Builder(mRS);
338         sampleBuilder.setMin(LINEAR);
339         sampleBuilder.setMag(LINEAR);
340         sampleBuilder.setWrapS(WRAP);
341         sampleBuilder.setWrapT(WRAP);
342         mSampler = sampleBuilder.create();
343 
344         ProgramFragment.Builder builder = new ProgramFragment.Builder(mRS, null, null);
345         builder.setTexEnable(true, 0);
346         builder.setTexEnvMode(REPLACE, 0);
347         mPfBackground = builder.create();
348         mPfBackground.setName("PFBackground");
349         mPfBackground.bindSampler(mSampler, 0);
350 
351         builder = new ProgramFragment.Builder(mRS, null, null);
352         builder.setTexEnable(true, 0);
353         builder.setTexEnvMode(MODULATE, 0);
354         mPfSky = builder.create();
355         mPfSky.setName("PFSky");
356         mPfSky.bindSampler(mSampler, 0);
357     }
358 
createProgramFragmentStore()359     private void createProgramFragmentStore() {
360         ProgramStore.Builder builder = new ProgramStore.Builder(mRS, null, null);
361         builder.setDepthFunc(ALWAYS);
362         builder.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ONE);
363         builder.setDitherEnable(false);
364         builder.setDepthMask(true);
365         mPfsBackground = builder.create();
366         mPfsBackground.setName("PFSBackground");
367 
368         builder = new ProgramStore.Builder(mRS, null, null);
369         builder.setDepthFunc(ALWAYS);
370         builder.setBlendFunc(BlendSrcFunc.SRC_ALPHA, BlendDstFunc.ONE_MINUS_SRC_ALPHA);
371         builder.setDitherEnable(false);
372         builder.setDepthMask(true);
373         mPfsLeaf = builder.create();
374         mPfsLeaf.setName("PFSLeaf");
375     }
376 
createProgramVertex()377     private void createProgramVertex() {
378         mPvOrthoAlloc = new ProgramVertex.MatrixAllocation(mRS);
379         mPvOrthoAlloc.setupProjectionNormalized(mWidth, mHeight);
380 
381         ProgramVertex.Builder builder = new ProgramVertex.Builder(mRS, null, null);
382         builder.setTextureMatrixEnable(true);
383         mPvSky = builder.create();
384         mPvSky.bindAllocation(mPvOrthoAlloc);
385         mPvSky.setName("PVSky");
386     }
387 
addDrop(float x, float y)388     void addDrop(float x, float y) {
389         if (mWorldState.rotate == 0) {
390             mDrop.dropX = (int) ((x / mWidth) * mMeshWidth);
391             mDrop.dropY = (int) ((y / mHeight) * mMeshHeight);
392         } else {
393             mDrop.dropY = (int) ((x / mWidth) * mMeshHeight);
394             mDrop.dropX = mMeshWidth - (int) ((y / mHeight) * mMeshWidth);
395         }
396         mDropState.data(mDrop);
397     }
398 }