1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-01-17 21:09:00 +01:00

#23 water caustics, render target cache

This commit is contained in:
XProger 2017-02-06 04:37:56 +03:00
parent 40378ebd20
commit 831e072943
15 changed files with 188 additions and 92 deletions

Binary file not shown.

View File

@ -48,8 +48,7 @@ struct Camera : Controller {
virtual bool activate(ActionCommand *cmd) {
Controller::activate(cmd);
if (cmd->timer)
this->timer = cmd->timer;
this->timer = max(max(1.0f, this->timer), cmd->timer);
if (cmd->action == TR::Action::CAMERA_TARGET)
actTargetEntity = cmd->value;
if (cmd->action == TR::Action::CAMERA_SWITCH) {

View File

@ -13,6 +13,7 @@
#define MAX_LAYERS 4
struct IGame {
virtual ~IGame() {}
virtual TR::Level* getLevel() { return NULL; }
virtual void waterDrop(const vec3 &pos, float radius, float strength) {}
};
@ -203,10 +204,10 @@ struct Controller {
float volume = (float)b.volume / 0x7FFF;
float pitch = b.flags.pitch ? (0.9f + randf() * 0.2f) : 1.0f;
if (b.flags.mode == 1) flags |= Sound::UNIQUE;
if (b.flags.mode == 2) flags |= Sound::REPLAY;
//if (b.flags.mode == 2) flags |= Sound::REPLAY;
if (b.flags.mode == 3) flags |= Sound::SYNC;
if (b.flags.gain) volume = max(0.0f, volume - randf() * 0.25f);
if (b.flags.fixed) flags &= ~Sound::PAN;
if (b.flags.fixed) flags |= Sound::LOOP;
Sound::play(level->getSampleStream(index), pos, volume, pitch, flags, entity * 1000 + index);
}
}

View File

@ -112,7 +112,7 @@
#define MAX_LIGHTS 3
#define MAX_CACHED_LIGHTS 3
#define MAX_RENDER_BUFFERS 11
#define MAX_RENDER_BUFFERS 32
struct Shader;
struct Texture;
@ -155,11 +155,18 @@ namespace Core {
enum Pass { passCompose, passShadow, passAmbient, passFilter, passWater } pass;
GLuint FBO;
GLuint renderBuffers[2][MAX_RENDER_BUFFERS];
struct RenderTargetCache {
int count;
struct Item {
GLuint ID;
int width;
int height;
} items[MAX_RENDER_BUFFERS];
} rtCache[2];
struct {
Shader *shader;
Texture *testures[8];
Texture *textures[8];
GLuint VAO;
} active;
@ -267,15 +274,7 @@ namespace Core {
LOG("\n");
glGenFramebuffers(1, &FBO);
glGenRenderbuffers(MAX_RENDER_BUFFERS * 2, &renderBuffers[0][0]);
for (int j = 0; j < 2; j++)
for (int i = 0; i < MAX_RENDER_BUFFERS; i++) {
glBindRenderbuffer(GL_RENDERBUFFER, renderBuffers[j][i]);
glRenderbufferStorage(GL_RENDERBUFFER, j ? GL_RGB565 : GL_DEPTH_COMPONENT16, 1 << i, 1 << i);
}
glBindRenderbuffer(GL_RENDERBUFFER, 0);
memset(rtCache, 0, sizeof(rtCache));
Sound::init();
@ -293,11 +292,40 @@ namespace Core {
void free() {
delete blackTex;
delete whiteTex;
// glDeleteRenderBuffers(MAX_RENDER_BUFFERS * 2, &renderBuffers[0][0]);
// glDeleteFrameBuffers(1, &FBO);
/*
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDeleteFrameBuffers(1, &FBO);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
for (int b = 0; b < 2; b++)
for (int i = 0; i < rtCache[b].count; i++)
glDeleteRenderBuffers(1, &rtCache[b].items[i].ID);
*/
Sound::free();
}
int cacheRenderTarget(bool depth, int width, int height) {
RenderTargetCache &cache = rtCache[depth];
for (int i = 0; i < cache.count; i++)
if (cache.items[i].width == width && cache.items[i].height == height)
return i;
ASSERT(cache.count < MAX_RENDER_BUFFERS);
RenderTargetCache::Item &item = cache.items[cache.count];
glGenRenderbuffers(1, &item.ID);
item.width = width;
item.height = height;
glBindRenderbuffer(GL_RENDERBUFFER, item.ID);
glRenderbufferStorage(GL_RENDERBUFFER, depth ? GL_RGB565 : GL_DEPTH_COMPONENT16, width, height);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
return cache.count++;
}
void clear(const vec4 &color) {
glClearColor(color.x, color.y, color.z, color.w);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
@ -373,17 +401,12 @@ namespace Core {
if (target->cube)
texTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
int i = target->width, dummyBuffer = 0;
while (i > 1) {
dummyBuffer++;
i >>= 1;
}
bool depth = target->format == Texture::DEPTH || target->format == Texture::SHADOW;
int rtIndex = cacheRenderTarget(depth, target->width, target->height);
ASSERT(target->width == (1 << dummyBuffer) )
glBindFramebuffer(GL_FRAMEBUFFER, FBO);
bool depth = target->format == Texture::DEPTH || target->format == Texture::SHADOW;
glFramebufferTexture2D (GL_FRAMEBUFFER, depth ? GL_DEPTH_ATTACHMENT : GL_COLOR_ATTACHMENT0, texTarget, target->ID, 0);
glFramebufferRenderbuffer (GL_FRAMEBUFFER, depth ? GL_COLOR_ATTACHMENT0 : GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderBuffers[depth][dummyBuffer]);
glFramebufferRenderbuffer (GL_FRAMEBUFFER, depth ? GL_COLOR_ATTACHMENT0 : GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rtCache[depth].items[rtIndex].ID);
if (depth)
glColorMask(false, false, false, false);

View File

@ -38,7 +38,7 @@ namespace Debug {
glUseProgram(0);
Core::active.shader = NULL;
Core::active.testures[0] = NULL;
Core::active.textures[0] = NULL;
}
void end() {

View File

@ -923,7 +923,7 @@ struct Lara : Character {
virtual void hit(int damage, Controller *enemy = NULL) {
health -= damage;
if (enemy && health > 0)
playSound(TR::SND_HIT, pos, Sound::PAN);
playSound(TR::SND_HIT, pos, Sound::PAN | Sound::REPLAY);
};
bool waterOut() {
@ -1394,12 +1394,15 @@ struct Lara : Character {
return STATE_PICK_UP;
if (state == STATE_FORWARD_JUMP || state == STATE_UP_JUMP || state == STATE_BACK_JUMP || state == STATE_LEFT_JUMP || state == STATE_RIGHT_JUMP || state == STATE_FALL || state == STATE_REACH) {
game->waterDrop(pos, 256.0f, 0.2f);
Sprite::add(game, TR::Entity::WATER_SPLASH, getRoomIndex(), (int)pos.x, (int)pos.y, (int)pos.z);
return animation.setAnim(ANIM_WATER_FALL); // TODO: wronng animation
}
if (state == STATE_SWAN_DIVE) {
angle.x = -PI * 0.5f;
game->waterDrop(pos, 128.0f, 0.2f);
Sprite::add(game, TR::Entity::WATER_SPLASH, getRoomIndex(), (int)pos.x, (int)pos.y, (int)pos.z);
return STATE_DIVE;
}
@ -1413,15 +1416,17 @@ struct Lara : Character {
if (state == STATE_WATER_OUT) return state;
if (state != STATE_SURF_TREAD && state != STATE_SURF_LEFT && state != STATE_SURF_RIGHT && state != STATE_SURF_SWIM && state != STATE_SURF_BACK && state != STATE_STOP)
if (state != STATE_SURF_TREAD && state != STATE_SURF_LEFT && state != STATE_SURF_RIGHT && state != STATE_SURF_SWIM && state != STATE_SURF_BACK && state != STATE_STOP) {
game->waterDrop(pos, 128.0f, 0.2f);
return animation.setAnim(ANIM_TO_ONWATER);
}
if (state == STATE_SURF_TREAD) {
if (animation.isFrameActive(0))
game->waterDrop(animation.getJoints(getMatrix(), 14).pos, 96.0f, 0.01f);
game->waterDrop(animation.getJoints(getMatrix(), 14).pos, 96.0f, 0.03f);
} else {
if (animation.frameIndex % 4 == 0)
game->waterDrop(animation.getJoints(getMatrix(), 14).pos, 96.0f, 0.01f);
game->waterDrop(animation.getJoints(getMatrix(), 14).pos, 96.0f, 0.02f);
}
if (input & FORTH) {

View File

@ -180,7 +180,7 @@ struct Level : IGame {
} *ambientCache;
struct WaterCache {
#define MAX_SURFACES 5
#define MAX_SURFACES 8
#define MAX_INVISIBLE_TIME 5.0f
#define SIMULATE_TIMESTEP (1.0f / 40.0f)
#define DETAIL (64.0f / 1024.0f)
@ -191,7 +191,7 @@ struct Level : IGame {
Texture *reflect;
struct Item {
int from, to;
int from, to, caust;
float timer;
bool visible;
bool blank;
@ -204,7 +204,7 @@ struct Level : IGame {
mask = caustics = data[0] = data[1] = NULL;
}
Item(int from, int to) : from(from), to(to), timer(SIMULATE_TIMESTEP), visible(true), blank(true) {
Item(int from, int to) : from(from), to(to), caust(to), timer(SIMULATE_TIMESTEP), visible(true), blank(true) {
mask = caustics = data[0] = data[1] = NULL;
}
@ -222,6 +222,8 @@ struct Level : IGame {
maxX = max(maxX, x);
maxZ = max(maxZ, z);
posY = s.ceiling * 256;
if (s.roomBelow != TR::NO_ROOM)
caust = s.roomBelow;
}
}
maxX++;
@ -230,15 +232,29 @@ struct Level : IGame {
int w = nextPow2(maxX - minX);
int h = nextPow2(maxZ - minZ);
uint8 *m = new uint8[w * h];
memset(m, 0, w * h);
uint16 *m = new uint16[w * h];
memset(m, 0, w * h * sizeof(m[0]));
for (int z = minZ; z < maxZ; z++)
for (int x = minX; x < maxX; x++) {
TR::Room::Sector &s = r.sectors[x * r.zSectors + z];
m[(x - minX) + w * (z - minZ)] = (s.roomAbove != TR::NO_ROOM && !level->level.rooms[s.roomAbove].flags.water) ? 255 : 0;
bool hasWater = (s.roomAbove != TR::NO_ROOM && !level->level.rooms[s.roomAbove].flags.water);
bool hasFlow = false;
if (hasWater) {
TR::Level::FloorInfo info;
level->level.getFloorInfo(to, x + r.info.x, r.info.yBottom, z + r.info.z, info);
if (info.trigCmdCount && info.trigger == TR::Level::Trigger::ACTIVATE)
for (int i = 0; i < info.trigCmdCount; i++)
if (info.trigCmd[i].action == TR::Action::FLOW) {
hasFlow = true;
break;
}
}
m[(x - minX) + w * (z - minZ)] = hasWater ? (hasFlow ? 0xFFFF : 0xFF00) : 0;
}
mask = new Texture(w, h, Texture::RED, false, m, false);
mask = new Texture(w, h, Texture::RGB16, false, m, false);
delete[] m;
size = vec3(float((maxX - minX) * 512), 1.0f, float((maxZ - minZ) * 512)); // half size
@ -246,7 +262,7 @@ struct Level : IGame {
data[0] = new Texture(nextPow2(w * 64), nextPow2(h * 64), Texture::RGBA_HALF, false);
data[1] = new Texture(data[0]->width, data[0]->height, Texture::RGBA_HALF, false);
caustics = new Texture(512, 512, Texture::RGBA, false);
caustics = new Texture(512, 512, Texture::RGB16, false);
blank = false;
Core::setTarget(data[0]);
@ -276,7 +292,7 @@ struct Level : IGame {
} drops[MAX_DROPS];
WaterCache(Level *level) : level(level), refract(NULL), count(0), checkVisibility(false), dropCount(0) {
reflect = new Texture(512, 512, Texture::RGBA, false);
reflect = new Texture(512, 512, Texture::RGB16, false);
}
~WaterCache() {
@ -309,9 +325,9 @@ struct Level : IGame {
void setVisible(int roomIndex, int nextRoom = TR::NO_ROOM) {
if (!checkVisibility) return;
if (nextRoom == TR::NO_ROOM) { // setVisible(underwaterRoom)
if (nextRoom == TR::NO_ROOM) { // setVisible(underwaterRoom) for caustics update
for (int i = 0; i < count; i++)
if (items[i].to == roomIndex) {
if (items[i].caust == roomIndex) {
nextRoom = items[i].from;
if (!items[i].visible) {
items[i].visible = true;
@ -350,7 +366,7 @@ struct Level : IGame {
void bindCaustics(int roomIndex) {
Item *item = NULL;
for (int i = 0; i < count; i++)
if (items[i].to == roomIndex) {
if (items[i].caust == roomIndex) {
item = &items[i];
break;
}
@ -390,8 +406,6 @@ struct Level : IGame {
level->mesh->renderQuad();
swap(item.data[0], item.data[1]);
}
dropCount = 0;
}
void step(Item &item) {
@ -458,7 +472,7 @@ struct Level : IGame {
// get refraction texture
if (!refract || Core::width > refract->width || Core::height > refract->height) {
delete refract;
refract = new Texture(nextPow2(Core::width), nextPow2(Core::height), Texture::RGBA, false);
refract = new Texture(nextPow2(Core::width), nextPow2(Core::height), Texture::RGBA16, false);
}
Core::copyTarget(refract, 0, 0, 0, 0, Core::width, Core::height); // copy framebuffer into refraction texture
@ -500,12 +514,11 @@ struct Level : IGame {
item.mask->bind(sMask);
if (item.timer >= SIMULATE_TIMESTEP || dropCount) {
Core::active.shader->setParam(uTexParam, vec4(1.0f / item.data[0]->width, 1.0f / item.data[0]->height, 1.0f, 1.0f));
drop(item);
// add water drops
drop(item);
// simulation step
step(item);
}
Core::setTarget(NULL);
@ -526,7 +539,7 @@ struct Level : IGame {
Core::active.shader->setParam(uViewPos, Core::viewPos);
Core::active.shader->setParam(uLightPos, Core::lightPos[0], 1);
Core::active.shader->setParam(uLightColor, Core::lightColor[0], 1);
Core::active.shader->setParam(uParam, vec4(float(Core::width) / refract->width, float(Core::height) / refract->height, 0.075f, 0.02f));
Core::active.shader->setParam(uParam, vec4(float(Core::width) / refract->width, float(Core::height) / refract->height, 0.05f, 0.02f));
float sx = item.size.x * DETAIL / (item.data[0]->width / 2);
float sz = item.size.z * DETAIL / (item.data[0]->height / 2);
@ -546,6 +559,7 @@ struct Level : IGame {
Core::setCulling(cfFront);
}
dropCount = 0;
}
#undef MAX_WATER_SURFACES
@ -717,9 +731,13 @@ struct Level : IGame {
waterCache = new WaterCache(this);
initReflections();
for (int i = 0; i < level.soundSourcesCount; i++) {
TR::SoundSource &src = level.soundSources[i];
lara->playSound(src.id, vec3(src.x, src.y, src.z), Sound::PAN | Sound::LOOP);
}
}
~Level() {
virtual ~Level() {
#ifdef _DEBUG
Debug::free();
#endif
@ -931,6 +949,14 @@ struct Level : IGame {
if (room.flags.water) {
Core::color = vec4(0.6f, 0.9f, 0.9f, intensity);
Core::active.shader->setParam(uCaustics, 1);
/*
// trace to water surface room
int wrIndex = roomIndex;
room.sectors[sx * room.zSectors + sz];
int sx = room.xSectors
*/
waterCache->bindCaustics(roomIndex);
} else {
Core::color = vec4(1.0f, 1.0f, 1.0f, intensity);
@ -1299,6 +1325,15 @@ struct Level : IGame {
#ifdef _DEBUG
camera->setup(true);
static int snd_index = 0;
if (Input::down[ikG]) {
snd_index = (snd_index + 1) % level.soundsInfoCount;
LOG("play sound: %d\n", snd_index);
lara->playSound(snd_index, lara->pos, 0);
Input::down[ikG] = false;
}
/*
static int modelIndex = 0;
static bool lastStateK = false;
static int lastEntity = -1;
@ -1322,7 +1357,7 @@ struct Level : IGame {
if (lastEntity > -1)
renderEntity(level.entities[lastEntity]);
// renderModel(level.models[modelIndex], level.entities[4]);
*/
Debug::begin();
glMatrixMode(GL_MODELVIEW);
@ -1343,11 +1378,13 @@ struct Level : IGame {
glDisable(GL_BLEND);
glColor3f(10, 10, 10);
int w = Core::active.textures[sDiffuse]->width / 2;
int h = Core::active.textures[sDiffuse]->height / 2;
glBegin(GL_QUADS);
glTexCoord2f(0, 0); glVertex2f(0, 0);
glTexCoord2f(1, 0); glVertex2f(256, 0);
glTexCoord2f(1, 1); glVertex2f(256, 256);
glTexCoord2f(0, 1); glVertex2f(0, 256);
glTexCoord2f(1, 0); glVertex2f(w, 0);
glTexCoord2f(1, 1); glVertex2f(w, h);
glTexCoord2f(0, 1); glVertex2f(0, h);
glEnd();
glColor3f(1, 1, 1);
@ -1369,7 +1406,7 @@ struct Level : IGame {
// Debug::Level::portals(level);
// Core::setDepthTest(true);
// Debug::Level::meshes(level);
// Debug::Level::entities(level);
Debug::Level::entities(level);
/*
static int dbg_ambient = 0;
dbg_ambient = int(time * 2) % 4;

View File

@ -39,7 +39,7 @@ struct MeshRange {
}
};
#define PLANE_DETAIL 100
#define PLANE_DETAIL 48
struct Mesh {
GLuint ID[2];

View File

@ -2,7 +2,7 @@
cls
set SRC=main.cpp
set PROJ=OpenLara
set FLAGS=-O3 -Wno-deprecated-register --llvm-opts 2 -fmax-type-align=2 -std=c++11 -I../../
set FLAGS=-O3 -Wno-deprecated-register --llvm-opts 2 -fmax-type-align=2 -std=c++11 -Wall -I../../
set PRELOAD=./LEVEL2.PSX
echo.
call em++ %SRC% %FLAGS% -o %PROJ%.js --preload-file %PRELOAD%

View File

@ -125,6 +125,9 @@
keyboad: move - WASD / arrows, jump - Space, action - E/Ctrl, draw weapon - Q, change weapon - 1-4, walk - Shift, side steps - ZX/walk+direction, camera - MouseR)<br>
gamepad: PSX controls on XBox controller<br>
FullScreen: Alt + Enter
</span>
</span>
<script>(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');ga('create', 'UA-60009035-1', 'auto');ga('send', 'pageview');</script>
</body>
</html>

View File

@ -24,14 +24,18 @@ struct Shader {
Shader(const char *text, const char *defines = "") {
#ifdef MOBILE
#define GLSL_DEFINE ""
#define GLSL_VERT ""
#define GLSL_FRAG "#extension GL_OES_standard_derivatives : enable\n"
#else
#define GLSL_DEFINE "#version 120\n"
#define GLSL_VERT ""
#define GLSL_FRAG ""
#endif
const int type[2] = { GL_VERTEX_SHADER, GL_FRAGMENT_SHADER };
const char *code[2][3] = {
{ GLSL_DEFINE "#define VERTEX\n", defines, text },
{ GLSL_DEFINE "#define FRAGMENT\n", defines, text }
{ GLSL_DEFINE GLSL_VERT "#define VERTEX\n", defines, text },
{ GLSL_DEFINE GLSL_FRAG "#define FRAGMENT\n", defines, text }
};
GLchar info[256];

View File

@ -4,7 +4,7 @@
#include "core.h"
struct Texture {
enum Format : uint32 { RGBA, RGBA_FLOAT, RGBA_HALF, RED, DEPTH, SHADOW, MAX };
enum Format : uint32 { RGBA, RGB16, RGBA16, RGBA_FLOAT, RGBA_HALF, DEPTH, SHADOW, MAX };
GLuint ID;
int width, height;
@ -58,13 +58,14 @@ struct Texture {
struct FormatDesc {
GLuint ifmt, fmt;
GLenum type;
} formats[MAX] = {
{ GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE }, // RGBA
{ GL_RGBA32F, GL_RGBA, GL_FLOAT }, // RGBA_FLOAT
{ GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT }, // RGBA_HALF
{ GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE }, // RED
{ GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT }, // DEPTH
{ GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT }, // SHADOW
} formats[MAX] = {
{ GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE }, // RGBA
{ GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5 }, // RGB16
{ GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1 }, // RGBA16
{ GL_RGBA32F, GL_RGBA, GL_FLOAT }, // RGBA_FLOAT
{ GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT }, // RGBA_HALF
{ GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT }, // DEPTH
{ GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT }, // SHADOW
};
FormatDesc &desc = formats[format];
@ -80,6 +81,7 @@ struct Texture {
}
void bind(int sampler) {
Core::active.textures[sampler] = this;
glActiveTexture(GL_TEXTURE0 + sampler);
glBindTexture(cube ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D, ID);
}

View File

@ -334,9 +334,11 @@ struct Waterfall : Trigger {
timer += SPLASH_TIMESTEP * (1.0f + randf() * 0.25f);
drop = true;
dropPos = pos + vec3(randf() * 1024.0f - 512.0f, 0.0f, randf() * 1024.0f - 512.0f);
dropRadius = 256.0f;//randf() * 128.0f + 128.0f;
dropStrength = 0.15f;//randf() * 0.1f + 0.05f;
dropRadius = randf() * 128.0f + 128.0f;
dropStrength = randf() * 0.1f + 0.05f;
vec2 p = (vec2(randf(), randf()) * 2.0f - 1.0f) * (512.0f - dropRadius);
dropPos = pos + vec3(p.x, 0.0f, p.y);
Sprite::add(game, TR::Entity::WATER_SPLASH, getRoomIndex(), (int)dropPos.x, (int)dropPos.y, (int)dropPos.z);
}

View File

@ -112,11 +112,29 @@ struct vec2 {
vec2(float s) : x(s), y(s) {}
vec2(float x, float y) : x(x), y(y) {}
vec2 operator + (const vec2 &v) const { return vec2(x+v.x, y+v.y); }
vec2 operator - (const vec2 &v) const { return vec2(x-v.x, y-v.y); }
vec2 operator * (float s) const { return vec2(x*s, y*s); }
float dot(const vec2 &v) const { return x*v.x + y*v.y; }
float cross(const vec2 &v) const { return x*v.y - y*v.x; }
float& operator [] (int index) const { ASSERT(index >= 0 && index <= 1); return ((float*)this)[index]; }
bool operator == (float s) const { return x == s && y == s; }
bool operator != (float s) const { return !(*this == s); }
vec2 operator - () const { return vec2(-x, -y); }
vec2& operator += (const vec2 &v) { x += v.x; y += v.y; return *this; }
vec2& operator -= (const vec2 &v) { x -= v.x; y -= v.y; return *this; }
vec2& operator *= (const vec2 &v) { x *= v.x; y *= v.y; return *this; }
vec2& operator += (float s) { x += s; y += s; return *this; }
vec2& operator -= (float s) { x -= s; y -= s; return *this; }
vec2& operator *= (float s) { x *= s; y *= s; return *this; }
vec2 operator + (const vec2 &v) const { return vec2(x + v.x, y + v.y); }
vec2 operator - (const vec2 &v) const { return vec2(x - v.x, y - v.y); }
vec2 operator * (const vec2 &v) const { return vec2(x * v.x, y * v.y); }
vec2 operator + (float s) const { return vec2(x + s, y + s ); }
vec2 operator - (float s) const { return vec2(x - s, y - s ); }
vec2 operator * (float s) const { return vec2(x * s, y * s ); }
float dot(const vec2 &v) const { return x * v.x + y * v.y; }
float cross(const vec2 &v) const { return x * v.y - y * v.x; }
float length2() const { return dot(*this); }
float length() const { return sqrtf(length2()); }
vec2 normal() const { float s = length(); return s == 0.0 ? (*this) : (*this)*(1.0f/s); }
@ -130,24 +148,29 @@ struct vec3 {
vec3(const vec2 &xy, float z = 0.0f) : x(xy.x), y(xy.y), z(z) {}
vec3(float lng, float lat) : x(sinf(lat) * cosf(lng)), y(-sinf(lng)), z(cosf(lat) * cosf(lng)) {}
float& operator [] (int index) const { return ((float*)this)[index]; }
float& operator [] (int index) const { ASSERT(index >= 0 && index <= 2); return ((float*)this)[index]; }
bool operator == (float s) const { return x == s && y == s && z == s; }
bool operator != (float s) const { return !(*this == s); }
vec3 operator - () const { return vec3(-x, -y, -z); }
vec3& operator += (const vec3 &v) { x += v.x; y += v.y; z += v.z; return *this; }
vec3& operator -= (const vec3 &v) { x -= v.x; y -= v.y; z -= v.z; return *this; }
vec3& operator *= (const vec3 &v) { x *= v.x; y *= v.y; z *= v.z; return *this; }
vec3& operator += (float s) { x += s; y += s; z += s; return *this; }
vec3& operator -= (float s) { x -= s; y -= s; z -= s; return *this; }
vec3& operator *= (float s) { x *= s; y *= s; z *= s; return *this; }
vec3 operator + (const vec3 &v) const { return vec3(x+v.x, y+v.y, z+v.z); }
vec3 operator - (const vec3 &v) const { return vec3(x-v.x, y-v.y, z-v.z); }
vec3 operator * (const vec3 &v) const { return vec3(x*v.x, y*v.y, z*v.z); }
vec3 operator * (float s) const { return vec3(x*s, y*s, z*s); }
vec3 operator - () const { return vec3(-x, -y, -z); }
vec3 operator + (const vec3 &v) const { return vec3(x + v.x, y + v.y, z + v.z); }
vec3 operator - (const vec3 &v) const { return vec3(x - v.x, y - v.y, z - v.z); }
vec3 operator * (const vec3 &v) const { return vec3(x * v.x, y * v.y, z * v.z); }
vec3 operator + (float s) const { return vec3(x + s, y + s, z + s); }
vec3 operator - (float s) const { return vec3(x - s, y - s, z - s); }
vec3 operator * (float s) const { return vec3(x * s, y * s, z * s); }
float dot(const vec3 &v) const { return x * v.x + y * v.y + z * v.z; }
vec3 cross(const vec3 &v) const { return vec3(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x); }
float dot(const vec3 &v) const { return x*v.x + y*v.y + z*v.z; }
vec3 cross(const vec3 &v) const { return vec3(y*v.z - z*v.y, z*v.x - x*v.z, x*v.y - y*v.x); }
float length2() const { return dot(*this); }
float length() const { return sqrtf(length2()); }
vec3 normal() const { float s = length(); return s == 0.0f ? (*this) : (*this)*(1.0f/s); }

View File

@ -1,8 +1,5 @@
R"====(
#ifdef GL_ES
#ifdef FRAGMENT
#extension GL_OES_standard_derivatives : enable
#endif
precision highp int;
precision highp float;
#endif
@ -43,7 +40,7 @@ uniform sampler2D sNormal;
float height = 0.0;
if (uType == WATER_COMPOSE) {
vTexCoord = (aCoord.xy * 0.01 * 0.5 + 0.5) * uTexParam.zw;
vTexCoord = (aCoord.xy * (1.0 / 48.0) * 0.5 + 0.5) * uTexParam.zw;
height = texture2D(sNormal, vTexCoord).x;
}
@ -120,11 +117,11 @@ uniform sampler2D sNormal;
v.zw = normalize( vec3(f.x - f.z, 64.0 / (1024.0 * 2.0), f.y - f.w) ).xz;
// integrate
const float vel = 1.8;
const float vel = 1.4;
const float vis = 0.995;
v.y *= vis;
v.y += (average - v.x) * vel;
v.y *= vis;
v.x += v.y;
return v;