blob: d1e3446214b0ad650e1133b98b00dcde1c1f4e62 [file] [log] [blame]
// 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 rs java_package_name(com.android.wallpaper.fall)
#include "rs_graphics.rsh"
#define LEAVES_TEXTURES_COUNT 8
#define LEAF_SIZE 0.55f
#define LEAVES_COUNT 14
// Things we need to set from the application
float g_glWidth;
float g_glHeight;
float g_meshWidth;
float g_meshHeight;
float g_xOffset;
float g_rotate;
rs_program_vertex g_PVWater;
rs_program_vertex g_PVSky;
rs_program_fragment g_PFSky;
rs_program_store g_PFSLeaf;
rs_program_fragment g_PFBackground;
rs_allocation g_TLeaves;
rs_allocation g_TRiverbed;
rs_mesh g_WaterMesh;
typedef struct Constants {
float4 Drop01;
float4 Drop02;
float4 Drop03;
float4 Drop04;
float4 Drop05;
float4 Drop06;
float4 Drop07;
float4 Drop08;
float4 Drop09;
float4 Drop10;
float4 Offset;
float Rotate;
} Constants_t;
Constants_t *g_Constants;
rs_program_store g_PFSBackground;
//float skyOffsetX;
//float skyOffsetY;
static float g_DT;
static int64_t g_LastTime;
typedef struct Drop {
float ampS;
float ampE;
float spread;
float x;
float y;
} Drop_t;
static Drop_t gDrops[10];
static int gMaxDrops;
typedef struct Leaves {
float x;
float y;
float scale;
float angle;
float spin;
float u1;
float u2;
float altitude;
float rippled;
float deltaX;
float deltaY;
int newLeaf;
} Leaves_t;
static Leaves_t gLeavesStore[LEAVES_COUNT];
static Leaves_t* gLeaves[LEAVES_COUNT];
static Leaves_t* gNextLeaves[LEAVES_COUNT];
void initLeaves() {
Leaves_t *leaf = gLeavesStore;
// globals haven't been set at this point yet. We need to find the correct
// function index to call this, we can wait until reflection works
float width = 2; //g_glWidth;
float height = 3.333; //g_glHeight;
int i;
for (i = 0; i < LEAVES_COUNT; i ++) {
gLeaves[i] = leaf;
int sprite = rsRand(LEAVES_TEXTURES_COUNT);
leaf->x = rsRand(-width, width);
leaf->y = rsRand(-height * 0.5f, height * 0.5f);
leaf->scale = rsRand(0.4f, 0.5f);
leaf->angle = rsRand(0.0f, 360.0f);
leaf->spin = degrees(rsRand(-0.02f, 0.02f)) * 0.25f;
leaf->u1 = (float)sprite / (float) LEAVES_TEXTURES_COUNT;
leaf->u2 = (float)(sprite + 1) / (float) LEAVES_TEXTURES_COUNT;
leaf->altitude = -1.0f;
leaf->rippled = 1.0f;
leaf->deltaX = rsRand(-0.01f, 0.01f);
leaf->deltaY = -rsRand(0.036f, 0.044f);
leaf++;
}
}
void init() {
int ct;
gMaxDrops = 10;
for (ct=0; ct<gMaxDrops; ct++) {
gDrops[ct].ampS = 0;
gDrops[ct].ampE = 0;
gDrops[ct].spread = 1;
}
initLeaves();
g_LastTime = rsUptimeMillis();
g_DT = 0.1f;
}
static void updateDrop(int ct) {
gDrops[ct].spread += 30.f * g_DT;
gDrops[ct].ampE = gDrops[ct].ampS / gDrops[ct].spread;
}
static void drop(int x, int y, float s) {
int ct;
int iMin = 0;
float minAmp = 10000.f;
for (ct = 0; ct < gMaxDrops; ct++) {
if (gDrops[ct].ampE < minAmp) {
iMin = ct;
minAmp = gDrops[ct].ampE;
}
}
gDrops[iMin].ampS = s;
gDrops[iMin].spread = 0;
gDrops[iMin].x = x;
gDrops[iMin].y = g_meshHeight - y - 1;
updateDrop(iMin);
}
static void generateRipples() {
int ct;
for (ct = 0; ct < gMaxDrops; ct++) {
Drop_t * d = &gDrops[ct];
float *v = (float*)&g_Constants->Drop01;
v += ct*4;
*(v++) = d->x;
*(v++) = d->y;
*(v++) = d->ampE * 0.12f;
*(v++) = d->spread;
}
g_Constants->Offset.x = g_xOffset;
for (ct = 0; ct < gMaxDrops; ct++) {
updateDrop(ct);
}
}
static void genLeafDrop(Leaves_t *leaf, float amp) {
float nx = (leaf->x + g_glWidth * 0.5f) / g_glWidth;
float ny = (leaf->y + g_glHeight * 0.5f) / g_glHeight;
drop(nx * g_meshWidth, g_meshHeight - ny * g_meshHeight, amp);
}
static int drawLeaf(Leaves_t *leaf) {
float x = leaf->x;
float y = leaf->y;
float u1 = leaf->u1;
float u2 = leaf->u2;
float a = leaf->altitude;
float s = leaf->scale;
float r = leaf->angle;
float tz = 0.0f;
if (a > 0.0f) {
tz = -a;
}
rs_matrix4x4 matrix;
if (a > 0.0f) {
float alpha = 1.0f;
if (a >= 0.4f) alpha = 1.0f - (a - 0.4f) / 0.1f;
rsgProgramFragmentConstantColor(g_PFSky, 0.0f, 0.0f, 0.0f, alpha * 0.15f);
rsMatrixLoadIdentity(&matrix);
if (!g_rotate) {
rsMatrixTranslate(&matrix, x - g_xOffset * 2, y, 0);
} else {
rsMatrixTranslate(&matrix, x, y, 0);
rsMatrixRotate(&matrix, 90.0f, 0.0f, 0.0f, 1.0f);
}
float shadowOffet = a * 0.2f;
rsMatrixScale(&matrix, s, s, 1.0f);
rsMatrixRotate(&matrix, r, 0.0f, 0.0f, 1.0f);
rsgProgramVertexLoadModelMatrix(&matrix);
rsgDrawQuadTexCoords(-LEAF_SIZE, -LEAF_SIZE, 0, u1, 1.0f,
LEAF_SIZE, -LEAF_SIZE, 0, u2, 1.0f,
LEAF_SIZE, LEAF_SIZE, 0, u2, 0.0f,
-LEAF_SIZE, LEAF_SIZE, 0, u1, 0.0f);
rsgProgramFragmentConstantColor(g_PFSky, 1.0f, 1.0f, 1.0f, alpha);
} else {
rsgProgramFragmentConstantColor(g_PFSky, 1.0f, 1.0f, 1.0f, 1.0f);
}
rsMatrixLoadIdentity(&matrix);
if (!g_rotate) {
rsMatrixTranslate(&matrix, x - g_xOffset * 2, y, tz);
} else {
rsMatrixTranslate(&matrix, x, y, tz);
rsMatrixRotate(&matrix, 90.0f, 0.0f, 0.0f, 1.0f);
}
rsMatrixScale(&matrix, s, s, 1.0f);
rsMatrixRotate(&matrix, r, 0.0f, 0.0f, 1.0f);
rsgProgramVertexLoadModelMatrix(&matrix);
rsgDrawQuadTexCoords(-LEAF_SIZE, -LEAF_SIZE, 0, u1, 1.0f,
LEAF_SIZE, -LEAF_SIZE, 0, u2, 1.0f,
LEAF_SIZE, LEAF_SIZE, 0, u2, 0.0f,
-LEAF_SIZE, LEAF_SIZE, 0, u1, 0.0f);
float spin = leaf->spin;
if (a <= 0.0f) {
float rippled = leaf->rippled;
if (rippled < 0.0f) {
genLeafDrop(leaf, 1.5f);
//drop(((x + g_glWidth * 0.5f) / g_glWidth) * meshWidth,
// meshHeight - ((y + g_glHeight * 0.5f) / g_glHeight) * meshHeight, 1);
spin *= 0.25f;
leaf->spin = spin;
leaf->rippled = 1.0f;
}
leaf->x = x + leaf->deltaX * g_DT;
leaf->y = y + leaf->deltaY * g_DT;
r += spin;
leaf->angle = r;
} else {
a -= 0.15f * g_DT;
leaf->altitude = a;
r += spin * 2.0f;
leaf->angle = r;
}
int newLeaf = 0;
if (-LEAF_SIZE * s + x > g_glWidth || LEAF_SIZE * s + x < -g_glWidth ||
LEAF_SIZE * s + y < -g_glHeight * 0.5f) {
int sprite = rsRand(LEAVES_TEXTURES_COUNT);
leaf->x = rsRand(-g_glWidth, g_glWidth);
leaf->y = rsRand(-g_glHeight * 0.5f, g_glHeight * 0.5f);
leaf->scale = rsRand(0.4f, 0.5f);
leaf->spin = degrees(rsRand(-0.02f, 0.02f)) * 0.35f;
leaf->u1 = sprite / (float) LEAVES_TEXTURES_COUNT;
leaf->u2 = (sprite + 1) / (float) LEAVES_TEXTURES_COUNT;
leaf->altitude = 0.7f;
leaf->rippled = -1.0f;
leaf->deltaX = rsRand(-0.01f, 0.01f);
leaf->deltaY = -rsRand(0.036f, 0.044f);
leaf->newLeaf = 1;
newLeaf = 1;
}
return newLeaf;
}
static void drawLeaves() {
rsgBindProgramFragment(g_PFSky);
rsgBindProgramStore(g_PFSLeaf);
rsgBindProgramVertex(g_PVSky);
rsgBindTexture(g_PFSky, 0, g_TLeaves);
int newLeaves = 0;
int i = 0;
for ( ; i < LEAVES_COUNT; i += 1) {
if (drawLeaf(gLeaves[i])) {
newLeaves = 1;
}
}
if (newLeaves > 0) {
int index = 0;
// Copy all the old leaves to the beginning of gNextLeaves
for (i=0; i < LEAVES_COUNT; i++) {
if (gLeaves[i]->newLeaf == 0) {
gNextLeaves[index] = gLeaves[i];
index++;
}
}
// Now copy all the newly falling leaves to the end of gNextLeaves
for (i=0; i < LEAVES_COUNT; i++) {
if (gLeaves[i]->newLeaf > 0) {
gNextLeaves[index] = gLeaves[i];
gNextLeaves[index]->newLeaf = 0;
index++;
}
}
// And move everything in gNextLeaves back to gLeaves
for (i=0; i < LEAVES_COUNT; i++) {
gLeaves[i] = gNextLeaves[i];
}
}
rs_matrix4x4 matrix;
rsMatrixLoadIdentity(&matrix);
rsgProgramVertexLoadModelMatrix(&matrix);
}
static void drawRiverbed() {
rsgBindProgramFragment(g_PFBackground);
rsgBindProgramStore(g_PFSBackground);
rsgBindTexture(g_PFBackground, 0, g_TRiverbed);
rsgDrawMesh(g_WaterMesh);
}
void addDrop(int x, int y) {
drop(x, y, 2);
}
int root(void) {
rsgClearColor(0.f, 0.f, 0.f, 1.f);
// Compute dt in seconds.
int64_t newTime = rsUptimeMillis();
g_DT = (newTime - g_LastTime) * 0.001f;
g_DT = min(g_DT, 0.2f);
g_LastTime = newTime;
g_Constants->Rotate = (float) g_rotate;
int ct;
int add = 0;
for (ct = 0; ct < gMaxDrops; ct++) {
if (gDrops[ct].ampE < 0.005f) {
add = 1;
}
}
if (add) {
int i = (int)rsRand(LEAVES_COUNT);
genLeafDrop(gLeaves[i], rsRand(0.3f) + 0.1f);
}
rsgBindProgramVertex(g_PVWater);
generateRipples();
rsgAllocationSyncAll(rsGetAllocation(g_Constants));
drawRiverbed();
drawLeaves();
return 50;
}