Home | History | Annotate | Download | only in magicsmoke
      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