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.Allocation; 33 import android.renderscript.Dimension; 34 import android.renderscript.Element; 35 import android.renderscript.Primitive; 36 import android.renderscript.ProgramFragment; 37 import android.renderscript.ProgramStore; 38 import android.renderscript.ProgramVertex; 39 import android.renderscript.Sampler; 40 import android.renderscript.ScriptC; 41 import android.renderscript.SimpleMesh; 42 import android.renderscript.Type; 43 import android.renderscript.Element.Builder; 44 import android.renderscript.ProgramStore.BlendDstFunc; 45 import android.renderscript.ProgramStore.BlendSrcFunc; 46 import android.util.Log; 47 import android.view.MotionEvent; 48 49 import java.util.TimeZone; 50 51 class MagicSmokeRS extends RenderScriptScene implements OnSharedPreferenceChangeListener { 52 53 static class WorldState { 54 public float mXOffset; 55 public float mTilt; 56 public int mPreset; 57 public int mTextureMask; 58 public int mRotate; 59 public int mTextureSwap; 60 public int mProcessTextureMode; 61 public int mBackCol; 62 public int mLowCol; 63 public int mHighCol; 64 public float mAlphaMul; 65 public int mPreMul; 66 public int mBlendFunc; 67 } 68 WorldState mWorldState = new WorldState(); 69 private Type mStateType; 70 private Allocation mState; 71 72 private ProgramStore mPfsBackgroundOne; 73 private ProgramStore mPfsBackgroundSrc; 74 private ProgramFragment mPfBackground; 75 private Sampler mSampler; 76 private Allocation[] mSourceTextures; 77 private Allocation[] mRealTextures; 78 79 private ProgramVertex mPVBackground; 80 private ProgramVertex.MatrixAllocation mPVAlloc; 81 82 private static final int RSID_STATE = 0; 83 //private static final int RSID_PROGRAMVERTEX = 3; 84 private static final int RSID_NOISESRC1 = 1; 85 private static final int RSID_NOISESRC2 = 2; 86 private static final int RSID_NOISESRC3 = 3; 87 private static final int RSID_NOISESRC4 = 4; 88 private static final int RSID_NOISESRC5 = 5; 89 private static final int RSID_NOISEDST1 = 6; 90 private static final int RSID_NOISEDST2 = 7; 91 private static final int RSID_NOISEDST3 = 8; 92 private static final int RSID_NOISEDST4 = 9; 93 private static final int RSID_NOISEDST5 = 10; 94 95 private Context mContext; 96 private SharedPreferences mSharedPref; 97 98 static class Preset { 99 Preset(int processmode, int backcol, int locol, int hicol, float mul, int mask, 100 boolean rot, int blend, boolean texswap, boolean premul) { 101 mProcessTextureMode = processmode; 102 mBackColor = backcol; 103 mLowColor = locol; 104 mHighColor = hicol; 105 mAlphaMul = mul; 106 mTextureMask = mask; 107 mRotate = rot; 108 mBlendFunc = blend; 109 mTextureSwap = texswap; 110 mPreMul = premul; 111 } 112 public int mProcessTextureMode; 113 public int mBackColor; 114 public int mLowColor; 115 public int mHighColor; 116 public float mAlphaMul; 117 public int mTextureMask; 118 public boolean mRotate; 119 public int mBlendFunc; 120 public boolean mTextureSwap; 121 public boolean mPreMul; 122 } 123 124 public static final int DEFAULT_PRESET = 4; 125 public static final Preset [] mPreset = new Preset[] { 126 // proc back low high alph mask rot blend swap premul 127 new Preset(1, 0x000000, 0x000000, 0xffffff, 2.0f, 0x0f, true, 0, false, false), 128 new Preset(1, 0x0000ff, 0x000000, 0xffffff, 2.0f, 0x0f, true, 0, false, false), 129 new Preset(1, 0x00ff00, 0x000000, 0xffffff, 2.0f, 0x0f, true, 0, false, false), 130 new Preset(1, 0x00ff00, 0x000000, 0xffffff, 2.0f, 0x0f, true, 0, false, true), 131 new Preset(1, 0x00ff00, 0x00ff00, 0xffffff, 2.5f, 0x1f, true, 0, true, true), 132 new Preset(1, 0x800000, 0xff0000, 0xffffff, 2.5f, 0x1f, true, 0, true, false), 133 new Preset(0, 0x000000, 0x000000, 0xffffff, 0.0f, 0x1f, true, 0, false, false), 134 new Preset(1, 0x0000ff, 0x00ff00, 0xffff00, 2.0f, 0x1f, true, 0, true, false), 135 new Preset(1, 0x008000, 0x00ff00, 0xffffff, 2.5f, 0x1f, true, 0, true, false), 136 new Preset(1, 0x800000, 0xff0000, 0xffffff, 2.5f, 0x1f, true, 0, true, true), 137 new Preset(1, 0x808080, 0x000000, 0xffffff, 2.0f, 0x0f, true, 0, false, true), 138 new Preset(1, 0x0000ff, 0x000000, 0xffffff, 2.0f, 0x0f, true, 0, false, true), 139 new Preset(1, 0x0000ff, 0x00ff00, 0xffff00, 1.5f, 0x1f, false, 0, false, true), 140 new Preset(1, 0x0000ff, 0x00ff00, 0xffff00, 2.0f, 0x1f, true, 0, true, true), 141 new Preset(1, 0x0000ff, 0x00ff00, 0xffff00, 1.5f, 0x1f, true, 0, true, true), 142 new Preset(1, 0x808080, 0x000000, 0xffffff, 2.0f, 0x0f, true, 0, false, false), 143 new Preset(1, 0x000000, 0x000000, 0xffffff, 2.0f, 0x0f, true, 0, true, false), 144 new Preset(2, 0x000000, 0x000070, 0xff2020, 2.5f, 0x1f, true, 0, false, false), 145 new Preset(2, 0x6060ff, 0x000070, 0xffffff, 2.5f, 0x1f, true, 0, false, false), 146 new Preset(3, 0x0000f0, 0x000000, 0xffffff, 2.0f, 0x0f, true, 0, true, false), 147 }; 148 149 private float mTouchY; 150 151 MagicSmokeRS(Context context, int width, int height) { 152 super(width, height); 153 mWidth = width; 154 mHeight = height; 155 mWorldState.mTilt = 0; 156 mContext = context; 157 mSharedPref = mContext.getSharedPreferences("magicsmoke", Context.MODE_PRIVATE); 158 makeNewState(); 159 } 160 161 public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { 162 163 makeNewState(); 164 mState.data(mWorldState); 165 } 166 167 void makeNewState() { 168 int p = mSharedPref.getInt("preset", DEFAULT_PRESET); 169 if (p >= mPreset.length) { 170 p = 0; 171 } 172 mWorldState.mPreset = p; 173 mWorldState.mTextureMask = mPreset[p].mTextureMask; 174 mWorldState.mRotate = mPreset[p].mRotate ? 1 : 0; 175 mWorldState.mTextureSwap = mPreset[p].mTextureSwap ? 1 : 0; 176 mWorldState.mProcessTextureMode = mPreset[p].mProcessTextureMode; 177 mWorldState.mBackCol = mPreset[p].mBackColor; 178 mWorldState.mLowCol = mPreset[p].mLowColor; 179 mWorldState.mHighCol = mPreset[p].mHighColor; 180 mWorldState.mAlphaMul = mPreset[p].mAlphaMul; 181 mWorldState.mPreMul = mPreset[p].mPreMul ? 1 : 0; 182 mWorldState.mBlendFunc = mPreset[p].mBlendFunc; 183 } 184 185 @Override 186 public void resize(int width, int height) { 187 super.resize(width, height); 188 if (mPVAlloc != null) { 189 mPVAlloc.setupProjectionNormalized(width, height); 190 } 191 } 192 193 @Override 194 public void onTouchEvent(MotionEvent event) { 195 switch(event.getAction()) { 196 case MotionEvent.ACTION_DOWN: 197 mTouchY = event.getY(); 198 break; 199 case MotionEvent.ACTION_MOVE: 200 float dy = event.getY() - mTouchY; 201 mTouchY += dy; 202 dy /= 20; 203 dy += mWorldState.mTilt; 204 if (dy > 4) { 205 dy = 4; 206 } else if (dy < -4) { 207 dy = -4; 208 } 209 mWorldState.mTilt = dy; 210 mState.data(mWorldState); 211 } 212 } 213 214 @Override 215 public void setOffset(float xOffset, float yOffset, float xStep, float yStep, 216 int xPixels, int yPixels) { 217 // update our state, then push it to the renderscript 218 mWorldState.mXOffset = xOffset; 219 mState.data(mWorldState); 220 } 221 222 @Override 223 public void stop() { 224 mSharedPref.unregisterOnSharedPreferenceChangeListener(this); 225 super.stop(); 226 } 227 228 @Override 229 public void start() { 230 super.start(); 231 mSharedPref.registerOnSharedPreferenceChangeListener(this); 232 makeNewState(); 233 mState.data(mWorldState); 234 } 235 236 float alphafactor; 237 Type mTextureType; 238 239 void loadBitmap(int id, int index, String name, float alphamul, int lowcol, int highcol) { 240 BitmapFactory.Options opts = new BitmapFactory.Options(); 241 opts.inPreferredConfig = Bitmap.Config.ARGB_8888; 242 Bitmap in = BitmapFactory.decodeResource(mResources, id, opts); 243 244 int pixels[] = new int[65536]; 245 in.getPixels(pixels, 0, 256, 0, 0, 256, 256); 246 mRealTextures[index] = Allocation.createTyped(mRS, mTextureType); 247 mSourceTextures[index] = Allocation.createTyped(mRS, mTextureType); 248 mSourceTextures[index].setName(name+"_src"); 249 mSourceTextures[index].data(pixels); 250 mRealTextures[index].setName(name); 251 in.recycle(); 252 } 253 254 void loadBitmaps() { 255 alphafactor = 1f; 256 float alphamul = mPreset[mWorldState.mPreset].mAlphaMul; 257 int lowcol = mPreset[mWorldState.mPreset].mLowColor; 258 int highcol = mPreset[mWorldState.mPreset].mHighColor; 259 //Log.i("@@@@", "preset " + mWorldState.mPreset + ", mul: " + alphamul + 260 // ", colors: " + Integer.toHexString(lowcol) + "/" + Integer.toHexString(highcol)); 261 262 // TODO: using different high and low colors for each layer offers some cool effects too 263 loadBitmap(R.drawable.noise1, 0, "Tnoise1", alphamul, lowcol, highcol); 264 loadBitmap(R.drawable.noise2, 1, "Tnoise2", alphamul, lowcol, highcol); 265 loadBitmap(R.drawable.noise3, 2, "Tnoise3", alphamul, lowcol, highcol); 266 loadBitmap(R.drawable.noise4, 3, "Tnoise4", alphamul, lowcol, highcol); 267 loadBitmap(R.drawable.noise5, 4, "Tnoise5", alphamul, lowcol, highcol); 268 } 269 270 @Override 271 protected ScriptC createScript() { 272 273 // Create a renderscript type from a java class. The specified name doesn't 274 // really matter; the name by which we refer to the object in RenderScript 275 // will be specified later. 276 mStateType = Type.createFromClass(mRS, WorldState.class, 1, "WorldState"); 277 // Create an allocation from the type we just created. 278 mState = Allocation.createTyped(mRS, mStateType); 279 mState.data(mWorldState); 280 281 // First set up the coordinate system and such 282 ProgramVertex.Builder pvb = new ProgramVertex.Builder(mRS, null, null); 283 mPVBackground = pvb.create(); 284 mPVBackground.setName("PVBackground"); 285 mPVAlloc = new ProgramVertex.MatrixAllocation(mRS); 286 mPVBackground.bindAllocation(mPVAlloc); 287 mPVAlloc.setupProjectionNormalized(mWidth, mHeight); 288 289 mSourceTextures = new Allocation[5]; 290 mRealTextures = new Allocation[5]; 291 292 Type.Builder tb = new Type.Builder(mRS, Element.RGBA_8888(mRS)); 293 tb.add(Dimension.X, 256); 294 tb.add(Dimension.Y, 256); 295 mTextureType = tb.create(); 296 loadBitmaps(); 297 298 Sampler.Builder samplerBuilder = new Sampler.Builder(mRS); 299 samplerBuilder.setMin(LINEAR); 300 samplerBuilder.setMag(LINEAR); 301 samplerBuilder.setWrapS(WRAP); 302 samplerBuilder.setWrapT(WRAP); 303 mSampler = samplerBuilder.create(); 304 305 { 306 ProgramFragment.Builder builder = new ProgramFragment.Builder(mRS); 307 builder.setTexture(ProgramFragment.Builder.EnvMode.REPLACE, 308 ProgramFragment.Builder.Format.RGBA, 0); 309 mPfBackground = builder.create(); 310 mPfBackground.setName("PFBackground"); 311 mPfBackground.bindSampler(mSampler, 0); 312 } 313 314 { 315 ProgramStore.Builder builder = new ProgramStore.Builder(mRS, null, null); 316 builder.setDepthFunc(ProgramStore.DepthFunc.EQUAL); 317 builder.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ONE_MINUS_SRC_ALPHA); 318 builder.setDitherEnable(true); // without dithering there is severe banding 319 builder.setDepthMask(false); 320 mPfsBackgroundOne = builder.create(); 321 mPfsBackgroundOne.setName("PFSBackgroundOne"); 322 builder.setBlendFunc(BlendSrcFunc.SRC_ALPHA, BlendDstFunc.ONE_MINUS_SRC_ALPHA); 323 mPfsBackgroundSrc = builder.create(); 324 mPfsBackgroundSrc.setName("PFSBackgroundSrc"); 325 } 326 327 // Time to create the script 328 ScriptC.Builder sb = new ScriptC.Builder(mRS); 329 // Specify the name by which to refer to the WorldState object in the 330 // renderscript. 331 sb.setType(mStateType, "State", RSID_STATE); 332 sb.setType(mTextureType, "noisesrc1", RSID_NOISESRC1); 333 sb.setType(mTextureType, "noisedst1", RSID_NOISEDST1); 334 sb.setType(mTextureType, "noisesrc2", RSID_NOISESRC2); 335 sb.setType(mTextureType, "noisedst2", RSID_NOISEDST2); 336 sb.setType(mTextureType, "noisesrc3", RSID_NOISESRC3); 337 sb.setType(mTextureType, "noisedst3", RSID_NOISEDST3); 338 sb.setType(mTextureType, "noisesrc4", RSID_NOISESRC4); 339 sb.setType(mTextureType, "noisedst4", RSID_NOISEDST4); 340 sb.setType(mTextureType, "noisesrc5", RSID_NOISESRC5); 341 sb.setType(mTextureType, "noisedst5", RSID_NOISEDST5); 342 sb.setScript(mResources, R.raw.clouds); 343 sb.setRoot(true); 344 345 ScriptC script = sb.create(); 346 script.setClearColor(0.0f, 0.0f, 0.0f, 1.0f); 347 script.setTimeZone(TimeZone.getDefault().getID()); 348 349 script.bindAllocation(mState, RSID_STATE); 350 script.bindAllocation(mSourceTextures[0], RSID_NOISESRC1); 351 script.bindAllocation(mRealTextures[0], RSID_NOISEDST1); 352 script.bindAllocation(mSourceTextures[1], RSID_NOISESRC2); 353 script.bindAllocation(mRealTextures[1], RSID_NOISEDST2); 354 script.bindAllocation(mSourceTextures[2], RSID_NOISESRC3); 355 script.bindAllocation(mRealTextures[2], RSID_NOISEDST3); 356 script.bindAllocation(mSourceTextures[3], RSID_NOISESRC4); 357 script.bindAllocation(mRealTextures[3], RSID_NOISEDST4); 358 script.bindAllocation(mSourceTextures[4], RSID_NOISESRC5); 359 script.bindAllocation(mRealTextures[4], RSID_NOISEDST5); 360 //script.bindAllocation(mPVAlloc.mAlloc, RSID_PROGRAMVERTEX); 361 362 363 return script; 364 } 365 } 366