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