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