Home | History | Annotate | Download | only in nexus
      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.nexus;
     18 
     19 import static android.renderscript.Element.RGBA_8888;
     20 import static android.renderscript.Element.RGB_565;
     21 import static android.renderscript.ProgramStore.DepthFunc.ALWAYS;
     22 import static android.renderscript.Sampler.Value.LINEAR;
     23 import static android.renderscript.Sampler.Value.CLAMP;
     24 import static android.renderscript.Sampler.Value.WRAP;
     25 
     26 import com.android.wallpaper.R;
     27 import com.android.wallpaper.RenderScriptScene;
     28 
     29 import android.content.res.Resources;
     30 import android.graphics.Bitmap;
     31 import android.graphics.BitmapFactory;
     32 import android.graphics.Rect;
     33 import android.os.Bundle;
     34 import android.renderscript.Allocation;
     35 import android.renderscript.ProgramFragment;
     36 import android.renderscript.ProgramStore;
     37 import android.renderscript.ProgramVertex;
     38 import android.renderscript.Sampler;
     39 import android.renderscript.Script;
     40 import android.renderscript.ScriptC;
     41 import android.renderscript.Type;
     42 import android.renderscript.ProgramStore.BlendDstFunc;
     43 import android.renderscript.ProgramStore.BlendSrcFunc;
     44 import android.view.SurfaceHolder;
     45 
     46 import java.util.TimeZone;
     47 
     48 class NexusRS extends RenderScriptScene {
     49 
     50     private static final int RSID_STATE = 0;
     51 
     52     private static final int RSID_COMMAND = 1;
     53 
     54     private static final int TEXTURES_COUNT = 3;
     55 
     56     private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options();
     57 
     58     private ProgramFragment mPfTexture;
     59     private ProgramFragment mPfTexture565;
     60 
     61     private ProgramFragment mPfColor;
     62 
     63     private ProgramStore mPsSolid;
     64 
     65     private ProgramStore mPsBlend;
     66 
     67     private ProgramVertex mPvOrtho;
     68 
     69     private ProgramVertex.MatrixAllocation mPvOrthoAlloc;
     70 
     71     private Sampler mClampSampler;
     72     private Sampler mWrapSampler;
     73 
     74     private Allocation mState;
     75 
     76     private Type mStateType;
     77 
     78     private WorldState mWorldState;
     79 
     80     private Allocation mCommandAllocation;
     81 
     82     private Type mCommandType;
     83 
     84     private CommandState mCommand;
     85 
     86     private Allocation[] mTextures = new Allocation[TEXTURES_COUNT];
     87 
     88     public NexusRS(int width, int height) {
     89         super(width, height);
     90 
     91         mOptionsARGB.inScaled = false;
     92         mOptionsARGB.inPreferredConfig = Bitmap.Config.ARGB_8888;
     93     }
     94 
     95     @Override
     96     public void setOffset(float xOffset, float yOffset, int xPixels, int yPixels) {
     97         mWorldState.xOffset = xOffset;
     98         mState.data(mWorldState);
     99     }
    100 
    101     @Override
    102     public void start() {
    103         super.start();
    104     }
    105 
    106     @Override
    107     public void resize(int width, int height) {
    108         super.resize(width, height); // updates mWidth, mHeight
    109 
    110         // android.util.Log.d("NexusRS", String.format("resize(%d, %d)", width, height));
    111 
    112         mWorldState.width = width;
    113         mWorldState.height = height;
    114         mWorldState.rotate = width > height ? 1 : 0;
    115         mState.data(mWorldState);
    116 
    117         mPvOrthoAlloc.setupOrthoWindow(mWidth, mHeight);
    118     }
    119 
    120     @Override
    121     protected ScriptC createScript() {
    122         createProgramVertex();
    123         createProgramFragmentStore();
    124         createProgramFragment();
    125         createState();
    126         loadTextures();
    127 
    128         ScriptC.Builder sb = new ScriptC.Builder(mRS);
    129         sb.setType(mStateType, "State", RSID_STATE);
    130         sb.setType(mCommandType, "Command", RSID_COMMAND);
    131         sb.setScript(mResources, R.raw.nexus);
    132         Script.Invokable invokable = sb.addInvokable("initPulses");
    133         sb.setRoot(true);
    134 
    135         ScriptC script = sb.create();
    136         script.setClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    137         script.setTimeZone(TimeZone.getDefault().getID());
    138 
    139         script.bindAllocation(mState, RSID_STATE);
    140         script.bindAllocation(mCommandAllocation, RSID_COMMAND);
    141 
    142         invokable.execute();
    143 
    144         return script;
    145     }
    146 
    147     static class WorldState {
    148         public int width;
    149         public int height;
    150         public float glWidth;
    151         public float glHeight;
    152         public int rotate;
    153         public int isPreview;
    154         public float xOffset;
    155         public int mode;
    156     }
    157 
    158     static class CommandState {
    159         public int x;
    160         public int y;
    161         public int command;
    162     }
    163 
    164     private void createState() {
    165         mWorldState = new WorldState();
    166         mWorldState.width = mWidth;
    167         mWorldState.height = mHeight;
    168         mWorldState.rotate = mWidth > mHeight ? 1 : 0;
    169         mWorldState.isPreview = isPreview() ? 1 : 0;
    170 
    171         try {
    172             mWorldState.mode = mResources.getInteger(R.integer.nexus_mode);
    173         } catch (Resources.NotFoundException exc) {
    174             mWorldState.mode = 0; // standard nexus mode
    175         }
    176 
    177         mStateType = Type.createFromClass(mRS, WorldState.class, 1, "WorldState");
    178         mState = Allocation.createTyped(mRS, mStateType);
    179         mState.data(mWorldState);
    180 
    181         mCommand = new CommandState();
    182         mCommand.x = -1;
    183         mCommand.y = -1;
    184         mCommand.command = 0;
    185 
    186         mCommandType = Type.createFromClass(mRS, CommandState.class, 1, "DropState");
    187         mCommandAllocation = Allocation.createTyped(mRS, mCommandType);
    188         mCommandAllocation.data(mCommand);
    189     }
    190 
    191     private void loadTextures() {
    192         mTextures[0] = loadTexture(R.drawable.pyramid_background, "TBackground");
    193         mTextures[1] = loadTextureARGB(R.drawable.pulse, "TPulse");
    194         mTextures[2] = loadTextureARGB(R.drawable.glow, "TGlow");
    195 
    196         final int count = mTextures.length;
    197         for (int i = 0; i < count; i++) {
    198             mTextures[i].uploadToTexture(0);
    199         }
    200     }
    201 
    202     private Allocation loadTexture(int id, String name) {
    203         final Allocation allocation = Allocation.createFromBitmapResource(mRS, mResources,
    204                 id, RGB_565(mRS), false);
    205         allocation.setName(name);
    206         return allocation;
    207     }
    208 
    209     private Allocation loadTextureARGB(int id, String name) {
    210         Bitmap b = BitmapFactory.decodeResource(mResources, id, mOptionsARGB);
    211         final Allocation allocation = Allocation.createFromBitmap(mRS, b, RGBA_8888(mRS), false);
    212         allocation.setName(name);
    213         return allocation;
    214     }
    215 
    216     private void createProgramFragment() {
    217         // sampler and program fragment for pulses
    218         Sampler.Builder sampleBuilder = new Sampler.Builder(mRS);
    219         sampleBuilder.setMin(LINEAR);
    220         sampleBuilder.setMag(LINEAR);
    221         sampleBuilder.setWrapS(WRAP);
    222         sampleBuilder.setWrapT(WRAP);
    223         mWrapSampler = sampleBuilder.create();
    224         ProgramFragment.Builder builder = new ProgramFragment.Builder(mRS);
    225         builder.setTexture(ProgramFragment.Builder.EnvMode.MODULATE,
    226                            ProgramFragment.Builder.Format.RGBA, 0);
    227         mPfTexture = builder.create();
    228         mPfTexture.setName("PFTexture");
    229         mPfTexture.bindSampler(mWrapSampler, 0);
    230 
    231         builder = new ProgramFragment.Builder(mRS);
    232         builder.setTexture(ProgramFragment.Builder.EnvMode.REPLACE,
    233                            ProgramFragment.Builder.Format.RGB, 0);
    234         mPfColor = builder.create();
    235         mPfColor.setName("PFColor");
    236         mPfColor.bindSampler(mWrapSampler, 0);
    237 
    238         // sampler and program fragment for background image
    239         sampleBuilder.setWrapS(CLAMP);
    240         sampleBuilder.setWrapT(CLAMP);
    241         mClampSampler = sampleBuilder.create();
    242         builder = new ProgramFragment.Builder(mRS);
    243         builder.setTexture(ProgramFragment.Builder.EnvMode.MODULATE,
    244                            ProgramFragment.Builder.Format.RGB, 0);
    245         mPfTexture565 = builder.create();
    246         mPfTexture565.setName("PFTexture565");
    247         mPfTexture565.bindSampler(mClampSampler, 0);
    248     }
    249 
    250     private void createProgramFragmentStore() {
    251         ProgramStore.Builder builder = new ProgramStore.Builder(mRS, null, null);
    252         builder.setDepthFunc(ALWAYS);
    253         builder.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ONE);
    254         builder.setDitherEnable(false);
    255         builder.setDepthMask(true);
    256         mPsSolid = builder.create();
    257         mPsSolid.setName("PSSolid");
    258 
    259         builder = new ProgramStore.Builder(mRS, null, null);
    260         builder.setDepthFunc(ALWAYS);
    261        //  builder.setBlendFunc(BlendSrcFunc.SRC_ALPHA, BlendDstFunc.ONE_MINUS_SRC_ALPHA);
    262         builder.setBlendFunc(BlendSrcFunc.SRC_ALPHA, BlendDstFunc.ONE);
    263 
    264         builder.setDitherEnable(false);
    265         builder.setDepthMask(true);
    266         mPsBlend = builder.create();
    267         mPsBlend.setName("PSBlend");
    268     }
    269 
    270     private void createProgramVertex() {
    271         mPvOrthoAlloc = new ProgramVertex.MatrixAllocation(mRS);
    272         mPvOrthoAlloc.setupOrthoWindow(mWidth, mHeight);
    273 
    274         ProgramVertex.Builder pvb = new ProgramVertex.Builder(mRS, null, null);
    275         pvb.setTextureMatrixEnable(true);
    276         mPvOrtho = pvb.create();
    277         mPvOrtho.bindAllocation(mPvOrthoAlloc);
    278         mPvOrtho.setName("PVOrtho");
    279     }
    280 
    281     @Override
    282     public Bundle onCommand(String action, int x, int y, int z, Bundle extras,
    283             boolean resultRequested) {
    284 
    285         final int dw = mWorldState.width;
    286         final int bw = 960; // XXX: hardcoded width of background texture
    287         if (mWorldState.rotate == 0) {
    288             // nexus.rs ignores the xOffset when rotated; we shall endeavor to do so as well
    289             x = (int) (x + mWorldState.xOffset * (bw-dw));
    290         }
    291 
    292         // android.util.Log.d("NexusRS", String.format(
    293         //     "dw=%d, bw=%d, xOffset=%g, x=%d",
    294         //     dw, bw, mWorldState.xOffset, x));
    295 
    296         if ("android.wallpaper.tap".equals(action)) {
    297             sendCommand(1, x, y);
    298         } else if ("android.home.drop".equals(action)) {
    299             sendCommand(2, x, y);
    300         }
    301         return null;
    302     }
    303 
    304     private void sendCommand(int command, int x, int y) {
    305         mCommand.x = x;
    306         mCommand.y = y;
    307         mCommand.command = command;
    308         mCommandAllocation.data(mCommand);
    309     }
    310 }
    311