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