1// Copyright (C) 2009 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#pragma version(1)
16
17#pragma rs java_package_name(com.android.wallpaper.fall)
18
19#include "rs_graphics.rsh"
20
21#define LEAVES_TEXTURES_COUNT 8
22#define LEAF_SIZE 0.55f
23#define LEAVES_COUNT 14
24
25// Things we need to set from the application
26float g_glWidth;
27float g_glHeight;
28float g_meshWidth;
29float g_meshHeight;
30float g_xOffset;
31float g_rotate;
32
33rs_program_vertex g_PVWater;
34rs_program_vertex g_PVSky;
35
36rs_program_fragment g_PFSky;
37rs_program_store g_PFSLeaf;
38rs_program_fragment g_PFBackground;
39
40rs_allocation g_TLeaves;
41rs_allocation g_TRiverbed;
42
43rs_mesh g_WaterMesh;
44
45typedef struct Constants {
46    float4 Drop01;
47    float4 Drop02;
48    float4 Drop03;
49    float4 Drop04;
50    float4 Drop05;
51    float4 Drop06;
52    float4 Drop07;
53    float4 Drop08;
54    float4 Drop09;
55    float4 Drop10;
56    float4 Offset;
57    float Rotate;
58} Constants_t;
59
60Constants_t *g_Constants;
61rs_program_store g_PFSBackground;
62
63//float skyOffsetX;
64//float skyOffsetY;
65static float g_DT;
66static int64_t g_LastTime;
67
68typedef struct Drop {
69    float ampS;
70    float ampE;
71    float spread;
72    float x;
73    float y;
74} Drop_t;
75static Drop_t gDrops[10];
76static int gMaxDrops;
77
78typedef struct Leaves {
79    float x;
80    float y;
81    float scale;
82    float angle;
83    float spin;
84    float u1;
85    float u2;
86    float altitude;
87    float rippled;
88    float deltaX;
89    float deltaY;
90    int newLeaf;
91} Leaves_t;
92
93static Leaves_t gLeavesStore[LEAVES_COUNT];
94static Leaves_t* gLeaves[LEAVES_COUNT];
95static Leaves_t* gNextLeaves[LEAVES_COUNT];
96
97void initLeaves() {
98    Leaves_t *leaf = gLeavesStore;
99    // globals haven't been set at this point yet. We need to find the correct
100    // function index to call this, we can wait until reflection works
101    float width = 2; //g_glWidth;
102    float height = 3.333; //g_glHeight;
103
104    int i;
105    for (i = 0; i < LEAVES_COUNT; i ++) {
106        gLeaves[i] = leaf;
107        int sprite = rsRand(LEAVES_TEXTURES_COUNT);
108        leaf->x = rsRand(-width, width);
109        leaf->y = rsRand(-height * 0.5f, height * 0.5f);
110        leaf->scale = rsRand(0.4f, 0.5f);
111        leaf->angle = rsRand(0.0f, 360.0f);
112        leaf->spin = degrees(rsRand(-0.02f, 0.02f)) * 0.25f;
113        leaf->u1 = (float)sprite / (float) LEAVES_TEXTURES_COUNT;
114        leaf->u2 = (float)(sprite + 1) / (float) LEAVES_TEXTURES_COUNT;
115        leaf->altitude = -1.0f;
116        leaf->rippled = 1.0f;
117        leaf->deltaX = rsRand(-0.01f, 0.01f);
118        leaf->deltaY = -rsRand(0.036f, 0.044f);
119        leaf++;
120    }
121}
122
123void init() {
124    int ct;
125    gMaxDrops = 10;
126    for (ct=0; ct<gMaxDrops; ct++) {
127        gDrops[ct].ampS = 0;
128        gDrops[ct].ampE = 0;
129        gDrops[ct].spread = 1;
130    }
131
132    initLeaves();
133    g_LastTime = rsUptimeMillis();
134    g_DT = 0.1f;
135}
136
137static void updateDrop(int ct) {
138    gDrops[ct].spread += 30.f * g_DT;
139    gDrops[ct].ampE = gDrops[ct].ampS / gDrops[ct].spread;
140}
141
142static void drop(int x, int y, float s) {
143    int ct;
144    int iMin = 0;
145    float minAmp = 10000.f;
146    for (ct = 0; ct < gMaxDrops; ct++) {
147        if (gDrops[ct].ampE < minAmp) {
148            iMin = ct;
149            minAmp = gDrops[ct].ampE;
150        }
151    }
152    gDrops[iMin].ampS = s;
153    gDrops[iMin].spread = 0;
154    gDrops[iMin].x = x;
155    gDrops[iMin].y = g_meshHeight - y - 1;
156    updateDrop(iMin);
157}
158
159static void generateRipples() {
160    int ct;
161    for (ct = 0; ct < gMaxDrops; ct++) {
162        Drop_t * d = &gDrops[ct];
163        float *v = (float*)&g_Constants->Drop01;
164        v += ct*4;
165        *(v++) = d->x;
166        *(v++) = d->y;
167        *(v++) = d->ampE * 0.12f;
168        *(v++) = d->spread;
169    }
170    g_Constants->Offset.x = g_xOffset;
171
172    for (ct = 0; ct < gMaxDrops; ct++) {
173        updateDrop(ct);
174    }
175}
176
177static void genLeafDrop(Leaves_t *leaf, float amp) {
178    float nx = (leaf->x + g_glWidth * 0.5f) / g_glWidth;
179    float ny = (leaf->y + g_glHeight * 0.5f) / g_glHeight;
180    drop(nx * g_meshWidth, g_meshHeight - ny * g_meshHeight, amp);
181}
182
183static int drawLeaf(Leaves_t *leaf) {
184
185    float x = leaf->x;
186    float y = leaf->y;
187
188    float u1 = leaf->u1;
189    float u2 = leaf->u2;
190
191    float a = leaf->altitude;
192    float s = leaf->scale;
193    float r = leaf->angle;
194
195    float tz = 0.0f;
196    if (a > 0.0f) {
197        tz = -a;
198    }
199
200    rs_matrix4x4 matrix;
201    if (a > 0.0f) {
202
203        float alpha = 1.0f;
204        if (a >= 0.4f) alpha = 1.0f - (a - 0.4f) / 0.1f;
205
206        rsgProgramFragmentConstantColor(g_PFSky, 0.0f, 0.0f, 0.0f, alpha * 0.15f);
207
208        rsMatrixLoadIdentity(&matrix);
209        if (!g_rotate) {
210            rsMatrixTranslate(&matrix, x - g_xOffset * 2, y, 0);
211        } else {
212            rsMatrixTranslate(&matrix, x, y, 0);
213            rsMatrixRotate(&matrix, 90.0f, 0.0f, 0.0f, 1.0f);
214        }
215
216        float shadowOffet = a * 0.2f;
217
218        rsMatrixScale(&matrix, s, s, 1.0f);
219        rsMatrixRotate(&matrix, r, 0.0f, 0.0f, 1.0f);
220        rsgProgramVertexLoadModelMatrix(&matrix);
221
222        rsgDrawQuadTexCoords(-LEAF_SIZE, -LEAF_SIZE, 0, u1, 1.0f,
223                           LEAF_SIZE, -LEAF_SIZE, 0, u2, 1.0f,
224                           LEAF_SIZE,  LEAF_SIZE, 0, u2, 0.0f,
225                          -LEAF_SIZE,  LEAF_SIZE, 0, u1, 0.0f);
226
227        rsgProgramFragmentConstantColor(g_PFSky, 1.0f, 1.0f, 1.0f, alpha);
228    } else {
229        rsgProgramFragmentConstantColor(g_PFSky, 1.0f, 1.0f, 1.0f, 1.0f);
230    }
231
232    rsMatrixLoadIdentity(&matrix);
233    if (!g_rotate) {
234        rsMatrixTranslate(&matrix, x - g_xOffset * 2, y, tz);
235    } else {
236        rsMatrixTranslate(&matrix, x, y, tz);
237        rsMatrixRotate(&matrix, 90.0f, 0.0f, 0.0f, 1.0f);
238    }
239    rsMatrixScale(&matrix, s, s, 1.0f);
240    rsMatrixRotate(&matrix, r, 0.0f, 0.0f, 1.0f);
241    rsgProgramVertexLoadModelMatrix(&matrix);
242
243    rsgDrawQuadTexCoords(-LEAF_SIZE, -LEAF_SIZE, 0, u1, 1.0f,
244                       LEAF_SIZE, -LEAF_SIZE, 0, u2, 1.0f,
245                       LEAF_SIZE,  LEAF_SIZE, 0, u2, 0.0f,
246                      -LEAF_SIZE,  LEAF_SIZE, 0, u1, 0.0f);
247
248    float spin = leaf->spin;
249    if (a <= 0.0f) {
250        float rippled = leaf->rippled;
251        if (rippled < 0.0f) {
252            genLeafDrop(leaf, 1.5f);
253            //drop(((x + g_glWidth * 0.5f) / g_glWidth) * meshWidth,
254            //     meshHeight - ((y + g_glHeight * 0.5f) / g_glHeight) * meshHeight, 1);
255            spin *= 0.25f;
256            leaf->spin = spin;
257            leaf->rippled = 1.0f;
258        }
259        leaf->x = x + leaf->deltaX * g_DT;
260        leaf->y = y + leaf->deltaY * g_DT;
261        r += spin;
262        leaf->angle = r;
263    } else {
264        a -= 0.15f * g_DT;
265        leaf->altitude = a;
266        r += spin * 2.0f;
267        leaf->angle = r;
268    }
269
270    int newLeaf = 0;
271    if (-LEAF_SIZE * s + x > g_glWidth || LEAF_SIZE * s + x < -g_glWidth ||
272            LEAF_SIZE * s + y < -g_glHeight * 0.5f) {
273
274        int sprite = rsRand(LEAVES_TEXTURES_COUNT);
275
276        leaf->x = rsRand(-g_glWidth, g_glWidth);
277        leaf->y = rsRand(-g_glHeight * 0.5f, g_glHeight * 0.5f);
278
279        leaf->scale = rsRand(0.4f, 0.5f);
280        leaf->spin = degrees(rsRand(-0.02f, 0.02f)) * 0.35f;
281        leaf->u1 = sprite / (float) LEAVES_TEXTURES_COUNT;
282        leaf->u2 = (sprite + 1) / (float) LEAVES_TEXTURES_COUNT;
283        leaf->altitude = 0.7f;
284        leaf->rippled = -1.0f;
285        leaf->deltaX = rsRand(-0.01f, 0.01f);
286        leaf->deltaY = -rsRand(0.036f, 0.044f);
287        leaf->newLeaf = 1;
288        newLeaf = 1;
289    }
290    return newLeaf;
291}
292
293static void drawLeaves() {
294    rsgBindProgramFragment(g_PFSky);
295    rsgBindProgramStore(g_PFSLeaf);
296    rsgBindProgramVertex(g_PVSky);
297    rsgBindTexture(g_PFSky, 0, g_TLeaves);
298
299    int newLeaves = 0;
300    int i = 0;
301    for ( ; i < LEAVES_COUNT; i += 1) {
302        if (drawLeaf(gLeaves[i])) {
303            newLeaves = 1;
304
305        }
306    }
307
308    if (newLeaves > 0) {
309        int index = 0;
310
311        // Copy all the old leaves to the beginning of gNextLeaves
312        for (i=0; i < LEAVES_COUNT; i++) {
313            if (gLeaves[i]->newLeaf == 0) {
314                gNextLeaves[index] = gLeaves[i];
315                index++;
316            }
317        }
318
319        // Now copy all the newly falling leaves to the end of gNextLeaves
320        for (i=0; i < LEAVES_COUNT; i++) {
321            if (gLeaves[i]->newLeaf > 0) {
322                gNextLeaves[index] = gLeaves[i];
323                gNextLeaves[index]->newLeaf = 0;
324                index++;
325            }
326        }
327
328        // And move everything in gNextLeaves back to gLeaves
329        for (i=0; i < LEAVES_COUNT; i++) {
330            gLeaves[i] = gNextLeaves[i];
331        }
332    }
333
334    rs_matrix4x4 matrix;
335    rsMatrixLoadIdentity(&matrix);
336    rsgProgramVertexLoadModelMatrix(&matrix);
337}
338
339static void drawRiverbed() {
340    rsgBindProgramFragment(g_PFBackground);
341    rsgBindProgramStore(g_PFSBackground);
342    rsgBindTexture(g_PFBackground, 0, g_TRiverbed);
343    rsgDrawMesh(g_WaterMesh);
344}
345
346void addDrop(int x, int y) {
347    drop(x, y, 2);
348}
349
350int root(void) {
351    rsgClearColor(0.f, 0.f, 0.f, 1.f);
352
353    // Compute dt in seconds.
354    int64_t newTime = rsUptimeMillis();
355    g_DT = (newTime - g_LastTime) * 0.001f;
356    g_DT = min(g_DT, 0.2f);
357    g_LastTime = newTime;
358
359    g_Constants->Rotate = (float) g_rotate;
360
361    int ct;
362    int add = 0;
363    for (ct = 0; ct < gMaxDrops; ct++) {
364        if (gDrops[ct].ampE < 0.005f) {
365            add = 1;
366        }
367    }
368
369    if (add) {
370        int i = (int)rsRand(LEAVES_COUNT);
371        genLeafDrop(gLeaves[i], rsRand(0.3f) + 0.1f);
372    }
373
374    rsgBindProgramVertex(g_PVWater);
375    generateRipples();
376    rsgAllocationSyncAll(rsGetAllocation(g_Constants));
377    drawRiverbed();
378
379    drawLeaves();
380
381    return 50;
382}
383