blob: 267b3eaa7e93f28968af00dec9e773887a318be1 [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 stateVertex(PVBackground)
#pragma stateFragment(PFBackground)
#pragma stateFragmentStore(PFSBackground)
#define RSID_STATE 0
#define RSID_FRAME_COUNT 0
#define RSID_WIDTH 1
#define RSID_HEIGHT 2
#define RSID_MESH_WIDTH 3
#define RSID_MESH_HEIGHT 4
#define RSID_RIPPLE_MAP_SIZE 5
#define RSID_RIPPLE_INDEX 6
#define RSID_DROP_X 7
#define RSID_DROP_Y 8
#define RSID_TEXTURES 1
#define RSID_RIPPLE_MAP 2
#define RSID_REFRACTION_MAP 3
#define REFRACTION 1.333f
#define DAMP 4
#define DROP_RADIUS 2
// The higher, the smaller the ripple
#define RIPPLE_HEIGHT 10.0f
int offset(int x, int y, int width) {
return x + 1 + (y + 1) * (width + 2);
}
void drop(int x, int y, int r) {
int width = loadI32(RSID_STATE, RSID_MESH_WIDTH);
int height = loadI32(RSID_STATE, RSID_MESH_HEIGHT);
if (x < r) x = r;
if (y < r) y = r;
if (x >= width - r) x = width - r - 1;
if (y >= height - r) x = height - r - 1;
x = width - x;
int rippleMapSize = loadI32(RSID_STATE, RSID_RIPPLE_MAP_SIZE);
int index = loadI32(RSID_STATE, RSID_RIPPLE_INDEX);
int origin = offset(0, 0, width);
int* current = loadArrayI32(RSID_RIPPLE_MAP, index * rippleMapSize + origin);
int sqr = r * r;
int h = 0;
for ( ; h < r; h++) {
int sqv = h * h;
int yn = origin + (y - h) * (width + 2);
int yp = origin + (y + h) * (width + 2);
int w = 0;
for ( ; w < r; w++) {
int squ = w * w;
if (squ + sqv < sqr) {
int v = -sqrtf((sqr - (squ + sqv)) << 16);
current[yn + x + w] = v;
current[yp + x + w] = v;
current[yn + x - w] = v;
current[yp + x - w] = v;
}
}
}
}
void updateRipples() {
int rippleMapSize = loadI32(RSID_STATE, RSID_RIPPLE_MAP_SIZE);
int width = loadI32(RSID_STATE, RSID_MESH_WIDTH);
int height = loadI32(RSID_STATE, RSID_MESH_HEIGHT);
int index = loadI32(RSID_STATE, RSID_RIPPLE_INDEX);
int origin = offset(0, 0, width);
int* current = loadArrayI32(RSID_RIPPLE_MAP, index * rippleMapSize + origin);
int* next = loadArrayI32(RSID_RIPPLE_MAP, (1 - index) * rippleMapSize + origin);
storeI32(RSID_STATE, RSID_RIPPLE_INDEX, 1 - index);
int a = 1;
int b = width + 2;
int h = height;
while (h) {
int w = width;
while (w) {
int droplet = ((current[-b] + current[b] + current[-a] + current[a]) >> 1) - next[0];
droplet -= (droplet >> DAMP);
next[0] = droplet;
current++;
next++;
w--;
}
current += 2;
next += 2;
h--;
}
}
void generateRipples() {
int rippleMapSize = loadI32(RSID_STATE, RSID_RIPPLE_MAP_SIZE);
int width = loadI32(RSID_STATE, RSID_MESH_WIDTH);
int height = loadI32(RSID_STATE, RSID_MESH_HEIGHT);
int index = loadI32(RSID_STATE, RSID_RIPPLE_INDEX);
int origin = offset(0, 0, width);
int b = width + 2;
int* current = loadArrayI32(RSID_RIPPLE_MAP, index * rippleMapSize + origin);
float *vertices = loadTriangleMeshVerticesF(NAMED_mesh);
int h = height - 1;
while (h >= 0) {
int w = width - 1;
int wave = current[0];
int offset = h * width;
while (w >= 0) {
int nextWave = current[1];
int dx = nextWave - wave;
int dy = current[b] - wave;
// Update Z coordinate of the vertex
vertices[(offset + w) * 8 + 7] = (dy / 512.0f) / RIPPLE_HEIGHT;
w--;
current++;
wave = nextWave;
}
h--;
current += 2;
}
// Compute the normals for lighting
int y = 0;
for ( ; y < height; y++) {
int x = 0;
int yOffset = y * width;
for ( ; x < width; x++) {
// V1
float v1x = vertices[(yOffset + x) * 8 + 5];
float v1y = vertices[(yOffset + x) * 8 + 6];
float v1z = vertices[(yOffset + x) * 8 + 7];
// V2
float v2x = vertices[(yOffset + x + 1) * 8 + 5];
float v2y = vertices[(yOffset + x + 1) * 8 + 6];
float v2z = vertices[(yOffset + x + 1) * 8 + 7];
// V3
float v3x = vertices[(yOffset + width + x) * 8 + 5];
float v3y = vertices[(yOffset + width + x) * 8 + 6];
float v3z = vertices[(yOffset + width + x) * 8 + 7];
// N1
float n1x = v2x - v1x;
float n1y = v2y - v1y;
float n1z = v2z - v1z;
// N2
float n2x = v3x - v1x;
float n2y = v3y - v1y;
float n2z = v3z - v1z;
// N1 x N2
float n3x = n1y * n2z - n1z * n2y;
float n3y = n1z * n2x - n1x * n2z;
float n3z = n1x * n2y - n1y * n2x;
// Normalize
float len = magf3(n3x, n3y, n3z);
n3x /= len;
n3y /= len;
n3z /= len;
vertices[(yOffset + x) * 8 + 0] = -n3x;
vertices[(yOffset + x) * 8 + 1] = -n3y;
vertices[(yOffset + x) * 8 + 2] = -n3z;
}
}
}
int main(int index) {
int dropX = loadI32(RSID_STATE, RSID_DROP_X);
if (dropX != -1) {
int dropY = loadI32(RSID_STATE, RSID_DROP_Y);
drop(dropX, dropY, DROP_RADIUS);
storeI32(RSID_STATE, RSID_DROP_X, -1);
storeI32(RSID_STATE, RSID_DROP_Y, -1);
}
updateRipples();
generateRipples();
updateTriangleMesh(NAMED_mesh);
ambient(0.0f, 0.1f, 0.9f, 1.0f);
diffuse(0.0f, 0.1f, 0.9f, 1.0f);
drawTriangleMesh(NAMED_mesh);
return 1;
}