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(-0.5f, 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 Allocation.MipmapControl.MIPMAP_NONE, 166 Allocation.USAGE_GRAPHICS_TEXTURE); 167 return allocation; 168 } 169 170 private void loadTextures() { 171 mDotAllocation = loadTexture(R.drawable.dot); 172 mScript.set_textureDot(mDotAllocation); 173 } 174 175 private void createProgramVertex() { 176 ProgramVertex.Builder backgroundBuilder = new ProgramVertex.Builder(mRS); 177 backgroundBuilder.setShader(mRes, R.raw.bg_vs); 178 backgroundBuilder.addInput(ScriptField_VertexColor_s.createElement(mRS)); 179 ProgramVertex programVertexBackground = backgroundBuilder.create(); 180 mScript.set_vertBg(programVertexBackground); 181 182 updateProjectionMatrices(); 183 184 ProgramVertex.Builder builder = new ProgramVertex.Builder(mRS); 185 builder = new ProgramVertex.Builder(mRS); 186 builder.setShader(mRes, R.raw.noisefield_vs); 187 builder.addConstant(mPvConsts.getType()); 188 builder.addInput(mDotMesh.getVertexAllocation(0).getType().getElement()); 189 190 ProgramVertex pvs = builder.create(); 191 pvs.bindConstants(mPvConsts.getAllocation(), 0); 192 mRS.bindProgramVertex(pvs); 193 mScript.set_vertDots(pvs); 194 } 195 196 private void createProgramFragment() { 197 ProgramFragment.Builder backgroundBuilder = new ProgramFragment.Builder(mRS); 198 backgroundBuilder.setShader(mRes, R.raw.bg_fs); 199 ProgramFragment programFragmentBackground = backgroundBuilder.create(); 200 mScript.set_fragBg(programFragmentBackground); 201 202 ProgramFragment.Builder builder = new ProgramFragment.Builder(mRS); 203 builder.setShader(mRes, R.raw.noisefield_fs); 204 builder.addTexture(Program.TextureType.TEXTURE_2D); 205 ProgramFragment pf = builder.create(); 206 pf.bindSampler(Sampler.CLAMP_LINEAR(mRS), 0); 207 mScript.set_fragDots(pf); 208 } 209 210 private void createProgramRaster() { 211 ProgramRaster.Builder builder = new ProgramRaster.Builder(mRS); 212 builder.setPointSpriteEnabled(true); 213 ProgramRaster pr = builder.create(); 214 mRS.bindProgramRaster(pr); 215 } 216 217 private void createProgramFragmentStore() { 218 ProgramStore.Builder builder = new ProgramStore.Builder(mRS); 219 builder.setBlendFunc(BlendSrcFunc.SRC_ALPHA, BlendDstFunc.ONE ); 220 mRS.bindProgramStore(builder.create()); 221 } 222 223 public void start() { 224 mRS.bindRootScript(mScript); 225 } 226 227 public void stop() { 228 mRS.bindRootScript(null); 229 } 230 231 public void resize(int w, int h) { 232 233 } 234 235 public void onTouchEvent(MotionEvent ev) { 236 int act = ev.getActionMasked(); 237 if (act == MotionEvent.ACTION_UP || act == MotionEvent.ACTION_POINTER_UP) { 238 if(mTouchDown){ 239 mTouchDown = false; 240 mScript.set_touchDown(mTouchDown); 241 } 242 return; 243 } else if( act == MotionEvent.ACTION_DOWN 244 || act == MotionEvent.ACTION_MOVE 245 || act == MotionEvent.ACTION_POINTER_DOWN) { 246 int pcount = ev.getPointerCount(); 247 248 if(!mTouchDown){ 249 mTouchDown = true; 250 mScript.set_touchDown(mTouchDown); 251 } 252 if(pcount > 0){ 253 // just send first pointer position 254 mScript.invoke_touch(ev.getX(0), ev.getY(0)); 255 } 256 } 257 } 258 }