1 package com.android.noisefield; 2 3 import android.content.res.Resources; 4 import android.graphics.Bitmap; 5 import android.graphics.BitmapFactory; 6 import android.renderscript.Allocation; 7 import android.renderscript.Float3; 8 import android.renderscript.Float4; 9 import android.renderscript.Matrix4f; 10 import android.renderscript.Mesh; 11 import android.renderscript.Program; 12 import android.renderscript.ProgramFragment; 13 import android.renderscript.ProgramFragmentFixedFunction; 14 import android.renderscript.ProgramRaster; 15 import android.renderscript.ProgramStore; 16 import android.renderscript.ProgramVertex; 17 import android.renderscript.ProgramVertexFixedFunction; 18 import android.renderscript.RenderScriptGL; 19 import android.renderscript.Sampler; 20 import android.renderscript.Mesh.Primitive; 21 import android.renderscript.ProgramStore.BlendDstFunc; 22 import android.renderscript.ProgramStore.BlendSrcFunc; 23 import android.os.Bundle; 24 import android.app.WallpaperManager; 25 import android.util.Log; 26 import android.view.MotionEvent; 27 import java.io.InputStreamReader; 28 import java.io.InputStream; 29 import java.io.BufferedReader; 30 import java.io.IOException; 31 import java.util.ArrayList; 32 33 public class NoiseFieldRS { 34 public static String LOG_TAG = "NoiseField"; 35 36 private Resources mRes; 37 private RenderScriptGL mRS; 38 private ScriptC_noisefield mScript; 39 private int mHeight; 40 private int mWidth; 41 private boolean mTouchDown; 42 private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options(); 43 44 private ScriptField_VpConsts mPvConsts; 45 private Allocation mDotAllocation; 46 private ScriptField_VertexColor_s mVertexColors; 47 private ScriptField_Particle mDotParticles; 48 private Mesh mDotMesh; 49 private int mDensityDPI; 50 51 public void init(int dpi, RenderScriptGL rs, 52 Resources res, int width, int height) { 53 mDensityDPI = dpi; 54 mRS = rs; 55 mRes = res; 56 57 mWidth = width; 58 mHeight = height; 59 60 mOptionsARGB.inScaled = false; 61 mOptionsARGB.inPreferredConfig = Bitmap.Config.ARGB_8888; 62 63 Mesh.AllocationBuilder smb2 = new Mesh.AllocationBuilder(mRS); 64 65 mDotParticles = new ScriptField_Particle(mRS, 83); 66 smb2.addVertexAllocation(mDotParticles.getAllocation()); 67 68 smb2.addIndexSetType(Mesh.Primitive.POINT); 69 mScript = new ScriptC_noisefield(mRS, mRes, R.raw.noisefield); 70 71 mDotMesh = smb2.create(); 72 mScript.set_dotMesh(mDotMesh); 73 mScript.bind_dotParticles(mDotParticles); 74 75 mPvConsts = new ScriptField_VpConsts(mRS, 1); 76 77 createProgramVertex(); 78 createProgramRaster(); 79 createProgramFragmentStore(); 80 createProgramFragment(); 81 createBackgroundMesh(); 82 loadTextures(); 83 84 mScript.set_densityDPI(mDensityDPI); 85 mScript.invoke_positionParticles(); 86 } 87 88 private Matrix4f getProjectionNormalized(int w, int h) { 89 // range -1,1 in the narrow axis at z = 0. 90 Matrix4f m1 = new Matrix4f(); 91 Matrix4f m2 = new Matrix4f(); 92 93 if (w > h) { 94 float aspect = ((float) w) / h; 95 m1.loadFrustum(-aspect, aspect, -1, 1, 1, 100); 96 } else { 97 float aspect = ((float) h) / w; 98 m1.loadFrustum(-1, 1, -aspect, aspect, 1, 100); 99 } 100 101 m2.loadRotate(180, 0, 1, 0); 102 m1.loadMultiply(m1, m2); 103 104 m2.loadScale(-1, 1, 1); 105 m1.loadMultiply(m1, m2); 106 107 m2.loadTranslate(0, 0, 1); 108 m1.loadMultiply(m1, m2); 109 return m1; 110 } 111 112 private void updateProjectionMatrices() { 113 Matrix4f projNorm = getProjectionNormalized(mWidth, mHeight); 114 ScriptField_VpConsts.Item i = new ScriptField_VpConsts.Item(); 115 i.MVP = projNorm; 116 i.scaleSize = mDensityDPI/240.0f; 117 mPvConsts.set(i, 0, true); 118 } 119 120 private void createBackgroundMesh() { 121 // The composition and colors of the background mesh were plotted on paper and photoshop 122 // first then translated to the csv file in raw. Points and colors are not random. 123 ArrayList<String> meshData = new ArrayList<String>(); 124 InputStream inputStream = mRes.openRawResource(R.raw.bgmesh); 125 BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); 126 try { 127 String line; 128 while ((line = reader.readLine()) != null) { 129 meshData.add(line); 130 } 131 } catch (IOException e) { 132 Log.e(LOG_TAG, "Unable to load background mesh from csv file."); 133 } finally { 134 try { 135 inputStream.close(); 136 } catch (IOException e) { 137 Log.e(LOG_TAG, "Unable to close background mesh csv file."); 138 } 139 } 140 141 int meshDataSize = meshData.size(); 142 mVertexColors = new ScriptField_VertexColor_s(mRS, meshDataSize); 143 for (int i=0; i<meshDataSize; i++) { 144 String line = (String) meshData.get(i); 145 String[] values = line.split(","); 146 float xPos = Float.parseFloat(values[0]); 147 float yPos = Float.parseFloat(values[1]); 148 float red = Float.parseFloat(values[2]); 149 float green = Float.parseFloat(values[3]); 150 float blue = Float.parseFloat(values[4]); 151 mVertexColors.set_position(i, new Float3(xPos, yPos, 0.0f), false); 152 mVertexColors.set_color(i, new Float4(red, green, blue, 1.0f), false); 153 } 154 mVertexColors.copyAll(); 155 156 Mesh.AllocationBuilder backgroundBuilder = new Mesh.AllocationBuilder(mRS); 157 backgroundBuilder.addIndexSetType(Primitive.TRIANGLE); 158 backgroundBuilder.addVertexAllocation(mVertexColors.getAllocation()); 159 mScript.set_gBackgroundMesh(backgroundBuilder.create()); 160 mScript.bind_vertexColors(mVertexColors); 161 } 162 163 private Allocation loadTexture(int id) { 164 final Allocation allocation = Allocation.createFromBitmapResource(mRS, mRes, id); 165 return allocation; 166 } 167 168 private void loadTextures() { 169 mDotAllocation = loadTexture(R.drawable.dot); 170 mScript.set_textureDot(mDotAllocation); 171 } 172 173 private void createProgramVertex() { 174 ProgramVertex.Builder backgroundBuilder = new ProgramVertex.Builder(mRS); 175 backgroundBuilder.setShader(mRes, R.raw.bg_vs); 176 backgroundBuilder.addInput(ScriptField_VertexColor_s.createElement(mRS)); 177 ProgramVertex programVertexBackground = backgroundBuilder.create(); 178 mScript.set_vertBg(programVertexBackground); 179 180 updateProjectionMatrices(); 181 182 ProgramVertex.Builder builder = new ProgramVertex.Builder(mRS); 183 builder = new ProgramVertex.Builder(mRS); 184 builder.setShader(mRes, R.raw.noisefield_vs); 185 builder.addConstant(mPvConsts.getType()); 186 builder.addInput(mDotMesh.getVertexAllocation(0).getType().getElement()); 187 188 ProgramVertex pvs = builder.create(); 189 pvs.bindConstants(mPvConsts.getAllocation(), 0); 190 mRS.bindProgramVertex(pvs); 191 mScript.set_vertDots(pvs); 192 } 193 194 private void createProgramFragment() { 195 ProgramFragment.Builder backgroundBuilder = new ProgramFragment.Builder(mRS); 196 backgroundBuilder.setShader(mRes, R.raw.bg_fs); 197 ProgramFragment programFragmentBackground = backgroundBuilder.create(); 198 mScript.set_fragBg(programFragmentBackground); 199 200 ProgramFragment.Builder builder = new ProgramFragment.Builder(mRS); 201 builder.setShader(mRes, R.raw.noisefield_fs); 202 builder.addTexture(Program.TextureType.TEXTURE_2D); 203 ProgramFragment pf = builder.create(); 204 pf.bindSampler(Sampler.CLAMP_LINEAR(mRS), 0); 205 mScript.set_fragDots(pf); 206 } 207 208 private void createProgramRaster() { 209 ProgramRaster.Builder builder = new ProgramRaster.Builder(mRS); 210 builder.setPointSpriteEnabled(true); 211 ProgramRaster pr = builder.create(); 212 mRS.bindProgramRaster(pr); 213 } 214 215 private void createProgramFragmentStore() { 216 ProgramStore.Builder builder = new ProgramStore.Builder(mRS); 217 builder.setBlendFunc(BlendSrcFunc.SRC_ALPHA, BlendDstFunc.ONE ); 218 mRS.bindProgramStore(builder.create()); 219 } 220 221 public void start() { 222 mRS.bindRootScript(mScript); 223 } 224 225 public void stop() { 226 mRS.bindRootScript(null); 227 } 228 229 public void resize(int w, int h) { 230 231 } 232 233 public void onTouchEvent(MotionEvent ev) { 234 int act = ev.getActionMasked(); 235 if (act == MotionEvent.ACTION_UP || act == MotionEvent.ACTION_POINTER_UP) { 236 if(mTouchDown){ 237 mTouchDown = false; 238 mScript.set_touchDown(mTouchDown); 239 } 240 return; 241 } else if( act == MotionEvent.ACTION_DOWN 242 || act == MotionEvent.ACTION_MOVE 243 || act == MotionEvent.ACTION_POINTER_DOWN) { 244 int pcount = ev.getPointerCount(); 245 246 if(!mTouchDown){ 247 mTouchDown = true; 248 mScript.set_touchDown(mTouchDown); 249 } 250 if(pcount > 0){ 251 // just send first pointer position 252 mScript.invoke_touch(ev.getX(0), ev.getY(0)); 253 } 254 } 255 } 256 }