Better ripples and leaves
diff --git a/libs/rs/java/Fall/res/drawable-hdpi/leaves.png b/libs/rs/java/Fall/res/drawable-hdpi/leaves.png
new file mode 100644
index 0000000..9eddd66
--- /dev/null
+++ b/libs/rs/java/Fall/res/drawable-hdpi/leaves.png
Binary files differ
diff --git a/libs/rs/java/Fall/res/raw/fall.c b/libs/rs/java/Fall/res/raw/fall.c
index ba9dd25..56aa506 100644
--- a/libs/rs/java/Fall/res/raw/fall.c
+++ b/libs/rs/java/Fall/res/raw/fall.c
@@ -28,12 +28,26 @@
 #define RSID_DROP_X 7
 #define RSID_DROP_Y 8
 #define RSID_RUNNING 9
+#define RSID_LEAVES_COUNT 10
     
-#define RSID_TEXTURES 1
+#define RSID_RIPPLE_MAP 1
+#define RSID_REFRACTION_MAP 2
+#define RSID_LEAVES 3
 
-#define RSID_RIPPLE_MAP 2
+#define LEAF_STRUCT_FIELDS_COUNT 11
+#define LEAF_STRUCT_X 0
+#define LEAF_STRUCT_Y 1
+#define LEAF_STRUCT_SCALE 2
+#define LEAF_STRUCT_ANGLE 3
+#define LEAF_STRUCT_SPIN 4
+#define LEAF_STRUCT_U1 5
+#define LEAF_STRUCT_U2 6
+#define LEAF_STRUCT_ALTITUDE 7
+#define LEAF_STRUCT_RIPPLED 8
+#define LEAF_STRUCT_DELTAX 9
+#define LEAF_STRUCT_DELTAY 10
 
-#define RSID_REFRACTION_MAP 3
+#define LEAF_SIZE 0.35f
 
 #define REFRACTION 1.333f
 #define DAMP 3
@@ -277,7 +291,43 @@
     }
 }
 
