Move Fall waveform calculation to vertex shader.
diff --git a/res/raw/fall.rs b/res/raw/fall.rs
index f27e156..e183178 100644
--- a/res/raw/fall.rs
+++ b/res/raw/fall.rs
@@ -26,20 +26,10 @@
 float g_DT;
 int g_LastTime;
 
-struct vert_s {
-    float x;
-    float y;
-    float s;
-    float t;
-};
-
 struct drop_s {
     float ampS;
     float ampE;
     float spread;
-    float spread2;
-    float invSpread;
-    float invSpread2;
     float x;
     float y;
 };
@@ -62,9 +52,7 @@
 };
 
 struct Leaves_s gLeavesStore[LEAVES_COUNT];
-
 struct Leaves_s* gLeaves[LEAVES_COUNT];
-
 struct Leaves_s* gNextLeaves[LEAVES_COUNT];
 
 void init() {
@@ -74,9 +62,6 @@
         gDrops[ct].ampS = 0;
         gDrops[ct].ampE = 0;
         gDrops[ct].spread = 1;
-        gDrops[ct].spread2 = gDrops[ct].spread * gDrops[ct].spread;
-        gDrops[ct].invSpread = 1 / gDrops[ct].spread;
-        gDrops[ct].invSpread2 = gDrops[ct].invSpread * gDrops[ct].invSpread;
     }
 }
 
