OSDN Git Service

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