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
33 float gXOffset;
34 float gYOffset;
35 int   gPreset;
36 int   gTextureMask;
37 int   gRotate;
38 int   gTextureSwap;
39 int   gProcessTextureMode;
40 int   gBackCol;
41 int   gLowCol;
42 int   gHighCol;
43 float gAlphaMul;
44 int   gPreMul;
45 
46 typedef struct VertexShaderConstants_s {
47     float4 layer0;
48     float4 layer1;
49     float4 layer2;
50     float4 layer3;
51     float4 layer4;
52     float2 panoffset;
53 } VertexShaderConstants;
54 VertexShaderConstants *gVSConstants;
55 
56 typedef struct FragmentShaderConstants_s {
57     float4 clearColor;
58 } FragmentShaderConstants;
59 FragmentShaderConstants *gFSConstants;
60 
61 typedef struct VertexInputs_s {
62     float4 position;
63     float2 texture0;
64 } VertexInputs;
65 VertexInputs *gVS;
66 
67 
68 rs_program_fragment gPF5tex;
69 rs_program_vertex gPV5tex;
70 rs_program_fragment gPF4tex;
71 rs_program_vertex gPV4tex;
72 
73 rs_program_store gPStore;
74 
75 rs_allocation gTnoise1;
76 rs_allocation gTnoise2;
77 rs_allocation gTnoise3;
78 rs_allocation gTnoise4;
79 rs_allocation gTnoise5;
80 
81 int *gNoisesrc1;
82 int *gNoisesrc2;
83 int *gNoisesrc3;
84 int *gNoisesrc4;
85 int *gNoisesrc5;
86 
87 int *gNoisedst1;
88 int *gNoisedst2;
89 int *gNoisedst3;
90 int *gNoisedst4;
91 int *gNoisedst5;
92 
93 // Local script variables
94 static float xshift[5];
95 static float rotation[5];
96 static float scale[5];
97 static float alphafactor;
98 static int currentpreset;
99 static int lastuptime;
100 static float timedelta;
101 static float4 clearColor = {0.5f, 0.0f, 0.0f, 1.0f};
102 static 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) \
113 do { \
114     float __agl = (3.1415927f / 180.0f) * a; \
115     s.x = sin(__agl); \
116     s.y = cos(__agl); \
117 } while (0)
118 
119 static 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 
178 static 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 
231 static 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 
242 static 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 
348 static 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 
357 void 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 
375 int 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