+void drawLeaf(int index, int frameCount) {
+    float *leafStruct = loadArrayF(RSID_LEAVES, index);
+
+    float x = leafStruct[LEAF_STRUCT_X];
+    float x1 = x - LEAF_SIZE;
+    float x2 = x + LEAF_SIZE;
+
+    float y = leafStruct[LEAF_STRUCT_Y];
+    float y1 = y - LEAF_SIZE;
+    float y2 = y + LEAF_SIZE;
+
+    float u1 = leafStruct[LEAF_STRUCT_U1];
+    float u2 = leafStruct[LEAF_STRUCT_U2];
+
+    drawQuadTexCoords(x1, y1, 0.0f, u1, 1.0f,
+                      x2, y1, 0.0f, u2, 1.0f,
+                      x2, y2, 0.0f, u2, 0.0f,
+                      x1, y2, 0.0f, u1, 0.0f);
+}
+
+void drawLeaves(int frameCount) {
+    bindProgramFragment(NAMED_PFLeaf);
+    bindProgramFragmentStore(NAMED_PFSLeaf);
+    bindTexture(NAMED_PFLeaf, 0, NAMED_TLeaves);
+
+    int leavesCount = loadI32(RSID_STATE, RSID_LEAVES_COUNT);
+    int count = leavesCount * LEAF_STRUCT_FIELDS_COUNT;
+
+    int i = 0;
+    for ( ; i < count; i += LEAF_STRUCT_FIELDS_COUNT) {
+        drawLeaf(i, frameCount);
+    }
+}
+
 int main(int index) {
+    int frameCount = loadI32(RSID_STATE, RSID_FRAME_COUNT);
+
     int dropX = loadI32(RSID_STATE, RSID_DROP_X);
     if (dropX != -1) {
         int dropY = loadI32(RSID_STATE, RSID_DROP_Y);
@@ -295,7 +345,7 @@
 
     bindTexture(NAMED_PFBackground, 0, NAMED_TRiverbed);
     drawTriangleMesh(NAMED_mesh);
-    
+
     ambient(0.0f, 0.0f, 0.0f, 1.0f);
     diffuse(0.0f, 0.0f, 0.0f, 1.0f);
     specular(0.44f, 0.44f, 0.44f, 1.0f);
@@ -303,16 +353,14 @@
     bindProgramFragment(NAMED_PFLighting);
     drawTriangleMesh(NAMED_mesh);
 
-//    bindProgramVertex(NAMED_PVSky);
-//    bindProgramFragment(NAMED_PFSky);
-//    bindProgramFragmentStore(NAMED_PFSSky);
-//    color(1.0f, 1.0f, 1.0f, 0.30f);
-//    bindTexture(NAMED_PFSky, 0, NAMED_TSky);
-//    drawTriangleMesh(NAMED_mesh);
+    drawLeaves(frameCount);
 
     if (!isRunning) {
         drawNormals();
     }
 
+    frameCount++;
+    storeI32(RSID_STATE, RSID_FRAME_COUNT, frameCount);
+
     return 1;
 }
diff --git a/libs/rs/java/Fall/src/com/android/fall/rs/FallRS.java b/libs/rs/java/Fall/src/com/android/fall/rs/FallRS.java
index 1685a62..36c7daa 100644
--- a/libs/rs/java/Fall/src/com/android/fall/rs/FallRS.java
+++ b/libs/rs/java/Fall/src/com/android/fall/rs/FallRS.java
@@ -33,6 +33,9 @@
 import static android.renderscript.ProgramStore.BlendSrcFunc;
 import static android.renderscript.ProgramFragment.EnvMode.*;
 import static android.renderscript.Element.*;
+import android.graphics.BitmapFactory;
+import android.graphics.Bitmap;
+import static android.util.MathUtils.*;
 
 import java.util.TimeZone;
 
@@ -50,20 +53,39 @@
     private static final int RSID_STATE_DROP_X = 7;
     private static final int RSID_STATE_DROP_Y = 8;
     private static final int RSID_STATE_RUNNING = 9;
+    private static final int RSID_STATE_LEAVES_COUNT = 10;
     
-    private static final int RSID_TEXTURES = 1;
-    private static final int TEXTURES_COUNT = 1;
+    private static final int TEXTURES_COUNT = 2;
+    private static final int LEAVES_TEXTURES_COUNT = 4;
     private static final int RSID_TEXTURE_RIVERBED = 0;
+    private static final int RSID_TEXTURE_LEAVES = 1;
 
-    private static final int RSID_RIPPLE_MAP = 2;
+    private static final int RSID_RIPPLE_MAP = 1;
+    
+    private static final int RSID_REFRACTION_MAP = 2;
 
-    private static final int RSID_REFRACTION_MAP = 3;
+    private static final int RSID_LEAVES = 3;
+    private static final int LEAVES_COUNT = 8;
+    private static final int LEAF_STRUCT_FIELDS_COUNT = 11;
+    private static final int LEAF_STRUCT_X = 0;
+    private static final int LEAF_STRUCT_Y = 1;
+    private static final int LEAF_STRUCT_SCALE = 2;
+    private static final int LEAF_STRUCT_ANGLE = 3;
+    private static final int LEAF_STRUCT_SPIN = 4;
+    private static final int LEAF_STRUCT_U1 = 5;
+    private static final int LEAF_STRUCT_U2 = 6;
+    private static final int LEAF_STRUCT_ALTITUDE = 7;
+    private static final int LEAF_STRUCT_RIPPLED = 8;
+    private static final int LEAF_STRUCT_DELTAX = 9;
+    private static final int LEAF_STRUCT_DELTAY = 10;
 
     private boolean mIsRunning = true;    
     
     private Resources mResources;
     private RenderScript mRS;
 
+    private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options();
+
     private final int mWidth;
     private final int mHeight;
 
@@ -71,15 +93,15 @@
     private Sampler mSampler;
     private ProgramFragment mPfBackground;
     private ProgramFragment mPfLighting;
+    private ProgramFragment mPfLeaf;
     private ProgramStore mPfsBackground;
+    private ProgramStore mPfsLeaf;
     private ProgramVertex mPvBackground;
     private ProgramVertex mPvLines;
     private ProgramVertex.MatrixAllocation mPvOrthoAlloc;
     private Light mLight;
 
-    private Allocation mTexturesIDs;
     private Allocation[] mTextures;
-    private int[] mTextureBufferIDs;
 
     private Allocation mState;
     private RenderScript.TriangleMesh mMesh;
@@ -88,10 +110,14 @@
 
     private Allocation mRippleMap;
     private Allocation mRefractionMap;
+    private Allocation mLeaves;
+    private float mGlHeight;
 
     public FallRS(int width, int height) {
         mWidth = width;
         mHeight = height;
+        mOptionsARGB.inScaled = false;
+        mOptionsARGB.inPreferredConfig = Bitmap.Config.ARGB_8888;
     }
 
     public void init(RenderScript rs, Resources res) {
@@ -107,18 +133,19 @@
         mPfsBackground.destroy();
         mPvBackground.destroy();
         mPvOrthoAlloc.mAlloc.destroy();
-        mTexturesIDs.destroy();
         for (Allocation a : mTextures) {
             a.destroy();
         }
         mState.destroy();
-        mTextureBufferIDs = null;
         mMesh.destroy();
         mLight.destroy();
         mRippleMap.destroy();
         mRefractionMap.destroy();
         mPvLines.destroy();
         mPfLighting.destroy();
+        mLeaves.destroy();
+        mPfsLeaf.destroy();
+        mPfLeaf.destroy();
     }
 
     @Override
@@ -146,9 +173,9 @@
         mScript.setTimeZone(TimeZone.getDefault().getID());
 
         mScript.bindAllocation(mState, RSID_STATE);
-        mScript.bindAllocation(mTexturesIDs, RSID_TEXTURES);
         mScript.bindAllocation(mRippleMap, RSID_RIPPLE_MAP);
         mScript.bindAllocation(mRefractionMap, RSID_REFRACTION_MAP);
+        mScript.bindAllocation(mLeaves, RSID_LEAVES);
 
         mRS.contextBindRootScript(mScript);
     }
