am 01d49d70: Fix http://b/2352067 .

Merge commit '01d49d700e55c3c32b8b1bc2c816be6cc76e6409'

* commit '01d49d700e55c3c32b8b1bc2c816be6cc76e6409':
  Fix http://b/2352067 .
diff --git a/Android.mk b/Android.mk
index 72859b0..9711570 100644
--- a/Android.mk
+++ b/Android.mk
@@ -17,7 +17,7 @@
 LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 
-# LOCAL_MODULE_TAGS := user
+LOCAL_MODULE_TAGS := optional
 
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
diff --git a/res/raw/fall.rs b/res/raw/fall.rs
index e5cd67b..2c9ce96 100644
--- a/res/raw/fall.rs
+++ b/res/raw/fall.rs
@@ -174,13 +174,13 @@
     v = vert;
     for (y = 0; y < height; y += 1) {
         for (x = 0; x < width; x += 1) {
-            struct vec3_s n1, n2, n3;
-            vec3Sub(&n1, (struct vec3_s *)&(v+1)->x, (struct vec3_s *)&v->x);
-            vec3Sub(&n2, (struct vec3_s *)&(v+width)->x, (struct vec3_s *)&v->x);
+            struct vecF32_3_s n1, n2, n3;
+            vec3Sub(&n1, (struct vecF32_3_s *)&(v+1)->x, (struct vecF32_3_s *)&v->x);
+            vec3Sub(&n2, (struct vecF32_3_s *)&(v+width)->x, (struct vecF32_3_s *)&v->x);
             vec3Cross(&n3, &n1, &n2);
 
             // Average of previous normal and N1 x N2
-            vec3Sub(&n1, (struct vec3_s *)&(v+width+1)->x, (struct vec3_s *)&v->x);
+            vec3Sub(&n1, (struct vecF32_3_s *)&(v+width+1)->x, (struct vecF32_3_s *)&v->x);
             vec3Cross(&n2, &n1, &n2);
             vec3Add(&n3, &n3, &n2);
             //vec3Norm(&n3);  // Not necessary for our constrained mesh.
diff --git a/res/raw/galaxy.rs b/res/raw/galaxy.rs
index 7c97de0..f37dc6d 100644
--- a/res/raw/galaxy.rs
+++ b/res/raw/galaxy.rs
@@ -13,7 +13,7 @@
 // limitations under the License.
 
 #pragma version(1)
-#pragma stateVertex(PVBackground)
+#pragma stateVertex(PVBkOrtho)
 #pragma stateRaster(parent)
 #pragma stateFragment(PFBackground)
 #pragma stateStore(PFSBackground)
@@ -51,25 +51,30 @@
     return x1 * w;
 }
 
+float gSpeed[12000];
+
 /**
  * Generates the properties for a given star.
  */
-void createParticle(struct Stars_s *star, struct Particles_s *part, float scale) {
+void createParticle(struct Particles_s *part, int idx, float scale) {
     float d = fabsf(randomGauss()) * State->galaxyRadius * 0.5f + randf(64.0f);
     float id = d / State->galaxyRadius;
     float z = randomGauss() * 0.4f * (1.0f - id);
     float p = -d * ELLIPSE_TWIST;
 
+    int r,g,b,a;
     if (d < State->galaxyRadius * 0.33f) {
-        part->r = (int) (220 + id * 35);
-        part->g = 220;
-        part->b = 220;
+        r = (int) (220 + id * 35);
+        g = 220;
+        b = 220;
     } else {
-        part->r= 180;
-        part->g = 180;
-        part->b = (int) clampf(140.f + id * 115.f, 140.f, 255.f);
+        r = 180;
+        g = 180;
+        b = (int) clampf(140.f + id * 115.f, 140.f, 255.f);
     }
-    part->a = (int) (140 + (1.0f - id) * 115);
+    // Stash point size * 10 in Alpha
+    a = (int) (randf2(1.2f, 2.1f) * 60);
+    part->color = r | g<<8 | b<<16 | a<<24;
 
     if (d > State->galaxyRadius * 0.15f) {
         z *= 0.6f * (1.0f - id);
@@ -80,14 +85,11 @@
     // Map to the projection coordinates (viewport.x = -1.0 -> 1.0)
     d = mapf(-4.0f, State->galaxyRadius + 4.0f, 0.0f, scale, d);
 
-    star->angle = randf(TWO_PI);
-    star->distance = d;
-    star->speed = randf2(0.0015f, 0.0025f) * (0.5f + (scale / d)) * 0.8f;
-    star->s = cosf(p);
-    star->t = sinf(p);
+    part->position.x = randf(TWO_PI);
+    part->position.y = d;
+    gSpeed[idx] = randf2(0.0015f, 0.0025f) * (0.5f + (scale / d)) * 0.8f;
 
-    part->z = z / 5.0f;
-    part->pointSize = randf2(1.2f, 2.1f) * 6;
+    part->position.z = z / 5.0f;
 }
 
 /**
@@ -98,15 +100,13 @@
         angle = 0.0f;
     }
 
-    struct Stars_s *star = Stars;
     struct Particles_s *part = Particles;
     int particlesCount = State->particlesCount;
     float scale = State->galaxyRadius / (State->width * 0.5f);
 
     int i;
     for (i = 0; i < particlesCount; i ++) {
-        createParticle(star, part, scale);
-        star++;
+        createParticle(part, i, scale);
         part++;
     }
 }
@@ -121,7 +121,7 @@
 }
 
 void drawLights(float xOffset, int width, int height) {
-    bindProgramVertex(NAMED_PVStars);
+    bindProgramVertex(NAMED_PVBkProj);
     bindProgramFragment(NAMED_PFBackground);
     bindTexture(NAMED_PFBackground, 0, NAMED_TLight1);
 
@@ -158,26 +158,16 @@
     vpLoadModelMatrix(matrix);
 
     // quadratic attenuation
-    pointAttenuation(0.1f + 0.3f * fabsf(offset), 0.0f, 0.06f  + 0.1f *  fabsf(offset));
+    //pointAttenuation(0.1f + 0.3f * fabsf(offset), 0.0f, 0.06f  + 0.1f *  fabsf(offset));
 
     int radius = State->galaxyRadius;
     int particlesCount = State->particlesCount;
 
-    struct Stars_s *star = Stars;
     struct Particles_s *vtx = Particles;
 
     int i = 0;
     for ( ; i < particlesCount; i++) {
-        float a = star->angle + star->speed;
-        float x = star->distance * sinf(a);
-        float y = star->distance * cosf(a) * ELLIPSE_RATIO;
-
-        vtx->x = star->t * x + star->s * y + xOffset;
-        vtx->y = star->s * x - star->t * y;
-
-        star->angle = a;
-
-        star++;
+        vtx->position.x = vtx->position.x + gSpeed[i];
         vtx++;
     }
 
diff --git a/res/raw/grass.rs b/res/raw/grass.rs
index f963791..563af1c 100644
--- a/res/raw/grass.rs
+++ b/res/raw/grass.rs
@@ -17,25 +17,8 @@
 #pragma stateFragment(PFBackground)
 #pragma stateStore(PFSBackground)
 
-#define RSID_STATE 0
-#define RSID_BLADES 1
 #define RSID_BLADES_BUFFER 2
 
-#define BLADE_STRUCT_FIELDS_COUNT 13
-#define BLADE_STRUCT_ANGLE 0
-#define BLADE_STRUCT_SIZE 1
-#define BLADE_STRUCT_XPOS 2
-#define BLADE_STRUCT_YPOS 3
-#define BLADE_STRUCT_OFFSET 4
-#define BLADE_STRUCT_SCALE 5
-#define BLADE_STRUCT_LENGTHX 6
-#define BLADE_STRUCT_LENGTHY 7
-#define BLADE_STRUCT_HARDNESS 8
-#define BLADE_STRUCT_H 9
-#define BLADE_STRUCT_S 10
-#define BLADE_STRUCT_B 11
-#define BLADE_STRUCT_TURBULENCEX 12
-
 #define TESSELATION 0.5f
 #define HALF_TESSELATION 0.25f
 
@@ -48,6 +31,21 @@
 
 #define REAL_TIME 1
 
+void updateBlades()
+{
+    int bladesCount = State->bladesCount;
+    struct Blades_s *bladeStruct = Blades;
+
+    int i;
+    for (i = 0; i < bladesCount; i ++) {
+        float xpos = randf2(-State->width, State->width);
+        bladeStruct->xPos = xpos;
+        bladeStruct->turbulencex = xpos * 0.006f;
+        bladeStruct->yPos = State->height;
+        bladeStruct++;
+    }
+}
+
 float time(int isPreview) {
     if (REAL_TIME && !isPreview) {
         return (hour() * 3600.0f + minute() * 60.0f + second()) / SECONDS_IN_DAY;
@@ -88,91 +86,62 @@
     drawRect(0.0f, 0.0f, width, height, 0.0f);
 }
 
-int drawBlade(float *bladeStruct, float *bladeBuffer, int *bladeColor,
+int drawBlade(struct Blades_s *bladeStruct, float *bladeBuffer, int *bladeColor,
         float brightness, float xOffset, float now) {
 
-    float offset = bladeStruct[BLADE_STRUCT_OFFSET];
-    float scale = bladeStruct[BLADE_STRUCT_SCALE];
-    float angle = bladeStruct[BLADE_STRUCT_ANGLE];
-    float hardness = bladeStruct[BLADE_STRUCT_HARDNESS];
-    float turbulenceX = bladeStruct[BLADE_STRUCT_TURBULENCEX];
+    float scale = bladeStruct->scale;
+    float angle = bladeStruct->angle;
+    float xpos = bladeStruct->xPos + xOffset;
+    int size = bladeStruct->size;
 
-    float xpos = bladeStruct[BLADE_STRUCT_XPOS] + xOffset;
-    float ypos = bladeStruct[BLADE_STRUCT_YPOS];
+    int color = hsbToAbgr(bladeStruct->h, bladeStruct->s,
+                          lerpf(0, bladeStruct->b, brightness), 1.0f);
 
-    float lengthX = bladeStruct[BLADE_STRUCT_LENGTHX];
-    float lengthY = bladeStruct[BLADE_STRUCT_LENGTHY];
-
-    int size = bladeStruct[BLADE_STRUCT_SIZE];
-
-    float h = bladeStruct[BLADE_STRUCT_H];
-    float s = bladeStruct[BLADE_STRUCT_S];
-    float b = bladeStruct[BLADE_STRUCT_B];
-
-    int color = hsbToAbgr(h, s, lerpf(0, b, brightness), 1.0f);
-
-    float newAngle = (turbulencef2(turbulenceX, now, 4.0f) - 0.5f) * 0.5f;
-    angle = clampf(angle + (newAngle + offset - angle) * 0.15f, -MAX_BEND, MAX_BEND);
+    float newAngle = (turbulencef2(bladeStruct->turbulencex, now, 4.0f) - 0.5f) * 0.5f;
+    angle = clampf(angle + (newAngle + bladeStruct->offset - angle) * 0.15f, -MAX_BEND, MAX_BEND);
 
     float currentAngle = HALF_PI;
 
     float bottomX = xpos;
-    float bottomY = ypos;
+    float bottomY = bladeStruct->yPos;
 
-    float d = angle * hardness;
+    float d = angle * bladeStruct->hardness;
 
-    int triangles = size * 2;
+
+    float si = size * scale;
+    float bottomLeft = bottomX - si;
+    float bottomRight = bottomX + si;
+    float bottom = bottomY + HALF_TESSELATION;
+
+    bladeColor[0] = color;                          // V1.ABGR
+    bladeBuffer[1] = bottomLeft;                    // V1.X
+    bladeBuffer[2] = bottom;                        // V1.Y
+    bladeColor[5] = color;                          // V2.ABGR
+    bladeBuffer[6] = bottomRight;                   // V2.X
+    bladeBuffer[7] = bottom;                        // V2.Y
+    bladeBuffer += 10;
+    bladeColor += 10;
 
     for ( ; size > 0; size -= 1) {
-        float topX = bottomX - cosf_fast(currentAngle) * lengthX;
-        float topY = bottomY - sinf_fast(currentAngle) * lengthY;
+        float topX = bottomX - cosf_fast(currentAngle) * bladeStruct->lengthX;
+        float topY = bottomY - sinf_fast(currentAngle) * bladeStruct->lengthY;
 
-        float si = size * scale;
+        si = (float)size * scale;
         float spi = si - scale;
 
-        float bottomLeft = bottomX - si;
-        float bottomRight = bottomX + si;
         float topLeft = topX - spi;
         float topRight = topX + spi;
-        float bottom = bottomY + HALF_TESSELATION;
-
-        // First triangle
-        bladeColor[0] = color;                          // V1.ABGR
-
-        bladeBuffer[1] = bottomLeft;                    // V1.X
-        bladeBuffer[2] = bottom;                        // V1.Y
-
-        bladeColor[5] = color;                          // V1.ABGR
-
-        bladeBuffer[6] = topLeft;                       // V2.X
-        bladeBuffer[7] = topY;                          // V2.Y
-
-        bladeColor[10] = color;                         // V3.ABGR
-
-        bladeBuffer[11] = topRight;                     // V3.X
-        bladeBuffer[12] = topY;                         // V3.Y
-
-        // Second triangle
-        bladeBuffer += 15;
-        bladeColor += 15;
 
         bladeColor[0] = color;                          // V1.ABGR
+        bladeBuffer[1] = topLeft;                       // V2.X
+        bladeBuffer[2] = topY;                          // V2.Y
 
-        bladeBuffer[1] = bottomLeft;                    // V1.X
-        bladeBuffer[2] = bottom;                        // V1.Y
+        bladeColor[5] = color;                         // V3.ABGR
+        bladeBuffer[6] = topRight;                     // V3.X
+        bladeBuffer[7] = topY;                         // V3.Y
 
-        bladeColor[5] = color;                          // V2.ABGR
-
-        bladeBuffer[6] = topRight;                      // V2.X
-        bladeBuffer[7] = topY;                          // V2.Y
-
-        bladeColor[10] = color;                         // V3.ABGR
-
-        bladeBuffer[11] = bottomRight;                  // V3.X
-        bladeBuffer[12] = bottom;                       // V3.Y
-
-        bladeBuffer += 15;
-        bladeColor += 15;
+        bladeBuffer += 10;
+        bladeColor += 10;
 
         bottomX = topX;
         bottomY = topY;
@@ -180,21 +149,20 @@
         currentAngle += d;
     }
 
-    bladeStruct[BLADE_STRUCT_ANGLE] = angle;
+    bladeStruct->angle = angle;
 
-    // 3 vertices per triangle, 5 properties per vertex (RGBA, X, Y, S, T)
-    return triangles * 15;
+    // 2 vertices per triangle, 5 properties per vertex (RGBA, X, Y, S, T)
+    return bladeStruct->size * 10 + 10;
 }
 
 void drawBlades(float brightness, float xOffset) {
     // For anti-aliasing
-    bindTexture(NAMED_PFBackground, 0, NAMED_TAa);
+    bindTexture(NAMED_PFGrass, 0, NAMED_TAa);
 
     int bladesCount = State->bladesCount;
-    int trianglesCount = State->trianglesCount;
 
     int i = 0;
-    float *bladeStruct = loadArrayF(RSID_BLADES, 0);
+    struct Blades_s *bladeStruct = Blades;
     float *bladeBuffer = loadArrayF(RSID_BLADES_BUFFER, 0);
     int *bladeColor = loadArrayI32(RSID_BLADES_BUFFER, 0);
 
@@ -204,11 +172,11 @@
         int offset = drawBlade(bladeStruct, bladeBuffer, bladeColor, brightness, xOffset, now);
         bladeBuffer += offset;
         bladeColor += offset;
-        bladeStruct += BLADE_STRUCT_FIELDS_COUNT;
+        bladeStruct ++;
     }
 
     uploadToBufferObject(NAMED_BladesBuffer);
-    drawSimpleMeshRange(NAMED_BladesMesh, 0, trianglesCount * 3);
+    drawSimpleMeshRange(NAMED_BladesMesh, 0, State->indexCount);
 }
 
 int main(int launchID) {
@@ -262,7 +230,8 @@
         newB = 0.0f;
     }
 
+    bindProgramFragment(NAMED_PFGrass);
     drawBlades(newB, x);
 
-    return 30;
+    return 50;
 }
diff --git a/res/raw/nexus.rs b/res/raw/nexus.rs
index 698529c..0ffaa9b 100644
--- a/res/raw/nexus.rs
+++ b/res/raw/nexus.rs
@@ -267,8 +267,8 @@
     gNow = uptimeMillis();
 
     if (Command->command != 0) {
-        debugF("x", Command->x);
-        debugF("y", Command->y);
+        //debugF("x", Command->x);
+        //debugF("y", Command->y);
         Command->command = 0;
         addTap(Command->x, Command->y);
     }
diff --git a/src/com/android/wallpaper/fall/FallRS.java b/src/com/android/wallpaper/fall/FallRS.java
index 069bedd..3700964 100644
--- a/src/com/android/wallpaper/fall/FallRS.java
+++ b/src/com/android/wallpaper/fall/FallRS.java
@@ -32,7 +32,6 @@
 import static android.renderscript.ProgramStore.DepthFunc.*;
 import static android.renderscript.ProgramStore.BlendDstFunc;
 import static android.renderscript.ProgramStore.BlendSrcFunc;
-import static android.renderscript.ProgramFragment.EnvMode.*;
 import static android.renderscript.Element.*;
 
 import android.app.WallpaperManager;
@@ -114,7 +113,7 @@
         }
         return null;
     }
-    
+
     @Override
     public void start() {
         super.start();
@@ -280,7 +279,7 @@
         mDropState = Allocation.createTyped(mRS, mDropType);
         mDropState.data(mDrop);
     }
-    
+
     private void loadTextures() {
         final Allocation[] textures = new Allocation[TEXTURES_COUNT];
         textures[RSID_TEXTURE_RIVERBED] = loadTexture(R.drawable.pond, "TRiverbed");
@@ -315,16 +314,16 @@
         sampleBuilder.setWrapT(WRAP);
         mSampler = sampleBuilder.create();
 
-        ProgramFragment.Builder builder = new ProgramFragment.Builder(mRS, null, null);
-        builder.setTexEnable(true, 0);
-        builder.setTexEnvMode(REPLACE, 0);
+        ProgramFragment.Builder builder = new ProgramFragment.Builder(mRS);
+        builder.setTexture(ProgramFragment.Builder.EnvMode.REPLACE,
+                           ProgramFragment.Builder.Format.RGBA, 0);
         mPfBackground = builder.create();
         mPfBackground.setName("PFBackground");
         mPfBackground.bindSampler(mSampler, 0);
 
-        builder = new ProgramFragment.Builder(mRS, null, null);
-        builder.setTexEnable(true, 0);
-        builder.setTexEnvMode(MODULATE, 0);
+        builder = new ProgramFragment.Builder(mRS);
+        builder.setTexture(ProgramFragment.Builder.EnvMode.MODULATE,
+                           ProgramFragment.Builder.Format.RGBA, 0);
         mPfSky = builder.create();
         mPfSky.setName("PFSky");
         mPfSky.bindSampler(mSampler, 0);
diff --git a/src/com/android/wallpaper/galaxy/GalaxyRS.java b/src/com/android/wallpaper/galaxy/GalaxyRS.java
index b01dcad..121f2eb 100644
--- a/src/com/android/wallpaper/galaxy/GalaxyRS.java
+++ b/src/com/android/wallpaper/galaxy/GalaxyRS.java
@@ -33,7 +33,6 @@
 import static android.renderscript.ProgramStore.DepthFunc.*;
 import static android.renderscript.ProgramStore.BlendDstFunc;
 import static android.renderscript.ProgramStore.BlendSrcFunc;
-import static android.renderscript.ProgramFragment.EnvMode.*;
 import static android.renderscript.Element.*;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
@@ -67,7 +66,9 @@
     @SuppressWarnings({"FieldCanBeLocal"})
     private ProgramStore mPfsLights;
     @SuppressWarnings({"FieldCanBeLocal"})
-    private ProgramVertex mPvBackground;
+    private ProgramVertex mPvBkOrtho;
+    @SuppressWarnings({"FieldCanBeLocal"})
+    private ProgramVertex mPvBkProj;
     @SuppressWarnings({"FieldCanBeLocal"})
     private ProgramVertex mPvStars;
     @SuppressWarnings({"FieldCanBeLocal"})
@@ -84,7 +85,6 @@
     private GalaxyState mGalaxyState;
     private Type mStateType;
     private Allocation mState;
-    private Allocation mParticles;
     private Type mParticlesType;
     private Allocation mParticlesBuffer;
     @SuppressWarnings({"FieldCanBeLocal"})
@@ -100,11 +100,11 @@
 
     @Override
     protected ScriptC createScript() {
+        createScriptStructures();
         createProgramVertex();
         createProgramRaster();
         createProgramFragmentStore();
         createProgramFragment();
-        createScriptStructures();
         loadTextures();
 
         ScriptC.Builder sb = new ScriptC.Builder(mRS);
@@ -120,7 +120,6 @@
         script.setTimeZone(TimeZone.getDefault().getID());
 
         script.bindAllocation(mState, RSID_STATE);
-        script.bindAllocation(mParticles, RSID_PARTICLES);
         script.bindAllocation(mParticlesBuffer, RSID_PARTICLES_BUFFER);
         mInitParticles.execute();
 
@@ -130,14 +129,12 @@
     private void createScriptStructures() {
         createState();
         createParticlesMesh();
-        createParticles();
     }
 
     private void createParticlesMesh() {
         final Builder elementBuilder = new Builder(mRS);
-        elementBuilder.addUNorm8RGBA("");
-        elementBuilder.addFloatXYZ("");
-        elementBuilder.addFloatPointSize("");
+        elementBuilder.add(Element.createAttrib(mRS, Element.DataType.UNSIGNED_8, Element.DataKind.USER, 4), "color");
+        elementBuilder.add(Element.createAttrib(mRS, Element.DataType.FLOAT_32, Element.DataKind.USER, 3), "position");
         final Element vertexElement = elementBuilder.create();
 
         final SimpleMesh.Builder meshBuilder = new SimpleMesh.Builder(mRS);
@@ -180,14 +177,6 @@
         public int scale;
     }
 
-    static class GalaxyParticle {
-        public float angle;
-        public float distance;
-        public float speed;
-        public float s;
-        public float t;
-    }
-
     private void createState() {
         boolean isPreview = isPreview();
 
@@ -207,11 +196,6 @@
         mState.data(mGalaxyState);
     }
 
-    private void createParticles() {
-        mParticlesType = Type.createFromClass(mRS, GalaxyParticle.class, PARTICLES_COUNT, "Particle");
-        mParticles = Allocation.createTyped(mRS, mParticlesType);
-    }
-
     private void loadTextures() {
         mTextures = new Allocation[TEXTURES_COUNT];
 
@@ -249,9 +233,9 @@
         samplerBuilder.setWrapT(WRAP);
         mSampler = samplerBuilder.create();
 
-        ProgramFragment.Builder builder = new ProgramFragment.Builder(mRS, null, null);
-        builder.setTexEnable(true, 0);
-        builder.setTexEnvMode(REPLACE, 0);
+        ProgramFragment.Builder builder = new ProgramFragment.Builder(mRS);
+        builder.setTexture(ProgramFragment.Builder.EnvMode.REPLACE,
+                           ProgramFragment.Builder.Format.RGB, 0);
         mPfBackground = builder.create();
         mPfBackground.setName("PFBackground");
         mPfBackground.bindSampler(mSampler, 0);
@@ -263,10 +247,10 @@
         samplerBuilder.setWrapT(WRAP);
         mStarSampler = samplerBuilder.create();
 
-        builder = new ProgramFragment.Builder(mRS, null, null);
+        builder = new ProgramFragment.Builder(mRS);
         builder.setPointSpriteTexCoordinateReplacement(true);
-        builder.setTexEnable(true, 0);
-        builder.setTexEnvMode(MODULATE, 0);
+        builder.setTexture(ProgramFragment.Builder.EnvMode.MODULATE,
+                           ProgramFragment.Builder.Format.RGBA, 0);
         mPfStars = builder.create();
         mPfStars.setName("PFStars");
         mPfBackground.bindSampler(mStarSampler, 0);
@@ -294,15 +278,40 @@
         mPvOrthoAlloc.setupOrthoWindow(mWidth, mHeight);
 
         ProgramVertex.Builder builder = new ProgramVertex.Builder(mRS, null, null);
-        mPvBackground = builder.create();
-        mPvBackground.bindAllocation(mPvOrthoAlloc);
-        mPvBackground.setName("PVBackground");
+        mPvBkOrtho = builder.create();
+        mPvBkOrtho.bindAllocation(mPvOrthoAlloc);
+        mPvBkOrtho.setName("PVBkOrtho");
 
         mPvProjectionAlloc = new ProgramVertex.MatrixAllocation(mRS);
         mPvProjectionAlloc.setupProjectionNormalized(mWidth, mHeight);
 
         builder = new ProgramVertex.Builder(mRS, null, null);
-        mPvStars = builder.create();
+        mPvBkProj = builder.create();
+        mPvBkProj.bindAllocation(mPvProjectionAlloc);
+        mPvBkProj.setName("PVBkProj");
+
+        ProgramVertex.ShaderBuilder sb = new ProgramVertex.ShaderBuilder(mRS);
+        String t = new String("void main() {\n" +
+                              "  float dist = ATTRIB_position.y;\n" +
+                              "  float angle = ATTRIB_position.x;\n" +
+                              "  float x = dist * sin(angle);\n" +
+                              "  float y = dist * cos(angle) * 0.892;\n" +
+                              "  float p = dist * 5.5;\n" +
+                              "  float s = cos(p);\n" +
+                              "  float t = sin(p);\n" +
+                              "  vec4 pos;\n" +
+                              "  pos.x = t * x + s * y;\n" +
+                              "  pos.y = s * x - t * y;\n" +
+                              "  pos.z = ATTRIB_position.z;\n" +
+                              "  pos.w = 1.0;\n" +
+                              "  gl_Position = uni_MVP * pos;\n" +
+                              "  gl_PointSize = ATTRIB_color.a * 10.0;\n" +
+                              "  varColor.rgb = ATTRIB_color.rgb;\n" +
+                              "  varColor.a = 1.0;\n" +
+                              "}\n");
+        sb.setShader(t);
+        sb.addInput(mParticlesMesh.getVertexType(0).getElement());
+        mPvStars = sb.create();
         mPvStars.bindAllocation(mPvProjectionAlloc);
         mPvStars.setName("PVStars");
     }
diff --git a/src/com/android/wallpaper/grass/GrassRS.java b/src/com/android/wallpaper/grass/GrassRS.java
index 1fa8ec5..3b604f5 100644
--- a/src/com/android/wallpaper/grass/GrassRS.java
+++ b/src/com/android/wallpaper/grass/GrassRS.java
@@ -17,7 +17,6 @@
 package com.android.wallpaper.grass;
 
 import android.renderscript.Sampler;
-import static android.renderscript.ProgramFragment.EnvMode.*;
 import static android.renderscript.ProgramStore.DepthFunc.*;
 import static android.renderscript.ProgramStore.BlendSrcFunc;
 import static android.renderscript.ProgramStore.BlendDstFunc;
@@ -53,7 +52,7 @@
     @SuppressWarnings({"UnusedDeclaration"})
     private static final String LOG_TAG = "Grass";
     private static final boolean DEBUG = false;
-    
+
     private static final int LOCATION_UPDATE_MIN_TIME = DEBUG ? 5 * 60 * 1000 : 60 * 60 * 1000; // 1 hour
     private static final int LOCATION_UPDATE_MIN_DISTANCE = DEBUG ? 10 : 150 * 1000; // 150 km
 
@@ -63,32 +62,35 @@
     private static final int RSID_STATE = 0;
     private static final int RSID_BLADES = 1;
     private static final int BLADES_COUNT = 200;
-    private static final int BLADE_STRUCT_FIELDS_COUNT = 13;
-    private static final int BLADE_STRUCT_ANGLE = 0;
-    private static final int BLADE_STRUCT_SIZE = 1;
-    private static final int BLADE_STRUCT_XPOS = 2;
-    private static final int BLADE_STRUCT_YPOS = 3;
-    private static final int BLADE_STRUCT_OFFSET = 4;
-    private static final int BLADE_STRUCT_SCALE = 5;
-    private static final int BLADE_STRUCT_LENGTHX = 6;
-    private static final int BLADE_STRUCT_LENGTHY = 7;
-    private static final int BLADE_STRUCT_HARDNESS = 8;
-    private static final int BLADE_STRUCT_H = 9;
-    private static final int BLADE_STRUCT_S = 10;
-    private static final int BLADE_STRUCT_B = 11;
-    private static final int BLADE_STRUCT_TURBULENCEX = 12;
+
+    class BladesStruct {
+        public float angle;
+        public int size;
+        public float xPos;
+        public float yPos;
+        public float offset;
+        public float scale;
+        public float lengthX;
+        public float lengthY;
+        public float hardness;
+        public float h;
+        public float s;
+        public float b;
+        public float turbulencex;
+    };
 
     private static final int RSID_BLADES_BUFFER = 2;
 
+    private ScriptC.Invokable mUpdateBladesInvokable;
     @SuppressWarnings({ "FieldCanBeLocal" })
     private ProgramFragment mPfBackground;
     @SuppressWarnings({ "FieldCanBeLocal" })
+    private ProgramFragment mPfGrass;
+    @SuppressWarnings({ "FieldCanBeLocal" })
     private ProgramStore mPfsBackground;
     @SuppressWarnings({ "FieldCanBeLocal" })
     private ProgramVertex mPvBackground;
     @SuppressWarnings({"FieldCanBeLocal"})
-    private Sampler mSampler;
-    @SuppressWarnings({"FieldCanBeLocal"})
     private ProgramVertex.MatrixAllocation mPvOrthoAlloc;
 
     @SuppressWarnings({ "FieldCanBeLocal" })
@@ -97,13 +99,17 @@
     private Type mStateType;
     private Allocation mState;
 
+    private Type mBladesType;
     private Allocation mBlades;
     private Allocation mBladesBuffer;
+    private Allocation mBladesIndicies;
     @SuppressWarnings({"FieldCanBeLocal"})
     private SimpleMesh mBladesMesh;
 
-    private int mTriangles;
-    private float[] mBladesData;
+
+    private int mVerticies;
+    private int mIndicies;
+    private int[] mBladeSizes;
     private final float[] mFloatData5 = new float[5];
 
     private WorldState mWorldState;
@@ -132,7 +138,7 @@
             filter.addAction(Intent.ACTION_DATE_CHANGED);
             filter.addAction(Intent.ACTION_TIME_CHANGED);
             filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
-    
+
             mContext.registerReceiver(mTimezoneTracker, filter);
         }
 
@@ -153,7 +159,7 @@
             mContext.unregisterReceiver(mTimezoneTracker);
             mTimezoneTracker = null;
         }
-        
+
         if (mLocationUpdater != null) {
             mLocationManager.removeUpdates(mLocationUpdater);
             mLocationUpdater = null;
@@ -168,27 +174,24 @@
         mWorldState.height = height;
         mState.data(mWorldState);
 
-        final float[] blades = mBladesData;
-        for (int i = 0; i < blades.length; i+= BLADE_STRUCT_FIELDS_COUNT) {
-            updateBlade(blades, i);
-        }
-        mBlades.data(blades);
-
-        mPvOrthoAlloc.setupOrthoWindow(width, height);        
+        mUpdateBladesInvokable.execute();
+        mPvOrthoAlloc.setupOrthoWindow(width, height);
     }
 
     @Override
     protected ScriptC createScript() {
         createProgramVertex();
         createProgramFragmentStore();
+        loadTextures();
         createProgramFragment();
         createScriptStructures();
-        loadTextures();
 
         ScriptC.Builder sb = new ScriptC.Builder(mRS);
         sb.setType(mStateType, "State", RSID_STATE);
+        sb.setType(mBladesType, "Blades", RSID_BLADES);
         sb.setScript(mResources, R.raw.grass);
         sb.setRoot(true);
+        mUpdateBladesInvokable = sb.addInvokable("updateBlades");
 
         ScriptC script = sb.create();
         script.setClearColor(0.0f, 0.0f, 0.0f, 1.0f);
@@ -214,7 +217,7 @@
 
     static class WorldState {
         public int bladesCount;
-        public int trianglesCount;
+        public int indexCount;
         public int width;
         public int height;
         public float xOffset;
@@ -232,7 +235,7 @@
         mWorldState.width = mWidth;
         mWorldState.height = mHeight;
         mWorldState.bladesCount = BLADES_COUNT;
-        mWorldState.trianglesCount = mTriangles;
+        mWorldState.indexCount = mIndicies;
         mWorldState.isPreview = isPreview ? 1 : 0;
         if (isPreview) {
             mWorldState.xOffset = 0.5f;
@@ -244,32 +247,35 @@
     }
 
     private void createBlades() {
-        int triangles = 0;
+        mVerticies = 0;
+        mIndicies = 0;
 
-        mBladesData = new float[BLADES_COUNT * BLADE_STRUCT_FIELDS_COUNT];
+        mBladesType = Type.createFromClass(mRS, BladesStruct.class, BLADES_COUNT, "Blade");
+        mBlades = Allocation.createTyped(mRS, mBladesType);
+        BladesStruct bs = new BladesStruct();
 
-        final float[] blades = mBladesData;
-        for (int i = 0; i < blades.length; i+= BLADE_STRUCT_FIELDS_COUNT) {
-            triangles += createBlade(blades, i);
+        mBladeSizes = new int[BLADES_COUNT];
+        for (int i = 0; i < BLADES_COUNT; i++) {
+            createBlade(bs);
+            mIndicies += bs.size * 2 * 3;
+            mVerticies += bs.size + 2;
+            mBlades.subData(i, bs);
+            mBladeSizes[i] = bs.size;
         }
 
-        mBlades = Allocation.createSized(mRS, USER_F32(mRS), blades.length);
-        mBlades.data(blades);
-
-        mTriangles = triangles;
-
-        createMesh(triangles);
+        createMesh();
     }
 
-    private void createMesh(int triangles) {
+    private void createMesh() {
         Builder elementBuilder = new Builder(mRS);
-        elementBuilder.addUNorm8RGBA();
-        elementBuilder.addFloatXY();
-        elementBuilder.addFloatST();
+        elementBuilder.add(Element.ATTRIB_COLOR_U8_4(mRS), "color");
+        elementBuilder.add(Element.ATTRIB_POSITION_2(mRS), "position");
+        elementBuilder.add(Element.ATTRIB_TEXTURE_2(mRS), "texture");
         final Element vertexElement = elementBuilder.create();
 
         final SimpleMesh.Builder meshBuilder = new SimpleMesh.Builder(mRS);
-        final int vertexSlot = meshBuilder.addVertexType(vertexElement, triangles * 3);
+        final int vertexSlot = meshBuilder.addVertexType(vertexElement, mVerticies  * 2);
+        meshBuilder.setIndexType(Element.INDEX_16(mRS), mIndicies);
         meshBuilder.setPrimitive(Primitive.TRIANGLE);
         mBladesMesh = meshBuilder.create();
         mBladesMesh.setName("BladesMesh");
@@ -277,74 +283,65 @@
         mBladesBuffer = mBladesMesh.createVertexAllocation(vertexSlot);
         mBladesBuffer.setName("BladesBuffer");
         mBladesMesh.bindVertexAllocation(mBladesBuffer, 0);
+        mBladesIndicies = mBladesMesh.createIndexAllocation();
+        mBladesMesh.bindIndexAllocation(mBladesIndicies);
 
         // Assign the texture coordinates of each triangle
         final float[] floatData = mFloatData5;
         final Allocation buffer = mBladesBuffer;
 
+        short[] idx = new short[mIndicies];
+
         int bufferIndex = 0;
-        for (int i = 0; i < triangles; i += 2) {
-            floatData[3] = 0.0f;
-            floatData[4] = 1.0f;
-            buffer.subData1D(bufferIndex, 1, floatData);
-            bufferIndex++;
-
+        int i2 = 0;
+        for (int i = 0; i < mVerticies; i +=2) {
             floatData[3] = 0.0f;
             floatData[4] = 0.0f;
-            buffer.subData1D(bufferIndex, 1, floatData);
-            bufferIndex++;
+            buffer.subData1D(bufferIndex++, 1, floatData);
 
             floatData[3] = 1.0f;
             floatData[4] = 0.0f;
-            buffer.subData1D(bufferIndex, 1, floatData);
-            bufferIndex++;
-
-            floatData[3] = 0.0f;
-            floatData[4] = 0.0f;
-            buffer.subData1D(bufferIndex, 1, floatData);
-            bufferIndex++;
-
-            floatData[3] = 1.0f;
-            floatData[4] = 1.0f;
-            buffer.subData1D(bufferIndex, 1, floatData);
-            bufferIndex++;
-
-            floatData[3] = 1.0f;
-            floatData[4] = 0.0f;
-            buffer.subData1D(bufferIndex, 1, floatData);
-            bufferIndex++;
+            buffer.subData1D(bufferIndex++, 1, floatData);
         }
+
+        int idxIdx = 0;
+        int vtxIdx = 0;
+        for (int i = 0; i < mBladeSizes.length; i++) {
+            for (int ct = 0; ct < mBladeSizes[i]; ct ++) {
+                idx[idxIdx + 0] = (short)(vtxIdx + 0);
+                idx[idxIdx + 1] = (short)(vtxIdx + 1);
+                idx[idxIdx + 2] = (short)(vtxIdx + 2);
+                idx[idxIdx + 3] = (short)(vtxIdx + 1);
+                idx[idxIdx + 4] = (short)(vtxIdx + 3);
+                idx[idxIdx + 5] = (short)(vtxIdx + 2);
+                idxIdx += 6;
+                vtxIdx += 2;
+            }
+            vtxIdx += 2;
+        }
+
+        mBladesIndicies.data(idx);
+        mBladesIndicies.uploadToBufferObject();
     }
 
-    private void updateBlade(float[] blades, int index) {
-        final int xpos = random(-mWidth, mWidth);
-        blades[index + BLADE_STRUCT_XPOS] = xpos;
-        blades[index + BLADE_STRUCT_TURBULENCEX] = xpos * 0.006f;
-        blades[index + BLADE_STRUCT_YPOS] = mHeight;
-    }
-
-    private int createBlade(float[] blades, int index) {
+    private void createBlade(BladesStruct blades) {
         final float size = random(4.0f) + 4.0f;
         final int xpos = random(-mWidth, mWidth);
 
         //noinspection PointlessArithmeticExpression
-        blades[index + BLADE_STRUCT_ANGLE] = 0.0f;
-        blades[index + BLADE_STRUCT_SIZE] = size / TESSELATION;
-        blades[index + BLADE_STRUCT_XPOS] = xpos;
-        blades[index + BLADE_STRUCT_YPOS] = mHeight;
-        blades[index + BLADE_STRUCT_OFFSET] = random(0.2f) - 0.1f;
-        blades[index + BLADE_STRUCT_SCALE] = 4.0f / (size / TESSELATION) +
-                (random(0.6f) + 0.2f) * TESSELATION;
-        blades[index + BLADE_STRUCT_LENGTHX] = (random(4.5f) + 3.0f) * TESSELATION * size;
-        blades[index + BLADE_STRUCT_LENGTHY] = (random(5.5f) + 2.0f) * TESSELATION * size;
-        blades[index + BLADE_STRUCT_HARDNESS] = (random(1.0f) + 0.2f) * TESSELATION;
-        blades[index + BLADE_STRUCT_H] = random(0.02f) + 0.2f;
-        blades[index + BLADE_STRUCT_S] = random(0.22f) + 0.78f;
-        blades[index + BLADE_STRUCT_B] = random(0.65f) + 0.35f;
-        blades[index + BLADE_STRUCT_TURBULENCEX] = xpos * 0.006f;
-
-        // Each blade is made of "size" quads, so we double to count the triangles
-        return (int) (blades[index + BLADE_STRUCT_SIZE]) * 2;
+        blades.angle = 0.0f;
+        blades.size = (int)(size / TESSELATION);
+        blades.xPos = xpos;
+        blades.yPos = mHeight;
+        blades.offset = random(0.2f) - 0.1f;
+        blades.scale = 4.0f / (size / TESSELATION) + (random(0.6f) + 0.2f) * TESSELATION;
+        blades.lengthX = (random(4.5f) + 3.0f) * TESSELATION * size;
+        blades.lengthY = (random(5.5f) + 2.0f) * TESSELATION * size;
+        blades.hardness = (random(1.0f) + 0.2f) * TESSELATION;
+        blades.h = random(0.02f) + 0.2f;
+        blades.s = random(0.22f) + 0.78f;
+        blades.b = random(0.65f) + 0.35f;
+        blades.turbulencex = xpos * 0.006f;
     }
 
     private void loadTextures() {
@@ -367,10 +364,21 @@
         final Type.Builder builder = new Type.Builder(mRS, A_8(mRS));
         builder.add(Dimension.X, width);
         builder.add(Dimension.Y, height);
+        builder.add(Dimension.LOD, 1);
 
         final Allocation allocation = Allocation.createTyped(mRS, builder.create());
-        allocation.data(data);
         allocation.setName(name);
+
+        int[] grey1 = new int[] {0x3f3f3f3f};
+        int[] grey2 = new int[] {0x00000000};
+        Allocation.Adapter2D a = allocation.createAdapter2D();
+        a.setConstraint(Dimension.LOD, 0);
+        a.subData(0, 0, 4, 1, data);
+        a.setConstraint(Dimension.LOD, 1);
+        a.subData(0, 0, 2, 1, grey1);
+        a.setConstraint(Dimension.LOD, 2);
+        a.subData(0, 0, 1, 1, grey2);
+
         return allocation;
     }
 
@@ -383,18 +391,29 @@
 
     private void createProgramFragment() {
         Sampler.Builder samplerBuilder = new Sampler.Builder(mRS);
-        samplerBuilder.setMin(LINEAR);
+        samplerBuilder.setMin(LINEAR_MIP_LINEAR);
         samplerBuilder.setMag(LINEAR);
         samplerBuilder.setWrapS(WRAP);
         samplerBuilder.setWrapT(WRAP);
-        mSampler = samplerBuilder.create();
+        Sampler sl = samplerBuilder.create();
 
-        ProgramFragment.Builder builder = new ProgramFragment.Builder(mRS, null, null);
-        builder.setTexEnable(true, 0);
-        builder.setTexEnvMode(REPLACE, 0);
+        samplerBuilder.setMin(NEAREST);
+        samplerBuilder.setMag(NEAREST);
+        Sampler sn = samplerBuilder.create();
+
+        ProgramFragment.Builder builder = new ProgramFragment.Builder(mRS);
+        builder.setTexture(ProgramFragment.Builder.EnvMode.REPLACE,
+                           ProgramFragment.Builder.Format.ALPHA, 0);
+        mPfGrass = builder.create();
+        mPfGrass.setName("PFGrass");
+        mPfGrass.bindSampler(sl, 0);
+
+        builder = new ProgramFragment.Builder(mRS);
+        builder.setTexture(ProgramFragment.Builder.EnvMode.REPLACE,
+                           ProgramFragment.Builder.Format.RGB, 0);
         mPfBackground = builder.create();
         mPfBackground.setName("PFBackground");
-        mPfBackground.bindSampler(mSampler, 0);
+        mPfBackground.bindSampler(sn, 0);
     }
 
     private void createProgramFragmentStore() {
@@ -412,7 +431,6 @@
         mPvOrthoAlloc.setupOrthoWindow(mWidth, mHeight);
 
         ProgramVertex.Builder pvb = new ProgramVertex.Builder(mRS, null, null);
-        pvb.setTextureMatrixEnable(true);
         mPvBackground = pvb.create();
         mPvBackground.bindAllocation(mPvOrthoAlloc);
         mPvBackground.setName("PVBackground");
diff --git a/src/com/android/wallpaper/nexus/NexusRS.java b/src/com/android/wallpaper/nexus/NexusRS.java
index 1f5b6d3..eda1983 100644
--- a/src/com/android/wallpaper/nexus/NexusRS.java
+++ b/src/com/android/wallpaper/nexus/NexusRS.java
@@ -18,8 +18,6 @@
 
 import static android.renderscript.Element.RGBA_8888;
 import static android.renderscript.Element.RGB_565;
-import static android.renderscript.ProgramFragment.EnvMode.MODULATE;
-import static android.renderscript.ProgramFragment.EnvMode.REPLACE;
 import static android.renderscript.ProgramStore.DepthFunc.ALWAYS;
 import static android.renderscript.Sampler.Value.LINEAR;
 import static android.renderscript.Sampler.Value.WRAP;
@@ -210,16 +208,16 @@
         sampleBuilder.setWrapT(WRAP);
         mSampler = sampleBuilder.create();
 
-        ProgramFragment.Builder builder = new ProgramFragment.Builder(mRS, null, null);
-        builder.setTexEnable(true, 0);
-        builder.setTexEnvMode(MODULATE, 0);
+        ProgramFragment.Builder builder = new ProgramFragment.Builder(mRS);
+        builder.setTexture(ProgramFragment.Builder.EnvMode.MODULATE,
+                           ProgramFragment.Builder.Format.RGBA, 0);
         mPfTexture = builder.create();
         mPfTexture.setName("PFTexture");
         mPfTexture.bindSampler(mSampler, 0);
 
-        builder = new ProgramFragment.Builder(mRS, null, null);
-        builder.setTexEnable(true, 0);
-        builder.setTexEnvMode(REPLACE, 0);
+        builder = new ProgramFragment.Builder(mRS);
+        builder.setTexture(ProgramFragment.Builder.EnvMode.REPLACE,
+                           ProgramFragment.Builder.Format.RGB, 0);
         mPfColor = builder.create();
         mPfColor.setName("PFColor");
         mPfColor.bindSampler(mSampler, 0);