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.magicsmoke)
18
19#include "rs_graphics.rsh"
20
21#define RSID_NOISESRC1 1
22#define RSID_NOISESRC2 2
23#define RSID_NOISESRC3 3
24#define RSID_NOISESRC4 4
25#define RSID_NOISESRC5 5
26#define RSID_NOISEDST1 6
27#define RSID_NOISEDST2 7
28#define RSID_NOISEDST3 8
29#define RSID_NOISEDST4 9
30#define RSID_NOISEDST5 10
31
32// State set from java
33float gXOffset;
34float gYOffset;
35int   gPreset;
36int   gTextureMask;
37int   gRotate;
38int   gTextureSwap;
39int   gProcessTextureMode;
40int   gBackCol;
41int   gLowCol;
42int   gHighCol;
43float gAlphaMul;
44int   gPreMul;
45
46typedef struct VertexShaderConstants_s {
47    float4 layer0;
48    float4 layer1;
49    float4 layer2;
50    float4 layer3;
51    float4 layer4;
52    float2 panoffset;
53} VertexShaderConstants;
54VertexShaderConstants *gVSConstants;
55
56typedef struct FragmentShaderConstants_s {
57    float4 clearColor;
58} FragmentShaderConstants;
59FragmentShaderConstants *gFSConstants;
60
61typedef struct VertexInputs_s {
62    float4 position;
63    float2 texture0;
64} VertexInputs;
65VertexInputs *gVS;
66
67
68rs_program_fragment gPF5tex;
69rs_program_vertex gPV5tex;
70rs_program_fragment gPF4tex;
71rs_program_vertex gPV4tex;
72
73rs_program_store gPStore;
74
75rs_allocation gTnoise1;
76rs_allocation gTnoise2;
77rs_allocation gTnoise3;
78rs_allocation gTnoise4;
79rs_allocation gTnoise5;
80
81int *gNoisesrc1;
82int *gNoisesrc2;
83int *gNoisesrc3;
84int *gNoisesrc4;
85int *gNoisesrc5;
86
87int *gNoisedst1;
88int *gNoisedst2;
89int *gNoisedst3;
90int *gNoisedst4;
91int *gNoisedst5;
92
93// Local script variables
94static float xshift[5];
95static float rotation[5];
96static float scale[5];
97static float alphafactor;
98static int currentpreset;
99static int lastuptime;
100static float timedelta;
101static float4 clearColor = {0.5f, 0.0f, 0.0f, 1.0f};
102static int countTextures()
103{
104    int pos = 0;
105    for (int i = 0; i < 5; i++)
106    {
107        if (gTextureMask & (1<<i))
108            pos++;
109    }
110    return pos;
111}
112#define rotate(s, a) \
113do { \
114    float __agl = (3.1415927f / 180.0f) * a; \
115    s.x = sin(__agl); \
116    s.y = cos(__agl); \
117} while (0)
118
119static void update()
120{
121    rs_program_vertex pv;
122    pv = gPV5tex;
123    rs_program_fragment pf;
124    pf = gPF5tex;
125
126    if (countTextures() == 4)
127    {
128        pv = gPV4tex;
129        pf = gPF4tex;
130    }
131    rsgBindProgramFragment(pf);
132    rsgBindProgramVertex(pv);
133    rsgBindProgramStore(gPStore);
134
135    rotate(gVSConstants->layer0, rotation[0]);
136    rotate(gVSConstants->layer1, rotation[1]);
137    rotate(gVSConstants->layer2, rotation[2]);
138    rotate(gVSConstants->layer3, rotation[3]);
139    rotate(gVSConstants->layer4, rotation[4]);
140
141    gVSConstants->layer0.w = xshift[0];
142    gVSConstants->layer1.w = xshift[1];
143    gVSConstants->layer2.w = xshift[2];
144    gVSConstants->layer3.w = xshift[3];
145    gVSConstants->layer4.w = xshift[4];
146
147    float m = 0.35f;
148    gVSConstants->layer0.z = m * scale[0];
149    gVSConstants->layer1.z = m * scale[1];
150    gVSConstants->layer2.z = m * scale[2];
151    gVSConstants->layer3.z = m * scale[3];
152    gVSConstants->layer4.z = m * scale[4];
153
154    gVSConstants->panoffset.x = gXOffset;
155    gVSConstants->panoffset.y = -gYOffset;
156
157    gFSConstants->clearColor = clearColor;
158
159    int pos = 0;
160    for (int i = 0; i < 5; i++)
161    {
162        if (gTextureMask & (1<<i))
163        {
164            switch (i)
165            {
166                case 0: rsgBindTexture(pf, pos, gTextureSwap != 0 ? gTnoise5 : gTnoise1); break;
167                case 1: rsgBindTexture(pf, pos, gTnoise2); break;
168                case 2: rsgBindTexture(pf, pos, gTnoise3); break;
169                case 3: rsgBindTexture(pf, pos, gTnoise4); break;
170                case 4: rsgBindTexture(pf, pos, gTnoise5); break;
171                default: break;
172            }
173            pos++;
174        }
175    }
176}
177
178static void drawClouds() {
179    if (gRotate != 0)
180    {
181        rotation[0] += 0.100f * timedelta;
182        rotation[1] += 0.102f * timedelta;
183        rotation[2] += 0.106f * timedelta;
184        rotation[3] += 0.114f * timedelta;
185        rotation[4] += 0.123f * timedelta;
186    }
187
188    int mask = gTextureMask;
189    if (mask & 1) {
190        xshift[0] += 0.00100f * timedelta;
191    }
192    if (mask & 2) {
193        xshift[1] += 0.00106f * timedelta;
194    }
195    if (mask & 4) {
196        xshift[2] += 0.00114f * timedelta;
197    }
198    if (mask & 8) {
199        xshift[3] += 0.00118f * timedelta;
200    }
201    if (mask & 16) {
202        xshift[4] += 0.00127f * timedelta;
203    }
204
205    update();
206
207    float z = 0;
208    rsgDrawQuad(
209        -1.0f, -1.0f, z,
210         1.0f, -1.0f, z,
211         1.0f,  1.0f, z,
212        -1.0f,  1.0f, z
213    );
214
215    // Make sure the texture coordinates don't continuously increase
216    int i;
217    for(i = 0; i < 5; i++) {
218        if (xshift[i] > 1.f) {
219            xshift[i] -= floor(xshift[i]);
220        }
221    }
222    // Make sure the rotation angles don't continuously increase
223    for(i = 0; i < 5; i++) {
224        if (rotation[i] > 360.f) {
225            float multiplier = floor(rotation[i]/360.f);
226            rotation[i] -= 360.f * multiplier;
227        }
228    }
229}
230
231static int premul(int rgb, int a) {
232    int r = (rgb >> 16) * a + 1;
233    r = (r + (r >> 8)) >> 8;
234    int g = ((rgb >> 8) & 0xff) * a + 1;
235    g = (g + (g >> 8)) >> 8;
236    int b = (rgb & 0xff) * a + 1;
237    b = (b + (b >> 8)) >> 8;
238    return r << 16 | g << 8 | b;
239}
240
241
242static void makeTexture(int *src, int *dst, rs_allocation rsid) {
243
244    int x;
245    int y;
246    int pm = gPreMul;
247
248    if (gProcessTextureMode == 1) {
249        int lowcol = gLowCol;
250        int highcol = gHighCol;
251
252        for (y=0;y<256;y++) {
253            for (x=0;x<256;x++) {
254                int pix = src[y*256+x];
255                int lum = pix & 0x00ff;
256                int newpix;
257                if (lum < 128) {
258                    newpix = lowcol;
259                    int newalpha = 255 - (lum * 2);
260                    newalpha /= alphafactor;
261                    if (pm) newpix = premul(newpix, newalpha);
262                    newpix = newpix | (newalpha << 24);
263                } else {
264                    newpix = highcol;
265                    int newalpha = (lum - 128) * 2;
266                    newalpha /= alphafactor;
267                    if (pm) newpix = premul(newpix, newalpha);
268                    newpix = newpix | (newalpha << 24);
269                }
270                // have ARGB, need ABGR
271                newpix = (newpix & 0xff00ff00) | ((newpix & 0xff) << 16) | ((newpix >> 16) & 0xff);
272                dst[y*256+x] = newpix;
273            }
274        }
275        alphafactor *= gAlphaMul;
276    } else if (gProcessTextureMode == 2) {
277        int lowcol = gLowCol;
278        int highcol = gHighCol;
279        float scale = 255.f / (255.f - lowcol);
280
281        for (y=0;y<256;y++) {
282            for (x=0;x<256;x++) {
283                int pix = src[y*256+x];
284                int alpha = pix & 0x00ff;
285                if (alpha < lowcol) {
286                    alpha = 0;
287                } else {
288                    alpha = (alpha - lowcol) * scale;
289                }
290                alpha /= alphafactor;
291                int newpix = highcol;
292                if (pm) newpix = premul(newpix, alpha);
293                newpix = newpix | (alpha << 24);
294                // have ARGB, need ABGR
295                newpix = (newpix & 0xff00ff00) | ((newpix & 0xff) << 16) | ((newpix >> 16) & 0xff);
296                dst[y*256+x] = newpix;
297            }
298        }
299        alphafactor *= gAlphaMul;
300    } else if (gProcessTextureMode == 3) {
301        int lowcol = gLowCol;
302        int highcol = gHighCol;
303        float scale = 255.f / (255.f - lowcol);
304
305        for (y=0;y<256;y++) {
306            for (x=0;x<256;x++) {
307                int pix = src[y*256+x];
308                int lum = pix & 0x00ff;
309                int newpix;
310                if (lum < 128) lum *= 2;
311                else lum = (255 - (lum - 128) * 2);
312                if (lum < 128) {
313                    newpix = lowcol;
314                    int newalpha = 255 - (lum * 2);
315                    newalpha /= alphafactor;
316                    if (pm) newpix = premul(newpix, newalpha);
317                    newpix = newpix | (newalpha << 24);
318                } else {
319                    newpix = highcol;
320                    int newalpha = (lum - 128) * 2;
321                    newalpha /= alphafactor;
322                    if (pm) newpix = premul(newpix, newalpha);
323                    newpix = newpix | (newalpha << 24);
324                }
325                // have ARGB, need ABGR
326                newpix = (newpix & 0xff00ff00) | ((newpix & 0xff) << 16) | ((newpix >> 16) & 0xff);
327                dst[y*256+x] = newpix;
328            }
329        }
330        alphafactor *= gAlphaMul;
331    } else {
332        for (y=0;y<256;y++) {
333            for (x=0;x<256;x++) {
334                int rgb = *src++;
335                int a = (rgb >> 24) & 0xff;
336                rgb &= 0x00ffffff;
337                rgb = premul(rgb, a);
338                int newpix = (a << 24) | rgb;
339                newpix = (newpix & 0xff00ff00) | ((newpix & 0xff) << 16) | ((newpix >> 16) & 0xff);
340                *dst++ = newpix;
341            }
342        }
343    }
344
345    rsgAllocationSyncAll(rsid);
346}
347
348static void makeTextures() {
349    alphafactor = 1.f;
350    makeTexture((int*)gNoisesrc1, (int*)gNoisedst1, gTnoise1);
351    makeTexture((int*)gNoisesrc2, (int*)gNoisedst2, gTnoise2);
352    makeTexture((int*)gNoisesrc3, (int*)gNoisedst3, gTnoise3);
353    makeTexture((int*)gNoisesrc4, (int*)gNoisedst4, gTnoise4);
354    makeTexture((int*)gNoisesrc5, (int*)gNoisedst5, gTnoise5);
355}
356
357void init() {
358    for (int i=0;i<5;i++) {
359        xshift[i] = 0.f;
360        rotation[i] = 360.f * i / 5.f;
361    }
362
363    scale[0] = 4.0f; // changed below based on preset
364    scale[1] = 3.0f;
365    scale[2] = 3.4f;
366    scale[3] = 3.8f;
367    scale[4] = 4.2f;
368
369    currentpreset = -1;
370    lastuptime = (int)rsUptimeMillis();
371    timedelta = 0;
372}
373
374
375int root(void) {
376    int i;
377
378    int now = (int)rsUptimeMillis();
379    timedelta = ((float)(now - lastuptime)) / 44.f;
380    lastuptime = now;
381    if (timedelta > 3) {
382        // Limit the step adjustment factor to 3, so we don't get a sudden jump
383        // after coming back from sleep.
384        timedelta = 3;
385    }
386
387    i = gPreset;
388    if (i != currentpreset) {
389        currentpreset = i;
390        clearColor.x = ((float)((gBackCol >> 16)  & 0xff)) / 255.0f;
391        clearColor.y = ((float)((gBackCol >> 8)  & 0xff)) / 255.0f;
392        clearColor.z = ((float)(gBackCol & 0xff)) / 255.0f;
393        makeTextures();
394    }
395
396    if (gTextureSwap != 0) {
397        scale[0] = .25f;
398    } else {
399        scale[0] = 4.f;
400    }
401    drawClouds();
402
403    return 55;
404}
405