OSDN Git Service

Add FallRS (called Water for the user) to the list of live wallpapers.
authorRomain Guy <romainguy@android.com>
Wed, 9 Sep 2009 20:07:58 +0000 (13:07 -0700)
committerRomain Guy <romainguy@android.com>
Wed, 9 Sep 2009 20:07:58 +0000 (13:07 -0700)
Change-Id: I484ee3a9e04d697f3116eb2e5e1f37397b9532b5

AndroidManifest.xml
res/drawable-hdpi/clouds.jpg [new file with mode: 0644]
res/drawable-hdpi/leaves.png [new file with mode: 0644]
res/drawable-hdpi/riverbed.jpg [new file with mode: 0644]
res/raw/fall.rs [new file with mode: 0644]
res/values/strings.xml
res/xml/fall.xml [new file with mode: 0644]
src/com/android/wallpaper/fall/Fall.java [new file with mode: 0644]
src/com/android/wallpaper/fall/FallRS.java [new file with mode: 0644]
src/com/android/wallpaper/fall/FallView.java [new file with mode: 0644]
src/com/android/wallpaper/fall/FallWallpaper.java [new file with mode: 0644]

index 7a84b4d..306a183 100644 (file)
 
         </activity>
         
+        <activity
+            android:label="@string/wallpaper_fall"
+            android:name="com.android.wallpaper.fall.Fall"
+            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>
+        
         <service
             android:label="@string/wallpaper_grass"
             android:name="com.android.wallpaper.grass.GrassWallpaper"
             <meta-data android:name="android.service.wallpaper" android:resource="@xml/galaxy" />
         </service>
 
+        <service
+            android:label="@string/wallpaper_fall"
+            android:name="com.android.wallpaper.fall.FallWallpaper"
+            android:permission="android.permission.BIND_WALLPAPER">
+            <intent-filter>
+                <action android:name="android.service.wallpaper.WallpaperService" />
+            </intent-filter>
+            <meta-data android:name="android.service.wallpaper" android:resource="@xml/fall" />
+        </service>
+
         <activity
             android:label="@string/clock_settings"
             android:name="com.android.wallpaper.polarclock.PolarClockSettings"
