blob: e25e04afa98e8861170755be470326b34c7d6f47 [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(PVSky)
#pragma stateFragment(PFBackground)
#pragma stateStore(PFSBackground)
#define LEAVES_TEXTURES_COUNT 8
#define LEAF_SIZE 0.55f
#define LEAVES_COUNT 14
float skyOffsetX;
float skyOffsetY;
float g_DT;
int g_LastTime;
struct vert_s {
float x;
float y;
float z;
float s;
float t;
};
struct drop_s {
float ampS;
float ampE;
float spread;
float spread2;
float invSpread;
float invSpread2;
float x;
float y;
};
struct drop_s gDrops[10];
int gMaxDrops;
struct Leaves_s {
float x;
float y;
float scale;
float angle;
float spin;
float u1;
float u2;
float altitude;
float rippled;
float deltaX;
float deltaY;
int newLeaf;
};
struct Leaves_s gLeavesStore[LEAVES_COUNT];
struct Leaves_s* gLeaves[LEAVES_COUNT];
struct Leaves_s* gNextLeaves[LEAVES_COUNT];
void init() {
int ct;
gMaxDrops = 10;
for (ct=0; ct<gMaxDrops; ct++) {
gDrops[ct].ampS = 0;
gDrops[ct].ampE = 0;
gDrops[ct].spread = 1;
gDrops[ct].spread2 = gDrops[ct].spread * gDrops[ct].spread;
gDrops[ct].invSpread = 1 / gDrops[ct].spread;
gDrops[ct].invSpread2 = gDrops[ct].invSpread * gDrops[ct].invSpread;
}
}
void initLeaves() {
struct Leaves_s *leaf = gLeavesStore;
float width = State->glWidth * 2;
float height = State->glHeight;
int i;
for (i = 0; i < LEAVES_COUNT; i ++) {
gLeaves[i] = leaf;
int sprite = randf(LEAVES_TEXTURES_COUNT);
leaf->x = randf2(-width * 0.5f, width * 0.5f);
leaf->y = randf2(-height * 0.5f, height * 0.5f);
leaf->scale = randf2(0.4f, 0.5f);
leaf->angle = randf2(0.0f, 360.0f);
leaf->spin = degf(randf2(-0.02f, 0.02f)) * 0.25f;
leaf->u1 = sprite / (float) LEAVES_TEXTURES_COUNT;
leaf->u2 = (sprite + 1) / (float) LEAVES_TEXTURES_COUNT;
leaf->altitude = -1.0f;
leaf->rippled = 1.0f;
leaf->deltaX = randf2(-0.02f, 0.02f) / 2.0f;
leaf->deltaY = -0.08f * randf2(0.9f, 1.1f) / 2.0f;
leaf++;
}
}
void updateDrop(int ct) {
gDrops[ct].spread += 30.f * g_DT;
gDrops[ct].spread2 = gDrops[ct].spread * gDrops[ct].spread;
gDrops[ct].invSpread = 1 / gDrops[ct].spread;
gDrops[ct].invSpread2 = gDrops[ct].invSpread * gDrops[ct].invSpread;
gDrops[ct].ampE = gDrops[ct].ampS * gDrops[ct].invSpread;
}
void drop(int x, int y, float s) {
int ct;
int iMin = 0;
float minAmp = 10000.f;
for (ct = 0; ct < gMaxDrops; ct++) {
if (gDrops[ct].ampE < minAmp) {
iMin = ct;
minAmp = gDrops[ct].ampE;
}
}
gDrops[iMin].ampS = s;
gDrops[iMin].spread = 0;
gDrops[iMin].x = x;
gDrops[iMin].y = State->meshHeight - y - 1;
updateDrop(iMin);
}
void generateRipples() {
int rippleMapSize = State->rippleMapSize;
int width = State->meshWidth;
int height = State->meshHeight;
int index = State->rippleIndex;
float ratio = (float)State->meshWidth / State->glWidth;
float xShift = State->xOffset * ratio * 2;
float *vertices = loadSimpleMeshVerticesF(NAMED_WaterMesh, 0);
struct vert_s *vert = (struct vert_s *)vertices;
float fw = 1.0f / width;
float fh = 1.0f / height;
int x, y, ct;
struct vert_s *v = vert;
for (y=0; y < height; y++) {
for (x=0; x < width; x++) {
struct drop_s * d = &gDrops[0];
float z = 0;
for (ct = 0; ct < gMaxDrops; ct++) {
if (d->ampE > 0.01f) {
float dx = (d->x - xShift) - x;
float dy = d->y - y;
float dist2 = dx*dx + dy*dy;
if (dist2 < d->spread2) {
float dist = sqrtf(dist2);
float a = d->ampE * (dist * d->invSpread);
z += sinf(d->spread - dist) * a;
}
}
d++;
}
v->z = z;
v ++;
}
}
for (ct = 0; ct < gMaxDrops; ct++) {
updateDrop(ct);
}
v = vert;
for (y = 0; y < height; y += 1) {
for (x = 0; x < width; x += 1) {
struct vec3_s n1, n2, n3;
vec3Sub(&n1, (struct vec3_s *)&(v+1)->x, (struct vec3_s *)&v->x);
vec3Sub(&n2, (struct vec3_s *)&(v+width)->x, (struct vec3_s *)&v->x);
vec3Cross(&n3, &n1, &n2);
// Average of previous normal and N1 x N2
vec3Sub(&n1, (struct vec3_s *)&(v+width+1)->x, (struct vec3_s *)&v->x);
vec3Cross(&n2, &n1, &n2);
vec3Add(&n3, &n3, &n2);
//vec3Norm(&n3); // Not necessary for our constrained mesh.
v->s = (float)x * fw + n3.x;// * 0.2;
v->t = (float)y * fh + n3.y;// * 0.2;
v->z = 0;
v += 1;
}
}
}
void genLeafDrop(struct Leaves_s *leaf, float amp) {
float nx = (leaf->x + State->glWidth * 0.5f) / State->glWidth;
float ny = (leaf->y + State->glHeight * 0.5f) / State->glHeight;
drop(nx * State->meshWidth, State->meshHeight - ny * State->meshHeight, amp);
}
int drawLeaf(struct Leaves_s *leaf) {
float x = leaf->x;
float y = leaf->y;
float u1 = leaf->u1;
float u2 = leaf->u2;
float a = leaf->altitude;
float s = leaf->scale;
float r = leaf->angle;
float tz = 0.0f;
if (a > 0.0f) {
tz = -a;
}
float matrix[16];
if (a > 0.0f) {
float alpha = 1.0f;
if (a >= 0.4f) alpha = 1.0f - (a - 0.4f) / 0.1f;
color(0.0f, 0.0f, 0.0f, alpha * 0.15f);
if (State->rotate) {
matrixLoadRotate(matrix, 90.0f, 0.0f, 0.0f, 1.0f);
} else {
matrixLoadIdentity(matrix);
}
float shadowOffet = a / 5;
matrixTranslate(matrix, (x - State->xOffset * 2) + (shadowOffet / 2), y - shadowOffet, tz);
matrixScale(matrix, s, s, 1.0f);
matrixRotate(matrix, r, 0.0f, 0.0f, 1.0f);
vpLoadModelMatrix(matrix);
drawQuadTexCoords(-LEAF_SIZE, -LEAF_SIZE, 0, u1, 1.0f,
LEAF_SIZE, -LEAF_SIZE, 0, u2, 1.0f,
LEAF_SIZE, LEAF_SIZE, 0, u2, 0.0f,
-LEAF_SIZE, LEAF_SIZE, 0, u1, 0.0f);
color(1.0f, 1.0f, 1.0f, alpha);
} else {
color(1.0f, 1.0f, 1.0f, 1.0f);
}
if (State->rotate) {
matrixLoadRotate(matrix, 90.0f, 0.0f, 0.0f, 1.0f);
} else {
matrixLoadIdentity(matrix);
}
matrixTranslate(matrix, x - State->xOffset * 2, y, tz);
matrixScale(matrix, s, s, 1.0f);
matrixRotate(matrix, r, 0.0f, 0.0f, 1.0f);
vpLoadModelMatrix(matrix);
drawQuadTexCoords(-LEAF_SIZE, -LEAF_SIZE, 0, u1, 1.0f,
LEAF_SIZE, -LEAF_SIZE, 0, u2, 1.0f,
LEAF_SIZE, LEAF_SIZE, 0, u2, 0.0f,
-LEAF_SIZE, LEAF_SIZE, 0, u1, 0.0f);
float spin = leaf->spin;
if (a <= 0.0f) {
float rippled = leaf->rippled;
if (rippled < 0.0f) {
genLeafDrop(leaf, 1.5f);
//drop(((x + State->glWidth * 0.5f) / State->glWidth) * meshWidth,
// meshHeight - ((y + State->glHeight * 0.5f) / State->glHeight) * meshHeight, 1);
spin /= 4.0f;
leaf->spin = spin;
leaf->rippled = 1.0f;
}
leaf->x = x + leaf->deltaX * g_DT;
leaf->y = y + leaf->deltaY * g_DT;
r += spin;
leaf->angle = r;
} else {
a -= 0.15f * g_DT;
leaf->altitude = a;
r += spin * 2.0f;
leaf->angle = r;
}
int newLeaf = 0;
if (-LEAF_SIZE * s + x > State->glWidth || LEAF_SIZE * s + x < -State->glWidth ||
LEAF_SIZE * s + y < -State->glHeight / 2.0f) {
int sprite = randf(LEAVES_TEXTURES_COUNT);
leaf->x = randf2(-State->glWidth, State->glWidth);
leaf->y = randf2(-State->glHeight * 0.5f, State->glHeight * 0.5f);
leaf->scale = randf2(0.4f, 0.5f);
leaf->spin = degf(randf2(-0.02f, 0.02f)) * 0.35f;
leaf->u1 = sprite / (float) LEAVES_TEXTURES_COUNT;
leaf->u2 = (sprite + 1) / (float) LEAVES_TEXTURES_COUNT;
leaf->altitude = 0.7f;
leaf->rippled = -1.0f;
leaf->deltaX = randf2(-0.02f, 0.02f) / 2.0f;
leaf->deltaY = -0.08f * randf2(0.9f, 1.1f) / 2.0f;
leaf->newLeaf = 1;
newLeaf = 1;
}
return newLeaf;
}
void drawLeaves() {
bindProgramFragment(NAMED_PFSky);
bindProgramFragmentStore(NAMED_PFSLeaf);
bindProgramVertex(NAMED_PVSky);
bindTexture(NAMED_PFSky, 0, NAMED_TLeaves);
color(1.0f, 1.0f, 1.0f, 1.0f);
int newLeaves = 0;
int i = 0;
for ( ; i < LEAVES_COUNT; i += 1) {
if (drawLeaf(gLeaves[i])) {
newLeaves = 1;
}
}
if (newLeaves > 0) {
int index = 0;
// Copy all the old leaves to the beginning of gNextLeaves
for (i=0; i < LEAVES_COUNT; i++) {
if (gLeaves[i]->newLeaf == 0) {
gNextLeaves[index] = gLeaves[i];
index++;
}
}
// Now copy all the newly falling leaves to the end of gNextLeaves
for (i=0; i < LEAVES_COUNT; i++) {
if (gLeaves[i]->newLeaf > 0) {
gNextLeaves[index] = gLeaves[i];
gNextLeaves[index]->newLeaf = 0;
index++;
}
}
// And move everything in gNextLeaves back to gLeaves
for (i=0; i < LEAVES_COUNT; i++) {
gLeaves[i] = gNextLeaves[i];
}
}
float matrix[16];
matrixLoadIdentity(matrix);
vpLoadModelMatrix(matrix);
}
void drawRiverbed() {
bindTexture(NAMED_PFBackground, 0, NAMED_TRiverbed);
float matrix[16];
matrixLoadScale(matrix, 0.5f * 960.0f / 1024.0f, -1.0f * 800.0f / 1024.0f, 1.0f);
matrixTranslate(matrix, State->xOffset, 0.0f, 0.0f);
vpLoadTextureMatrix(matrix);
drawSimpleMesh(NAMED_WaterMesh);
matrixLoadIdentity(matrix);
vpLoadTextureMatrix(matrix);
}
/*
void drawSky() {
color(1.0f, 1.0f, 1.0f, 0.5f);
bindProgramFragment(NAMED_PFSky);
bindProgramFragmentStore(NAMED_PFSLeaf);
bindTexture(NAMED_PFSky, 0, NAMED_TSky);
float x = skyOffsetX + State->skySpeedX;
float y = skyOffsetY + State->skySpeedY;
if (x > 1.0f) x = 0.0f;
if (x < -1.0f) x = 0.0f;
if (y > 1.0f) y = 0.0f;
skyOffsetX = x;
skyOffsetY = y;
float matrix[16];
matrixLoadTranslate(matrix, x + State->xOffset, y, 0.0f);
vpLoadTextureMatrix(matrix);
drawSimpleMesh(NAMED_WaterMesh);
matrixLoadIdentity(matrix);
vpLoadTextureMatrix(matrix);
}
*/
int main(int index) {
// Compute dt in seconds.
int newTime = uptimeMillis();
g_DT = (newTime - g_LastTime) / 1000.f;
g_LastTime = newTime;
g_DT = minf(g_DT, 0.2f);
if (Drop->dropX != -1) {
drop(Drop->dropX, Drop->dropY, 2);
Drop->dropX = -1;
Drop->dropY = -1;
}
int ct;
int add = 0;
for (ct = 0; ct < gMaxDrops; ct++) {
if (gDrops[ct].ampE < 0.005f) {
add = 1;
}
}
if (add) {
int i = (int)randf(LEAVES_COUNT);
genLeafDrop(gLeaves[i], randf(0.3f) + 0.1f);
}
generateRipples();
updateSimpleMesh(NAMED_WaterMesh);
if (State->rotate) {
float matrix[16];
matrixLoadRotate(matrix, 90.0f, 0.0f, 0.0f, 1.0f);
vpLoadModelMatrix(matrix);
}
drawRiverbed();
// drawSky();
drawLeaves();
return 1;
}