First pass at implementing the Grass live wallpaper in RenderScript.

This change also adds second(), minute() and hour() to the RS library.
diff --git a/java/Grass/Android.mk b/java/Grass/Android.mk
new file mode 100644
index 0000000..ce5294e
--- /dev/null
+++ b/java/Grass/Android.mk
@@ -0,0 +1,25 @@
+#
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+#LOCAL_STATIC_JAVA_LIBRARIES := android.renderscript
+
+LOCAL_PACKAGE_NAME := GrassRS
+
+include $(BUILD_PACKAGE)
diff --git a/java/Grass/AndroidManifest.xml b/java/Grass/AndroidManifest.xml
new file mode 100644
index 0000000..a40f378
--- /dev/null
+++ b/java/Grass/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.grass.rs">
+
+    <application android:label="GrassRS">
+
+        <activity
+            android:name="Grass"
+            android:theme="@android:style/Theme.NoTitleBar">
+
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+
+        </activity>
+
+    </application>
+
+</manifest>
diff --git a/java/Grass/res/drawable-hdpi/night.jpg b/java/Grass/res/drawable-hdpi/night.jpg
new file mode 100644
index 0000000..9989abf
--- /dev/null
+++ b/java/Grass/res/drawable-hdpi/night.jpg
Binary files differ
diff --git a/java/Grass/res/drawable-hdpi/sky.jpg b/java/Grass/res/drawable-hdpi/sky.jpg
new file mode 100644
index 0000000..a12fe20
--- /dev/null
+++ b/java/Grass/res/drawable-hdpi/sky.jpg
Binary files differ
diff --git a/java/Grass/res/drawable-hdpi/sunrise.jpg b/java/Grass/res/drawable-hdpi/sunrise.jpg
new file mode 100644
index 0000000..db016b2
--- /dev/null
+++ b/java/Grass/res/drawable-hdpi/sunrise.jpg
Binary files differ
diff --git a/java/Grass/res/drawable-hdpi/sunset.jpg b/java/Grass/res/drawable-hdpi/sunset.jpg
new file mode 100644
index 0000000..49bb0c6
--- /dev/null
+++ b/java/Grass/res/drawable-hdpi/sunset.jpg
Binary files differ
diff --git a/java/Grass/res/raw/grass.c b/java/Grass/res/raw/grass.c
new file mode 100644
index 0000000..50c7675
--- /dev/null
+++ b/java/Grass/res/raw/grass.c
@@ -0,0 +1,84 @@
+// Grass live wallpaper
+
+#pragma version(1)
+#pragma stateVertex(default)
+#pragma stateFragment(PFBackground)
+#pragma stateFragmentStore(PFSBackground)
+
+#define WVGA_PORTRAIT_WIDTH 480.0f
+#define WVGA_PORTRAIT_HEIGHT 762.0f
+
+#define RSID_SKY_TEXTURES 0
+#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 MIDNIGHT 0.0f
+#define MORNING 0.375f
+#define AFTERNOON 0.6f
+#define DUSK 0.8f
+
+float time() {
+    return (second() % 60) / 60.0f;
+}
+
+void alpha(float a) {
+    color(1.0f, 1.0f, 1.0f, a);
+}
+
+float norm(float a, float start, float end) {
+    return (a - start) / (end - start);
+}
+
+void drawNight() {
+    bindTexture(NAMED_PFBackground, 0, loadI32(RSID_SKY_TEXTURES, RSID_SKY_TEXTURE_NIGHT));
+    // NOTE: Hacky way to draw the night sky
+    drawRect(WVGA_PORTRAIT_WIDTH - 512.0f, -32.0f, WVGA_PORTRAIT_WIDTH, 1024.0f - 32.0f, 0.0f);
+}
+
+void drawSunrise() {
+    bindTexture(NAMED_PFBackground, 0, loadI32(RSID_SKY_TEXTURES, RSID_SKY_TEXTURE_SUNRISE));
+    drawRect(0.0f, 0.0f, WVGA_PORTRAIT_WIDTH, WVGA_PORTRAIT_HEIGHT, 0.0f);
+}
+
+void drawNoon() {
+    bindTexture(NAMED_PFBackground, 0, loadI32(RSID_SKY_TEXTURES, RSID_SKY_TEXTURE_NOON));
+    drawRect(0.0f, 0.0f, WVGA_PORTRAIT_WIDTH, WVGA_PORTRAIT_HEIGHT, 0.0f);
+}
+
+void drawSunset() {
+    bindTexture(NAMED_PFBackground, 0, loadI32(RSID_SKY_TEXTURES, RSID_SKY_TEXTURE_SUNSET));
+    drawRect(0.0f, 0.0f, WVGA_PORTRAIT_WIDTH, WVGA_PORTRAIT_HEIGHT, 0.0f);
+}
+
+int main(int launchID) {
+    float now = time();
+    alpha(1.0f);
+
+    if (now >= MIDNIGHT && now < MORNING) {
+        drawNight();
+        alpha(norm(now, MIDNIGHT, MORNING));
+        drawSunrise();
+    }
+    
+    if (now >= MORNING && now < AFTERNOON) {
+        drawSunrise();
+        alpha(norm(now, MORNING, AFTERNOON));
+        drawNoon();
+    }
+
+    if (now >= AFTERNOON && now < DUSK) {
+        drawNoon();
+        alpha(norm(now, AFTERNOON, DUSK));
+        drawSunset();
+    }
+    
+    if (now >= DUSK) {
+        drawSunset();
+        alpha(norm(now, DUSK, 1.0f));
+        drawNight();
+    }
+
+    return 1;
+}
diff --git a/java/Grass/src/com/android/grass/rs/Grass.java b/java/Grass/src/com/android/grass/rs/Grass.java
new file mode 100644
index 0000000..260fcee
--- /dev/null
+++ b/java/Grass/src/com/android/grass/rs/Grass.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.grass.rs;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class Grass extends Activity {
+    private GrassView mView;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        mView = new GrassView(this);
+        setContentView(mView);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        mView.onResume();
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        mView.onPause();
+
+        Runtime.getRuntime().exit(0);
+    }
+}
diff --git a/java/Grass/src/com/android/grass/rs/GrassRS.java b/java/Grass/src/com/android/grass/rs/GrassRS.java
new file mode 100644
index 0000000..9ca7173
--- /dev/null
+++ b/java/Grass/src/com/android/grass/rs/GrassRS.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.grass.rs;
+
+import android.content.res.Resources;
+import android.renderscript.RenderScript;
+import static android.renderscript.RenderScript.ElementPredefined.*;
+import static android.renderscript.RenderScript.SamplerParam.*;
+import static android.renderscript.RenderScript.SamplerValue.*;
+import static android.renderscript.RenderScript.EnvMode.*;
+import static android.renderscript.RenderScript.DepthFunc.*;
+import static android.renderscript.RenderScript.BlendSrcFunc;
+import static android.renderscript.RenderScript.BlendDstFunc;
+import android.graphics.BitmapFactory;
+import android.graphics.Bitmap;
+
+import java.util.TimeZone;
+
+class GrassRS {
+    private static final int RSID_SKY_TEXTURES = 0;
+    private static final int SKY_TEXTURES_COUNT = 4;
+
+    private Resources mResources;
+    private RenderScript mRS;
+
+    @SuppressWarnings({"FieldCanBeLocal"})
+    private RenderScript.Script mScript;
+    @SuppressWarnings({"FieldCanBeLocal"})
+    private RenderScript.Sampler mSampler;
+    @SuppressWarnings({"FieldCanBeLocal"})
+    private RenderScript.ProgramFragment mPfBackground;
+    @SuppressWarnings({"FieldCanBeLocal"})
+    private RenderScript.ProgramFragmentStore mPfsBackground;
+
+    @SuppressWarnings({"FieldCanBeLocal"})
+    private RenderScript.Allocation mSkyTexturesIDs;
+    @SuppressWarnings({"FieldCanBeLocal"})
+    private RenderScript.Allocation[] mSkyTextures;
+    @SuppressWarnings({"FieldCanBeLocal"})
+    private int[] mSkyBufferIDs;
+
+    public GrassRS() {
+    }
+
+    public void init(RenderScript rs, Resources res) {
+        mRS = rs;
+        mResources = res;
+        initRS();
+    }
+
+    private void initRS() {
+        createProgramVertex();
+        createProgramFragmentStore();
+        createProgramFragment();
+        
+        mRS.scriptCBegin();
+        mRS.scriptCSetClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+        mRS.scriptCSetScript(mResources, R.raw.grass);
+        mRS.scriptCSetTimeZone(TimeZone.getDefault().getID());
+        mRS.scriptCSetRoot(true);
+
+        mScript = mRS.scriptCCreate();
+
+        loadSkyTextures();        
+        mScript.bindAllocation(mSkyTexturesIDs, RSID_SKY_TEXTURES);
+
+        mRS.contextBindRootScript(mScript);        
+    }
+
+    private void loadSkyTextures() {
+        mSkyBufferIDs = new int[SKY_TEXTURES_COUNT];
+        mSkyTextures = new RenderScript.Allocation[SKY_TEXTURES_COUNT];
+        mSkyTexturesIDs = mRS.allocationCreatePredefSized(
+                USER_FLOAT, SKY_TEXTURES_COUNT);
+
+        final RenderScript.Allocation[] textures = mSkyTextures;
+        textures[0] = loadTexture(R.drawable.night, "night");
+        textures[1] = loadTexture(R.drawable.sunrise, "sunrise");
+        textures[2] = loadTexture(R.drawable.sky, "sky");
+        textures[3] = loadTexture(R.drawable.sunset, "sunset");
+
+        final int[] bufferIds = mSkyBufferIDs;
+        final int count = textures.length;
+
+        for (int i = 0; i < count; i++) {
+            final RenderScript.Allocation texture = textures[i];
+            texture.uploadToTexture(0);
+            bufferIds[i] = texture.getID();
+        }
+
+        mSkyTexturesIDs.data(bufferIds);
+    }
+
+    private RenderScript.Allocation loadTexture(int id, String name) {
+        RenderScript.Allocation allocation = mRS.allocationCreateFromBitmapResource(mResources, id,
+                RGB_565, false);
+        allocation.setName(name);
+        return allocation;
+    }
+
+    private void createProgramFragment() {
+        mRS.samplerBegin();
+        mRS.samplerSet(FILTER_MIN, LINEAR);
+        mRS.samplerSet(FILTER_MAG, LINEAR);
+        mRS.samplerSet(WRAP_MODE_S, CLAMP);
+        mRS.samplerSet(WRAP_MODE_T, CLAMP);
+        mSampler = mRS.samplerCreate();
+
+        mRS.programFragmentBegin(null, null);
+        mRS.programFragmentSetTexEnable(0, true);
+        mRS.programFragmentSetTexEnvMode(0, REPLACE);
+        mPfBackground = mRS.programFragmentCreate();
+        mPfBackground.setName("PFBackground");
+        mPfBackground.bindSampler(mSampler, 0);
+    }
+
+    private void createProgramFragmentStore() {
+        mRS.programFragmentStoreBegin(null, null);
+        mRS.programFragmentStoreDepthFunc(ALWAYS);
+        mRS.programFragmentStoreBlendFunc(BlendSrcFunc.SRC_ALPHA, BlendDstFunc.ONE_MINUS_SRC_ALPHA);
+        mRS.programFragmentStoreDitherEnable(true);
+        mRS.programFragmentStoreDepthMask(false);
+        mPfsBackground = mRS.programFragmentStoreCreate();
+        mPfsBackground.setName("PFSBackground");
+    }
+
+    private void createProgramVertex() {
+    }
+}
diff --git a/java/Grass/src/com/android/grass/rs/GrassView.java b/java/Grass/src/com/android/grass/rs/GrassView.java
new file mode 100644
index 0000000..a641e1e
--- /dev/null
+++ b/java/Grass/src/com/android/grass/rs/GrassView.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.grass.rs;
+
+import android.content.Context;
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+import android.view.SurfaceHolder;
+
+class GrassView extends RSSurfaceView {
+    public GrassView(Context context) {
+        super(context);
+    }
+
+    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
+        super.surfaceChanged(holder, format, w, h);
+
+        RenderScript RS = createRenderScript();
+        GrassRS render = new GrassRS();
+        render.init(RS, getResources());
+    }
+}
diff --git a/rs.spec b/rs.spec
index 45e6d1b..d9a6456 100644
--- a/rs.spec
+++ b/rs.spec
@@ -280,6 +280,11 @@
 	param float a
 	}
 