diff --git a/res/drawable-hdpi/clouds.jpg b/res/drawable-hdpi/clouds.jpg
new file mode 100644 (file)
index 0000000..565a63b
Binary files /dev/null and b/res/drawable-hdpi/clouds.jpg differ
diff --git a/res/drawable-hdpi/leaves.png b/res/drawable-hdpi/leaves.png
new file mode 100644 (file)
index 0000000..9eddd66
Binary files /dev/null and b/res/drawable-hdpi/leaves.png differ
diff --git a/res/drawable-hdpi/riverbed.jpg b/res/drawable-hdpi/riverbed.jpg
new file mode 100644 (file)
index 0000000..1698f28
Binary files /dev/null and b/res/drawable-hdpi/riverbed.jpg differ
diff --git a/res/raw/fall.rs b/res/raw/fall.rs
new file mode 100644 (file)
index 0000000..e04e1ff
--- /dev/null
@@ -0,0 +1,478 @@
+// 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.
+
+#pragma version(1)
+#pragma stateVertex(PVSky)
+#pragma stateFragment(PFBackground)
+#pragma stateFragmentStore(PFSBackground)
+
+#define RSID_STATE 0
+#define RSID_RIPPLE_MAP 1
+#define RSID_REFRACTION_MAP 2
+#define RSID_LEAVES 3
+#define RSID_DROP 4
+
+#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 LEAVES_TEXTURES_COUNT 4
+
+#define LEAF_SIZE 0.55f
+
+#define REFRACTION 1.333f
+#define DAMP 3
+
+#define DROP_RADIUS 2
+// The higher, the smaller the ripple
+#define RIPPLE_HEIGHT 10.0f
+
+float g_SkyOffsetX;
+float g_SkyOffsetY;
+
+struct vert_s {
+    float nx;
+    float ny;
+    float nz;
+    float s;
+    float t;
+    float x;
+    float y;
+    float z;
+};
+
+int offset(int x, int y, int width) {
+    return x + 1 + (y + 1) * (width + 2);
+}
+
+void dropWithStrength(int x, int y, int r, int s) {
+    int width = State->meshWidth;
+    int height = State->meshHeight;
+
+    if (x < r) x = r;
+    if (y < r) y = r;
+    if (x >= width - r) x = width - r - 1;
+    if (y >= height - r) y = height - r - 1;
+
+    x = width - x;
+
+    int rippleMapSize = State->rippleMapSize;
+    int index = State->rippleIndex;
+    int origin = offset(0, 0, width);
+
+    int* current = loadArrayI32(RSID_RIPPLE_MAP, index * rippleMapSize + origin);
+    int sqr = r * r;
+    float invs = 1.0f / s;
+
+    int h = 0;
+    for ( ; h < r; h += 1) {
+        int sqv = h * h;
+        int yn = origin + (y - h) * (width + 2);
+        int yp = origin + (y + h) * (width + 2);
+        int w = 0;
+        for ( ; w < r; w += 1) {
+            int squ = w * w;
+            if (squ + sqv < sqr) {
+                int v = -sqrtf((sqr - (squ + sqv)) << 16) * invs;
+                current[yn + x + w] = v;
+                current[yp + x + w] = v;
+                current[yn + x - w] = v;
+                current[yp + x - w] = v;
+            }
+        }
+    }
+}
+
+void drop(int x, int y, int r) {
+    dropWithStrength(x, y, r, 1);
+}
+
+void updateRipples() {
+    int rippleMapSize = State->rippleMapSize;
+    int width = State->meshWidth;
+    int height = State->meshHeight;
+    int index = State->rippleIndex;
+    int origin = offset(0, 0, width);
+
+    int* current = loadArrayI32(RSID_RIPPLE_MAP, index * rippleMapSize + origin);
+    int* next = loadArrayI32(RSID_RIPPLE_MAP, (1 - index) * rippleMapSize + origin);
+
+    storeI32(RSID_STATE, OFFSETOF_WorldState_rippleIndex, 1 - index);
+
+    int a = 1;
+    int b = width + 2;
+    int h = height;
+    while (h) {
+        int w = width;
+        while (w) {
+            int droplet = ((current[-b] + current[b] + current[-a] + current[a]) >> 1) - *next;
+            droplet -= (droplet >> DAMP);
+            *next = droplet;
+            current += 1;
+            next += 1;
+            w -= 1;
+        }
+        current += 2;
+        next += 2;
+        h -= 1;
+    }
+}
+
+int refraction(int d, int wave, int *map) {
+    int i = d;
+    if (i < 0) i = -i;
+    if (i > 512) i = 512;
+    int w = (wave + 0x10000) >> 8;
+    w &= ~(w >> 31);
+    int r = (map[i] * w) >> 3;
+    if (d < 0) {
+        return -r;
+    }
+    return r;
+}
+
+void generateRipples() {
+    int rippleMapSize = loadI32(RSID_STATE, OFFSETOF_WorldState_rippleMapSize);
+    int width = State->meshWidth;
+    int height = State->meshHeight;
+    int index = State->rippleIndex;
+    int origin = offset(0, 0, width);
+
+    int b = width + 2;
+
+    int* current = loadArrayI32(RSID_RIPPLE_MAP, index * rippleMapSize + origin);
+    int *map = loadArrayI32(RSID_REFRACTION_MAP, 0);
+    float *vertices = loadTriangleMeshVerticesF(NAMED_WaterMesh);
+    struct vert_s *vert = (struct vert_s *)vertices;
+
+    float fw = 1.f / width;
+    float fh = 1.f / height;
+    float fy = (1.0f / 512.0f) * (1.0f / RIPPLE_HEIGHT);
+
+    int h = height - 1;
+    while (h >= 0) {
+        int w = width - 1;
+        int wave = *current;
+        int offset = h * width;
+        struct vert_s *vtx = vert + offset + w;
+
+        while (w >= 0) {
+            int nextWave = current[1];
+            int dx = nextWave - wave;
+            int dy = current[b] - wave;
+
+            int offsetx = refraction(dx, wave, map) >> 16;
+            int u = (width - w) + offsetx;
+            u &= ~(u >> 31);
+            if (u >= width) u = width - 1;
+
+            int offsety = refraction(dy, wave, map) >> 16;
+            int v = (height - h) + offsety;
+            v &= ~(v >> 31);
+            if (v >= height) v = height - 1;
+
+            vtx->s = u * fw;
+            vtx->t = v * fh;
+            vtx->z = dy * fy;
+            vtx --;
+
+            w -= 1;
+            current += 1;
+            wave = nextWave;
+        }
+        h -= 1;
+        current += 2;
+    }
+
+    // Compute the normals for lighting
+    int y = 0;
+    for ( ; y < height; y += 1) {
+        int x = 0;
+        int yOffset = y * width;
+        struct vert_s *v = vert;
+
+        for ( ; 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);
+            vec3Cross(&n3, &n1, &n2);
+            vec3Norm(&n3);
+
+            // Average of previous normal and N1 x N2
+            vec3Sub(&n1, (struct vec3_s *)&(v+width+1)->x, (struct vec3_s *)&v->x);
+            vec3Cross(&n2, &n1, &n2);
+            vec3Add(&n3, &n3, &n2);
+            vec3Norm(&n3);
+
+            v->nx = n3.x;
+            v->ny = n3.y;
+            v->nz = -n3.z;
+            v += 1;
+
+            // reset Z
+            //vertices[(yOffset + x) << 3 + 7] = 0.0f;
+        }
+    }
+}
+
+float averageZ(float x1, float x2, float y1, float y2, float* vertices,
+        int meshWidth, int meshHeight, float glWidth, float glHeight) {
+
+    x1 = ((x1 + glWidth * 0.5f) / glWidth) * meshWidth;
+    x2 = ((x2 + glWidth * 0.5f) / glWidth) * meshWidth;
+    y1 = ((y1 + glHeight * 0.5f) / glHeight) * meshHeight;
+    y2 = ((y2 + glHeight * 0.5f) / glHeight) * meshHeight;
+
+    int quadX1 = clamp(x1, 0, meshWidth);
+    int quadX2 = clamp(x2, 0, meshWidth);
+    int quadY1 = clamp(y1, 0, meshHeight);
+    int quadY2 = clamp(y2, 0, meshHeight);
+
+    float z = 0.0f;
+    int vertexCount = 0;
+
+    int y = quadY1;
+    for ( ; y < quadY2; y += 1) {
+        int x = quadX1;
+        int yOffset = y * meshWidth;
+        for ( ; x < quadX2; x += 1) {
+            z += vertices[(yOffset + x) << 3 + 7];
+            vertexCount += 1;
+        }
+    }
+
+    return 55.0f * z / vertexCount;
+}
+
+void drawLeaf(int index, float* vertices, int meshWidth, int meshHeight,
+        float glWidth, float glHeight) {
+
+    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];
+
+    float z1 = 0.0f;
+    float z2 = 0.0f;
+    float z3 = 0.0f;
+    float z4 = 0.0f;
+
+    float a = leafStruct[LEAF_STRUCT_ALTITUDE];
+    float s = leafStruct[LEAF_STRUCT_SCALE];
+    float r = leafStruct[LEAF_STRUCT_ANGLE];
+
+    float tz = 0.0f;
+    if (a > 0.0f) {
+        tz = -a;
+    } else {
+//        z1 = averageZ(x1, x, y1, y, vertices, meshWidth, meshHeight, glWidth, glHeight);
+//        z2 = averageZ(x, x2, y1, y, vertices, meshWidth, meshHeight, glWidth, glHeight);
+//        z3 = averageZ(x, x2, y, y2, vertices, meshWidth, meshHeight, glWidth, glHeight);
+//        z4 = averageZ(x1, x, y, y2, vertices, meshWidth, meshHeight, glWidth, glHeight);
+    }
+
+    x1 -= x;
+    x2 -= x;
+    y1 -= y;
+    y2 -= y;
+
+    float matrix[16];
+    matrixLoadIdentity(matrix);
+    matrixTranslate(matrix, x, y, tz);
+    matrixScale(matrix, s, s, 1.0f);
+    matrixRotate(matrix, r, 0.0f, 0.0f, 1.0f);
+    vpLoadModelMatrix(matrix);
+
+    drawQuadTexCoords(x1, y1, z1, u1, 1.0f,
+                      x2, y1, z2, u2, 1.0f,
+                      x2, y2, z3, u2, 0.0f,
+                      x1, y2, z4, u1, 0.0f);
+
+    float spin = leafStruct[LEAF_STRUCT_SPIN];
+    if (a <= 0.0f) {
+        float rippled = leafStruct[LEAF_STRUCT_RIPPLED];
+        if (rippled < 0.0f) {
+            drop(((x + glWidth * 0.5f) / glWidth) * meshWidth,
+                 meshHeight - ((y + glHeight * 0.5f) / glHeight) * meshHeight,
+                 DROP_RADIUS);
+            spin /= 4.0f;
+            leafStruct[LEAF_STRUCT_SPIN] = spin;
+            leafStruct[LEAF_STRUCT_RIPPLED] = 1.0f;
+        } else {
+//            dropWithStrength(((x + glWidth / 2.0f) / glWidth) * meshWidth,
+//                meshHeight - ((y + glHeight / 2.0f) / glHeight) * meshHeight,
+//                2, 5);
+        }
+        leafStruct[LEAF_STRUCT_X] = x + leafStruct[LEAF_STRUCT_DELTAX];
+        leafStruct[LEAF_STRUCT_Y] = y + leafStruct[LEAF_STRUCT_DELTAY];
+        r += spin;
+        leafStruct[LEAF_STRUCT_ANGLE] = r;
+    } else {
+        a -= 0.005f;
+        leafStruct[LEAF_STRUCT_ALTITUDE] = a;
+        r += spin * 2.0f;
+        leafStruct[LEAF_STRUCT_ANGLE] = r;
+    }
+
+    if (-LEAF_SIZE * s + x > glWidth / 2.0f || LEAF_SIZE * s + x < -glWidth / 2.0f ||
+        LEAF_SIZE * s + y < -glHeight / 2.0f) {
+
+        int sprite = randf(LEAVES_TEXTURES_COUNT);
+        leafStruct[LEAF_STRUCT_X] = randf2(-1.0f, 1.0f);
+        leafStruct[LEAF_STRUCT_Y] = glHeight / 2.0f + LEAF_SIZE * 2 * randf(1.0f);
+        leafStruct[LEAF_STRUCT_SCALE] = randf2(0.4f, 0.5f);
+        leafStruct[LEAF_STRUCT_SPIN] = degf(randf2(-0.02f, 0.02f)) / 4.0f;
+        leafStruct[LEAF_STRUCT_U1] = sprite / (float) LEAVES_TEXTURES_COUNT;
+        leafStruct[LEAF_STRUCT_U2] = (sprite + 1) / (float) LEAVES_TEXTURES_COUNT;
+        leafStruct[LEAF_STRUCT_DELTAX] = randf2(-0.02f, 0.02f) / 60.0f;
+        leafStruct[LEAF_STRUCT_DELTAY] = -0.08f * randf2(0.9f, 1.1f) / 60.0f;
+    }
+}
+
+void drawLeaves() {
+    bindProgramFragment(NAMED_PFBackground);
+    bindProgramFragmentStore(NAMED_PFSLeaf);
+    bindProgramVertex(NAMED_PVSky);
+    bindTexture(NAMED_PFBackground, 0, NAMED_TLeaves);
+
+    int leavesCount = State->leavesCount;
+    int count = leavesCount * LEAF_STRUCT_FIELDS_COUNT;
+    int width = State->meshWidth;
+    int height = State->meshHeight;
+    float glWidth = State->glWidth;
+    float glHeight = State->glHeight;
+
+    float *vertices = loadTriangleMeshVerticesF(NAMED_WaterMesh);
+
+    int i = 0;
+    for ( ; i < count; i += LEAF_STRUCT_FIELDS_COUNT) {
+        drawLeaf(i, vertices, width, height, glWidth, glHeight);
+    }
+
+    float matrix[16];
+    matrixLoadIdentity(matrix);
+    vpLoadModelMatrix(matrix);
+}
+
+void drawRiverbed() {
+    bindTexture(NAMED_PFBackground, 0, NAMED_TRiverbed);
+
+    drawTriangleMesh(NAMED_WaterMesh);
+}
+
+void drawSky() {
+    color(1.0f, 1.0f, 1.0f, 0.8f);
+
+    bindProgramFragment(NAMED_PFSky);
+    bindProgramFragmentStore(NAMED_PFSLeaf);
+    bindTexture(NAMED_PFSky, 0, NAMED_TSky);
+
+    float x = g_SkyOffsetX + State->skySpeedX;
+    float y = g_SkyOffsetY + State->skySpeedY;
+
+    if (x > 1.0f) x = 0.0f;
+    if (x < -1.0f) x = 0.0f;
+    if (y > 1.0f) y = 0.0f;
+
+    g_SkyOffsetX = x;
+    g_SkyOffsetY = y;
+
+    float matrix[16];
+    matrixLoadTranslate(matrix, x, y, 0.0f);
+    vpLoadTextureMatrix(matrix);
+
+    drawTriangleMesh(NAMED_WaterMesh);
+
+    matrixLoadIdentity(matrix);
+    vpLoadTextureMatrix(matrix);
+}
+
+void drawLighting() {
+    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);
+    shininess(40.0f);
+
+    bindProgramFragmentStore(NAMED_PFSBackground);
+    bindProgramFragment(NAMED_PFLighting);
+    bindProgramVertex(NAMED_PVLight);
+
+    drawTriangleMesh(NAMED_WaterMesh);
+}
+
+void drawNormals() {
+    int width = State->meshWidth;
+    int height = State->meshHeight;
+
+    float *vertices = loadTriangleMeshVerticesF(NAMED_WaterMesh);
+
+    bindProgramVertex(NAMED_PVSky);
+    bindProgramFragment(NAMED_PFLighting);
+
+    color(1.0f, 0.0f, 0.0f, 1.0f);
+
+    float scale = 1.0f / 10.0f;
+    int y = 0;
+    for ( ; y < height; y += 1) {
+        int yOffset = y * width;
+        int x = 0;
+        for ( ; x < width; x += 1) {
+            int offset = (yOffset + x) << 3;
+            float vx = vertices[offset + 5];
+            float vy = vertices[offset + 6];
+            float vz = vertices[offset + 7];
+            float nx = vertices[offset + 0];
+            float ny = vertices[offset + 1];
+            float nz = vertices[offset + 2];
+            drawLine(vx, vy, vz, vx + nx * scale, vy + ny * scale, vz + nz * scale);
+        }
+    }
+}
+
+int main(int index) {
+    if (Drop->dropX != -1) {
+        drop(Drop->dropX, Drop->dropY, DROP_RADIUS);
+        Drop->dropX = -1;
+        Drop->dropY = -1;
+    }
+
+    updateRipples();
+    generateRipples();
+    updateTriangleMesh(NAMED_WaterMesh);
+
+    drawRiverbed();
+    drawSky();
+    drawLighting();
+    drawLeaves();
+    //drawNormals();
+
+    return 1;
+}
index 3108f77..9e47e15 100644 (file)
@@ -31,6 +31,9 @@
     
     <!-- Wallpaper showing a galaxy -->
     <string name="wallpaper_galaxy">Galaxy</string>
