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 26 float g_glWidth; 27 float g_glHeight; 28 float g_meshWidth; 29 float g_meshHeight; 30 float g_xOffset; 31 float g_rotate; 32 33 rs_program_vertex g_PVWater; 34 rs_program_vertex g_PVSky; 35 36 rs_program_fragment g_PFSky; 37 rs_program_store g_PFSLeaf; 38 rs_program_fragment g_PFBackground; 39 40 rs_allocation g_TLeaves; 41 rs_allocation g_TRiverbed; 42 43 rs_mesh g_WaterMesh; 44 45 typedef 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 60 Constants_t *g_Constants; 61 rs_program_store g_PFSBackground; 62 63 //float skyOffsetX; 64 //float skyOffsetY; 65 static float g_DT; 66 static int64_t g_LastTime; 67 68 typedef struct Drop { 69 float ampS; 70 float ampE; 71 float spread; 72 float x; 73 float y; 74 } Drop_t; 75 static Drop_t gDrops[10]; 76 static int gMaxDrops; 77 78 typedef 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 93 static Leaves_t gLeavesStore[LEAVES_COUNT]; 94 static Leaves_t* gLeaves[LEAVES_COUNT]; 95 static Leaves_t* gNextLeaves[LEAVES_COUNT]; 96 97 void 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 123 void 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 137 static void updateDrop(int ct) { 138 gDrops[ct].spread += 30.f * g_DT; 139 gDrops[ct].ampE = gDrops[ct].ampS / gDrops[ct].spread; 140 } 141 142 static 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 159 static 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 177 static 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 183 static 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 293 static 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 339 static void drawRiverbed() { 340 rsgBindProgramFragment(g_PFBackground); 341 rsgBindProgramStore(g_PFSBackground); 342 rsgBindTexture(g_PFBackground, 0, g_TRiverbed); 343 rsgDrawMesh(g_WaterMesh); 344 } 345 346 void addDrop(int x, int y) { 347 drop(x, y, 2); 348 } 349 350 int 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