mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-15 01:24:35 +02:00
#23 water shader, fixed simulation step, caustics
This commit is contained in:
@@ -89,11 +89,11 @@ struct Camera : Controller {
|
|||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
if (Input::down[ikMouseR]) {
|
if (Input::down[ikMouseL]) {
|
||||||
vec2 delta = Input::mouse.pos - Input::mouse.start.R;
|
vec2 delta = Input::mouse.pos - Input::mouse.start.L;
|
||||||
angleAdv.x -= delta.y * 0.01f;
|
angleAdv.x -= delta.y * 0.01f;
|
||||||
angleAdv.y += delta.x * 0.01f;
|
angleAdv.y += delta.x * 0.01f;
|
||||||
Input::mouse.start.R = Input::mouse.pos;
|
Input::mouse.start.L = Input::mouse.pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
angleAdv.x -= Input::joy.R.y * 2.0f * Core::deltaTime;
|
angleAdv.x -= Input::joy.R.y * 2.0f * Core::deltaTime;
|
||||||
|
@@ -341,6 +341,7 @@ namespace Core {
|
|||||||
if (!target) {
|
if (!target) {
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
glColorMask(true, true, true, true);
|
glColorMask(true, true, true, true);
|
||||||
|
setViewport(0, 0, Core::width, Core::height);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -362,6 +363,7 @@ namespace Core {
|
|||||||
|
|
||||||
if (depth)
|
if (depth)
|
||||||
glColorMask(false, false, false, false);
|
glColorMask(false, false, false, false);
|
||||||
|
setViewport(0, 0, target->width, target->height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void resetStates() {
|
void resetStates() {
|
||||||
|
11
src/debug.h
11
src/debug.h
@@ -411,7 +411,6 @@ namespace Debug {
|
|||||||
Box box = controller->animation.getBoundingBox(vec3(0.0f), 0);
|
Box box = controller->animation.getBoundingBox(vec3(0.0f), 0);
|
||||||
Debug::Draw::box(matrix, box.min, box.max, vec4(1.0));
|
Debug::Draw::box(matrix, box.min, box.max, vec4(1.0));
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
for (int j = 0; j < level.modelsCount; j++) {
|
for (int j = 0; j < level.modelsCount; j++) {
|
||||||
TR::Model &m = level.models[j];
|
TR::Model &m = level.models[j];
|
||||||
@@ -424,7 +423,7 @@ namespace Debug {
|
|||||||
int fSize = sizeof(TR::AnimFrame) + m.mCount * sizeof(uint16) * 2;
|
int fSize = sizeof(TR::AnimFrame) + m.mCount * sizeof(uint16) * 2;
|
||||||
|
|
||||||
TR::Animation *anim = controller->animation;
|
TR::Animation *anim = controller->animation;
|
||||||
TR::AnimFrame *frame = (TR::AnimFrame*)&level.frameData[(anim->frameOffset + (controller ? int((controller->animTime * 30.0f / anim->frameRate)) * fSize : 0) >> 1)];
|
TR::AnimFrame *frame = (TR::AnimFrame*)&level.frameData[(anim->frameOffset + (controller ? int((controller->animation.time * 30.0f / anim->frameRate)) * fSize : 0) >> 1)];
|
||||||
|
|
||||||
//mat4 m;
|
//mat4 m;
|
||||||
//m.identity();
|
//m.identity();
|
||||||
@@ -461,12 +460,13 @@ namespace Debug {
|
|||||||
joint = joint * rot;
|
joint = joint * rot;
|
||||||
|
|
||||||
int offset = level.meshOffsets[m.mStart + k];
|
int offset = level.meshOffsets[m.mStart + k];
|
||||||
TR::Mesh *mesh = (TR::Mesh*)&level.meshData[offset / 2];
|
TR::Mesh *mesh = (TR::Mesh*)&level.meshes[offset];
|
||||||
Debug::Draw::sphere(matrix * joint * mesh->center, mesh->collider.radius, mesh->collider.info ? vec4(1, 0, 0, 0.5f) : vec4(0, 1, 1, 0.5f));
|
if (!mesh->flags) continue;
|
||||||
|
Debug::Draw::sphere(matrix * joint * mesh->center, mesh->radius, vec4(0, 1, 1, 0.5f));
|
||||||
|
|
||||||
{ //if (e.id != 0) {
|
{ //if (e.id != 0) {
|
||||||
char buf[255];
|
char buf[255];
|
||||||
sprintf(buf, "(%d) radius %d info %d flags %d", e.id, (int)mesh->collider.radius, (int)mesh->collider.info, (int)mesh->collider.flags);
|
sprintf(buf, "(%d) radius %d flags %d", (int)e.type, (int)mesh->radius, (int)mesh->flags);
|
||||||
Debug::Draw::text(matrix * joint * mesh->center, vec4(0.5, 1, 0.5, 1), buf);
|
Debug::Draw::text(matrix * joint * mesh->center, vec4(0.5, 1, 0.5, 1), buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -477,7 +477,6 @@ namespace Debug {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,9 @@
|
|||||||
R"====(
|
R"====(
|
||||||
|
#ifdef GL_ES
|
||||||
|
precision highp int;
|
||||||
|
precision highp float;
|
||||||
|
#endif
|
||||||
|
|
||||||
varying vec2 vTexCoord;
|
varying vec2 vTexCoord;
|
||||||
|
|
||||||
#define FILTER_DOWNSAMPLE 0
|
#define FILTER_DOWNSAMPLE 0
|
||||||
|
20
src/format.h
20
src/format.h
@@ -320,10 +320,10 @@ namespace TR {
|
|||||||
uint16 boxIndex:15, end:1;
|
uint16 boxIndex:15, end:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Collider {
|
//struct Collider {
|
||||||
uint16 radius:10, info:6;
|
// uint16 radius:10, info:6;
|
||||||
uint16 flags:16;
|
// uint16 flags:16;
|
||||||
};
|
//};
|
||||||
|
|
||||||
// internal mesh structure
|
// internal mesh structure
|
||||||
struct Mesh {
|
struct Mesh {
|
||||||
@@ -333,8 +333,9 @@ namespace TR {
|
|||||||
short4 normal;
|
short4 normal;
|
||||||
};
|
};
|
||||||
|
|
||||||
Collider collider;
|
|
||||||
TR::Vertex center;
|
TR::Vertex center;
|
||||||
|
uint16 radius;
|
||||||
|
uint16 flags;
|
||||||
int16 vCount;
|
int16 vCount;
|
||||||
int16 rCount;
|
int16 rCount;
|
||||||
int16 tCount;
|
int16 tCount;
|
||||||
@@ -669,7 +670,7 @@ namespace TR {
|
|||||||
uint16 volume;
|
uint16 volume;
|
||||||
uint16 chance; // If !=0 and ((rand()&0x7fff) > Chance), this sound is not played
|
uint16 chance; // If !=0 and ((rand()&0x7fff) > Chance), this sound is not played
|
||||||
union {
|
union {
|
||||||
struct { uint16 replay:2, count:6, unknown:5, pitch:1, gain:1, :1; };
|
struct { uint16 mode:2, count:4, unused:6, fixed:1, pitch:1, gain:1, :1; };
|
||||||
uint16 value;
|
uint16 value;
|
||||||
} flags;
|
} flags;
|
||||||
};
|
};
|
||||||
@@ -872,7 +873,6 @@ namespace TR {
|
|||||||
} else if (version == VER_TR1_PC) {
|
} else if (version == VER_TR1_PC) {
|
||||||
// tiles
|
// tiles
|
||||||
stream.read(tiles8, stream.read(tilesCount));
|
stream.read(tiles8, stream.read(tilesCount));
|
||||||
stream.read(unused);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!version /*PSX cutscene*/ || version == VER_TR1_PSX) {
|
if (!version /*PSX cutscene*/ || version == VER_TR1_PSX) {
|
||||||
@@ -880,8 +880,9 @@ namespace TR {
|
|||||||
// tiles
|
// tiles
|
||||||
stream.read(tiles4, tilesCount = 13);
|
stream.read(tiles4, tilesCount = 13);
|
||||||
stream.read(cluts, 512);
|
stream.read(cluts, 512);
|
||||||
stream.seek(0x4000 + 4);
|
stream.seek(0x4000);
|
||||||
}
|
}
|
||||||
|
stream.read(unused);
|
||||||
|
|
||||||
// rooms
|
// rooms
|
||||||
rooms = new Room[stream.read(roomsCount)];
|
rooms = new Room[stream.read(roomsCount)];
|
||||||
@@ -1116,7 +1117,8 @@ namespace TR {
|
|||||||
mesh.offset = stream.pos - start;
|
mesh.offset = stream.pos - start;
|
||||||
|
|
||||||
stream.read(mesh.center);
|
stream.read(mesh.center);
|
||||||
stream.read(mesh.collider);
|
stream.read(mesh.radius);
|
||||||
|
stream.read(mesh.flags);
|
||||||
stream.read(mesh.vCount);
|
stream.read(mesh.vCount);
|
||||||
|
|
||||||
switch (version) {
|
switch (version) {
|
||||||
|
@@ -1,4 +1,9 @@
|
|||||||
R"====(
|
R"====(
|
||||||
|
#ifdef GL_ES
|
||||||
|
precision highp int;
|
||||||
|
precision highp float;
|
||||||
|
#endif
|
||||||
|
|
||||||
varying vec2 vTexCoord;
|
varying vec2 vTexCoord;
|
||||||
|
|
||||||
#ifdef VERTEX
|
#ifdef VERTEX
|
||||||
|
219
src/level.h
219
src/level.h
@@ -47,6 +47,7 @@ struct Level {
|
|||||||
Texture *waterRefract;
|
Texture *waterRefract;
|
||||||
Texture *waterReflect;
|
Texture *waterReflect;
|
||||||
Texture *waterCaustics;
|
Texture *waterCaustics;
|
||||||
|
float waterTimer;
|
||||||
|
|
||||||
float time;
|
float time;
|
||||||
float clipHeight;
|
float clipHeight;
|
||||||
@@ -130,7 +131,6 @@ struct Level {
|
|||||||
int size = 64 >> (i << 1);
|
int size = 64 >> (i << 1);
|
||||||
|
|
||||||
Core::active.shader->setParam(uParam, vec4(float(size << 2), 0.0f, 0.0f, 0.0f));
|
Core::active.shader->setParam(uParam, vec4(float(size << 2), 0.0f, 0.0f, 0.0f));
|
||||||
Core::setViewport(0, 0, size, size);
|
|
||||||
|
|
||||||
for (int j = 0; j < 6; j++) {
|
for (int j = 0; j < 6; j++) {
|
||||||
Texture *src = textures[j * 4 + i - 1];
|
Texture *src = textures[j * 4 + i - 1];
|
||||||
@@ -364,15 +364,23 @@ struct Level {
|
|||||||
delete camera;
|
delete camera;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define WATER_SIMULATE_TIMESTEP (1.0f / 40.0f)
|
||||||
|
|
||||||
void initTextures() {
|
void initTextures() {
|
||||||
shadow = new Texture(1024, 1024, Texture::SHADOW, false);
|
shadow = new Texture(1024, 1024, Texture::SHADOW, false);
|
||||||
|
|
||||||
water[0] = new Texture(256, 256, Texture::RGBA_HALF, false);
|
water[0] = new Texture(256, 256, Texture::RGBA_HALF, false);
|
||||||
water[1] = new Texture(256, 256, Texture::RGBA_HALF, false);
|
water[1] = new Texture(256, 256, Texture::RGBA_HALF, false);
|
||||||
|
|
||||||
waterRefract = new Texture(1024, 1024, Texture::RGBA, false);
|
waterRefract = NULL;
|
||||||
waterReflect = new Texture(1024, 1024, Texture::RGBA, false);
|
waterReflect = new Texture( 512, 512, Texture::RGBA, false);
|
||||||
waterCaustics = new Texture(1024, 1024, Texture::RGBA, false);
|
waterCaustics = new Texture( 256, 256, Texture::RGBA, false);
|
||||||
|
|
||||||
|
waterTimer = WATER_SIMULATE_TIMESTEP;
|
||||||
|
|
||||||
|
Core::setTarget(waterRefract); // clear refract mask (frame borders)
|
||||||
|
Core::clear(vec4(0.0f));
|
||||||
|
Core::setTarget(NULL);
|
||||||
|
|
||||||
if (!level.tilesCount) {
|
if (!level.tilesCount) {
|
||||||
atlas = NULL;
|
atlas = NULL;
|
||||||
@@ -415,6 +423,12 @@ struct Level {
|
|||||||
level.tiles = NULL;
|
level.tiles = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void checkRefractTexture() {
|
||||||
|
if (waterRefract && Core::width <= waterRefract->width && Core::height <= waterRefract->height) return;
|
||||||
|
delete waterRefract;
|
||||||
|
waterRefract = new Texture(nextPow2(Core::width), nextPow2(Core::height), Texture::RGBA, false);
|
||||||
|
}
|
||||||
|
|
||||||
void initShaders() {
|
void initShaders() {
|
||||||
char def[255], ext[255];
|
char def[255], ext[255];
|
||||||
|
|
||||||
@@ -721,6 +735,7 @@ struct Level {
|
|||||||
|
|
||||||
void update() {
|
void update() {
|
||||||
time += Core::deltaTime;
|
time += Core::deltaTime;
|
||||||
|
waterTimer += Core::deltaTime;
|
||||||
|
|
||||||
for (int i = 0; i < level.entitiesCount; i++)
|
for (int i = 0; i < level.entitiesCount; i++)
|
||||||
if (level.entities[i].type != TR::Entity::NONE) {
|
if (level.entities[i].type != TR::Entity::NONE) {
|
||||||
@@ -861,10 +876,10 @@ struct Level {
|
|||||||
Core::setBlending(bmAlpha);
|
Core::setBlending(bmAlpha);
|
||||||
Texture *target = targets[0]->cube ? targets[0] : targets[i * stride];
|
Texture *target = targets[0]->cube ? targets[0] : targets[i * stride];
|
||||||
Core::setTarget(target, i);
|
Core::setTarget(target, i);
|
||||||
Core::setViewport(0, 0, target->width, target->height);
|
|
||||||
Core::clear(vec4(0, 0, 0, 1));
|
Core::clear(vec4(0, 0, 0, 1));
|
||||||
renderScene(roomIndex);
|
renderScene(roomIndex);
|
||||||
}
|
}
|
||||||
|
Core::setTarget(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderShadows(int roomIndex) {
|
void renderShadows(int roomIndex) {
|
||||||
@@ -874,7 +889,6 @@ struct Level {
|
|||||||
setPassShader(Core::passShadow);
|
setPassShader(Core::passShadow);
|
||||||
Core::setBlending(bmNone);
|
Core::setBlending(bmNone);
|
||||||
Core::setTarget(shadow);
|
Core::setTarget(shadow);
|
||||||
Core::setViewport(0, 0, shadow->width, shadow->height);
|
|
||||||
Core::clear(vec4(1.0));
|
Core::clear(vec4(1.0));
|
||||||
Core::setCulling(cfBack);
|
Core::setCulling(cfBack);
|
||||||
renderScene(roomIndex);
|
renderScene(roomIndex);
|
||||||
@@ -891,72 +905,40 @@ struct Level {
|
|||||||
shadow->bind(sShadow);
|
shadow->bind(sShadow);
|
||||||
renderScene(roomIndex);
|
renderScene(roomIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderWater() {
|
|
||||||
|
|
||||||
|
void waterSimulate() {
|
||||||
|
if (waterTimer < WATER_SIMULATE_TIMESTEP) return;
|
||||||
|
|
||||||
|
Core::active.shader->setParam(uParam, vec4(1.0f / water[0]->width, 1.0f / water[0]->height, 0.0f, 0.0f));
|
||||||
|
Core::active.shader->setParam(uType, Shader::WATER_STEP);
|
||||||
|
|
||||||
|
while (waterTimer >= WATER_SIMULATE_TIMESTEP) {
|
||||||
|
// water step
|
||||||
|
water[0]->bind(sDiffuse);
|
||||||
|
Core::setTarget(water[1]);
|
||||||
|
mesh->renderQuad();
|
||||||
|
swap(water[0], water[1]);
|
||||||
|
waterTimer -= WATER_SIMULATE_TIMESTEP;
|
||||||
|
}
|
||||||
|
|
||||||
|
// calc normals
|
||||||
|
//water[0]->bind(sDiffuse);
|
||||||
|
//Core::setTarget(water[1]);
|
||||||
|
//Core::active.shader->setParam(uType, Shader::WATER_NORMAL);
|
||||||
|
//mesh->renderQuad();
|
||||||
|
//swap(water[0], water[1]);
|
||||||
|
|
||||||
|
// calc caustics
|
||||||
|
Core::active.shader->setParam(uScale, 1.0f / PLANE_DETAIL);
|
||||||
|
water[0]->bind(sNormal);
|
||||||
|
waterCaustics->unbind(sReflect);
|
||||||
|
Core::setTarget(waterCaustics);
|
||||||
|
Core::active.shader->setParam(uType, Shader::WATER_CAUSTICS);
|
||||||
|
mesh->renderPlane();
|
||||||
|
Core::active.shader->setParam(uScale, 1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void render() {
|
void waterDrop() {
|
||||||
clipHeight = 1000000.0f;
|
|
||||||
clipSign = 1.0f;
|
|
||||||
Core::resetStates();
|
|
||||||
|
|
||||||
ambientCache->precessQueue();
|
|
||||||
renderShadows(lara->getRoomIndex());
|
|
||||||
Core::setViewport(0, 0, Core::width, Core::height);
|
|
||||||
renderCompose(camera->getRoomIndex());
|
|
||||||
|
|
||||||
|
|
||||||
Core::setViewport(0, 0, waterRefract->width, waterRefract->height);
|
|
||||||
|
|
||||||
bool underwater = level.rooms[camera->getRoomIndex()].flags.water;
|
|
||||||
|
|
||||||
Core::setTarget(waterRefract);
|
|
||||||
renderCompose(camera->getRoomIndex());
|
|
||||||
|
|
||||||
setPassShader(Core::passWater);
|
|
||||||
atlas->bind(sNormal);
|
|
||||||
atlas->bind(sReflect);
|
|
||||||
|
|
||||||
Core::active.shader->setParam(uType, Shader::WATER_MASK);
|
|
||||||
Core::active.shader->setParam(uViewProj, Core::mViewProj);
|
|
||||||
Core::setBlending(bmNone);
|
|
||||||
Core::setCulling(cfNone);
|
|
||||||
glColorMask(false, false, false, true);
|
|
||||||
mesh->renderQuad();
|
|
||||||
glColorMask(true, true, true, true);
|
|
||||||
|
|
||||||
Core::setTarget(waterReflect);
|
|
||||||
vec3 p = vec3(40448, 3584, 60928);
|
|
||||||
vec3 n = vec3(0, 1, 0);
|
|
||||||
|
|
||||||
vec4 reflectPlane = vec4(n.x, n.y, n.z, -n.dot(p));
|
|
||||||
|
|
||||||
camera->reflectPlane = &reflectPlane;
|
|
||||||
Core::setCulling(cfBack);
|
|
||||||
clipSign = underwater ? -1.0f : 1.0f;
|
|
||||||
clipHeight = 3584.0 * clipSign;
|
|
||||||
renderCompose(underwater ? 13 : lara->getRoomIndex());
|
|
||||||
clipHeight = 1000000.0f;
|
|
||||||
clipSign = 1.0f;
|
|
||||||
Core::setCulling(cfFront);
|
|
||||||
camera->reflectPlane = NULL;
|
|
||||||
|
|
||||||
Core::setTarget(NULL);
|
|
||||||
Core::setViewport(0, 0, Core::width, Core::height);
|
|
||||||
|
|
||||||
camera->setup(true);
|
|
||||||
|
|
||||||
// Core::mViewInv = camera->mViewInv;
|
|
||||||
// Core::mView = Core::mViewInv.inverse();
|
|
||||||
|
|
||||||
|
|
||||||
glDisable(GL_BLEND);
|
|
||||||
glDisable(GL_DEPTH_TEST);
|
|
||||||
Core::setViewport(0, 0, water[0]->width, water[0]->height);
|
|
||||||
setPassShader(Core::passWater);
|
|
||||||
|
|
||||||
static vec3 lastPos = vec3(0.0);
|
static vec3 lastPos = vec3(0.0);
|
||||||
vec3 head = lara->animation.getJoints(lara->getMatrix(), 14).pos;
|
vec3 head = lara->animation.getJoints(lara->getMatrix(), 14).pos;
|
||||||
bool flag = (head - lastPos).length() > 16.0f;
|
bool flag = (head - lastPos).length() > 16.0f;
|
||||||
@@ -981,8 +963,6 @@ struct Level {
|
|||||||
strength = 0.05f;
|
strength = 0.05f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
water[0]->bind(sDiffuse);
|
water[0]->bind(sDiffuse);
|
||||||
Core::setTarget(water[1]);
|
Core::setTarget(water[1]);
|
||||||
Core::active.shader->setParam(uType, Shader::WATER_DROP);
|
Core::active.shader->setParam(uType, Shader::WATER_DROP);
|
||||||
@@ -991,38 +971,63 @@ struct Level {
|
|||||||
swap(water[0], water[1]);
|
swap(water[0], water[1]);
|
||||||
Input::down[ikU] = false;
|
Input::down[ikU] = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void renderWater() {
|
||||||
|
bool underwater = level.rooms[camera->getRoomIndex()].flags.water;
|
||||||
|
|
||||||
Core::active.shader->setParam(uParam, vec4(1.0f / water[0]->width, 1.0f / water[0]->height, Core::deltaTime * 4.0f, 0.0f));
|
// mask underwater geometry by zero alpha
|
||||||
|
setPassShader(Core::passWater);
|
||||||
|
atlas->bind(sNormal);
|
||||||
|
atlas->bind(sReflect);
|
||||||
|
|
||||||
water[0]->bind(sDiffuse);
|
Core::active.shader->setParam(uType, Shader::WATER_MASK);
|
||||||
Core::setTarget(water[1]);
|
Core::active.shader->setParam(uViewProj, Core::mViewProj);
|
||||||
Core::active.shader->setParam(uType, Shader::WATER_STEP);
|
Core::active.shader->setParam(uScale, 1.0f);
|
||||||
|
Core::setBlending(bmNone);
|
||||||
|
Core::setCulling(cfNone);
|
||||||
|
glDepthMask(false);
|
||||||
|
glColorMask(false, false, false, true);
|
||||||
mesh->renderQuad();
|
mesh->renderQuad();
|
||||||
swap(water[0], water[1]);
|
glColorMask(true, true, true, true);
|
||||||
|
glDepthMask(true);
|
||||||
|
|
||||||
water[0]->bind(sDiffuse);
|
// get refraction texture
|
||||||
Core::setTarget(water[1]);
|
checkRefractTexture();
|
||||||
Core::active.shader->setParam(uType, Shader::WATER_NORMAL);
|
waterRefract->bind(sDiffuse);
|
||||||
mesh->renderQuad();
|
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, Core::width, Core::height);
|
||||||
swap(water[0], water[1]);
|
|
||||||
|
|
||||||
Core::setViewport(0, 0, waterCaustics->width, waterCaustics->height);
|
// render mirror reflection
|
||||||
|
Core::setTarget(waterReflect);
|
||||||
|
vec3 p = vec3(40448, 3584, 60928);
|
||||||
|
vec3 n = vec3(0, 1, 0);
|
||||||
|
|
||||||
water[0]->bind(sDiffuse);
|
vec4 reflectPlane = vec4(n.x, n.y, n.z, -n.dot(p));
|
||||||
Core::setTarget(waterCaustics);
|
|
||||||
Core::active.shader->setParam(uType, Shader::WATER_CAUSTICS);
|
camera->reflectPlane = &reflectPlane;
|
||||||
mesh->renderQuad();
|
Core::setCulling(cfBack);
|
||||||
swap(water[0], water[1]);
|
clipSign = underwater ? -1.0f : 1.0f;
|
||||||
|
clipHeight = 3584.0 * clipSign;
|
||||||
|
renderCompose(underwater ? 13 : lara->getRoomIndex());
|
||||||
|
clipHeight = 1000000.0f;
|
||||||
|
clipSign = 1.0f;
|
||||||
|
Core::setCulling(cfFront);
|
||||||
|
camera->reflectPlane = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
// simulate water
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
|
||||||
|
setPassShader(Core::passWater);
|
||||||
|
waterDrop();
|
||||||
|
waterSimulate();
|
||||||
Core::setTarget(NULL);
|
Core::setTarget(NULL);
|
||||||
|
|
||||||
Core::setViewport(0, 0, Core::width, Core::height);
|
|
||||||
|
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
|
||||||
|
// render water plane
|
||||||
int dx, dz;
|
int dx, dz;
|
||||||
TR::Room::Sector &s = level.getSector(lara->getRoomIndex(), int(lara->pos.x), int(lara->pos.z), dx, dz);
|
TR::Room::Sector &s = level.getSector(lara->getRoomIndex(), int(lara->pos.x), int(lara->pos.z), dx, dz);
|
||||||
if (s.roomAbove != 0xFF && level.rooms[s.roomAbove].lightsCount) {
|
if (s.roomAbove != 0xFF && level.rooms[s.roomAbove].lightsCount) {
|
||||||
@@ -1032,11 +1037,14 @@ struct Level {
|
|||||||
Core::lightColor[0] = vec4(lum, lum, lum, float(light.radius) * float(light.radius));
|
Core::lightColor[0] = vec4(lum, lum, lum, float(light.radius) * float(light.radius));
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::active.shader->setParam(uType, Shader::WATER_COMPOSE);
|
Core::active.shader->setParam(uType, Shader::WATER_COMPOSE);
|
||||||
Core::active.shader->setParam(uViewProj, Core::mViewProj);
|
Core::active.shader->setParam(uViewProj, Core::mViewProj);
|
||||||
Core::active.shader->setParam(uViewPos, Core::viewPos);
|
Core::active.shader->setParam(uViewPos, Core::viewPos);
|
||||||
Core::active.shader->setParam(uLightPos, Core::lightPos[0], 1);
|
Core::active.shader->setParam(uLightPos, Core::lightPos[0], 1);
|
||||||
Core::active.shader->setParam(uLightColor, Core::lightColor[0], 1);
|
Core::active.shader->setParam(uLightColor, Core::lightColor[0], 1);
|
||||||
|
Core::active.shader->setParam(uParam, vec4(float(Core::width) / waterRefract->width, float(Core::height) / waterRefract->height, 0.075f, 0.02f));
|
||||||
|
// Core::active.shader->setParam(uParam, vec4(1.0f, 1.0f, 0.075f, 0.02f));
|
||||||
|
Core::active.shader->setParam(uScale, 1.0f);
|
||||||
|
|
||||||
waterRefract->bind(sDiffuse);
|
waterRefract->bind(sDiffuse);
|
||||||
waterReflect->bind(sReflect);
|
waterReflect->bind(sReflect);
|
||||||
@@ -1044,9 +1052,25 @@ struct Level {
|
|||||||
Core::setCulling(cfNone);
|
Core::setCulling(cfNone);
|
||||||
mesh->renderQuad();
|
mesh->renderQuad();
|
||||||
Core::setCulling(cfFront);
|
Core::setCulling(cfFront);
|
||||||
|
}
|
||||||
|
|
||||||
|
void render() {
|
||||||
|
clipHeight = 1000000.0f;
|
||||||
|
clipSign = 1.0f;
|
||||||
|
Core::resetStates();
|
||||||
|
|
||||||
|
ambientCache->precessQueue();
|
||||||
|
renderShadows(lara->getRoomIndex());
|
||||||
|
Core::setViewport(0, 0, Core::width, Core::height);
|
||||||
|
renderCompose(camera->getRoomIndex());
|
||||||
|
|
||||||
|
renderWater();
|
||||||
|
|
||||||
|
// Core::mViewInv = camera->mViewInv;
|
||||||
|
// Core::mView = Core::mViewInv.inverse();
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
|
camera->setup(true);
|
||||||
static int modelIndex = 0;
|
static int modelIndex = 0;
|
||||||
static bool lastStateK = false;
|
static bool lastStateK = false;
|
||||||
static int lastEntity = -1;
|
static int lastEntity = -1;
|
||||||
@@ -1072,7 +1096,7 @@ struct Level {
|
|||||||
// renderModel(level.models[modelIndex], level.entities[4]);
|
// renderModel(level.models[modelIndex], level.entities[4]);
|
||||||
|
|
||||||
Debug::begin();
|
Debug::begin();
|
||||||
|
|
||||||
glMatrixMode(GL_MODELVIEW);
|
glMatrixMode(GL_MODELVIEW);
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
glLoadIdentity();
|
glLoadIdentity();
|
||||||
@@ -1081,7 +1105,6 @@ struct Level {
|
|||||||
glLoadIdentity();
|
glLoadIdentity();
|
||||||
glOrtho(0, Core::width, 0, Core::height, 0, 1);
|
glOrtho(0, Core::width, 0, Core::height, 0, 1);
|
||||||
|
|
||||||
|
|
||||||
waterCaustics->bind(sDiffuse);
|
waterCaustics->bind(sDiffuse);
|
||||||
glEnable(GL_TEXTURE_2D);
|
glEnable(GL_TEXTURE_2D);
|
||||||
glDisable(GL_CULL_FACE);
|
glDisable(GL_CULL_FACE);
|
||||||
@@ -1108,7 +1131,7 @@ struct Level {
|
|||||||
// Debug::Level::rooms(level, lara->pos, lara->getEntity().room);
|
// Debug::Level::rooms(level, lara->pos, lara->getEntity().room);
|
||||||
// Debug::Level::lights(level, lara->getRoomIndex());
|
// Debug::Level::lights(level, lara->getRoomIndex());
|
||||||
// Debug::Level::sectors(level, lara->getRoomIndex(), (int)lara->pos.y);
|
// Debug::Level::sectors(level, lara->getRoomIndex(), (int)lara->pos.y);
|
||||||
// Debug::Level::portals(level);
|
Debug::Level::portals(level);
|
||||||
// Debug::Level::meshes(level);
|
// Debug::Level::meshes(level);
|
||||||
// Debug::Level::entities(level);
|
// Debug::Level::entities(level);
|
||||||
/*
|
/*
|
||||||
@@ -1206,7 +1229,7 @@ struct Level {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
// Debug::Level::info(level, lara->getEntity(), lara->animation);
|
Debug::Level::info(level, lara->getEntity(), lara->animation);
|
||||||
|
|
||||||
|
|
||||||
Debug::end();
|
Debug::end();
|
||||||
|
110
src/mesh.h
110
src/mesh.h
@@ -39,6 +39,8 @@ struct MeshRange {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define PLANE_DETAIL 100
|
||||||
|
|
||||||
struct Mesh {
|
struct Mesh {
|
||||||
GLuint ID[2];
|
GLuint ID[2];
|
||||||
GLuint *VAO;
|
GLuint *VAO;
|
||||||
@@ -142,6 +144,7 @@ struct MeshBuilder {
|
|||||||
MeshRange shadowBlob;
|
MeshRange shadowBlob;
|
||||||
MeshRange bar;
|
MeshRange bar;
|
||||||
MeshRange quad;
|
MeshRange quad;
|
||||||
|
MeshRange plane;
|
||||||
|
|
||||||
vec2 *animTexRanges;
|
vec2 *animTexRanges;
|
||||||
vec2 *animTexOffsets;
|
vec2 *animTexOffsets;
|
||||||
@@ -180,6 +183,9 @@ struct MeshBuilder {
|
|||||||
range.geometry.iStart = iCount;
|
range.geometry.iStart = iCount;
|
||||||
iCount += d.rCount * 6 + d.tCount * 3;
|
iCount += d.rCount * 6 + d.tCount * 3;
|
||||||
vCount += d.rCount * 4 + d.tCount * 3;
|
vCount += d.rCount * 4 + d.tCount * 3;
|
||||||
|
|
||||||
|
if (roomCheckWaterPortal(r))
|
||||||
|
roomRemoveWaterSurfaces(r, iCount, vCount);
|
||||||
|
|
||||||
for (int j = 0; j < r.meshesCount; j++) {
|
for (int j = 0; j < r.meshesCount; j++) {
|
||||||
TR::Room::Mesh &m = r.meshes[j];
|
TR::Room::Mesh &m = r.meshes[j];
|
||||||
@@ -236,25 +242,33 @@ struct MeshBuilder {
|
|||||||
shadowBlob.vStart = vCount;
|
shadowBlob.vStart = vCount;
|
||||||
shadowBlob.iStart = iCount;
|
shadowBlob.iStart = iCount;
|
||||||
shadowBlob.iCount = 8 * 3;
|
shadowBlob.iCount = 8 * 3;
|
||||||
aCount++;
|
|
||||||
iCount += shadowBlob.iCount;
|
iCount += shadowBlob.iCount;
|
||||||
vCount += 8;
|
vCount += 8;
|
||||||
|
aCount++;
|
||||||
|
|
||||||
// bar (health, oxygen)
|
// bar (health, oxygen)
|
||||||
bar.vStart = vCount;
|
bar.vStart = vCount;
|
||||||
bar.iStart = iCount;
|
bar.iStart = iCount;
|
||||||
bar.iCount = 2 * 3;
|
bar.iCount = 2 * 3;
|
||||||
aCount++;
|
|
||||||
iCount += bar.iCount;
|
iCount += bar.iCount;
|
||||||
vCount += 4;
|
vCount += 4;
|
||||||
|
aCount++;
|
||||||
|
|
||||||
// quad (post effect filter)
|
// quad (post effect filter)
|
||||||
quad.vStart = vCount;
|
quad.vStart = vCount;
|
||||||
quad.iStart = iCount;
|
quad.iStart = iCount;
|
||||||
quad.iCount = 2 * 3;
|
quad.iCount = 2 * 3;
|
||||||
aCount++;
|
|
||||||
iCount += quad.iCount;
|
iCount += quad.iCount;
|
||||||
vCount += 4;
|
vCount += 4;
|
||||||
|
aCount++;
|
||||||
|
|
||||||
|
// detailed plane
|
||||||
|
plane.vStart = vCount;
|
||||||
|
plane.iStart = iCount;
|
||||||
|
plane.iCount = PLANE_DETAIL * 2 * PLANE_DETAIL * 2 * (2 * 3);
|
||||||
|
iCount += plane.iCount;
|
||||||
|
vCount += (PLANE_DETAIL * 2 + 1) * (PLANE_DETAIL * 2 + 1);
|
||||||
|
aCount++;
|
||||||
|
|
||||||
// make meshes buffer (single vertex buffer object for all geometry & sprites on level)
|
// make meshes buffer (single vertex buffer object for all geometry & sprites on level)
|
||||||
Index *indices = new Index[iCount];
|
Index *indices = new Index[iCount];
|
||||||
@@ -272,6 +286,8 @@ struct MeshBuilder {
|
|||||||
TR::Rectangle &f = d.rectangles[j];
|
TR::Rectangle &f = d.rectangles[j];
|
||||||
TR::ObjectTexture &t = level.objectTextures[f.texture];
|
TR::ObjectTexture &t = level.objectTextures[f.texture];
|
||||||
|
|
||||||
|
if (f.vertices[0] == 0xFFFF) continue; // skip if marks as unused (removing water planes)
|
||||||
|
|
||||||
addQuad(indices, iCount, vCount, vStart, vertices, &t);
|
addQuad(indices, iCount, vCount, vStart, vertices, &t);
|
||||||
|
|
||||||
TR::Vertex n;
|
TR::Vertex n;
|
||||||
@@ -290,6 +306,8 @@ struct MeshBuilder {
|
|||||||
TR::Triangle &f = d.triangles[j];
|
TR::Triangle &f = d.triangles[j];
|
||||||
TR::ObjectTexture &t = level.objectTextures[f.texture];
|
TR::ObjectTexture &t = level.objectTextures[f.texture];
|
||||||
|
|
||||||
|
if (f.vertices[0] == 0xFFFF) continue; // skip if marks as unused (removing water planes)
|
||||||
|
|
||||||
addTriangle(indices, iCount, vCount, vStart, vertices, &t);
|
addTriangle(indices, iCount, vCount, vStart, vertices, &t);
|
||||||
|
|
||||||
TR::Vertex n;
|
TR::Vertex n;
|
||||||
@@ -405,6 +423,22 @@ struct MeshBuilder {
|
|||||||
}
|
}
|
||||||
vCount += 4;
|
vCount += 4;
|
||||||
|
|
||||||
|
// plane
|
||||||
|
for (int16 j = -PLANE_DETAIL; j <= PLANE_DETAIL; j++)
|
||||||
|
for (int16 i = -PLANE_DETAIL; i <= PLANE_DETAIL; i++) {
|
||||||
|
vertices[vCount++].coord = { i, j, 0, 0 };
|
||||||
|
if (j < PLANE_DETAIL && i < PLANE_DETAIL) {
|
||||||
|
int idx = (j + PLANE_DETAIL) * (PLANE_DETAIL * 2 + 1) + i + PLANE_DETAIL;
|
||||||
|
indices[iCount + 0] = idx + PLANE_DETAIL * 2 + 1;
|
||||||
|
indices[iCount + 1] = idx + 1;
|
||||||
|
indices[iCount + 2] = idx;
|
||||||
|
indices[iCount + 3] = idx + PLANE_DETAIL * 2 + 2;
|
||||||
|
indices[iCount + 4] = idx + 1;
|
||||||
|
indices[iCount + 5] = idx + PLANE_DETAIL * 2 + 1;
|
||||||
|
iCount += 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// compile buffer and ranges
|
// compile buffer and ranges
|
||||||
mesh = new Mesh(indices, iCount, vertices, vCount, aCount);
|
mesh = new Mesh(indices, iCount, vertices, vCount, aCount);
|
||||||
delete[] indices;
|
delete[] indices;
|
||||||
@@ -428,6 +462,7 @@ struct MeshBuilder {
|
|||||||
mesh->initRange(shadowBlob);
|
mesh->initRange(shadowBlob);
|
||||||
mesh->initRange(bar);
|
mesh->initRange(bar);
|
||||||
mesh->initRange(quad);
|
mesh->initRange(quad);
|
||||||
|
mesh->initRange(plane);
|
||||||
}
|
}
|
||||||
|
|
||||||
~MeshBuilder() {
|
~MeshBuilder() {
|
||||||
@@ -461,6 +496,70 @@ struct MeshBuilder {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool roomCheckWaterPortal(TR::Room room) {
|
||||||
|
for (int i = 0; i < room.portalsCount; i++)
|
||||||
|
if (room.flags.water ^ level->rooms[room.portals[i].roomIndex].flags.water)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void roomRemoveWaterSurfaces(TR::Room room, int &iCount, int &vCount) {
|
||||||
|
// remove animated water polygons from room geometry
|
||||||
|
for (int j = 0; j < room.portalsCount; j++) {
|
||||||
|
TR::Room::Portal &p = room.portals[j];
|
||||||
|
if (!(room.flags.water ^ level->rooms[p.roomIndex].flags.water)) // check if portal is not on water surface
|
||||||
|
continue;
|
||||||
|
|
||||||
|
TR::Vertex pMin, pMax;
|
||||||
|
pMin.x = min(min(min(p.vertices[0].x, p.vertices[1].x), p.vertices[2].x), p.vertices[3].x);
|
||||||
|
pMin.z = min(min(min(p.vertices[0].z, p.vertices[1].z), p.vertices[2].z), p.vertices[3].z);
|
||||||
|
pMax.x = max(max(max(p.vertices[0].x, p.vertices[1].x), p.vertices[2].x), p.vertices[3].x);
|
||||||
|
pMax.z = max(max(max(p.vertices[0].z, p.vertices[1].z), p.vertices[2].z), p.vertices[3].z);
|
||||||
|
pMin.y = pMax.y = p.vertices[0].y;
|
||||||
|
|
||||||
|
for (int i = 0; i < room.data.rCount; i++) {
|
||||||
|
TR::Rectangle &f = room.data.rectangles[i];
|
||||||
|
TR::Vertex &a = room.data.vertices[f.vertices[0]].vertex;
|
||||||
|
TR::Vertex &b = room.data.vertices[f.vertices[1]].vertex;
|
||||||
|
TR::Vertex &c = room.data.vertices[f.vertices[2]].vertex;
|
||||||
|
TR::Vertex &d = room.data.vertices[f.vertices[3]].vertex;
|
||||||
|
|
||||||
|
if (abs(a.y - pMin.y) > 1 || a.y != b.y || a.y != c.y || a.y != d.y) // skip non-horizontal or not in portal plane primitive
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int cx = (int(a.x) + int(b.x) + int(c.x) + int(d.x)) / 4;
|
||||||
|
int cz = (int(a.z) + int(b.z) + int(c.z) + int(d.z)) / 4;
|
||||||
|
|
||||||
|
if (c.x < pMin.x || c.x > pMax.x || c.z < pMin.z || c.z > pMax.z) // check for portal borders
|
||||||
|
continue;
|
||||||
|
|
||||||
|
f.vertices[0] = 0xFFFF; // mark it as unused
|
||||||
|
iCount -= 3 * 2;
|
||||||
|
vCount -= 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < room.data.tCount; i++) {
|
||||||
|
TR::Triangle &f = room.data.triangles[i];
|
||||||
|
TR::Vertex &a = room.data.vertices[f.vertices[0]].vertex;
|
||||||
|
TR::Vertex &b = room.data.vertices[f.vertices[1]].vertex;
|
||||||
|
TR::Vertex &c = room.data.vertices[f.vertices[2]].vertex;
|
||||||
|
|
||||||
|
if (abs(a.y - pMin.y) > 1 || a.y != b.y || a.y != c.y) // skip non-horizontal or not in portal plane primitive
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int cx = (int(a.x) + int(b.x) + int(c.x)) / 3;
|
||||||
|
int cz = (int(a.z) + int(b.z) + int(c.z)) / 3;
|
||||||
|
|
||||||
|
if (c.x < pMin.x || c.x > pMax.x || c.z < pMin.z || c.z > pMax.z) // check for portal borders
|
||||||
|
continue;
|
||||||
|
|
||||||
|
f.vertices[0] = 0xFFFF; // mark it as unused
|
||||||
|
iCount -= 3;
|
||||||
|
vCount -= 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void buildMesh(const TR::Mesh &mesh, const TR::Level &level, Index *indices, Vertex *vertices, int &iCount, int &vCount, int vStart, int16 joint, int x, int y, int z, int dir) {
|
void buildMesh(const TR::Mesh &mesh, const TR::Level &level, Index *indices, Vertex *vertices, int &iCount, int &vCount, int vStart, int16 joint, int x, int y, int z, int dir) {
|
||||||
TR::Color24 COLOR_WHITE = { 255, 255, 255 };
|
TR::Color24 COLOR_WHITE = { 255, 255, 255 };
|
||||||
|
|
||||||
@@ -503,7 +602,6 @@ struct MeshBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
vec2 getTexCoord(const TR::ObjectTexture &tex) {
|
vec2 getTexCoord(const TR::ObjectTexture &tex) {
|
||||||
int tile = tex.tile.index;
|
int tile = tex.tile.index;
|
||||||
int tx = (tile % 4) * 256;
|
int tx = (tile % 4) * 256;
|
||||||
@@ -682,6 +780,10 @@ struct MeshBuilder {
|
|||||||
mesh->render(quad);
|
mesh->render(quad);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void renderPlane() {
|
||||||
|
mesh->render(plane);
|
||||||
|
}
|
||||||
|
|
||||||
void renderBar(const vec2 &size, float value) {
|
void renderBar(const vec2 &size, float value) {
|
||||||
/*
|
/*
|
||||||
float w = size.y / 9.0f;
|
float w = size.y / 9.0f;
|
||||||
|
@@ -330,6 +330,9 @@ int main(int argc, char** argv) {
|
|||||||
Core::stats.tris = 0;
|
Core::stats.tris = 0;
|
||||||
Game::render();
|
Game::render();
|
||||||
SwapBuffers(hDC);
|
SwapBuffers(hDC);
|
||||||
|
#ifdef _DEBUG
|
||||||
|
Sleep(20);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (fpsTime < getTime()) {
|
if (fpsTime < getTime()) {
|
||||||
LOG("FPS: %d DIP: %d TRI: %d\n", fps, Core::stats.dips, Core::stats.tris);
|
LOG("FPS: %d DIP: %d TRI: %d\n", fps, Core::stats.dips, Core::stats.tris);
|
||||||
|
@@ -1,4 +1,9 @@
|
|||||||
R"====(
|
R"====(
|
||||||
|
#ifdef GL_ES
|
||||||
|
precision highp int;
|
||||||
|
precision highp float;
|
||||||
|
#endif
|
||||||
|
|
||||||
varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
|
varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
|
||||||
|
|
||||||
#ifndef PASS_SHADOW
|
#ifndef PASS_SHADOW
|
||||||
@@ -78,10 +83,6 @@ uniform int uType;
|
|||||||
|
|
||||||
vTexCoord.xy = (aTexCoord.xy + offset) * TEXCOORD_SCALE; // first frame + offset * isAnimated
|
vTexCoord.xy = (aTexCoord.xy + offset) * TEXCOORD_SCALE; // first frame + offset * isAnimated
|
||||||
vNormal = vec4(mulQuat(rBasisRot, aNormal.xyz), aNormal.w);
|
vNormal = vec4(mulQuat(rBasisRot, aNormal.xyz), aNormal.w);
|
||||||
|
|
||||||
if (aTexCoord.z > 0.0)
|
|
||||||
coord.w = -1.0;
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
coord.xyz += uViewInv[0].xyz * aTexCoord.z - uViewInv[1].xyz * aTexCoord.w;
|
coord.xyz += uViewInv[0].xyz * aTexCoord.z - uViewInv[1].xyz * aTexCoord.w;
|
||||||
vTexCoord.xy = aTexCoord.xy * TEXCOORD_SCALE;
|
vTexCoord.xy = aTexCoord.xy * TEXCOORD_SCALE;
|
||||||
|
10
src/shader.h
10
src/shader.h
@@ -5,11 +5,11 @@
|
|||||||
|
|
||||||
enum AttribType { aCoord, aTexCoord, aNormal, aColor, aMAX };
|
enum AttribType { aCoord, aTexCoord, aNormal, aColor, aMAX };
|
||||||
enum SamplerType { sDiffuse, sNormal, sReflect, sShadow, sEnvironment, sMAX };
|
enum SamplerType { sDiffuse, sNormal, sReflect, sShadow, sEnvironment, sMAX };
|
||||||
enum UniformType { uType, uCaustics, uParam, uViewProj, uViewInv, uBasis, uLightProj, uColor, uAmbient, uViewPos, uLightsCount, uLightPos, uLightColor, uAnimTexRanges, uAnimTexOffsets, uRoomSize, uMAX };
|
enum UniformType { uType, uCaustics, uParam, uViewProj, uViewInv, uBasis, uLightProj, uColor, uAmbient, uViewPos, uLightsCount, uLightPos, uLightColor, uAnimTexRanges, uAnimTexOffsets, uRoomSize, uScale, uMAX };
|
||||||
|
|
||||||
const char *AttribName[aMAX] = { "aCoord", "aTexCoord", "aNormal", "aColor" };
|
const char *AttribName[aMAX] = { "aCoord", "aTexCoord", "aNormal", "aColor" };
|
||||||
const char *SamplerName[sMAX] = { "sDiffuse", "sNormal", "sReflect", "sShadow", "sEnvironment" };
|
const char *SamplerName[sMAX] = { "sDiffuse", "sNormal", "sReflect", "sShadow", "sEnvironment" };
|
||||||
const char *UniformName[uMAX] = { "uType", "uCaustics", "uParam", "uViewProj", "uViewInv", "uBasis", "uLightProj", "uColor", "uAmbient", "uViewPos", "uLightsCount", "uLightPos", "uLightColor", "uAnimTexRanges", "uAnimTexOffsets", "uRoomSize" };
|
const char *UniformName[uMAX] = { "uType", "uCaustics", "uParam", "uViewProj", "uViewInv", "uBasis", "uLightProj", "uColor", "uAmbient", "uViewPos", "uLightsCount", "uLightPos", "uLightColor", "uAnimTexRanges", "uAnimTexOffsets", "uRoomSize", "uScale" };
|
||||||
|
|
||||||
struct Shader {
|
struct Shader {
|
||||||
GLuint ID;
|
GLuint ID;
|
||||||
@@ -18,14 +18,14 @@ struct Shader {
|
|||||||
enum : GLint {
|
enum : GLint {
|
||||||
/* shader */ SPRITE = 0, FLASH = 1, ROOM = 2, ENTITY = 3, MIRROR = 4,
|
/* shader */ SPRITE = 0, FLASH = 1, ROOM = 2, ENTITY = 3, MIRROR = 4,
|
||||||
/* filter */ FILTER_DOWNSAMPLE = 0,
|
/* filter */ FILTER_DOWNSAMPLE = 0,
|
||||||
/* water */ WATER_DROP = 0, WATER_STEP = 1, WATER_NORMAL = 2, WATER_CAUSTICS = 3, WATER_MASK = 4, WATER_COMPOSE = 5,
|
/* water */ WATER_DROP = 0, WATER_STEP = 1, WATER_CAUSTICS = 2, WATER_MASK = 3, WATER_COMPOSE = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
Shader(const char *text, const char *defines = "") {
|
Shader(const char *text, const char *defines = "") {
|
||||||
#ifdef MOBILE
|
#ifdef MOBILE
|
||||||
#define GLSL_DEFINE "precision highp int;\nprecision highp float;\n"
|
#define GLSL_DEFINE ""
|
||||||
#else
|
#else
|
||||||
#define GLSL_DEFINE "#version 120\n"
|
#define GLSL_DEFINE "#version 120\n"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const int type[2] = { GL_VERTEX_SHADER, GL_FRAGMENT_SHADER };
|
const int type[2] = { GL_VERTEX_SHADER, GL_FRAGMENT_SHADER };
|
||||||
|
11
src/utils.h
11
src/utils.h
@@ -95,6 +95,17 @@ float decrease(float delta, float &value, float &speed) {
|
|||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int nextPow2(uint32 x) {
|
||||||
|
x--;
|
||||||
|
x |= x >> 1;
|
||||||
|
x |= x >> 2;
|
||||||
|
x |= x >> 4;
|
||||||
|
x |= x >> 8;
|
||||||
|
x |= x >> 16;
|
||||||
|
x++;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
struct vec2 {
|
struct vec2 {
|
||||||
float x, y;
|
float x, y;
|
||||||
vec2() {}
|
vec2() {}
|
||||||
|
180
src/water.glsl
Normal file
180
src/water.glsl
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
R"====(
|
||||||
|
#ifdef GL_ES
|
||||||
|
#ifdef FRAGMENT
|
||||||
|
#extension GL_OES_standard_derivatives : enable
|
||||||
|
#endif
|
||||||
|
precision highp int;
|
||||||
|
precision highp float;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
varying vec3 vCoord;
|
||||||
|
varying vec2 vTexCoord;
|
||||||
|
varying vec4 vProjCoord;
|
||||||
|
varying vec3 vRefPos1;
|
||||||
|
varying vec3 vRefPos2;
|
||||||
|
|
||||||
|
#define WATER_DROP 0
|
||||||
|
#define WATER_STEP 1
|
||||||
|
#define WATER_CAUSTICS 2
|
||||||
|
#define WATER_MASK 3
|
||||||
|
#define WATER_COMPOSE 4
|
||||||
|
|
||||||
|
uniform int uType;
|
||||||
|
uniform vec3 uViewPos;
|
||||||
|
uniform mat4 uViewProj;
|
||||||
|
uniform float uScale;
|
||||||
|
|
||||||
|
uniform sampler2D sNormal;
|
||||||
|
|
||||||
|
#ifdef VERTEX
|
||||||
|
#define ETA_AIR 1.000
|
||||||
|
#define ETA_WATER 1.333
|
||||||
|
|
||||||
|
attribute vec4 aCoord;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 rCoord = aCoord * uScale;
|
||||||
|
|
||||||
|
if (uType >= WATER_MASK) {
|
||||||
|
// hardcoded pool geometry
|
||||||
|
vec2 p = rCoord.xy * 2560.0;
|
||||||
|
vCoord = vec3(p.x + 40448.0, 3584.0, p.y + 60928.0);
|
||||||
|
vec4 cp = uViewProj * vec4(vCoord, 1.0);
|
||||||
|
|
||||||
|
vProjCoord = cp;
|
||||||
|
gl_Position = cp;
|
||||||
|
} else {
|
||||||
|
vProjCoord = vec4(0.0);
|
||||||
|
if (uType == WATER_CAUSTICS) {
|
||||||
|
vec4 info = texture2D(sNormal, rCoord.xy * 0.5 + 0.5);
|
||||||
|
info.ba *= 0.5;
|
||||||
|
vec3 normal = vec3(info.b, -sqrt(1.0 - dot(info.ba, info.ba)), info.a);
|
||||||
|
|
||||||
|
vec3 light = vec3(0.0, -1.0, 0.0);
|
||||||
|
vec3 refractedLight = refract(-light, vec3(0.0, 1.0, 0.0), ETA_AIR / ETA_WATER);
|
||||||
|
vec3 ray = refract(-light, normal, ETA_AIR / ETA_WATER);
|
||||||
|
vRefPos1 = rCoord.xzy + vec3(0.0, 1.0, 0.0);
|
||||||
|
vRefPos2 = rCoord.xzy + vec3(0.0, info.r, 0.0) + ray / ray.y;
|
||||||
|
|
||||||
|
gl_Position = vec4((vRefPos2.xz + 0.0 * refractedLight.xz / refractedLight.y), 0.0, 1.0);
|
||||||
|
} else {
|
||||||
|
vRefPos1 = vRefPos2 = vec3(0.0);
|
||||||
|
vCoord = vec3(rCoord.xy, 0.0);
|
||||||
|
|
||||||
|
gl_Position = vec4(rCoord.xyz, 1.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vTexCoord = rCoord.xy * 0.5 + 0.5;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
uniform sampler2D sDiffuse;
|
||||||
|
uniform sampler2D sReflect;
|
||||||
|
|
||||||
|
uniform vec4 uParam; // texture size
|
||||||
|
|
||||||
|
uniform vec3 uLightPos;
|
||||||
|
uniform vec4 uLightColor;
|
||||||
|
|
||||||
|
#define PI 3.141592653589793
|
||||||
|
|
||||||
|
vec3 cubeProj(vec3 ray, vec3 cubePos, vec3 cubeMin, vec3 cubeMax) {
|
||||||
|
vec3 i1 = (cubeMax - vCoord) / ray;
|
||||||
|
vec3 i2 = (cubeMin - vCoord) / ray;
|
||||||
|
vec3 i0 = max(i1, i2);
|
||||||
|
float dist = min(min(i0.x, i0.y), i0.z);
|
||||||
|
return vCoord + ray * dist - cubePos;
|
||||||
|
}
|
||||||
|
|
||||||
|
float calcFresnel(float NdotL, float fbias, float fpow) {
|
||||||
|
float f = (1.0 - abs(NdotL));
|
||||||
|
return clamp(fbias + (1.0 - fbias) * pow(f, fpow), 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 drop() {
|
||||||
|
vec4 value = texture2D(sDiffuse, vTexCoord);
|
||||||
|
float drop = max(0.0, 1.0 - length(uParam.xy - vTexCoord) / uParam.z);
|
||||||
|
drop = 0.5 - cos(drop * PI) * 0.5;
|
||||||
|
value.r += drop * uParam.w;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 step() {
|
||||||
|
vec2 dx = vec2(uParam.x, 0.0);
|
||||||
|
vec2 dy = vec2(0.0, uParam.y);
|
||||||
|
|
||||||
|
vec4 v = texture2D(sDiffuse, vTexCoord);
|
||||||
|
vec4 f = vec4(texture2D(sDiffuse, vTexCoord + dx).r, texture2D(sDiffuse, vTexCoord + dy).r,
|
||||||
|
texture2D(sDiffuse, vTexCoord - dx).r, texture2D(sDiffuse, vTexCoord - dy).r);
|
||||||
|
|
||||||
|
float average = dot(f, vec4(0.25));
|
||||||
|
|
||||||
|
// normal
|
||||||
|
f.xy -= v.r;
|
||||||
|
vec3 nx = vec3(uParam.x, f.x, 0.0);
|
||||||
|
vec3 ny = vec3(0.0, f.y, uParam.y);
|
||||||
|
v.ba = normalize(cross(ny, nx)).xz;
|
||||||
|
|
||||||
|
// velocity
|
||||||
|
v.g += (average - v.r) * 2.0;
|
||||||
|
v.g *= 0.995;
|
||||||
|
|
||||||
|
// amplitude
|
||||||
|
v.r += v.g * 0.4;
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 caustics() {
|
||||||
|
vec4 v = texture2D(sNormal, vTexCoord);
|
||||||
|
v.ba *= 0.5;
|
||||||
|
vec3 normal = vec3(v.b, sqrt(1.0 - dot(v.ba, v.ba)), v.a);
|
||||||
|
|
||||||
|
float area1 = length(dFdx(vRefPos1)) * length(dFdy(vRefPos1));
|
||||||
|
float area2 = length(dFdx(vRefPos2)) * length(dFdy(vRefPos2));
|
||||||
|
|
||||||
|
return vec4(vec3(area1 / area2 * 0.2), 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 mask() {
|
||||||
|
return vec4(0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 compose() {
|
||||||
|
vec2 tc = vProjCoord.xy / vProjCoord.w * 0.5 + 0.5;
|
||||||
|
|
||||||
|
vec4 value = texture2D(sNormal, vTexCoord);
|
||||||
|
|
||||||
|
value.ba *= 0.5;
|
||||||
|
vec3 normal = normalize(vec3(value.b, -sqrt(1.0 - dot(value.ba, value.ba)), value.a));
|
||||||
|
vec2 dudv = (uViewProj * vec4(normal.x, 0.0, normal.z, 0.0)).xy;
|
||||||
|
|
||||||
|
vec3 viewVec = normalize(uViewPos - vCoord);
|
||||||
|
vec3 rv = reflect(-viewVec, normal);
|
||||||
|
vec3 lv = normalize(uLightPos - vCoord.xyz);
|
||||||
|
|
||||||
|
float spec = pow(max(0.0, dot(rv, -lv)), 64.0) * 0.5;
|
||||||
|
|
||||||
|
vec4 refrA = texture2D(sDiffuse, uParam.xy * clamp(tc + dudv * uParam.z, 0.0, 0.999) );
|
||||||
|
vec4 refrB = texture2D(sDiffuse, uParam.xy * (tc) );
|
||||||
|
vec4 refr = vec4(mix(refrA.xyz, refrB.xyz, refrA.w), 1.0);
|
||||||
|
vec4 refl = texture2D(sReflect, tc + dudv * uParam.w);
|
||||||
|
|
||||||
|
float fresnel = calcFresnel(dot(normal, viewVec), 0.1, 2.0);
|
||||||
|
return mix(refr, refl, fresnel) + spec;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 pass() {
|
||||||
|
if (uType == WATER_DROP) return drop();
|
||||||
|
if (uType == WATER_STEP) return step();
|
||||||
|
if (uType == WATER_CAUSTICS) return caustics();
|
||||||
|
if (uType == WATER_MASK) return mask();
|
||||||
|
if (uType == WATER_COMPOSE) return compose();
|
||||||
|
return vec4(1.0, 0.0, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
gl_FragColor = pass();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
)===="
|
Reference in New Issue
Block a user