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.galaxy)
18
19#include "rs_graphics.rsh"
20
21#pragma stateVertex(parent);
22#pragma stateStore(parent);
23
24#define ELLIPSE_RATIO 0.892f
25#define PI 3.1415f
26#define TWO_PI 6.283f
27#define ELLIPSE_TWIST 0.023333333f
28
29static float angle = 50.f;
30static int gOldWidth;
31static int gOldHeight;
32static int gWidth;
33static int gHeight;
34static float gSpeed[12000];
35static int gGalaxyRadius = 300;
36static rs_allocation gParticlesBuffer;
37
38float gXOffset;
39int gIsPreview;
40
41rs_program_fragment gPFBackground;
42rs_program_fragment gPFStars;
43rs_program_vertex gPVStars;
44rs_program_vertex gPVBkProj;
45rs_program_store gPSLights;
46
47rs_allocation gTSpace;
48rs_allocation gTFlares;
49rs_allocation gTLight1;
50rs_mesh gParticlesMesh;
51
52typedef struct __attribute__((packed, aligned(4))) Particle {
53    uchar4 color;
54    float3 position;
55} Particle_t;
56Particle_t *Particles;
57
58typedef struct VpConsts {
59    rs_matrix4x4 Proj;
60    rs_matrix4x4 MVP;
61} VpConsts_t;
62VpConsts_t *vpConstants;
63
64static float mapf(float minStart, float minStop, float maxStart, float maxStop, float value) {
65    return maxStart + (maxStart - maxStop) * ((value - minStart) / (minStop - minStart));
66}
67
68/**
69 * Helper function to generate the stars.
70 */
71static float randomGauss() {
72    float x1;
73    float x2;
74    float w = 2.f;
75
76    while (w >= 1.0f) {
77        x1 = rsRand(2.0f) - 1.0f;
78        x2 = rsRand(2.0f) - 1.0f;
79        w = x1 * x1 + x2 * x2;
80    }
81
82    w = sqrt(-2.0f * log(w) / w);
83    return x1 * w;
84}
85
86/**
87 * Generates the properties for a given star.
88 */
89static void createParticle(Particle_t *part, int idx, float scale) {
90    float d = fabs(randomGauss()) * gGalaxyRadius * 0.5f + rsRand(64.0f);
91    float id = d / gGalaxyRadius;
92    float z = randomGauss() * 0.4f * (1.0f - id);
93    float p = -d * ELLIPSE_TWIST;
94
95    if (d < gGalaxyRadius * 0.33f) {
96        part->color.x = (uchar) (220 + id * 35);
97        part->color.y = 220;
98        part->color.z = 220;
99    } else {
100        part->color.x = 180;
101        part->color.y = 180;
102        part->color.z = (uchar) clamp(140.f + id * 115.f, 140.f, 255.f);
103    }
104    // Stash point size * 10 in Alpha
105    part->color.w = (uchar) (rsRand(1.2f, 2.1f) * 60);
106
107    if (d > gGalaxyRadius * 0.15f) {
108        z *= 0.6f * (1.0f - id);
109    } else {
110        z *= 0.72f;
111    }
112
113    // Map to the projection coordinates (viewport.x = -1.0 -> 1.0)
114    d = mapf(-4.0f, gGalaxyRadius + 4.0f, 0.0f, scale, d);
115
116    part->position.x = rsRand(TWO_PI);
117    part->position.y = d;
118    gSpeed[idx] = rsRand(0.0015f, 0.0025f) * (0.5f + (scale / d)) * 0.8f;
119
120    part->position.z = z / 5.0f;
121}
122
123/**
124 * Initialize all the stars. Called from Java.
125 */
126void initParticles() {
127    if (gIsPreview == 1) {
128        angle = 0.0f;
129    }
130
131    Particle_t *part = Particles;
132    float scale = gGalaxyRadius / (gWidth * 0.5f);
133    int count = rsAllocationGetDimX(gParticlesBuffer);
134    for (int i = 0; i < count; i ++) {
135        createParticle(part, i, scale);
136        part++;
137    }
138}
139
140static void drawSpace() {
141    rsgBindProgramFragment(gPFBackground);
142    rsgBindTexture(gPFBackground, 0, gTSpace);
143    rsgDrawQuadTexCoords(
144            0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
145            gWidth, 0.0f, 0.0f, 2.0f, 1.0f,
146            gWidth, gHeight, 0.0f, 2.0f, 0.0f,
147            0.0f, gHeight, 0.0f, 0.0f, 0.0f);
148}
149
150static void calcMatrix(rs_matrix4x4 *out, float offset) {
151    float a = offset * angle;
152    float absoluteAngle = fabs(a);
153
154    rsMatrixLoadTranslate(out, 0.0f, 0.0f, 10.0f - 6.0f * absoluteAngle / 50.0f);
155    if (gHeight > gWidth) {
156        rsMatrixScale(out, 6.6f, 6.0f, 1.0f);
157    } else {
158        rsMatrixScale(out, 12.6f, 12.0f, 1.0f);
159    }
160    rsMatrixRotate(out, absoluteAngle, 1.0f, 0.0f, 0.0f);
161    rsMatrixRotate(out, a, 0.0f, 0.4f, 0.1f);
162}
163
164static void drawLights(const rs_matrix4x4 *m) {
165    rsgBindProgramVertex(gPVBkProj);
166    rsgBindProgramFragment(gPFBackground);
167    rsgBindTexture(gPFBackground, 0, gTLight1);
168    rsgProgramVertexLoadModelMatrix(m);
169
170    float sx = (512.0f / gWidth) * 1.1f;
171    float sy = (512.0f / gWidth) * 1.2f;
172    rsgDrawQuad(-sx, -sy, 0.0f,
173                 sx, -sy, 0.0f,
174                 sx,  sy, 0.0f,
175                -sx,  sy, 0.0f);
176}
177
178static void drawParticles(const rs_matrix4x4 *m) {
179    rsMatrixLoad(&vpConstants->MVP, &vpConstants->Proj);
180    rsMatrixMultiply(&vpConstants->MVP, m);
181    rsgAllocationSyncAll(rsGetAllocation(vpConstants));
182
183    rsgBindProgramVertex(gPVStars);
184    rsgBindProgramFragment(gPFStars);
185    rsgBindProgramStore(gPSLights);
186    rsgBindTexture(gPFStars, 0, gTFlares);
187
188    Particle_t *vtx = Particles;
189    int count = rsAllocationGetDimX(gParticlesBuffer);
190    for (int i = 0; i < count; i++) {
191        vtx->position.x = vtx->position.x + gSpeed[i];
192        vtx++;
193    }
194
195    rsgDrawMesh(gParticlesMesh);
196}
197
198int root() {
199    rsgClearColor(0.f, 0.f, 0.f, 1.f);
200
201    gParticlesBuffer = rsGetAllocation(Particles);
202    rsgBindProgramFragment(gPFBackground);
203
204    gWidth = rsgGetWidth();
205    gHeight = rsgGetHeight();
206    if ((gWidth != gOldWidth) || (gHeight != gOldHeight)) {
207        initParticles();
208        gOldWidth = gWidth;
209        gOldHeight = gHeight;
210    }
211
212    drawSpace();
213
214    rs_matrix4x4 matrix;
215    calcMatrix(&matrix, mix(-0.5f, 0.5f, gXOffset));
216    drawParticles(&matrix);
217    drawLights(&matrix);
218
219    return 45;
220}
221