+
+    <!-- Wallpaper showing leaves floating on water -->
+    <string name="wallpaper_fall">Water</string>    
     
     <!-- Wallpaper showing a clock -->
     <string name="wallpaper_clock">Polar clock</string>
diff --git a/res/xml/fall.xml b/res/xml/fall.xml
new file mode 100644 (file)
index 0000000..fedfa7e
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+
+<!-- The attributes in this XML file provide configuration information -->
+<!-- about the fall wallpaper. -->
+
+<wallpaper xmlns:android="http://schemas.android.com/apk/res/android"
+/>
diff --git a/src/com/android/wallpaper/fall/Fall.java b/src/com/android/wallpaper/fall/Fall.java
new file mode 100644 (file)
index 0000000..aa3901c
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+package com.android.wallpaper.fall;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class Fall extends Activity {
+    private FallView mView;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        mView = new FallView(this);
+        setContentView(mView);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        mView.onResume();
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        mView.onPause();
+
+        Runtime.getRuntime().exit(0);
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/wallpaper/fall/FallRS.java b/src/com/android/wallpaper/fall/FallRS.java
new file mode 100644 (file)
index 0000000..e39df3c
--- /dev/null
@@ -0,0 +1,445 @@
+/*
+ * 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.
+ */
+
+package com.android.wallpaper.fall;
+
+import android.renderscript.RenderScript;
+import android.renderscript.ScriptC;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.renderscript.Allocation;
+import android.renderscript.Sampler;
+import android.renderscript.Element;
+import android.renderscript.Light;
+import android.renderscript.Type;
+import static android.renderscript.Sampler.Value.LINEAR;
+import static android.renderscript.Sampler.Value.WRAP;
+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.BitmapFactory;
+import android.graphics.Bitmap;
+import static android.util.MathUtils.*;
+
+import java.util.TimeZone;
+
+import com.android.wallpaper.R;
+import com.android.wallpaper.RenderScriptScene;
+
+class FallRS extends RenderScriptScene {
+    private static final int MESH_RESOLUTION = 48;
+
+    private static final int RSID_STATE = 0;
+
+    private static final int TEXTURES_COUNT = 3;
+    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_TEXTURE_SKY = 2;
+
+    private static final int RSID_RIPPLE_MAP = 1;
+
+    private static final int RSID_REFRACTION_MAP = 2;
+
+    private static final int RSID_LEAVES = 3;
+    private static final int LEAVES_COUNT = 14;
+    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;
+
+    class Leaf {
+        float x;
+        float y;
+        float scale;
+        float angle;
+        float spin;
+        float u1;
+        float u2;
+        float altitude;
+        float rippled;
+        float deltaX;
+        float deltaY;
+    }
+
+    private static final int RSID_DROP = 4;
+
+    private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options();
+
+    @SuppressWarnings({"FieldCanBeLocal"})
+    private ProgramFragment mPfBackground;
+    @SuppressWarnings({"FieldCanBeLocal"})
+    private ProgramFragment mPfLighting;
+    @SuppressWarnings({"FieldCanBeLocal"})
+    private ProgramFragment mPfSky;
+    @SuppressWarnings({"FieldCanBeLocal"})
+    private ProgramStore mPfsBackground;
+    @SuppressWarnings({"FieldCanBeLocal"})
+    private ProgramStore mPfsLeaf;
+    @SuppressWarnings({"FieldCanBeLocal"})
+    private ProgramVertex mPvLight;
+    @SuppressWarnings({"FieldCanBeLocal"})
+    private ProgramVertex mPvSky;
+    private ProgramVertex.MatrixAllocation mPvOrthoAlloc;
+    @SuppressWarnings({"FieldCanBeLocal"})
+    private Light mLight;
+    @SuppressWarnings({"FieldCanBeLocal"})
+    private Sampler mSampler;
+
+    private Allocation mState;
+    private Allocation mDropState;
+    private DropState mDrop;
+    private Type mStateType;
+    private Type mDropType;
+    private int mMeshWidth;
+
+    private int mMeshHeight;
+    @SuppressWarnings({"FieldCanBeLocal"})
+    private RenderScript.TriangleMesh mMesh;
+    private WorldState mWorldState;    
+
+    private Allocation mRippleMap;
+    private Allocation mRefractionMap;
+
+    private Allocation mLeaves;
+    private float mGlHeight;
+
+    public FallRS(int width, int height) {
+        super(width, height);
+
+        mOptionsARGB.inScaled = false;
+        mOptionsARGB.inPreferredConfig = Bitmap.Config.ARGB_8888;
+    }
+
+    @Override
+    public void resize(int width, int height) {
+        super.resize(width, height);
+
+        mWorldState.width = width;
+        mWorldState.height = height;
+        mState.data(mWorldState);
+
+        mPvOrthoAlloc.setupOrthoWindow(mWidth, mHeight);
+
+        // TODO: Resize everything else, including the mesh and glHeight
+    }
+
+    @Override
+    protected ScriptC createScript() {
+        createProgramVertex();
+        createProgramFragmentStore();
+        createProgramFragment();
+        createMesh();
+        createScriptStructures();
+        loadTextures();
+
+        ScriptC.Builder sb = new ScriptC.Builder(mRS);
+        sb.setType(mStateType, "State", RSID_STATE);
+        sb.setType(mDropType, "Drop", RSID_DROP);
+        sb.setScript(mResources, R.raw.fall);
+        sb.setRoot(true);
+
+        ScriptC script = sb.create();
+        script.setClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+        script.setTimeZone(TimeZone.getDefault().getID());
+
+        script.bindAllocation(mState, RSID_STATE);
+        script.bindAllocation(mRippleMap, RSID_RIPPLE_MAP);
+        script.bindAllocation(mRefractionMap, RSID_REFRACTION_MAP);
+        script.bindAllocation(mLeaves, RSID_LEAVES);
+        script.bindAllocation(mDropState, RSID_DROP);
+
+        return script;
+    }
+
+    private void createMesh() {
+        final RenderScript rs = mRS;
+        rs.triangleMeshBegin(Element.NORM_ST_XYZ_F32, Element.INDEX_16);
+
+        int wResolution;
+        int hResolution;
+
+        final int width = mWidth;
+        final int height = mHeight;
+
+        if (width < height) {
+            wResolution = MESH_RESOLUTION;
+            hResolution = (int) (MESH_RESOLUTION * height / (float) width);
+        } else {
+            wResolution = (int) (MESH_RESOLUTION * width / (float) height);
+            hResolution = MESH_RESOLUTION;
+        }
+
+        mGlHeight = 2.0f * height / (float) width;
+        final float glHeight = mGlHeight;
+
+        float quadWidth = 2.0f / (float) wResolution;
+        float quadHeight = glHeight / (float) hResolution;
+
+        wResolution += 2;
+        hResolution += 2;
+
+        for (int y = 0; y <= hResolution; y++) {
+            final boolean shift = (y & 0x1) == 0;
+            final float yOffset = y * quadHeight - glHeight / 2.0f - quadHeight;
+            final float t = 1.0f - y / (float) hResolution;
+            for (int x = 0; x <= wResolution; x++) {
+                if (shift) {
+                    rs.triangleMeshAddVertex_XYZ_ST_NORM(
+                            -1.0f + x * quadWidth - quadWidth, yOffset, 0.0f,
+                            x / (float) wResolution, t,
+                            0.0f, 0.0f, -1.0f);
+                } else {
+                    rs.triangleMeshAddVertex_XYZ_ST_NORM(
+                            -1.0f + x * quadWidth - quadWidth * 0.5f, yOffset, 0.0f,
+                            x / (float) wResolution, t,
+                            0.0f, 0.0f, -1.0f);
+                }
+            }
+        }
+
+        for (int y = 0; y < hResolution; y++) {
+            final boolean shift = (y & 0x1) == 0;
+            final int yOffset = y * (wResolution + 1);
+            for (int x = 0; x < wResolution; x++) {
+                final int index = yOffset + x;
+                final int iWR1 = index + wResolution + 1;
+                if (shift) {
+                    rs.triangleMeshAddTriangle(index, index + 1, iWR1);
+                    rs.triangleMeshAddTriangle(index + 1, iWR1 + 1, iWR1);
+                } else {
+                    rs.triangleMeshAddTriangle(index, iWR1 + 1, iWR1);
+                    rs.triangleMeshAddTriangle(index, index + 1, iWR1 + 1);
+                }
+            }
+        }
+
+        mMesh = rs.triangleMeshCreate();
+        mMesh.setName("WaterMesh");
+
+        mMeshWidth = wResolution + 1;
+        mMeshHeight = hResolution + 1;
+    }
+
+    private void createScriptStructures() {
+        final int rippleMapSize = (mMeshWidth + 2) * (mMeshHeight + 2);
+
+        createState(rippleMapSize);
+        createRippleMap(rippleMapSize);
+        createRefractionMap();
+        createLeaves();
+    }
+
+    private void createLeaves() {
+        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 createRefractionMap() {
+        final int[] refractionMap = new int[513];
+        float ir = 1.0f / 1.333f;
+        for (int i = 0; i < refractionMap.length; i++) {
+            float d = (float) Math.tan(Math.asin(Math.sin(Math.atan(i * (1.0f / 256.0f))) * ir));
+            refractionMap[i] = (int) Math.floor(d * (1 << 16) + 0.5f);
+        }
+        mRefractionMap = Allocation.createSized(mRS, USER_I32, refractionMap.length);
+        mRefractionMap.data(refractionMap);
+    }
+
+    private void createRippleMap(int rippleMapSize) {
+        final int[] rippleMap = new int[rippleMapSize * 2];
+        mRippleMap = Allocation.createSized(mRS, USER_I32, rippleMap.length);
+        mRippleMap.data(rippleMap);
+    }
+
+    static class WorldState {
+        public int frameCount;
+        public int width;
+        public int height;
+        public int meshWidth;
+        public int meshHeight;
+        public int rippleMapSize;
+        public int rippleIndex;
+        public int leavesCount;
+        public float glWidth;
+        public float glHeight;
+        public float skySpeedX;
+        public float skySpeedY;
+    }
+
+    static class DropState {
+        public int dropX;
+        public int dropY;
+    }
+
+    private void createState(int rippleMapSize) {
+        mWorldState = new WorldState();
+        mWorldState.width = mWidth;
+        mWorldState.height = mHeight;
+        mWorldState.meshWidth = mMeshWidth;
+        mWorldState.meshHeight = mMeshHeight;
+        mWorldState.rippleMapSize = rippleMapSize;
+        mWorldState.rippleIndex = 0;
+        mWorldState.leavesCount = LEAVES_COUNT;
+        mWorldState.glWidth = 2.0f;
+        mWorldState.glHeight = mGlHeight;
+        mWorldState.skySpeedX = random(-0.001f, 0.001f);
+        mWorldState.skySpeedY = random(0.00008f, 0.0002f);
+
+        mStateType = Type.createFromClass(mRS, WorldState.class, 1, "WorldState");
+        mState = Allocation.createTyped(mRS, mStateType);
+        mState.data(mWorldState);
+
+        mDrop = new DropState();
+        mDrop.dropX = -1;
+        mDrop.dropY = -1;
+
+        mDropType = Type.createFromClass(mRS, DropState.class, 1, "DropState");
+        mDropState = Allocation.createTyped(mRS, mDropType);
+        mDropState.data(mDrop);
+    }
+
+    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.4f, 0.5f);
+        leaves[index + LEAF_STRUCT_ANGLE] = random(0.0f, 360.0f);
+        leaves[index + LEAF_STRUCT_SPIN] = degrees(random(-0.02f, 0.02f)) / 4.0f;
+        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] = -1.0f;
+        leaves[index + LEAF_STRUCT_RIPPLED] = 1.0f;
+        leaves[index + LEAF_STRUCT_DELTAX] = random(-0.02f, 0.02f) / 60.0f;
+        leaves[index + LEAF_STRUCT_DELTAY] = -0.08f * random(0.9f, 1.1f) / 60.0f;
+    }
+
+    private void loadTextures() {
+        final Allocation[] textures = new Allocation[TEXTURES_COUNT];
+        textures[RSID_TEXTURE_RIVERBED] = loadTexture(R.drawable.riverbed, "TRiverbed");
+        textures[RSID_TEXTURE_LEAVES] = loadTextureARGB(R.drawable.leaves, "TLeaves");
+        textures[RSID_TEXTURE_SKY] = loadTextureARGB(R.drawable.clouds, "TSky");
+
+        final int count = textures.length;
+        for (int i = 0; i < count; i++) {
+            final Allocation texture = textures[i];
+            texture.uploadToTexture(0);
+        }
+    }
+
+    private Allocation loadTexture(int id, String name) {
+        final Allocation allocation = Allocation.createFromBitmapResource(mRS, mResources,
+                id, RGB_565, false);
+        allocation.setName(name);
+        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);
+        sampleBuilder.setMag(LINEAR);
+        sampleBuilder.setWrapS(WRAP);
+        sampleBuilder.setWrapT(WRAP);
+        mSampler = sampleBuilder.create();
+
+        ProgramFragment.Builder builder = new ProgramFragment.Builder(mRS, null, null);
+        builder.setTexEnable(true, 0);
+        builder.setTexEnvMode(REPLACE, 0);
+        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(MODULATE, 0);
+        mPfSky = builder.create();
+        mPfSky.setName("PFSky");
+        mPfSky.bindSampler(mSampler, 0);
+    }
+
+    private void createProgramFragmentStore() {
+        ProgramStore.Builder builder = new ProgramStore.Builder(mRS, null, null);
+        builder.setDepthFunc(ALWAYS);
+        builder.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ONE);
+        builder.setDitherEnable(false);
+        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(false);
+        builder.setDepthMask(true);
+        mPfsLeaf = builder.create();
+        mPfsLeaf.setName("PFSLeaf");
+    }
+
+    private void createProgramVertex() {
+        mPvOrthoAlloc = new ProgramVertex.MatrixAllocation(mRS);
+        mPvOrthoAlloc.setupProjectionNormalized(mWidth, mHeight);
+
+        mLight = new Light.Builder(mRS).create();
+        mLight.setPosition(0.0f, 2.0f, -8.0f);
+
+        ProgramVertex.Builder builder = new ProgramVertex.Builder(mRS, null, null);
+        builder.addLight(mLight);
+        mPvLight = builder.create();
+        mPvLight.bindAllocation(mPvOrthoAlloc);
+        mPvLight.setName("PVLight");
+
+        builder = new ProgramVertex.Builder(mRS, null, null);
+        builder.setTextureMatrixEnable(true);
+        mPvSky = builder.create();
+        mPvSky.bindAllocation(mPvOrthoAlloc);
+        mPvSky.setName("PVSky");
+    }
+
+    void addDrop(float x, float y) {
+        mDrop.dropX = (int) ((x / mWidth) * mMeshWidth);
+        mDrop.dropY = (int) ((y / mHeight) * mMeshHeight);
+        mDropState.data(mDrop);
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/wallpaper/fall/FallView.java b/src/com/android/wallpaper/fall/FallView.java
new file mode 100644 (file)
index 0000000..2e4c0d2
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+
+package com.android.wallpaper.fall;
+
+import android.content.Context;
+import android.view.SurfaceHolder;
+import android.view.MotionEvent;
+import android.renderscript.RenderScript;
+import android.renderscript.RSSurfaceView;
+
+class FallView extends RSSurfaceView {
+    private FallRS mRender;
+
+    public FallView(Context context) {
+        super(context);
+        setFocusable(true);
+        setFocusableInTouchMode(true);
+    }
+
+    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
+        super.surfaceChanged(holder, format, w, h);
+
+        RenderScript RS = createRenderScript(false);
+        mRender = new FallRS(w, h);
+        mRender.init(RS, getResources());
+        mRender.start();
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        switch (event.getAction()) {
+            case MotionEvent.ACTION_DOWN:
+            case MotionEvent.ACTION_MOVE:
+                mRender.addDrop(event.getX(), event.getY());
+                try {
+                    Thread.sleep(16);
+                } catch (InterruptedException e) {
+                    // Ignore
+                }
+                break;
+        }
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/wallpaper/fall/FallWallpaper.java b/src/com/android/wallpaper/fall/FallWallpaper.java
new file mode 100644 (file)
index 0000000..8902bbd
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+package com.android.wallpaper.fall;
+
+import com.android.wallpaper.RenderScriptWallpaper;
+import com.android.wallpaper.RenderScriptScene;
+
+public class FallWallpaper extends RenderScriptWallpaper {
+    protected RenderScriptScene createScene(int width, int height) {
+        return new FallRS(width, height);
+    }
+}
\ No newline at end of file