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 = 4; 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 NexusRS(int width, int height)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 setOffset(float xOffset, float yOffset, int xPixels, int yPixels)96 public void setOffset(float xOffset, float yOffset, int xPixels, int yPixels) { 97 mWorldState.xOffset = xOffset; 98 mState.data(mWorldState); 99 } 100 101 @Override start()102 public void start() { 103 super.start(); 104 } 105 106 @Override resize(int width, int height)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 createScript()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 createState()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 loadTextures()191 private void loadTextures() { 192 mTextures[0] = loadTextureARGB(R.drawable.pyramid_background, "TBackground"); 193 mTextures[1] = loadTextureARGB(R.drawable.pulse, "TPulse"); 194 mTextures[2] = loadTextureARGB(R.drawable.pulse_vert, "TPulseVert"); 195 mTextures[3] = loadTextureARGB(R.drawable.glow, "TGlow"); 196 197 final int count = mTextures.length; 198 for (int i = 0; i < count; i++) { 199 mTextures[i].uploadToTexture(0); 200 } 201 } 202 loadTexture(int id, String name)203 private Allocation loadTexture(int id, String name) { 204 final Allocation allocation = Allocation.createFromBitmapResource(mRS, mResources, 205 id, RGB_565(mRS), false); 206 allocation.setName(name); 207 return allocation; 208 } 209 loadTextureARGB(int id, String name)210 private Allocation loadTextureARGB(int id, String name) { 211 Bitmap b = BitmapFactory.decodeResource(mResources, id, mOptionsARGB); 212 final Allocation allocation = Allocation.createFromBitmap(mRS, b, RGBA_8888(mRS), false); 213 allocation.setName(name); 214 return allocation; 215 } 216 createProgramFragment()217 private void createProgramFragment() { 218 // sampler and program fragment for pulses 219 Sampler.Builder sampleBuilder = new Sampler.Builder(mRS); 220 sampleBuilder.setMin(LINEAR); 221 sampleBuilder.setMag(LINEAR); 222 sampleBuilder.setWrapS(CLAMP); 223 sampleBuilder.setWrapT(CLAMP); 224 mWrapSampler = sampleBuilder.create(); 225 ProgramFragment.Builder builder = new ProgramFragment.Builder(mRS); 226 builder.setTexture(ProgramFragment.Builder.EnvMode.MODULATE, 227 ProgramFragment.Builder.Format.RGBA, 0); 228 mPfTexture = builder.create(); 229 mPfTexture.setName("PFTexture"); 230 mPfTexture.bindSampler(mWrapSampler, 0); 231 232 builder = new ProgramFragment.Builder(mRS); 233 mPfColor = builder.create(); 234 mPfColor.setName("PFColor"); 235 mPfColor.bindSampler(mWrapSampler, 0); 236 237 // sampler and program fragment for background image 238 sampleBuilder.setWrapS(CLAMP); 239 sampleBuilder.setWrapT(CLAMP); 240 mClampSampler = sampleBuilder.create(); 241 builder = new ProgramFragment.Builder(mRS); 242 builder.setTexture(ProgramFragment.Builder.EnvMode.MODULATE, 243 ProgramFragment.Builder.Format.RGB, 0); 244 mPfTexture565 = builder.create(); 245 mPfTexture565.setName("PFTextureBG"); 246 mPfTexture565.bindSampler(mClampSampler, 0); 247 } 248 createProgramFragmentStore()249 private void createProgramFragmentStore() { 250 ProgramStore.Builder builder = new ProgramStore.Builder(mRS, null, null); 251 builder.setDepthFunc(ALWAYS); 252 builder.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ONE); 253 builder.setDitherEnable(false); 254 builder.setDepthMask(true); 255 mPsSolid = builder.create(); 256 mPsSolid.setName("PSSolid"); 257 258 builder = new ProgramStore.Builder(mRS, null, null); 259 builder.setDepthFunc(ALWAYS); 260 // builder.setBlendFunc(BlendSrcFunc.SRC_ALPHA, BlendDstFunc.ONE_MINUS_SRC_ALPHA); 261 builder.setBlendFunc(BlendSrcFunc.SRC_ALPHA, BlendDstFunc.ONE); 262 263 builder.setDitherEnable(false); 264 builder.setDepthMask(true); 265 mPsBlend = builder.create(); 266 mPsBlend.setName("PSBlend"); 267 } 268 createProgramVertex()269 private void createProgramVertex() { 270 mPvOrthoAlloc = new ProgramVertex.MatrixAllocation(mRS); 271 mPvOrthoAlloc.setupOrthoWindow(mWidth, mHeight); 272 273 ProgramVertex.Builder pvb = new ProgramVertex.Builder(mRS, null, null); 274 pvb.setTextureMatrixEnable(true); 275 mPvOrtho = pvb.create(); 276 mPvOrtho.bindAllocation(mPvOrthoAlloc); 277 mPvOrtho.setName("PVOrtho"); 278 } 279 280 @Override onCommand(String action, int x, int y, int z, Bundle extras, boolean resultRequested)281 public Bundle onCommand(String action, int x, int y, int z, Bundle extras, 282 boolean resultRequested) { 283 284 final int dw = mWorldState.width; 285 final int bw = 960; // XXX: hardcoded width of background texture 286 if (mWorldState.rotate == 0) { 287 // nexus.rs ignores the xOffset when rotated; we shall endeavor to do so as well 288 x = (int) (x + mWorldState.xOffset * (bw-dw)); 289 } 290 291 // android.util.Log.d("NexusRS", String.format( 292 // "dw=%d, bw=%d, xOffset=%g, x=%d", 293 // dw, bw, mWorldState.xOffset, x)); 294 295 if ("android.wallpaper.tap".equals(action)) { 296 sendCommand(1, x, y); 297 } else if ("android.home.drop".equals(action)) { 298 sendCommand(2, x, y); 299 } 300 return null; 301 } 302 sendCommand(int command, int x, int y)303 private void sendCommand(int command, int x, int y) { 304 mCommand.x = x; 305 mCommand.y = y; 306 mCommand.command = command; 307 mCommandAllocation.data(mCommand); 308 } 309 } 310