blob: 751f603a25cc6e617ae7ce567b7160024c5b1d4e [file] [log] [blame]
#pragma version(1)
#pragma rs java_package_name(com.android.noisefield)
#include "rs_graphics.rsh"
#pragma stateVertex(parent);
#pragma stateStore(parent);
rs_allocation textureDot;
rs_allocation textureVignette;
rs_program_vertex vertBg;
rs_program_fragment fragBg;
rs_program_vertex vertDots;
rs_program_fragment fragDots;
rs_program_store storeAlpha;
rs_program_store storeAdd;
typedef struct VpConsts {
rs_matrix4x4 MVP;
float scaleSize;
} VpConsts_t;
VpConsts_t *vpConstants;
typedef struct Particle {
float3 position;
float speed;
float wander;
float alphaStart;
float alpha;
int life;
int death;
} Particle_t;
Particle_t *dotParticles;
typedef struct VertexColor_s {
float3 position;
float4 color;
float offsetX;
} VertexColor;
VertexColor* vertexColors;
rs_mesh dotMesh;
rs_mesh gBackgroundMesh;
float densityDPI;
bool touchDown = false;
#define B 0x100
#define BM 0xff
#define N 0x1000
static int p[B + B + 2];
static float g3[B + B + 2][3];
static float g2[B + B + 2][2];
static float g1[B + B + 2];
// used for motion easing from touch to non-touch state
static float touchInfluence = 0;
static float touchX = 0;
static float touchY = 0;
static float noise_sCurve(float t) {
return t * t * (3.0f - 2.0f * t);
}
static void normalizef2(float v[]) {
float s = (float)sqrt(v[0] * v[0] + v[1] * v[1]);
v[0] = v[0] / s;
v[1] = v[1] / s;
}
static void normalizef3(float v[]) {
float s = (float)sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
v[0] = v[0] / s;
v[1] = v[1] / s;
v[2] = v[2] / s;
}
void init() {
int i, j, k;
for (i = 0; i < B; i++) {
p[i] = i;
g1[i] = (float)(rsRand(B * 2) - B) / B;
for (j = 0; j < 2; j++)
g2[i][j] = (float)(rsRand(B * 2) - B) / B;
normalizef2(g2[i]);
for (j = 0; j < 3; j++)
g3[i][j] = (float)(rsRand(B * 2) - B) / B;
normalizef3(g3[i]);
}
for (i = B-1; i >= 0; i--) {
k = p[i];
p[i] = p[j = rsRand(B)];
p[j] = k;
}
for (i = 0; i < B + 2; i++) {
p[B + i] = p[i];
g1[B + i] = g1[i];
for (j = 0; j < 2; j++)
g2[B + i][j] = g2[i][j];
for (j = 0; j < 3; j++)
g3[B + i][j] = g3[i][j];
}
}
static float noisef2(float x, float y) {
int bx0, bx1, by0, by1, b00, b10, b01, b11;
float rx0, rx1, ry0, ry1, sx, sy, a, b, t, u, v;
float *q;
int i, j;
t = x + N;
bx0 = ((int)t) & BM;
bx1 = (bx0+1) & BM;
rx0 = t - (int)t;
rx1 = rx0 - 1.0f;
t = y + N;
by0 = ((int)t) & BM;
by1 = (by0+1) & BM;
ry0 = t - (int)t;
ry1 = ry0 - 1.0f;
i = p[bx0];
j = p[bx1];
b00 = p[i + by0];
b10 = p[j + by0];
b01 = p[i + by1];
b11 = p[j + by1];
sx = noise_sCurve(rx0);
sy = noise_sCurve(ry0);
q = g2[b00]; u = rx0 * q[0] + ry0 * q[1];
q = g2[b10]; v = rx1 * q[0] + ry0 * q[1];
a = mix(u, v, sx);
q = g2[b01]; u = rx0 * q[0] + ry1 * q[1];
q = g2[b11]; v = rx1 * q[0] + ry1 * q[1];
b = mix(u, v, sx);
return 1.5f * mix(a, b, sy);
}
void positionParticles() {
Particle_t* particle = dotParticles;
int size = rsAllocationGetDimX(rsGetAllocation(dotParticles));
for(int i=0; i<size; i++) {
particle->position.x = rsRand(-1.0f, 1.0f);
particle->position.y = rsRand(-1.0f, 1.0f);
particle->speed = rsRand(0.0002f, 0.02f);
particle->wander = rsRand(0.50f, 1.5f);
particle->death = 0;
particle->life = rsRand(300, 800);
particle->alphaStart = rsRand(0.01f, 1.0f);
particle->alpha = particle->alphaStart;
particle++;
}
}
void touch(float x, float y) {
bool landscape = rsgGetWidth() > rsgGetHeight();
float wRatio;
float hRatio;
if(!landscape){
wRatio = 1.0;
hRatio = rsgGetHeight()/rsgGetWidth();
} else {
hRatio = 1.0;
wRatio = rsgGetWidth()/rsgGetHeight();
}
touchInfluence = 1.0;
touchX = x/rsgGetWidth() * wRatio * 2 - wRatio;
touchY = -(y/rsgGetHeight() * hRatio * 2 - hRatio);
}
int root() {
rsgClearColor(0.0, 0.0, 0.0, 1.0f);
int size = rsAllocationGetDimX(rsGetAllocation(vertexColors));
rsgBindProgramVertex(vertDots);
rsgBindProgramFragment(fragDots);
rsgBindTexture(fragDots, 0, textureDot);
rsgDrawMesh(dotMesh);
// bg
rsgBindProgramVertex(vertBg);
rsgBindProgramFragment(fragBg);
rsgDrawMesh(gBackgroundMesh);
// dots
Particle_t* particle = dotParticles;
size = rsAllocationGetDimX(rsGetAllocation(dotParticles));
float rads;
float speed;
for(int i=0; i<size; i++) {
if(particle->life < 0 || particle->position.x < -1.2 ||
particle->position.x >1.2 || particle->position.y < -1.7 ||
particle->position.y >1.7) {
particle->position.x = rsRand(-1.0f, 1.0f);
particle->position.y = rsRand(-1.0f, 1.0f);
particle->speed = rsRand(0.0002f, 0.02f);
particle->wander = rsRand(0.50f, 1.5f);
particle->death = 0;
particle->life = rsRand(300, 800);
particle->alphaStart = rsRand(0.01f, 1.0f);
particle->alpha = particle->alphaStart;
}
float touchDist = sqrt(pow(touchX - particle->position.x, 2) +
pow(touchY - particle->position.y, 2));
float noiseval = noisef2(particle->position.x, particle->position.y);
if(touchDown || touchInfluence > 0.0) {
if(touchDown){
touchInfluence = 1.0;
}
rads = atan2(touchX - particle->position.x + noiseval,
touchY - particle->position.y + noiseval);
if(touchDist != 0){
speed = ( (0.25 + (noiseval * particle->speed + 0.01)) / touchDist * 0.3 );
speed = speed * touchInfluence;
} else {
speed = .3;
}
particle->position.x += cos(rads) * speed * 0.2;
particle->position.y += sin(rads) * speed * 0.2;
}
float angle = 360 * noiseval * particle->wander;
speed = noiseval * particle->speed + 0.01;
rads = angle * 3.14159265 / 180.0;
particle->position.x += cos(rads) * speed * 0.33;
particle->position.y += sin(rads) * speed * 0.33;
particle->life--;
particle->death++;
float dist = sqrt(particle->position.x*particle->position.x +
particle->position.y*particle->position.y);
if(dist < 0.95) {
dist = 0;
particle->alphaStart *= (1-dist);
} else {
dist = dist-0.95;
if(particle->alphaStart < 1.0f) {
particle->alphaStart +=0.01;
particle->alphaStart *= (1-dist);
}
}
if(particle->death < 101) {
particle->alpha = (particle->alphaStart)*(particle->death)/100.0;
} else if(particle->life < 101) {
particle->alpha = particle->alpha*particle->life/100.0;
} else {
particle->alpha = particle->alphaStart;
}
particle++;
}
if(touchInfluence > 0) {
touchInfluence-=0.01;
}
return 35;
}