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.nexus) 18 19 #include "rs_graphics.rsh" 20 #pragma stateVertex(parent) 21 22 #define MAX_PULSES 20 23 #define MAX_EXTRAS 40 24 #define PULSE_SIZE 14 // Size in pixels of a cell 25 #define HALF_PULSE_SIZE 7 26 #define GLOW_SIZE 64 // Size of the leading glow in pixels 27 #define HALF_GLOW_SIZE 32 28 #define SPEED 0.2f // (200 / 1000) Pixels per ms 29 #define SPEED_DELTA_MIN 0.7f 30 #define SPEED_DELTA_MAX 1.7f 31 #define PULSE_NORMAL 0 32 #define PULSE_EXTRA 1 33 #define TRAIL_SIZE 40 // Number of cells in a trail 34 #define MAX_DELAY 2000 // Delay between a pulse going offscreen and restarting 35 36 typedef struct pulse_s { 37 int pulseType; 38 float originX; 39 float originY; 40 int color; 41 int startTime; 42 float dx; 43 float dy; 44 float scale; 45 int active; 46 } pulse_t; 47 48 static pulse_t gPulses[MAX_PULSES]; 49 static pulse_t gExtras[MAX_EXTRAS]; 50 static int gNow; 51 static int gWidth; 52 static int gHeight; 53 static int gRotate; 54 55 float gXOffset; 56 int gIsPreview; 57 int gMode; 58 59 rs_program_fragment gPFTexture; 60 rs_program_store gPSBlend; 61 rs_program_fragment gPFTexture565; 62 63 rs_allocation gTBackground; 64 rs_allocation gTPulse; 65 rs_allocation gTGlow; 66 67 static void setColor(int c) { 68 if (gMode == 1) { 69 // sholes red 70 rsgProgramFragmentConstantColor(gPFTexture, 0.9f, 0.1f, 0.1f, 0.8f); 71 } else if (c == 0) { 72 // red 73 rsgProgramFragmentConstantColor(gPFTexture, 1.0f, 0.0f, 0.0f, 0.8f); 74 } else if (c == 1) { 75 // green 76 rsgProgramFragmentConstantColor(gPFTexture, 0.0f, 0.8f, 0.0f, 0.8f); 77 } else if (c == 2) { 78 // blue 79 rsgProgramFragmentConstantColor(gPFTexture, 0.0f, 0.4f, 0.9f, 0.8f); 80 } else if (c == 3) { 81 // yellow 82 rsgProgramFragmentConstantColor(gPFTexture, 1.0f, 0.8f, 0.0f, 0.8f); 83 } 84 } 85 86 static void initPulse(struct pulse_s * pulse, int pulseType) { 87 float scale = rsRand(SPEED_DELTA_MIN, SPEED_DELTA_MAX); 88 pulse->scale = scale; 89 gWidth = rsgGetWidth(); 90 gHeight = rsgGetHeight(); 91 if (rsRand(1.f) > 0.5f) { 92 pulse->originX = rsRand(gWidth * 2 / PULSE_SIZE) * PULSE_SIZE; 93 pulse->dx = 0; 94 if (rsRand(1.f) > 0.5f) { 95 // Top 96 pulse->originY = 0; 97 pulse->dy = scale; 98 } else { 99 // Bottom 100 pulse->originY = gHeight / scale; 101 pulse->dy = -scale; 102 } 103 } else { 104 pulse->originY = rsRand(gHeight / PULSE_SIZE) * PULSE_SIZE; 105 pulse->dy = 0; 106 if (rsRand(1.f) > 0.5f) { 107 // Left 108 pulse->originX = 0; 109 pulse->dx = scale; 110 } else { 111 // Right 112 pulse->originX = gWidth * 2 / scale; 113 pulse->dx = -scale; 114 } 115 } 116 pulse->startTime = gNow + rsRand(MAX_DELAY); 117 118 pulse->color = rsRand(4); 119 120 pulse->pulseType = pulseType; 121 if (pulseType == PULSE_EXTRA) { 122 pulse->active = 0; 123 } else { 124 pulse->active = 1; 125 } 126 } 127 128 void initPulses() { 129 gNow = (int)rsUptimeMillis(); 130 int i; 131 for (i=0; i<MAX_PULSES; i++) { 132 initPulse(&gPulses[i], PULSE_NORMAL); 133 } 134 for (i=0; i<MAX_EXTRAS; i++) { 135 struct pulse_s * p = &gExtras[i]; 136 p->pulseType = PULSE_EXTRA; 137 p->active = 0; 138 } 139 } 140 141 static void drawBackground() { 142 rsgBindProgramFragment(gPFTexture565); 143 rsgBindTexture(gPFTexture565, 0, gTBackground); 144 if (gRotate) { 145 rsgDrawRect(0.0f, 0.0f, gHeight*2, gWidth, 0.0f); 146 } else { 147 rsgDrawRect(0.0f, 0.0f, gWidth*2, gHeight, 0.0f); 148 } 149 } 150 151 static void drawPulses(pulse_t * pulseSet, int setSize) { 152 rsgBindProgramFragment(gPFTexture); 153 rsgBindProgramStore(gPSBlend); 154 155 rs_matrix4x4 matrix; 156 rs_matrix4x4 modelMatrix; 157 for (int i=0; i<setSize; i++) { 158 struct pulse_s * p = &pulseSet[i]; 159 int delta = gNow - p->startTime; 160 161 if (p->active != 0 && delta >= 0) { 162 163 rsMatrixLoadIdentity(&modelMatrix); 164 if (gRotate) { 165 //matrixLoadRotate(modelMatrix, 90.0f, 0.0f, 0.0f, 1.0f); 166 //matrixTranslate(modelMatrix, 0.0f, -height, 1.0f); 167 // XXX: HAX: do not slide display in landscape 168 } else { 169 rsMatrixTranslate(&modelMatrix, -(gXOffset * gWidth), 0, 0); 170 } 171 rsMatrixScale(&modelMatrix, p->scale, p->scale, 1.0f); 172 rsgProgramVertexLoadModelMatrix(&modelMatrix); 173 174 float x = p->originX + (p->dx * SPEED * delta); 175 float y = p->originY + (p->dy * SPEED * delta); 176 177 rsMatrixLoadIdentity(&matrix); 178 if (p->dx < 0) { 179 rsgProgramVertexLoadTextureMatrix(&matrix); 180 float xx = x + (TRAIL_SIZE * PULSE_SIZE); 181 if (xx <= 0) { 182 initPulse(p, p->pulseType); 183 } else { 184 setColor(p->color); 185 rsgBindTexture(gPFTexture, 0, gTPulse); 186 rsgDrawRect(x, y, xx, y + PULSE_SIZE, 0.0f); 187 rsgBindTexture(gPFTexture, 0, gTGlow); 188 rsgDrawRect(x + HALF_PULSE_SIZE - HALF_GLOW_SIZE, 189 y + HALF_PULSE_SIZE - HALF_GLOW_SIZE, 190 x + HALF_PULSE_SIZE + HALF_GLOW_SIZE, 191 y + HALF_PULSE_SIZE + HALF_GLOW_SIZE, 192 0.0f); 193 } 194 } else if (p->dx > 0) { 195 x += PULSE_SIZE; // need to start on the other side of this cell 196 rsMatrixRotate(&matrix, 180.0f, 0.0f, 0.0f, 1.0f); 197 rsgProgramVertexLoadTextureMatrix(&matrix); 198 float xx = x - (TRAIL_SIZE * PULSE_SIZE); 199 if (xx >= gWidth * 2) { 200 initPulse(p, p->pulseType); 201 } else { 202 setColor(p->color); 203 rsgBindTexture(gPFTexture, 0, gTPulse); 204 rsgDrawRect(xx, y, x, y + PULSE_SIZE, 0.0f); 205 rsgBindTexture(gPFTexture, 0, gTGlow); 206 rsgDrawRect(x - HALF_PULSE_SIZE - HALF_GLOW_SIZE, 207 y + HALF_PULSE_SIZE - HALF_GLOW_SIZE, 208 x - HALF_PULSE_SIZE + HALF_GLOW_SIZE, 209 y + HALF_PULSE_SIZE + HALF_GLOW_SIZE, 210 0.0f); 211 } 212 } else if (p->dy < 0) { 213 rsMatrixRotate(&matrix, -90.0f, 0.0f, 0.0f, 1.0f); 214 rsgProgramVertexLoadTextureMatrix(&matrix); 215 float yy = y + (TRAIL_SIZE * PULSE_SIZE); 216 if (yy <= 0) { 217 initPulse(p, p->pulseType); 218 } else { 219 setColor(p->color); 220 rsgBindTexture(gPFTexture, 0, gTPulse); 221 rsgDrawRect(x, y, x + PULSE_SIZE, yy, 0.0f); 222 rsgBindTexture(gPFTexture, 0, gTGlow); 223 rsgDrawRect(x + HALF_PULSE_SIZE - HALF_GLOW_SIZE, 224 y + HALF_PULSE_SIZE - HALF_GLOW_SIZE, 225 x + HALF_PULSE_SIZE + HALF_GLOW_SIZE, 226 y + HALF_PULSE_SIZE + HALF_GLOW_SIZE, 227 0.0f); 228 } 229 } else if (p->dy > 0) { 230 y += PULSE_SIZE; // need to start on the other side of this cell 231 rsMatrixRotate(&matrix, 90.0f, 0.0f, 0.0f, 1.0f); 232 rsgProgramVertexLoadTextureMatrix(&matrix); 233 float yy = y - (TRAIL_SIZE * PULSE_SIZE); 234 if (yy >= gHeight) { 235 initPulse(p, p->pulseType); 236 } else { 237 setColor(p->color); 238 rsgBindTexture(gPFTexture, 0, gTPulse); 239 rsgDrawRect(x, yy, x + PULSE_SIZE, y, 0.0f); 240 rsgBindTexture(gPFTexture, 0, gTGlow); 241 rsgDrawRect(x + HALF_PULSE_SIZE - HALF_GLOW_SIZE, 242 y - HALF_PULSE_SIZE - HALF_GLOW_SIZE, 243 x + HALF_PULSE_SIZE + HALF_GLOW_SIZE, 244 y - HALF_PULSE_SIZE + HALF_GLOW_SIZE, 245 0.0f); 246 } 247 } 248 } 249 } 250 251 rsMatrixLoadIdentity(&matrix); 252 rsgProgramVertexLoadTextureMatrix(&matrix); 253 } 254 255 void addTap(int x, int y) { 256 int count = 0; 257 int color = rsRand(4); 258 float scale = rsRand(0.9f, 1.9f); 259 x = (x / PULSE_SIZE) * PULSE_SIZE; 260 y = (y / PULSE_SIZE) * PULSE_SIZE; 261 for (int i=0; i<MAX_EXTRAS; i++) { 262 struct pulse_s * p = &gExtras[i]; 263 if (p->active == 0) { 264 p->originX = x/scale; 265 p->originY = y/scale; 266 p->scale = scale; 267 268 if (count == 0) { 269 p->dx = scale; 270 p->dy = 0.0f; 271 } else if (count == 1) { 272 p->dx = -scale; 273 p->dy = 0.0f; 274 } else if (count == 2) { 275 p->dx = 0.0f; 276 p->dy = scale; 277 } else if (count == 3) { 278 p->dx = 0.0f; 279 p->dy = -scale; 280 } 281 282 p->active = 1; 283 p->color = color; 284 color++; 285 if (color >= 4) { 286 color = 0; 287 } 288 p->startTime = gNow; 289 count++; 290 if (count == 4) { 291 break; 292 } 293 } 294 } 295 } 296 297 int root() { 298 rsgClearColor(0.f, 0.f, 0.f, 1.f); 299 300 gWidth = rsgGetWidth(); 301 gHeight = rsgGetHeight(); 302 gRotate = gWidth > gHeight ? 1 : 0; 303 304 gNow = (int)rsUptimeMillis(); 305 306 rs_matrix4x4 matrix; 307 rsMatrixLoadIdentity(&matrix); 308 309 if (gRotate) { 310 //matrixLoadRotate(matrix, 90.0f, 0.0f, 0.0f, 1.0f); 311 //matrixTranslate(matrix, 0.0f, -height, 1.0f); 312 // XXX: HAX: do not slide display in landscape 313 } else { 314 rsMatrixTranslate(&matrix, -(gXOffset * gWidth), 0, 0); 315 } 316 317 rsgProgramVertexLoadModelMatrix(&matrix); 318 319 drawBackground(); 320 drawPulses(gPulses, MAX_PULSES); 321 drawPulses(gExtras, MAX_EXTRAS); 322 323 return 45; 324 } 325