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)" },