Home | History | Annotate | Download | only in fall
      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 
     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
     99     public void setOffset(float xOffset, float yOffset, int xPixels, int yPixels) {
    100         mWorldState.xOffset = xOffset;
    101         mState.data(mWorldState);
    102     }
    103 
    104     @Override
    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
    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
    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
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 }