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 {
Preset(int processmode, int backcol, int locol, int hicol, float mul, int mask, boolean rot, boolean texswap, boolean premul)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 
MagicSmokeRS(Context context, int width, int height)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 
onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)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 
makeNewState()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
resize(int width, int height)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
onCommand(String action, int x, int y, int z, Bundle extras, boolean resultRequested)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
setOffset(float xOffset, float yOffset, float xStep, float yStep, int xPixels, int yPixels)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
stop(boolean forReal)245     public void stop(boolean forReal) {
246         if (forReal) {
247             mSharedPref.unregisterOnSharedPreferenceChangeListener(this);
248         }
249         super.stop(forReal);
250     }
251 
252     @Override
start()253     public void start() {
254         makeNewState();
255         super.start();
256     }
257 
258     float alphafactor;
259     Type mTextureType;
260 
loadBitmap(int id, int index, String name, float alphamul, int lowcol, int highcol)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 
loadBitmaps()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
createScript()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