blob: e012164127049f3930aedea592afb20ad3bc65fa [file] [log] [blame]
// Copyright (C) 2009 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma version(1)
#pragma rs java_package_name(com.android.magicsmoke)
#include "rs_graphics.rsh"
#define RSID_NOISESRC1 1
#define RSID_NOISESRC2 2
#define RSID_NOISESRC3 3
#define RSID_NOISESRC4 4
#define RSID_NOISESRC5 5
#define RSID_NOISEDST1 6
#define RSID_NOISEDST2 7
#define RSID_NOISEDST3 8
#define RSID_NOISEDST4 9
#define RSID_NOISEDST5 10
// State set from java
float gXOffset;
float gTilt;
int gPreset;
int gTextureMask;
int gRotate;
int gTextureSwap;
int gProcessTextureMode;
int gBackCol;
int gLowCol;
int gHighCol;
float gAlphaMul;
int gPreMul;
int gBlendFunc;
typedef struct VertexShaderConstants_s {
float4 layer0;
float4 layer1;
float4 layer2;
float4 layer3;
float4 layer4;
} VertexShaderConstants;
VertexShaderConstants *gVSConstants;
typedef struct FragmentShaderConstants_s {
float4 clearColor;
} FragmentShaderConstants;
FragmentShaderConstants *gFSConstants;
typedef struct VertexInputs_s {
float4 position;
float2 texture0;
} VertexInputs;
VertexInputs *gVS;
rs_program_fragment gPF5tex;
rs_program_vertex gPV5tex;
rs_program_fragment gPF4tex;
rs_program_vertex gPV4tex;
rs_program_store gPStore;
rs_allocation gTnoise1;
rs_allocation gTnoise2;
rs_allocation gTnoise3;
rs_allocation gTnoise4;
rs_allocation gTnoise5;
int *gNoisesrc1;
int *gNoisesrc2;
int *gNoisesrc3;
int *gNoisesrc4;
int *gNoisesrc5;
int *gNoisedst1;
int *gNoisedst2;
int *gNoisedst3;
int *gNoisedst4;
int *gNoisedst5;
#pragma rs_export_func()
// Local script variables
static float xshift[5];
static float rotation[5];
static float scale[5];
static float alphafactor;
static int currentpreset;
static int lastuptime;
static float timedelta;
static float4 clearColor = {0.5f, 0.0f, 0.0f, 1.0f};
int countTextures()
{
int pos = 0;
for (int i = 0; i < 5; i++)
{
if (gTextureMask & (1<<i))
pos++;
}
return pos;
}
#define rotate(s, a) \
do { \
float __agl = (3.1415927f / 180.0f) * a; \
s.x = sin(__agl); \
s.y = cos(__agl); \
} while (0)
void update()
{
rs_program_vertex pv;
rsSetObject(&pv, gPV5tex);
rs_program_fragment pf;
rsSetObject(&pf, gPF5tex);
if (countTextures() == 4)
{
rsSetObject(&pv, gPV4tex);
rsSetObject(&pf, gPF4tex);
}
rsgBindProgramFragment(pf);
rsgBindProgramVertex(pv);
rsgBindProgramStore(gPStore);
rotate(gVSConstants->layer0, rotation[0]);
rotate(gVSConstants->layer1, rotation[1]);
rotate(gVSConstants->layer2, rotation[2]);
rotate(gVSConstants->layer3, rotation[3]);
rotate(gVSConstants->layer4, rotation[4]);
gVSConstants->layer0.w = -gXOffset * 0 + xshift[0];
gVSConstants->layer1.w = -gXOffset * 8 + xshift[1];
gVSConstants->layer2.w = -gXOffset * 16 + xshift[2];
gVSConstants->layer3.w = -gXOffset * 24 + xshift[3];
gVSConstants->layer4.w = -gXOffset * 32 + xshift[4];
float m = 0.35f;
gVSConstants->layer0.z = m * scale[0];
gVSConstants->layer1.z = m * scale[1];
gVSConstants->layer2.z = m * scale[2];
gVSConstants->layer3.z = m * scale[3];
gVSConstants->layer4.z = m * scale[4];
gFSConstants->clearColor = clearColor;
int pos = 0;
for (int i = 0; i < 5; i++)
{
if (gTextureMask & (1<<i))
{
switch (i)
{
case 0: rsgBindTexture(pf, pos, gTextureSwap != 0 ? gTnoise5 : gTnoise1); break;
case 1: rsgBindTexture(pf, pos, gTnoise2); break;
case 2: rsgBindTexture(pf, pos, gTnoise3); break;
case 3: rsgBindTexture(pf, pos, gTnoise4); break;
case 4: rsgBindTexture(pf, pos, gTnoise5); break;
default: break;
}
pos++;
}
}
}
void drawClouds() {
if (gRotate != 0)
{
rotation[0] += 0.100f * timedelta;
rotation[1] += 0.102f * timedelta;
rotation[2] += 0.106f * timedelta;
rotation[3] += 0.114f * timedelta;
rotation[4] += 0.123f * timedelta;
}
int mask = gTextureMask;
if (mask & 1) {
xshift[0] += 0.00100f * timedelta;
}
if (mask & 2) {
xshift[1] += 0.00106f * timedelta;
}
if (mask & 4) {
xshift[2] += 0.00114f * timedelta;
}
if (mask & 8) {
xshift[3] += 0.00118f * timedelta;
}
if (mask & 16) {
xshift[4] += 0.00127f * timedelta;
}
update();
float z = 0;
rsgDrawQuad(
-1.0f, -1.0f, z,
1.0f, -1.0f, z,
1.0f, 1.0f, z,
-1.0f, 1.0f, z
);
// Make sure the texture coordinates don't continuously increase
int i;
for(i = 0; i < 5; i++) {
if (xshift[i] > 1.f) {
xshift[i] -= floor(xshift[i]);
}
}
// Make sure the rotation angles don't continuously increase
for(i = 0; i < 5; i++) {
if (rotation[i] > 360.f) {
float multiplier = floor(rotation[i]/360.f);
rotation[i] -= 360.f * multiplier;
}
}
}
int premul(int rgb, int a) {
int r = (rgb >> 16) * a + 1;
r = (r + (r >> 8)) >> 8;
int g = ((rgb >> 8) & 0xff) * a + 1;
g = (g + (g >> 8)) >> 8;
int b = (rgb & 0xff) * a + 1;
b = (b + (b >> 8)) >> 8;
return r << 16 | g << 8 | b;
}
void makeTexture(int *src, int *dst, rs_allocation rsid) {
int x;
int y;
int pm = gPreMul;
if (gProcessTextureMode == 1) {
int lowcol = gLowCol;
int highcol = gHighCol;
for (y=0;y<256;y++) {
for (x=0;x<256;x++) {
int pix = src[y*256+x];
int lum = pix & 0x00ff;
int newpix;
if (lum < 128) {
newpix = lowcol;
int newalpha = 255 - (lum * 2);
newalpha /= alphafactor;
if (pm) newpix = premul(newpix, newalpha);
newpix = newpix | (newalpha << 24);
} else {
newpix = highcol;
int newalpha = (lum - 128) * 2;
newalpha /= alphafactor;
if (pm) newpix = premul(newpix, newalpha);
newpix = newpix | (newalpha << 24);
}
// have ARGB, need ABGR
newpix = (newpix & 0xff00ff00) | ((newpix & 0xff) << 16) | ((newpix >> 16) & 0xff);
dst[y*256+x] = newpix;
}
}
alphafactor *= gAlphaMul;
} else if (gProcessTextureMode == 2) {
int lowcol = gLowCol;
int highcol = gHighCol;
float scale = 255.f / (255.f - lowcol);
for (y=0;y<256;y++) {
for (x=0;x<256;x++) {
int pix = src[y*256+x];
int alpha = pix & 0x00ff;
if (alpha < lowcol) {
alpha = 0;
} else {
alpha = (alpha - lowcol) * scale;
}
alpha /= alphafactor;
int newpix = highcol;
if (pm) newpix = premul(newpix, alpha);
newpix = newpix | (alpha << 24);
// have ARGB, need ABGR
newpix = (newpix & 0xff00ff00) | ((newpix & 0xff) << 16) | ((newpix >> 16) & 0xff);
dst[y*256+x] = newpix;
}
}
alphafactor *= gAlphaMul;
} else if (gProcessTextureMode == 3) {
int lowcol = gLowCol;
int highcol = gHighCol;
float scale = 255.f / (255.f - lowcol);
for (y=0;y<256;y++) {
for (x=0;x<256;x++) {
int pix = src[y*256+x];
int lum = pix & 0x00ff;
int newpix;
if (lum < 128) lum *= 2;
else lum = (255 - (lum - 128) * 2);
if (lum < 128) {
newpix = lowcol;
int newalpha = 255 - (lum * 2);
newalpha /= alphafactor;
if (pm) newpix = premul(newpix, newalpha);
newpix = newpix | (newalpha << 24);
} else {
newpix = highcol;
int newalpha = (lum - 128) * 2;
newalpha /= alphafactor;
if (pm) newpix = premul(newpix, newalpha);
newpix = newpix | (newalpha << 24);
}
// have ARGB, need ABGR
newpix = (newpix & 0xff00ff00) | ((newpix & 0xff) << 16) | ((newpix >> 16) & 0xff);
dst[y*256+x] = newpix;
}
}
alphafactor *= gAlphaMul;
} else {
for (y=0;y<256;y++) {
for (x=0;x<256;x++) {
int rgb = *src++;
int a = (rgb >> 24) & 0xff;
rgb &= 0x00ffffff;
rgb = premul(rgb, a);
int newpix = (a << 24) | rgb;
newpix = (newpix & 0xff00ff00) | ((newpix & 0xff) << 16) | ((newpix >> 16) & 0xff);
*dst++ = newpix;
}
}
}
rsgUploadToTexture(rsid, 0);
}
void makeTextures() {
alphafactor = 1.f;
makeTexture((int*)gNoisesrc1, (int*)gNoisedst1, gTnoise1);
makeTexture((int*)gNoisesrc2, (int*)gNoisedst2, gTnoise2);
makeTexture((int*)gNoisesrc3, (int*)gNoisedst3, gTnoise3);
makeTexture((int*)gNoisesrc4, (int*)gNoisedst4, gTnoise4);
makeTexture((int*)gNoisesrc5, (int*)gNoisedst5, gTnoise5);
}
void init() {
for (int i=0;i<5;i++) {
xshift[i] = 0.f;
rotation[i] = 360.f * i / 5.f;
}
scale[0] = 4.0f; // changed below based on preset
scale[1] = 3.0f;
scale[2] = 3.4f;
scale[3] = 3.8f;
scale[4] = 4.2f;
currentpreset = -1;
lastuptime = (int)rsUptimeMillis();
timedelta = 0;
}
int root(int launchID) {
int i;
int now = (int)rsUptimeMillis();
timedelta = ((float)(now - lastuptime)) / 44.f;
lastuptime = now;
if (timedelta > 3) {
// Limit the step adjustment factor to 3, so we don't get a sudden jump
// after coming back from sleep.
timedelta = 3;
}
i = gPreset;
if (i != currentpreset) {
currentpreset = i;
clearColor.x = ((float)((gBackCol >> 16) & 0xff)) / 255.0f;
clearColor.y = ((float)((gBackCol >> 8) & 0xff)) / 255.0f;
clearColor.z = ((float)(gBackCol & 0xff)) / 255.0f;
makeTextures();
}
if (gTextureSwap != 0) {
scale[0] = .25f;
} else {
scale[0] = 4.f;
}
drawClouds();
return 55;
}