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.magicsmoke; 18 19 import static android.renderscript.Sampler.Value.LINEAR; 20 import static android.renderscript.Sampler.Value.WRAP; 21 22 import com.android.magicsmoke.R; 23 24 import android.content.Context; 25 import android.content.SharedPreferences; 26 import android.content.SharedPreferences.Editor; 27 import android.content.SharedPreferences.OnSharedPreferenceChangeListener; 28 import android.graphics.Bitmap; 29 import android.graphics.BitmapFactory; 30 import android.media.MediaPlayer; 31 import android.os.Handler; 32 import android.renderscript.*; 33 import android.renderscript.Element.Builder; 34 import android.renderscript.ProgramStore.BlendDstFunc; 35 import android.renderscript.ProgramStore.BlendSrcFunc; 36 import android.util.Log; 37 import android.view.MotionEvent; 38 import android.os.Bundle; 39 40 import java.util.TimeZone; 41 42 class MagicSmokeRS extends RenderScriptScene implements OnSharedPreferenceChangeListener { 43 44 static class WorldState { 45 public float mXOffset; 46 public float mYOffset; 47 public int mPreset; 48 public int mTextureMask; 49 public int mRotate; 50 public int mTextureSwap; 51 public int mProcessTextureMode; 52 public int mBackCol; 53 public int mLowCol; 54 public int mHighCol; 55 public float mAlphaMul; 56 public int mPreMul; 57 } 58 WorldState mWorldState = new WorldState(); 59 //private Type mStateType; 60 //private Allocation mState; 61 62 private ProgramStore mPStore; 63 private ProgramFragment mPF5tex; 64 private ProgramFragment mPF4tex; 65 private Sampler[] mSampler; 66 private Allocation[] mSourceTextures; 67 private Allocation[] mRealTextures; 68 69 private ScriptC_clouds mScript; 70 71 private ScriptField_VertexShaderConstants_s mVSConst; 72 private ScriptField_FragmentShaderConstants_s mFSConst; 73 74 private ProgramVertex mPV5tex; 75 private ProgramVertex mPV4tex; 76 private ProgramVertexFixedFunction.Constants mPVAlloc; 77 78 private static final int RSID_STATE = 0; 79 //private static final int RSID_PROGRAMVERTEX = 3; 80 private static final int RSID_NOISESRC1 = 1; 81 private static final int RSID_NOISESRC2 = 2; 82 private static final int RSID_NOISESRC3 = 3; 83 private static final int RSID_NOISESRC4 = 4; 84 private static final int RSID_NOISESRC5 = 5; 85 private static final int RSID_NOISEDST1 = 6; 86 private static final int RSID_NOISEDST2 = 7; 87 private static final int RSID_NOISEDST3 = 8; 88 private static final int RSID_NOISEDST4 = 9; 89 private static final int RSID_NOISEDST5 = 10; 90 91 private Context mContext; 92 private SharedPreferences mSharedPref; 93 94 static class Preset { 95 Preset(int processmode, int backcol, int locol, int hicol, float mul, int mask, 96 boolean rot, boolean texswap, boolean premul) { 97 mProcessTextureMode = processmode; 98 mBackColor = backcol; 99 mLowColor = locol; 100 mHighColor = hicol; 101 mAlphaMul = mul; 102 mTextureMask = mask; 103 mRotate = rot; 104 mTextureSwap = texswap; 105 mPreMul = premul; 106 } 107 public int mProcessTextureMode; 108 public int mBackColor; 109 public int mLowColor; 110 public int mHighColor; 111 public float mAlphaMul; 112 public int mTextureMask; 113 public boolean mRotate; 114 public boolean mTextureSwap; 115 public boolean mPreMul; 116 } 117 118 public static final int DEFAULT_PRESET = 16; 119 public static final Preset [] mPreset = new Preset[] { 120 // proc back low high alph mask rot swap premul 121 new Preset(1, 0x000000, 0x000000, 0xffffff, 2.0f, 0x0f, true, false, false), 122 new Preset(1, 0x0000ff, 0x000000, 0xffffff, 2.0f, 0x0f, true, false, false), 123 new Preset(1, 0x00ff00, 0x000000, 0xffffff, 2.0f, 0x0f, true, false, false), 124 new Preset(1, 0x00ff00, 0x000000, 0xffffff, 2.0f, 0x0f, true, false, true), 125 new Preset(1, 0x00ff00, 0x00ff00, 0xffffff, 2.5f, 0x1f, true, true, true), 126 new Preset(1, 0x800000, 0xff0000, 0xffffff, 2.5f, 0x1f, true, true, false), 127 new Preset(0, 0x000000, 0x000000, 0xffffff, 0.0f, 0x1f, true, false, false), 128 new Preset(1, 0x0000ff, 0x00ff00, 0xffff00, 2.0f, 0x1f, true, true, false), 129 new Preset(1, 0x008000, 0x00ff00, 0xffffff, 2.5f, 0x1f, true, true, false), 130 new Preset(1, 0x800000, 0xff0000, 0xffffff, 2.5f, 0x1f, true, true, true), 131 new Preset(1, 0x808080, 0x000000, 0xffffff, 2.0f, 0x0f, true, false, true), 132 new Preset(1, 0x0000ff, 0x000000, 0xffffff, 2.0f, 0x0f, true, false, true), 133 new Preset(1, 0x0000ff, 0x00ff00, 0xffff00, 1.5f, 0x1f, false, false, true), 134 new Preset(1, 0x0000ff, 0x00ff00, 0xffff00, 2.0f, 0x1f, true, true, true), 135 new Preset(1, 0x0000ff, 0x00ff00, 0xffff00, 1.5f, 0x1f, true, true, true), 136 new Preset(1, 0x808080, 0x000000, 0xffffff, 2.0f, 0x0f, true, false, false), 137 new Preset(1, 0x000000, 0x000000, 0xffffff, 2.0f, 0x0f, true, true, false), 138 new Preset(2, 0x000000, 0x000070, 0xff2020, 2.5f, 0x1f, true, false, false), 139 new Preset(2, 0x6060ff, 0x000070, 0xffffff, 2.5f, 0x1f, true, false, false), 140 new Preset(3, 0x0000f0, 0x000000, 0xffffff, 2.0f, 0x0f, true, true, false), 141 }; 142 143 private float mTouchY; 144 145 MagicSmokeRS(Context context, int width, int height) { 146 super(width, height); 147 mWidth = width; 148 mHeight = height; 149 mContext = context; 150 mSharedPref = mContext.getSharedPreferences("magicsmoke", Context.MODE_PRIVATE); 151 mSharedPref.registerOnSharedPreferenceChangeListener(this); 152 makeNewState(); 153 } 154 155 public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { 156 157 if (!mIsStarted) { 158 start(); 159 mRS.finish(); 160 stop(false); 161 } else { 162 makeNewState(); 163 } 164 } 165 166 void makeNewState() { 167 int p = mSharedPref.getInt("preset", DEFAULT_PRESET); 168 if (p >= mPreset.length) { 169 p = 0; 170 } 171 mWorldState.mPreset = p; 172 mWorldState.mTextureMask = mPreset[p].mTextureMask; 173 mWorldState.mRotate = mPreset[p].mRotate ? 1 : 0; 174 mWorldState.mTextureSwap = mPreset[p].mTextureSwap ? 1 : 0; 175 mWorldState.mProcessTextureMode = mPreset[p].mProcessTextureMode; 176 mWorldState.mBackCol = mPreset[p].mBackColor; 177 mWorldState.mLowCol = mPreset[p].mLowColor; 178 mWorldState.mHighCol = mPreset[p].mHighColor; 179 mWorldState.mAlphaMul = mPreset[p].mAlphaMul; 180 mWorldState.mPreMul = mPreset[p].mPreMul ? 1 : 0; 181 182 if(mScript != null) { 183 mScript.set_gPreset(mWorldState.mPreset); 184 mScript.set_gTextureMask(mWorldState.mTextureMask); 185 mScript.set_gRotate(mWorldState.mRotate); 186 mScript.set_gTextureSwap(mWorldState.mTextureSwap); 187 mScript.set_gProcessTextureMode(mWorldState.mProcessTextureMode); 188 mScript.set_gBackCol(mWorldState.mBackCol); 189 mScript.set_gLowCol(mWorldState.mLowCol); 190 mScript.set_gHighCol(mWorldState.mHighCol); 191 mScript.set_gAlphaMul(mWorldState.mAlphaMul); 192 mScript.set_gPreMul(mWorldState.mPreMul); 193 } 194 } 195 196 @Override 197 public void resize(int width, int height) { 198 super.resize(width, height); 199 if (mPVAlloc != null) { 200 Matrix4f proj = new Matrix4f(); 201 proj.loadProjectionNormalized(width, height); 202 mPVAlloc.setProjection(proj); 203 } 204 } 205 206 @Override 207 public Bundle onCommand(String action, int x, int y, int z, Bundle extras, 208 boolean resultRequested) { 209 210 if ("android.wallpaper.tap".equals(action)) { 211 mTouchY = y; 212 } 213 return null; 214 } 215 216 /*@Override 217 public void onTouchEvent(MotionEvent event) { 218 switch(event.getAction()) { 219 case MotionEvent.ACTION_DOWN: 220 mTouchY = event.getY(); 221 break; 222 case MotionEvent.ACTION_MOVE: 223 float dy = event.getY() - mTouchY; 224 mTouchY += dy; 225 dy /= 20; 226 if (dy > 4) { 227 dy = 4; 228 } else if (dy < -4) { 229 dy = -4; 230 } 231 //mState.data(mWorldState); 232 } 233 }*/ 234 235 @Override 236 public void setOffset(float xOffset, float yOffset, float xStep, float yStep, int xPixels, int yPixels) { 237 // update our state, then push it to the renderscript 238 mWorldState.mXOffset = xOffset; 239 mWorldState.mYOffset = yOffset; 240 mScript.set_gXOffset(mWorldState.mXOffset); 241 mScript.set_gYOffset(mWorldState.mYOffset); 242 } 243 244 @Override 245 public void stop(boolean forReal) { 246 if (forReal) { 247 mSharedPref.unregisterOnSharedPreferenceChangeListener(this); 248 } 249 super.stop(forReal); 250 } 251 252 @Override 253 public void start() { 254 makeNewState(); 255 super.start(); 256 } 257 258 float alphafactor; 259 Type mTextureType; 260 261 void loadBitmap(int id, int index, String name, float alphamul, int lowcol, int highcol) { 262 BitmapFactory.Options opts = new BitmapFactory.Options(); 263 opts.inPreferredConfig = Bitmap.Config.ARGB_8888; 264 Bitmap in = BitmapFactory.decodeResource(mResources, id, opts); 265 266 // Bitmaps are stored in memory in premultiplied form. We want non-premultiplied, 267 // which is what getPixels gives us. 268 int pixels[] = new int[65536]; 269 in.getPixels(pixels, 0, 256, 0, 0, 256, 256); 270 mRealTextures[index] = Allocation.createTyped(mRS, mTextureType, 271 Allocation.MipmapControl.MIPMAP_NONE, 272 Allocation.USAGE_SCRIPT | 273 Allocation.USAGE_GRAPHICS_TEXTURE); 274 mSourceTextures[index] = Allocation.createTyped(mRS, mTextureType, 275 Allocation.MipmapControl.MIPMAP_NONE, 276 Allocation.USAGE_SCRIPT); 277 278 // copyFrom needs a byte[], not an int[], so we need to copy the data first 279 byte bpixels[] = new byte[65536*4]; 280 for (int i = 0; i < 65536; i++) { 281 bpixels[i * 4 + 0] = (byte)(pixels[i] & 0xff); 282 bpixels[i * 4 + 1] = (byte)((pixels[i] >> 8) & 0xff); 283 bpixels[i * 4 + 2] = (byte)((pixels[i] >>16) & 0xff); 284 bpixels[i * 4 + 3] = (byte)((pixels[i] >> 24) & 0xff); 285 } 286 mSourceTextures[index].copyFrom(bpixels); 287 in.recycle(); 288 } 289 290 void loadBitmaps() { 291 alphafactor = 1f; 292 float alphamul = mPreset[mWorldState.mPreset].mAlphaMul; 293 int lowcol = mPreset[mWorldState.mPreset].mLowColor; 294 int highcol = mPreset[mWorldState.mPreset].mHighColor; 295 //Log.i("@@@@", "preset " + mWorldState.mPreset + ", mul: " + alphamul + 296 // ", colors: " + Integer.toHexString(lowcol) + "/" + Integer.toHexString(highcol)); 297 298 // TODO: using different high and low colors for each layer offers some cool effects too 299 loadBitmap(R.drawable.noise1, 0, "Tnoise1", alphamul, lowcol, highcol); 300 loadBitmap(R.drawable.noise2, 1, "Tnoise2", alphamul, lowcol, highcol); 301 loadBitmap(R.drawable.noise3, 2, "Tnoise3", alphamul, lowcol, highcol); 302 loadBitmap(R.drawable.noise4, 3, "Tnoise4", alphamul, lowcol, highcol); 303 loadBitmap(R.drawable.noise5, 4, "Tnoise5", alphamul, lowcol, highcol); 304 305 mScript.set_gTnoise1(mRealTextures[0]); 306 mScript.set_gTnoise2(mRealTextures[1]); 307 mScript.set_gTnoise3(mRealTextures[2]); 308 mScript.set_gTnoise4(mRealTextures[3]); 309 mScript.set_gTnoise5(mRealTextures[4]); 310 311 mScript.bind_gNoisesrc1(mSourceTextures[0]); 312 mScript.bind_gNoisesrc2(mSourceTextures[1]); 313 mScript.bind_gNoisesrc3(mSourceTextures[2]); 314 mScript.bind_gNoisesrc4(mSourceTextures[3]); 315 mScript.bind_gNoisesrc5(mSourceTextures[4]); 316 317 mScript.bind_gNoisedst1(mRealTextures[0]); 318 mScript.bind_gNoisedst2(mRealTextures[1]); 319 mScript.bind_gNoisedst3(mRealTextures[2]); 320 mScript.bind_gNoisedst4(mRealTextures[3]); 321 mScript.bind_gNoisedst5(mRealTextures[4]); 322 } 323 324 @Override 325 protected ScriptC createScript() { 326 327 mScript = new ScriptC_clouds(mRS, mResources, R.raw.clouds); 328 329 mVSConst = new ScriptField_VertexShaderConstants_s(mRS, 1); 330 mScript.bind_gVSConstants(mVSConst); 331 332 { 333 ProgramVertex.Builder builder = new ProgramVertex.Builder(mRS); 334 builder.setShader(mResources, R.raw.pv5tex); 335 builder.addConstant(mVSConst.getAllocation().getType()); 336 builder.addInput(ScriptField_VertexInputs_s.createElement(mRS)); 337 338 mPV5tex = builder.create(); 339 mPV5tex.bindConstants(mVSConst.getAllocation(), 0); 340 341 builder.setShader(mResources, R.raw.pv4tex); 342 mPV4tex = builder.create(); 343 mPV4tex.bindConstants(mVSConst.getAllocation(), 0); 344 } 345 mScript.set_gPV5tex(mPV5tex); 346 mScript.set_gPV4tex(mPV4tex); 347 348 mSourceTextures = new Allocation[5]; 349 mRealTextures = new Allocation[5]; 350 351 Type.Builder tb = new Type.Builder(mRS, Element.RGBA_8888(mRS)); 352 tb.setX(256); 353 tb.setY(256); 354 mTextureType = tb.create(); 355 loadBitmaps(); 356 357 Sampler.Builder samplerBuilder = new Sampler.Builder(mRS); 358 samplerBuilder.setMinification(LINEAR); 359 samplerBuilder.setMagnification(LINEAR); 360 samplerBuilder.setWrapS(WRAP); 361 samplerBuilder.setWrapT(WRAP); 362 mSampler = new Sampler[5]; 363 for (int i = 0; i < 5; i++) 364 mSampler[i] = samplerBuilder.create(); 365 366 { 367 mFSConst = new ScriptField_FragmentShaderConstants_s(mRS, 1); 368 mScript.bind_gFSConstants(mFSConst); 369 370 ProgramFragment.Builder builder = new ProgramFragment.Builder(mRS); 371 builder.setShader(mResources, R.raw.pf5tex); 372 for (int texCount = 0; texCount < 5; texCount ++) { 373 builder.addTexture(Program.TextureType.TEXTURE_2D); 374 } 375 builder.addConstant(mFSConst.getAllocation().getType()); 376 377 mPF5tex = builder.create(); 378 for (int i = 0; i < 5; i++) 379 mPF5tex.bindSampler(mSampler[i], i); 380 mPF5tex.bindConstants(mFSConst.getAllocation(), 0); 381 382 builder = new ProgramFragment.Builder(mRS); 383 builder.setShader(mResources, R.raw.pf4tex); 384 for (int texCount = 0; texCount < 4; texCount ++) { 385 builder.addTexture(Program.TextureType.TEXTURE_2D); 386 } 387 builder.addConstant(mFSConst.getAllocation().getType()); 388 mPF4tex = builder.create(); 389 for (int i = 0; i < 4; i++) 390 mPF4tex.bindSampler(mSampler[i], i); 391 mPF4tex.bindConstants(mFSConst.getAllocation(), 0); 392 } 393 394 mScript.set_gPF5tex(mPF5tex); 395 mScript.set_gPF4tex(mPF4tex); 396 397 398 { 399 ProgramStore.Builder builder = new ProgramStore.Builder(mRS); 400 builder.setDepthFunc(ProgramStore.DepthFunc.ALWAYS); 401 builder.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ZERO); 402 builder.setDitherEnabled(true); // without dithering there is severe banding 403 builder.setDepthMaskEnabled(false); 404 mPStore = builder.create(); 405 } 406 407 mScript.set_gPStore(mPStore); 408 409 mScript.set_gPreset(mWorldState.mPreset); 410 mScript.set_gTextureMask(mWorldState.mTextureMask); 411 mScript.set_gRotate(mWorldState.mRotate); 412 mScript.set_gTextureSwap(mWorldState.mTextureSwap); 413 mScript.set_gProcessTextureMode(mWorldState.mProcessTextureMode); 414 mScript.set_gBackCol(mWorldState.mBackCol); 415 mScript.set_gLowCol(mWorldState.mLowCol); 416 mScript.set_gHighCol(mWorldState.mHighCol); 417 mScript.set_gAlphaMul(mWorldState.mAlphaMul); 418 mScript.set_gPreMul(mWorldState.mPreMul); 419 mScript.set_gXOffset(mWorldState.mXOffset); 420 421 return mScript; 422 } 423 } 424