+ScriptCSetTimeZone {
+	param const char * timeZone
+	param uint32_t length
+	}
+
 ScriptCSetClearDepth {
 	param float depth
 	}
diff --git a/rsScript.h b/rsScript.h
index 7dd2b61..a8e04a6 100644
--- a/rsScript.h
+++ b/rsScript.h
@@ -43,6 +43,9 @@
         float mClearDepth;
         uint32_t mClearStencil;
 
+        uint32_t mStartTimeMillis;
+        const char* mTimeZone;
+
         ObjectBaseRef<ProgramVertex> mVertex;
         ObjectBaseRef<ProgramFragment> mFragment;
         //ObjectBaseRef<ProgramRaster> mRaster;
diff --git a/rsScriptC.cpp b/rsScriptC.cpp
index 842c836..3b9d27a 100644
--- a/rsScriptC.cpp
+++ b/rsScriptC.cpp
@@ -230,6 +230,12 @@
     ss->mEnviroment.mClearColor[3] = a;
 }
 
+void rsi_ScriptCSetTimeZone(Context * rsc, const char * timeZone, uint32_t length)
+{
+    ScriptCState *ss = &rsc->mScriptC;
+    ss->mEnviroment.mTimeZone = timeZone;
+}
+
 void rsi_ScriptCSetClearDepth(Context * rsc, float v)
 {
     ScriptCState *ss = &rsc->mScriptC;
diff --git a/rsScriptC_Lib.cpp b/rsScriptC_Lib.cpp
index 7db3619..ca05114 100644
--- a/rsScriptC_Lib.cpp
+++ b/rsScriptC_Lib.cpp
@@ -24,6 +24,9 @@
 #include <GLES/gl.h>
 #include <GLES/glext.h>
 
+#include <time.h>
+#include <cutils/tztime.h>
+
 using namespace android;
 using namespace android::renderscript;
 
@@ -133,7 +136,63 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
+// Time routines
+//////////////////////////////////////////////////////////////////////////////
 
+static uint32_t SC_second()
+{
+    GET_TLS();
+
+    time_t rawtime;
+    time(&rawtime);
+
+    if (sc->mEnviroment.mTimeZone) {
+        struct tm timeinfo;
+        localtime_tz(&rawtime, &timeinfo, sc->mEnviroment.mTimeZone);
+        return timeinfo.tm_sec;
+    } else {
+        struct tm *timeinfo;
+        timeinfo = localtime(&rawtime);
+        return timeinfo->tm_sec;
+    }
+}
+
+static uint32_t SC_minute()
+{
+    GET_TLS();
+    
+    time_t rawtime;
+    time(&rawtime);
+    
+    if (sc->mEnviroment.mTimeZone) {
+        struct tm timeinfo;
+        localtime_tz(&rawtime, &timeinfo, sc->mEnviroment.mTimeZone);
+        return timeinfo.tm_min;
+    } else {
+        struct tm *timeinfo;
+        timeinfo = localtime(&rawtime);
+        return timeinfo->tm_min;
+    }
+}   
+
+static uint32_t  SC_hour()
+{
+    GET_TLS();
+    
+    time_t rawtime;
+    time(&rawtime);
+    
+    if (sc->mEnviroment.mTimeZone) {
+        struct tm timeinfo;
+        localtime_tz(&rawtime, &timeinfo, sc->mEnviroment.mTimeZone);
+        return timeinfo.tm_hour;
+    } else {
+        struct tm *timeinfo;
+        timeinfo = localtime(&rawtime);
+        return timeinfo->tm_hour;
+    }
+}   
 
 //////////////////////////////////////////////////////////////////////////////
 // Matrix routines
@@ -460,6 +519,14 @@
     { "ceilf", (void *)&ceilf,
         "float", "(float)" },
 
+    // time
+    { "second", (void *)&SC_second,
+        "int", "()" },
+    { "minute", (void *)&SC_minute,
+        "int", "()" },
+    { "hour", (void *)&SC_hour,
+        "int", "()" },
+
     // matrix
     { "matrixLoadIdentity", (void *)&SC_matrixLoadIdentity,
         "void", "(float *mat)" },