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