@@ -106,10 +91,7 @@
 
 void updateDrop(int ct) {
     gDrops[ct].spread += 30.f * g_DT;
-    gDrops[ct].spread2 = gDrops[ct].spread * gDrops[ct].spread;
-    gDrops[ct].invSpread = 1 / gDrops[ct].spread;
-    gDrops[ct].invSpread2 = gDrops[ct].invSpread * gDrops[ct].invSpread;
-    gDrops[ct].ampE = gDrops[ct].ampS * gDrops[ct].invSpread;
+    gDrops[ct].ampE = gDrops[ct].ampS / gDrops[ct].spread;
 }
 
 void drop(int x, int y, float s) {
@@ -130,43 +112,18 @@
 }
 
 void generateRipples() {
-    int width = State->meshWidth;
-    int height = State->meshHeight;
-    int index = State->rippleIndex;
-    float ratio = (float)State->meshWidth / State->glWidth;
-    float xShift = State->xOffset * ratio * 2;
-
-    float *vertices = loadSimpleMeshVerticesF(NAMED_WaterMesh, 0);
-    struct vert_s *v = (struct vert_s *)vertices;
-
-    float fw = 1.0f / width;
-    float fh = 1.0f / height;
-    int x, y, ct;
-    for (y=0; y < height; y++) {
-        for (x=0; x < width; x++) {
-            struct drop_s * d = &gDrops[0];
-            float z = 0;
-
-            v->s = (float)x * fw;
-            v->t = (float)y * fh;
-            for (ct = 0; ct < gMaxDrops; ct++) {
-                if (d->ampE > 0.01f) {
-                    float dx = (d->x - xShift) - x;
-                    float dy = d->y - y;
-                    float dist2 = dx*dx + dy*dy;
-                    if (dist2 < d->spread2) {
-                        float dist = sqrtf(dist2);
-                        float a = d->ampE * (dist * d->invSpread2);
-                        a *= sinf(d->spread - dist) * 0.15f;
-                        v->s += dx * a;
-                        v->t += dy * a;
-                    }
-                }
-                d++;
-            }
-            v ++;
-        }
+    int ct;
+    for (ct = 0; ct < gMaxDrops; ct++) {
+        struct drop_s * d = &gDrops[ct];
+        vecF32_4_t *v = &Constants->Drop01;
+        v += ct;
+        v->x = d->x;
+        v->y = d->y;
+        v->z = d->ampE * 0.12f;
+        v->w = d->spread;
     }
+    Constants->Offset.x = State->xOffset;
+
     for (ct = 0; ct < gMaxDrops; ct++) {
         updateDrop(ct);
     }
@@ -336,47 +293,9 @@
 
 void drawRiverbed() {
     bindTexture(NAMED_PFBackground, 0, NAMED_TRiverbed);
-
-    float matrix[16];
-    matrixLoadScale(matrix, 0.5f * 960.0f / 1024.0f, -1.0f * 800.0f / 1024.0f, 1.0f);
-    matrixTranslate(matrix, State->xOffset, 0.0f, 0.0f);
-    vpLoadTextureMatrix(matrix);
-
     drawSimpleMesh(NAMED_WaterMesh);
-
-    matrixLoadIdentity(matrix);
-    vpLoadTextureMatrix(matrix);
 }
 
-/*
-void drawSky() {
-    color(1.0f, 1.0f, 1.0f, 0.5f);
-
-    bindProgramFragment(NAMED_PFSky);
-    bindProgramFragmentStore(NAMED_PFSLeaf);
-    bindTexture(NAMED_PFSky, 0, NAMED_TSky);
-
-    float x = skyOffsetX + State->skySpeedX;
-    float y = skyOffsetY + State->skySpeedY;
-
-    if (x > 1.0f) x = 0.0f;
-    if (x < -1.0f) x = 0.0f;
-    if (y > 1.0f) y = 0.0f;
-
-    skyOffsetX = x;
-    skyOffsetY = y;
-
-    float matrix[16];
-    matrixLoadTranslate(matrix, x + State->xOffset, y, 0.0f);
-    vpLoadTextureMatrix(matrix);
-
-    drawSimpleMesh(NAMED_WaterMesh);
-
-    matrixLoadIdentity(matrix);
-    vpLoadTextureMatrix(matrix);
-}
-*/
-
 int main(int index) {
     // Compute dt in seconds.
     int newTime = uptimeMillis();
@@ -404,17 +323,17 @@
         genLeafDrop(gLeaves[i], randf(0.3f) + 0.1f);
     }
 
-    generateRipples();
-    updateSimpleMesh(NAMED_WaterMesh);
-
     if (State->rotate) {
         float matrix[16];
         matrixLoadRotate(matrix, 90.0f, 0.0f, 0.0f, 1.0f);
         vpLoadModelMatrix(matrix);
     }
 
+    bindProgramVertex(NAMED_PVWater);
+    generateRipples();
     drawRiverbed();
-    // drawSky();
+
+    bindProgramVertex(NAMED_PVSky);
     drawLeaves();
 
     return 30;
diff --git a/src/com/android/wallpaper/fall/FallRS.java b/src/com/android/wallpaper/fall/FallRS.java
index a10adea..dc86cfb 100644
--- a/src/com/android/wallpaper/fall/FallRS.java
+++ b/src/com/android/wallpaper/fall/FallRS.java
@@ -17,6 +17,7 @@
 package com.android.wallpaper.fall;
 
 import android.os.Bundle;
+import android.renderscript.Element;
 import android.renderscript.ScriptC;
 import android.renderscript.ProgramFragment;
 import android.renderscript.ProgramStore;
@@ -28,7 +29,7 @@
 import android.renderscript.SimpleMesh;
 import android.renderscript.Script;
 import static android.renderscript.Sampler.Value.LINEAR;
-import static android.renderscript.Sampler.Value.WRAP;
+import static android.renderscript.Sampler.Value.CLAMP;
 import static android.renderscript.ProgramStore.DepthFunc.*;
 import static android.renderscript.ProgramStore.BlendDstFunc;
 import static android.renderscript.ProgramStore.BlendSrcFunc;
@@ -48,13 +49,14 @@
     private static final int MESH_RESOLUTION = 48;
 
     private static final int RSID_STATE = 0;
+    private static final int RSID_CONSTANTS = 1;
+    private static final int RSID_DROP = 2;
 
     private static final int TEXTURES_COUNT = 2;
     private static final int RSID_TEXTURE_RIVERBED = 0;
     private static final int RSID_TEXTURE_LEAVES = 1;
     private static final int RSID_TEXTURE_SKY = 2;
 
-    private static final int RSID_DROP = 2;
 
 
     static class Defines {
@@ -73,6 +75,7 @@
     private ProgramStore mPfsLeaf;
     @SuppressWarnings({"FieldCanBeLocal"})
     private ProgramVertex mPvSky;
+    private ProgramVertex mPvWater;
     private ProgramVertex.MatrixAllocation mPvOrthoAlloc;
     @SuppressWarnings({"FieldCanBeLocal"})
     private Sampler mSampler;
@@ -83,6 +86,7 @@
     private Type mStateType;
     private Type mDropType;
     private int mMeshWidth;
+    private Allocation mUniformAlloc;
 
     private int mMeshHeight;
     @SuppressWarnings({"FieldCanBeLocal"})
@@ -139,16 +143,19 @@
 
     @Override
     protected ScriptC createScript() {
+        createMesh();
+        createState();
         createProgramVertex();
         createProgramFragmentStore();
         createProgramFragment();
-        createMesh();
-        createState();
         loadTextures();
 
+
+
         ScriptC.Builder sb = new ScriptC.Builder(mRS);
         sb.setType(mStateType, "State", RSID_STATE);
         sb.setType(mDropType, "Drop", RSID_DROP);
+        sb.setType(mUniformAlloc.getType(), "Constants", RSID_CONSTANTS);
         sb.setScript(mResources, R.raw.fall);
         Script.Invokable invokable = sb.addInvokable("initLeaves");
         sb.setRoot(true);
@@ -158,6 +165,7 @@
         script.setTimeZone(TimeZone.getDefault().getID());
 
         script.bindAllocation(mState, RSID_STATE);
+        script.bindAllocation(mUniformAlloc, RSID_CONSTANTS);
         script.bindAllocation(mDropState, RSID_DROP);
 
         invokable.execute();
@@ -166,8 +174,7 @@
     }
 
     private void createMesh() {
-        SimpleMesh.TriangleMeshBuilder tmb = new SimpleMesh.TriangleMeshBuilder(mRS, 2,
-                SimpleMesh.TriangleMeshBuilder.TEXTURE_0);
+        SimpleMesh.TriangleMeshBuilder tmb = new SimpleMesh.TriangleMeshBuilder(mRS, 2, 0);
 
         final int width = mWidth > mHeight ? mHeight : mWidth;
         final int height = mWidth > mHeight ? mWidth : mHeight;
@@ -185,11 +192,9 @@
         hResolution += 2;
 
         for (int y = 0; y <= hResolution; y++) {
-            final float yOffset = y * quadHeight - glHeight / 2.0f - quadHeight;
-            final float t = 1.0f - y / (float) hResolution;
+            final float yOffset = (((float)y / hResolution) * 2.f - 1.f) * height / width;
             for (int x = 0; x <= wResolution; x++) {
-                tmb.setTexture(x / (float) wResolution, t);
-                tmb.addVertex(-1.0f + x * quadWidth - quadWidth, yOffset);
+                tmb.addVertex(((float)x / wResolution) * 2.f - 1.f, yOffset);
             }
         }
 
@@ -295,8 +300,8 @@
         Sampler.Builder sampleBuilder = new Sampler.Builder(mRS);
         sampleBuilder.setMin(LINEAR);
         sampleBuilder.setMag(LINEAR);
-        sampleBuilder.setWrapS(WRAP);
-        sampleBuilder.setWrapT(WRAP);
+        sampleBuilder.setWrapS(CLAMP);
+        sampleBuilder.setWrapT(CLAMP);
         mSampler = sampleBuilder.create();
 
         ProgramFragment.Builder builder = new ProgramFragment.Builder(mRS);
@@ -337,10 +342,157 @@
         mPvOrthoAlloc.setupProjectionNormalized(mWidth, mHeight);
 
         ProgramVertex.Builder builder = new ProgramVertex.Builder(mRS, null, null);
-        builder.setTextureMatrixEnable(true);
         mPvSky = builder.create();
         mPvSky.bindAllocation(mPvOrthoAlloc);
         mPvSky.setName("PVSky");
+
+        float dw = 480.f / mMeshWidth;
+        float dh = 800.f / mMeshHeight;
+
+        Element.Builder eb = new Element.Builder(mRS);
+        // Make this an array when we can.
+        eb.add(Element.createVector(mRS, Element.DataType.FLOAT_32, 4), "Drop01");
+        eb.add(Element.createVector(mRS, Element.DataType.FLOAT_32, 4), "Drop02");
+        eb.add(Element.createVector(mRS, Element.DataType.FLOAT_32, 4), "Drop03");
+        eb.add(Element.createVector(mRS, Element.DataType.FLOAT_32, 4), "Drop04");
+        eb.add(Element.createVector(mRS, Element.DataType.FLOAT_32, 4), "Drop05");
+        eb.add(Element.createVector(mRS, Element.DataType.FLOAT_32, 4), "Drop06");
+        eb.add(Element.createVector(mRS, Element.DataType.FLOAT_32, 4), "Drop07");
+        eb.add(Element.createVector(mRS, Element.DataType.FLOAT_32, 4), "Drop08");
+        eb.add(Element.createVector(mRS, Element.DataType.FLOAT_32, 4), "Drop09");
+        eb.add(Element.createVector(mRS, Element.DataType.FLOAT_32, 4), "Drop10");
+        eb.add(Element.createVector(mRS, Element.DataType.FLOAT_32, 4), "Offset");
+        Element e = eb.create();
+
+        mUniformAlloc = Allocation.createSized(mRS, e, 1);
+
+
+        ProgramVertex.ShaderBuilder sb = new ProgramVertex.ShaderBuilder(mRS);
+        String t = new String("void main() {\n" +
+                              "  vec4 pos;\n" +
+                              "  pos.x = ATTRIB_position.x;\n" +
+                              "  pos.y = ATTRIB_position.y;\n" +
+                              "  pos.z = 0.0;\n" +
+                              "  pos.w = 1.0;\n" +
+                              "  gl_Position = pos;\n" +
+
+                              // When we resize the texture we will need to tweak this.
+                              "  varTex0.x = (pos.x + 1.0) * 0.25;\n" +
+                              "  varTex0.x += UNI_Offset.x * 0.5 * 0.85;\n" +
+                              "  varTex0.y = (pos.y + 1.6666) * 0.33;\n" +
+                              "  varTex0.w = 0.0;\n" +
+                              "  varColor = vec4(1.0, 1.0, 1.0, 1.0);\n" +
+
+                              "  pos.x += UNI_Offset.x * 2.0;\n" +
+                              "  pos.x += 1.0;\n" +
+                              "  pos.y += 1.0;\n" +
+                              "  pos.x *= 25.0;\n" +
+                              "  pos.y *= 42.0;\n" +
+
+                              "  vec2 delta;\n" +
+                              "  float dist;\n" +
+                              "  float amp;\n" +
+
+                              "  delta = UNI_Drop01.xy - pos.xy;\n" +
+                              "  dist = length(delta);\n" +
+                              "  if (dist < UNI_Drop01.w) { \n" +
+                              "    amp = UNI_Drop01.z * dist;\n" +
+                              "    amp /= UNI_Drop01.w * UNI_Drop01.w;\n" +
+                              "    amp *= sin(UNI_Drop01.w - dist);\n" +
+                              "    varTex0.xy += delta * amp;\n" +
+                              "  }\n" +
+
+                              "  delta = UNI_Drop02.xy - pos.xy;\n" +
+                              "  dist = length(delta);\n" +
+                              "  if (dist < UNI_Drop02.w) { \n" +
+                              "    amp = UNI_Drop02.z * dist;\n" +
+                              "    amp /= UNI_Drop02.w * UNI_Drop02.w;\n" +
+                              "    amp *= sin(UNI_Drop02.w - dist);\n" +
+                              "    varTex0.xy += delta * amp;\n" +
+                              "  }\n" +
+
+                              "  delta = UNI_Drop03.xy - pos.xy;\n" +
+                              "  dist = length(delta);\n" +
+                              "  if (dist < UNI_Drop03.w) { \n" +
+                              "    amp = UNI_Drop03.z * dist;\n" +
+                              "    amp /= UNI_Drop03.w * UNI_Drop03.w;\n" +
+                              "    amp *= sin(UNI_Drop03.w - dist);\n" +
+                              "    varTex0.xy += delta * amp;\n" +
+                              "  }\n" +
+
+                              "  delta = UNI_Drop04.xy - pos.xy;\n" +
+                              "  dist = length(delta);\n" +
+                              "  if (dist < UNI_Drop04.w) { \n" +
+                              "    amp = UNI_Drop04.z * dist;\n" +
+                              "    amp /= UNI_Drop04.w * UNI_Drop04.w;\n" +
+                              "    amp *= sin(UNI_Drop04.w - dist);\n" +
+                              "    varTex0.xy += delta * amp;\n" +
+                              "  }\n" +
+
+                              "  delta = UNI_Drop05.xy - pos.xy;\n" +
+                              "  dist = length(delta);\n" +
+                              "  if (dist < UNI_Drop05.w) { \n" +
+                              "    amp = UNI_Drop05.z * dist;\n" +
+                              "    amp /= UNI_Drop05.w * UNI_Drop05.w;\n" +
+                              "    amp *= sin(UNI_Drop05.w - dist);\n" +
+                              "    varTex0.xy += delta * amp;\n" +
+                              "  }\n" +
+
+                              "  delta = UNI_Drop06.xy - pos.xy;\n" +
+                              "  dist = length(delta);\n" +
+                              "  if (dist < UNI_Drop06.w) { \n" +
+                              "    amp = UNI_Drop06.z * dist;\n" +
+                              "    amp /= UNI_Drop06.w * UNI_Drop06.w;\n" +
+                              "    amp *= sin(UNI_Drop06.w - dist);\n" +
+                              "    varTex0.xy += delta * amp;\n" +
+                              "  }\n" +
+
+                              "  delta = UNI_Drop07.xy - pos.xy;\n" +
+                              "  dist = length(delta);\n" +
+                              "  if (dist < UNI_Drop07.w) { \n" +
+                              "    amp = UNI_Drop07.z * dist;\n" +
+                              "    amp /= UNI_Drop07.w * UNI_Drop07.w;\n" +
+                              "    amp *= sin(UNI_Drop07.w - dist);\n" +
+                              "    varTex0.xy += delta * amp;\n" +
+                              "  }\n" +
+
+                              "  delta = UNI_Drop08.xy - pos.xy;\n" +
+                              "  dist = length(delta);\n" +
+                              "  if (dist < UNI_Drop08.w) { \n" +
+                              "    amp = UNI_Drop08.z * dist;\n" +
+                              "    amp /= UNI_Drop08.w * UNI_Drop08.w;\n" +
+                              "    amp *= sin(UNI_Drop08.w - dist);\n" +
+                              "    varTex0.xy += delta * amp;\n" +
+                              "  }\n" +
+
+                              "  delta = UNI_Drop09.xy - pos.xy;\n" +
+                              "  dist = length(delta);\n" +
+                              "  if (dist < UNI_Drop09.w) { \n" +
+                              "    amp = UNI_Drop09.z * dist;\n" +
+                              "    amp /= UNI_Drop09.w * UNI_Drop09.w;\n" +
+                              "    amp *= sin(UNI_Drop09.w - dist);\n" +
+                              "    varTex0.xy += delta * amp;\n" +
+                              "  }\n" +
+
+                              "  delta = UNI_Drop10.xy - pos.xy;\n" +
+                              "  dist = length(delta);\n" +
+                              "  if (dist < UNI_Drop10.w) { \n" +
+                              "    amp = UNI_Drop10.z * dist;\n" +
+                              "    amp /= UNI_Drop10.w * UNI_Drop10.w;\n" +
+                              "    amp *= sin(UNI_Drop10.w - dist);\n" +
+                              "    varTex0.xy += delta * amp;\n" +
+                              "  }\n" +
+
+
+                              "}\n");
+        sb.setShader(t);
+        sb.addConstant(mUniformAlloc.getType());
+        sb.addInput(mMesh.getVertexType(0).getElement());
+        mPvWater = sb.create();
+        mPvWater.bindAllocation(mPvOrthoAlloc);
+        mPvWater.setName("PVWater");
+        mPvWater.bindConstants(mUniformAlloc, 1);
+
     }
 
     void addDrop(float x, float y) {