@@ -171,15 +198,15 @@
             hResolution = MESH_RESOLUTION;
         }
 
-        final float glHeight = 2.0f * height / (float) width;
+        mGlHeight = 2.0f * height / (float) width;
         final float quadWidth = 2.0f / (float) wResolution;
-        final float quadHeight = glHeight / (float) hResolution;
+        final float quadHeight = mGlHeight / (float) hResolution;
 
         wResolution += 2;
         hResolution += 2;        
         
         for (int y = 0; y <= hResolution; y++) {
-            final float yOffset = y * quadHeight - glHeight / 2.0f - quadHeight;
+            final float yOffset = y * quadHeight - mGlHeight / 2.0f - quadHeight;
             final float t = 1.0f - y / (float) hResolution;
             for (int x = 0; x <= wResolution; x++) {
                 rs.triangleMeshAddVertex_XYZ_ST_NORM(
@@ -208,7 +235,7 @@
     private void createScriptStructures() {
         final int rippleMapSize = (mMeshWidth + 2) * (mMeshHeight + 2);
 
-        final int[] data = new int[10];
+        final int[] data = new int[11];
         mState = Allocation.createSized(mRS, USER_I32, data.length);
         data[RSID_STATE_FRAMECOUNT] = 0;
         data[RSID_STATE_WIDTH] = mWidth;
@@ -220,6 +247,7 @@
         data[RSID_STATE_DROP_X] = mMeshWidth / 2;
         data[RSID_STATE_DROP_Y] = mMeshHeight / 2;
         data[RSID_STATE_RUNNING] = 1;
+        data[RSID_STATE_LEAVES_COUNT] = LEAVES_COUNT;
         mState.data(data);
 
         final int[] rippleMap = new int[rippleMapSize * 2];
@@ -233,26 +261,43 @@
         }
         mRefractionMap = Allocation.createSized(mRS, USER_I32, refractionMap.length);
         mRefractionMap.data(refractionMap);
+
+        final float[] leaves = new float[LEAVES_COUNT * LEAF_STRUCT_FIELDS_COUNT];
+        mLeaves = Allocation.createSized(mRS, USER_FLOAT, leaves.length);
+        for (int i = 0; i < leaves.length; i += LEAF_STRUCT_FIELDS_COUNT) {
+            createLeaf(leaves, i);
+        }
+        mLeaves.data(leaves);
+    }
+
+    private void createLeaf(float[] leaves, int index) {
+        int sprite = random(LEAVES_TEXTURES_COUNT);
+        //noinspection PointlessArithmeticExpression
+        leaves[index + LEAF_STRUCT_X] = random(-1.0f, 1.0f);
+        leaves[index + LEAF_STRUCT_Y] = random(-mGlHeight / 2.0f, mGlHeight / 2.0f);
+        leaves[index + LEAF_STRUCT_SCALE] = random(0.3f, 0.4f);
+        leaves[index + LEAF_STRUCT_ANGLE] = random(0.0f, (float) (Math.PI * 2.0));
+        leaves[index + LEAF_STRUCT_SPIN] = random(-0.02f, 0.02f);
+        leaves[index + LEAF_STRUCT_U1] = sprite / (float) LEAVES_TEXTURES_COUNT;
+        leaves[index + LEAF_STRUCT_U2] = (sprite + 1) / (float) LEAVES_TEXTURES_COUNT;
+        leaves[index + LEAF_STRUCT_ALTITUDE] = 0.2f;
+        leaves[index + LEAF_STRUCT_RIPPLED] = -1.0f;
+        leaves[index + LEAF_STRUCT_DELTAX] = random(-0.02f, 0.02f) / 100.0f;
+        leaves[index + LEAF_STRUCT_DELTAY] = 0.08f * random(0.9f, 1.1f) / 100.0f;
     }
 
     private void loadTextures() {
-        mTextureBufferIDs = new int[TEXTURES_COUNT];
         mTextures = new Allocation[TEXTURES_COUNT];
-        mTexturesIDs = Allocation.createSized(mRS, USER_FLOAT, TEXTURES_COUNT);
 
         final Allocation[] textures = mTextures;
         textures[RSID_TEXTURE_RIVERBED] = loadTexture(R.drawable.riverbed, "TRiverbed");
+        textures[RSID_TEXTURE_LEAVES] = loadTextureARGB(R.drawable.leaves, "TLeaves");
 
-        final int[] bufferIds = mTextureBufferIDs;
         final int count = textures.length;
-
         for (int i = 0; i < count; i++) {
             final Allocation texture = textures[i];
             texture.uploadToTexture(0);
-            bufferIds[i] = texture.getID();
         }
-
-        mTexturesIDs.data(bufferIds);
     }
 
     private Allocation loadTexture(int id, String name) {
@@ -262,6 +307,13 @@
         return allocation;
     }
 
+    private Allocation loadTextureARGB(int id, String name) {
+        Bitmap b = BitmapFactory.decodeResource(mResources, id, mOptionsARGB);
+        final Allocation allocation = Allocation.createFromBitmap(mRS, b, RGBA_8888, false);
+        allocation.setName(name);
+        return allocation;
+    }    
+
     private void createProgramFragment() {
         Sampler.Builder sampleBuilder = new Sampler.Builder(mRS);
         sampleBuilder.setMin(LINEAR);
@@ -276,12 +328,19 @@
         mPfBackground = builder.create();
         mPfBackground.setName("PFBackground");
         mPfBackground.bindSampler(mSampler, 0);
-        
+
         builder = new ProgramFragment.Builder(mRS, null, null);
         builder.setTexEnable(false, 0);
         mPfLighting = builder.create();
         mPfLighting.setName("PFLighting");
         mPfLighting.bindSampler(mSampler, 0);
+        
+        builder = new ProgramFragment.Builder(mRS, null, null);
+        builder.setTexEnable(true, 0);
+        builder.setTexEnvMode(REPLACE, 0);
+        mPfLeaf = builder.create();
+        mPfLeaf.setName("PFLeaf");
+        mPfLeaf.bindSampler(mSampler, 0);
     }
 
     private void createProgramFragmentStore() {
@@ -292,6 +351,14 @@
         builder.setDepthMask(true);
         mPfsBackground = builder.create();
         mPfsBackground.setName("PFSBackground");
+
+        builder = new ProgramStore.Builder(mRS, null, null);
+        builder.setDepthFunc(ALWAYS);
+        builder.setBlendFunc(BlendSrcFunc.SRC_ALPHA, BlendDstFunc.ONE_MINUS_SRC_ALPHA);
+        builder.setDitherEnable(true);
+        builder.setDepthMask(true);
+        mPfsLeaf = builder.create();
+        mPfsLeaf.setName("PFSLeaf");
     }
 
     private void createProgramVertex() {
diff --git a/libs/rs/java/Grass/res/raw/grass.c b/libs/rs/java/Grass/res/raw/grass.c
index 59c6d9a..1490012 100644
--- a/libs/rs/java/Grass/res/raw/grass.c
+++ b/libs/rs/java/Grass/res/raw/grass.c
@@ -23,14 +23,7 @@
 #define RSID_WIDTH 2
 #define RSID_HEIGHT 3
 
-#define RSID_TEXTURES 1
-#define RSID_SKY_TEXTURE_NIGHT 0
-#define RSID_SKY_TEXTURE_SUNRISE 1
-#define RSID_SKY_TEXTURE_NOON 2
-#define RSID_SKY_TEXTURE_SUNSET 3
-#define RSID_GRASS_TEXTURE 4
-
-#define RSID_BLADES 2
+#define RSID_BLADES 1
 #define BLADE_STRUCT_FIELDS_COUNT 12
 #define BLADE_STRUCT_ANGLE 0
 #define BLADE_STRUCT_SIZE 1
diff --git a/libs/rs/java/Grass/src/com/android/grass/rs/GrassRS.java b/libs/rs/java/Grass/src/com/android/grass/rs/GrassRS.java
index 6c17967..7af600f 100644
--- a/libs/rs/java/Grass/src/com/android/grass/rs/GrassRS.java
+++ b/libs/rs/java/Grass/src/com/android/grass/rs/GrassRS.java
@@ -43,10 +43,9 @@
     private static final int RSID_STATE_WIDTH = 2;
     private static final int RSID_STATE_HEIGHT = 3;
 
-    private static final int RSID_TEXTURES = 1;
     private static final int TEXTURES_COUNT = 5;
 
-    private static final int RSID_BLADES = 2;
+    private static final int RSID_BLADES = 1;
     private static final int BLADES_COUNT = 100;
     private static final int BLADE_STRUCT_FIELDS_COUNT = 12;
     private static final int BLADE_STRUCT_ANGLE = 0;
@@ -75,9 +74,7 @@
     private ProgramVertex mPvBackground;
     private ProgramVertex.MatrixAllocation mPvOrthoAlloc;
 
-    private Allocation mTexturesIDs;
     private Allocation[] mTextures;
-    private int[] mTextureBufferIDs;
 
     private Allocation mState;
     private Allocation mBlades;
@@ -100,13 +97,11 @@
         mPfsBackground.destroy();
         mPvBackground.destroy();
         mPvOrthoAlloc.mAlloc.destroy();
-        mTexturesIDs.destroy();
         for (Allocation a : mTextures) {
             a.destroy();
         }
         mState.destroy();
         mBlades.destroy();
-        mTextureBufferIDs = null;
     }
 
     @Override
@@ -133,7 +128,6 @@
         mScript.setTimeZone(TimeZone.getDefault().getID());
 
         mScript.bindAllocation(mState, RSID_STATE);
-        mScript.bindAllocation(mTexturesIDs, RSID_TEXTURES);
         mScript.bindAllocation(mBlades, RSID_BLADES);
 
         mRS.contextBindRootScript(mScript);
@@ -173,9 +167,7 @@
     }
 
     private void loadTextures() {
-        mTextureBufferIDs = new int[TEXTURES_COUNT];
         mTextures = new Allocation[TEXTURES_COUNT];
-        mTexturesIDs = Allocation.createSized(mRS, USER_FLOAT, TEXTURES_COUNT);
 
         final Allocation[] textures = mTextures;
         textures[0] = loadTexture(R.drawable.night, "TNight");
@@ -184,16 +176,11 @@
         textures[3] = loadTexture(R.drawable.sunset, "TSunset");
         textures[4] = generateTextureAlpha(4, 1, new int[] { 0x00FFFF00 }, "TAa");
 
-        final int[] bufferIds = mTextureBufferIDs;
         final int count = textures.length;
-
         for (int i = 0; i < count; i++) {
             final Allocation texture = textures[i];
             texture.uploadToTexture(0);
-            bufferIds[i] = texture.getID();
         }
-
-        mTexturesIDs.data(bufferIds);
     }
 
     private Allocation generateTextureAlpha(int width, int height, int[] data, String name) {
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
index 813af5d..87ddf58 100644
--- a/libs/rs/rsScriptC_Lib.cpp
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -202,6 +202,11 @@
     return v * v; 
 }
 
+static int SC_sqr(int v)
+{
+    return v * v;
+}
+
 static float SC_distf2(float x1, float y1, float x2, float y2)
 {
     float x = x2 - x1;
@@ -562,22 +567,25 @@
     glDrawArrays(GL_LINES, 0, 2);
 }
 
-static void SC_drawQuad(float x1, float y1, float z1,
-                        float x2, float y2, float z2,
-                        float x3, float y3, float z3,
-                        float x4, float y4, float z4)
+static void SC_drawQuadTexCoords(float x1, float y1, float z1,
+                                 float u1, float v1,
+                                 float x2, float y2, float z2,
+                                 float u2, float v2,
+                                 float x3, float y3, float z3,
+                                 float u3, float v3,
+                                 float x4, float y4, float z4,
+                                 float u4, float v4)
 {
     GET_TLS();
-
+    
     //LOGE("Quad");
     //LOGE("%4.2f, %4.2f, %4.2f", x1, y1, z1);
     //LOGE("%4.2f, %4.2f, %4.2f", x2, y2, z2);
     //LOGE("%4.2f, %4.2f, %4.2f", x3, y3, z3);
     //LOGE("%4.2f, %4.2f, %4.2f", x4, y4, z4);
-
+    
     float vtx[] = {x1,y1,z1, x2,y2,z2, x3,y3,z3, x4,y4,z4};
-    static const float tex[] = {0,1, 1,1, 1,0, 0,0};
-
+    const float tex[] = {u1,v1, u2,v2, u3,v3, u4,v4};
 
     rsc->setupCheck();
 
@@ -603,6 +611,17 @@
     glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
 }
 
+static void SC_drawQuad(float x1, float y1, float z1,
+                        float x2, float y2, float z2,
+                        float x3, float y3, float z3,
+                        float x4, float y4, float z4)
+{
+    SC_drawQuadTexCoords(x1, y1, z1, 0, 1,
+                         x2, y2, z2, 1, 1,
+                         x3, y3, z3, 1, 0,
+                         x4, y4, z4, 0, 0);
+}
+
 static void SC_drawRect(float x1, float y1,
                         float x2, float y2, float z)
 {
@@ -765,6 +784,10 @@
         "void", "(int)" },
 
     // math
+    { "abs", (void *)&abs,
+        "int", "(int)" },
+    { "absf", (void *)&fabs,
+        "float", "(float)" },
     { "sinf", (void *)&sinf,
         "float", "(float)" },
     { "cosf", (void *)&cosf,
@@ -797,8 +820,12 @@
         "float", "(float, float)" },
     { "minf", (void *)&SC_minf,
         "float", "(float, float)" },
+    { "sqrt", (void *)&sqrt,
+        "int", "(int)" },
     { "sqrtf", (void *)&sqrtf,
         "float", "(float)" },
+    { "sqr", (void *)&SC_sqr,
+        "int", "(int)" },
     { "sqrf", (void *)&SC_sqrf,
         "float", "(float)" },
     { "clampf", (void *)&SC_clampf,
@@ -895,6 +922,8 @@
         "void", "(float x1, float y1, float x2, float y2, float z)" },
     { "drawQuad", (void *)&SC_drawQuad,
         "void", "(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float x4, float y4, float z4)" },
+    { "drawQuadTexCoords", (void *)&SC_drawQuadTexCoords,
+        "void", "(float x1, float y1, float z1, float u1, float v1, float x2, float y2, float z2, float u2, float v2, float x3, float y3, float z3, float u3, float v3, float x4, float y4, float z4, float u4, float v4)" },
     { "drawTriangleArray", (void *)&SC_drawTriangleArray,
         "void", "(int ialloc, int count)" },
     { "drawTriangleMesh", (void *)&SC_drawTriangleMesh,