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.app.WallpaperManager; 30 import android.content.res.Resources; 31 import android.graphics.Bitmap; 32 import android.graphics.BitmapFactory; 33 import android.graphics.Rect; 34 import android.os.Bundle; 35 import android.renderscript.*; 36 import android.renderscript.ProgramStore.BlendDstFunc; 37 import android.renderscript.ProgramStore.BlendSrcFunc; 38 import android.view.SurfaceHolder; 39 40 import java.util.TimeZone; 41 42 class NexusRS extends RenderScriptScene { 43 private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options(); 44 45 private ProgramVertexFixedFunction.Constants mPvOrthoAlloc; 46 47 private int mInitialWidth; 48 private int mInitialHeight; 49 private float mWorldScaleX; 50 private float mWorldScaleY; 51 private float mXOffset; 52 private ScriptC_nexus mScript; 53 54 public NexusRS(int width, int height) { 55 super(width, height); 56 57 mInitialWidth = width; 58 mInitialHeight = height; 59 mWorldScaleX = 1.0f; 60 mWorldScaleY = 1.0f; 61 62 mOptionsARGB.inScaled = false; 63 mOptionsARGB.inPreferredConfig = Bitmap.Config.ARGB_8888; 64 } 65 66 @Override 67 public void setOffset(float xOffset, float yOffset, int xPixels, int yPixels) { 68 mXOffset = xOffset; 69 mScript.set_gXOffset(xOffset); 70 } 71 72 @Override 73 public void start() { 74 super.start(); 75 } 76 77 @Override 78 public void resize(int width, int height) { 79 super.resize(width, height); // updates mWidth, mHeight 80 81 // android.util.Log.d("NexusRS", String.format("resize(%d, %d)", width, height)); 82 83 mWorldScaleX = (float)mInitialWidth / width; 84 mWorldScaleY = (float)mInitialHeight / height; 85 mScript.set_gWorldScaleX(mWorldScaleX); 86 mScript.set_gWorldScaleY(mWorldScaleY); 87 } 88 89 @Override 90 protected ScriptC createScript() { 91 mScript = new ScriptC_nexus(mRS, mResources, R.raw.nexus); 92 93 createProgramFragmentStore(); 94 createProgramFragment(); 95 createProgramVertex(); 96 createState(); 97 98 mScript.set_gTBackground(loadTexture(R.drawable.pyramid_background)); 99 mScript.set_gTPulse(loadTextureARGB(R.drawable.pulse)); 100 mScript.set_gTGlow(loadTextureARGB(R.drawable.glow)); 101 mScript.setTimeZone(TimeZone.getDefault().getID()); 102 mScript.invoke_initPulses(); 103 return mScript; 104 } 105 106 private void createState() { 107 int mode; 108 try { 109 mode = mResources.getInteger(R.integer.nexus_mode); 110 } catch (Resources.NotFoundException exc) { 111 mode = 0; // standard nexus mode 112 } 113 114 mScript.set_gIsPreview(isPreview() ? 1 : 0); 115 mScript.set_gMode(mode); 116 mScript.set_gXOffset(0.f); 117 mScript.set_gWorldScaleX(mWorldScaleX); 118 mScript.set_gWorldScaleY(mWorldScaleY); 119 } 120 121 private Allocation loadTexture(int id) { 122 return Allocation.createFromBitmapResource(mRS, mResources, id, 123 Allocation.MipmapControl.MIPMAP_NONE, 124 Allocation.USAGE_GRAPHICS_TEXTURE); 125 } 126 127 private Allocation loadTextureARGB(int id) { 128 Bitmap b = BitmapFactory.decodeResource(mResources, id, mOptionsARGB); 129 return Allocation.createFromBitmap(mRS, b, 130 Allocation.MipmapControl.MIPMAP_NONE, 131 Allocation.USAGE_GRAPHICS_TEXTURE); 132 } 133 134 135 private void createProgramFragment() { 136 // sampler and program fragment for pulses 137 ProgramFragmentFixedFunction.Builder builder = new ProgramFragmentFixedFunction.Builder(mRS); 138 builder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.MODULATE, 139 ProgramFragmentFixedFunction.Builder.Format.RGBA, 0); 140 ProgramFragment pft = builder.create(); 141 pft.bindSampler(Sampler.WRAP_LINEAR(mRS), 0); 142 mScript.set_gPFTexture(pft); 143 144 // sampler and program fragment for background image 145 builder = new ProgramFragmentFixedFunction.Builder(mRS); 146 builder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.MODULATE, 147 ProgramFragmentFixedFunction.Builder.Format.RGB, 0); 148 ProgramFragment pft565 = builder.create(); 149 pft565.bindSampler(Sampler.CLAMP_NEAREST(mRS), 0); 150 mScript.set_gPFTexture565(pft565); 151 } 152 153 private void createProgramFragmentStore() { 154 ProgramStore.Builder builder = new ProgramStore.Builder(mRS); 155 builder.setDepthFunc(ALWAYS); 156 builder.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ONE); 157 builder.setDitherEnabled(false); 158 ProgramStore solid = builder.create(); 159 mRS.bindProgramStore(solid); 160 161 builder.setBlendFunc(BlendSrcFunc.SRC_ALPHA, BlendDstFunc.ONE); 162 mScript.set_gPSBlend(builder.create()); 163 } 164 165 private void createProgramVertex() { 166 mPvOrthoAlloc = new ProgramVertexFixedFunction.Constants(mRS); 167 Matrix4f proj = new Matrix4f(); 168 proj.loadOrthoWindow(mWidth, mHeight); 169 mPvOrthoAlloc.setProjection(proj); 170 171 ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS); 172 pvb.setTextureMatrixEnable(true); 173 ProgramVertex pv = pvb.create(); 174 ((ProgramVertexFixedFunction)pv).bindConstants(mPvOrthoAlloc); 175 mRS.bindProgramVertex(pv); 176 } 177 178 @Override 179 public Bundle onCommand(String action, int x, int y, int z, Bundle extras, 180 boolean resultRequested) { 181 182 if (mWidth < mHeight) { 183 // nexus.rs ignores the xOffset when rotated; we shall endeavor to do so as well 184 x = (int) (x + mXOffset * mWidth / mWorldScaleX); 185 } 186 187 // android.util.Log.d("NexusRS", String.format( 188 // "dw=%d, bw=%d, xOffset=%g, x=%d", 189 // dw, bw, mWorldState.xOffset, x)); 190 191 if (WallpaperManager.COMMAND_TAP.equals(action) 192 || WallpaperManager.COMMAND_SECONDARY_TAP.equals(action) 193 || WallpaperManager.COMMAND_DROP.equals(action)) { 194 mScript.invoke_addTap(x, y); 195 } 196 return null; 197 } 198 } 199