1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-08-14 00:54:05 +02:00

#23 water shader, fixed simulation step, caustics

This commit is contained in:
XProger
2017-01-27 02:56:24 +03:00
parent 80552ff1b5
commit 1a8e61e05e
13 changed files with 462 additions and 129 deletions

View File

@@ -89,11 +89,11 @@ struct Camera : Controller {
} else
#endif
{
if (Input::down[ikMouseR]) {
vec2 delta = Input::mouse.pos - Input::mouse.start.R;
if (Input::down[ikMouseL]) {
vec2 delta = Input::mouse.pos - Input::mouse.start.L;
angleAdv.x -= delta.y * 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;

View File

@@ -341,6 +341,7 @@ namespace Core {
if (!target) {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glColorMask(true, true, true, true);
setViewport(0, 0, Core::width, Core::height);
return;
}
@@ -362,6 +363,7 @@ namespace Core {
if (depth)
glColorMask(false, false, false, false);
setViewport(0, 0, target->width, target->height);
}
void resetStates() {

View File

@@ -411,7 +411,6 @@ namespace Debug {
Box box = controller->animation.getBoundingBox(vec3(0.0f), 0);
Debug::Draw::box(matrix, box.min, box.max, vec4(1.0));
/*
for (int j = 0; j < level.modelsCount; j++) {
TR::Model &m = level.models[j];
@@ -424,7 +423,7 @@ namespace Debug {
int fSize = sizeof(TR::AnimFrame) + m.mCount * sizeof(uint16) * 2;
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;
//m.identity();
@@ -461,12 +460,13 @@ namespace Debug {
joint = joint * rot;
int offset = level.meshOffsets[m.mStart + k];
TR::Mesh *mesh = (TR::Mesh*)&level.meshData[offset / 2];
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));
TR::Mesh *mesh = (TR::Mesh*)&level.meshes[offset];
if (!mesh->flags) continue;
Debug::Draw::sphere(matrix * joint * mesh->center, mesh->radius, vec4(0, 1, 1, 0.5f));
{ //if (e.id != 0) {
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);
}
@@ -477,7 +477,6 @@ namespace Debug {
}
}
*/
}
}

View File

@@ -1,4 +1,9 @@
R"====(
#ifdef GL_ES
precision highp int;
precision highp float;
#endif
varying vec2 vTexCoord;
#define FILTER_DOWNSAMPLE 0

View File

@@ -320,10 +320,10 @@ namespace TR {
uint16 boxIndex:15, end:1;
};
struct Collider {
uint16 radius:10, info:6;
uint16 flags:16;
};
//struct Collider {
// uint16 radius:10, info:6;
// uint16 flags:16;
//};
// internal mesh structure
struct Mesh {
@@ -333,8 +333,9 @@ namespace TR {
short4 normal;
};
Collider collider;
TR::Vertex center;
uint16 radius;
uint16 flags;
int16 vCount;
int16 rCount;
int16 tCount;
@@ -669,7 +670,7 @@ namespace TR {
uint16 volume;
uint16 chance; // If !=0 and ((rand()&0x7fff) > Chance), this sound is not played
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;
} flags;
};
@@ -872,7 +873,6 @@ namespace TR {
} else if (version == VER_TR1_PC) {
// tiles
stream.read(tiles8, stream.read(tilesCount));
stream.read(unused);
}
if (!version /*PSX cutscene*/ || version == VER_TR1_PSX) {
@@ -880,8 +880,9 @@ namespace TR {
// tiles
stream.read(tiles4, tilesCount = 13);
stream.read(cluts, 512);
stream.seek(0x4000 + 4);
stream.seek(0x4000);
}
stream.read(unused);
// rooms
rooms = new Room[stream.read(roomsCount)];
@@ -1116,7 +1117,8 @@ namespace TR {
mesh.offset = stream.pos - start;
stream.read(mesh.center);
stream.read(mesh.collider);
stream.read(mesh.radius);
stream.read(mesh.flags);
stream.read(mesh.vCount);
switch (version) {

View File

@@ -1,4 +1,9 @@
R"====(
#ifdef GL_ES
precision highp int;
precision highp float;
#endif
varying vec2 vTexCoord;
#ifdef VERTEX

View File

@@ -47,6 +47,7 @@ struct Level {
Texture *waterRefract;
Texture *waterReflect;
Texture *waterCaustics;
float waterTimer;
float time;
float clipHeight;
@@ -130,7 +131,6 @@ struct Level {
int size = 64 >> (i << 1);
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++) {
Texture *src = textures[j * 4 + i - 1];
@@ -364,15 +364,23 @@ struct Level {
delete camera;
}
#define WATER_SIMULATE_TIMESTEP (1.0f / 40.0f)
void initTextures() {
shadow = new Texture(1024, 1024, Texture::SHADOW, false);
water[0] = 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);
waterReflect = new Texture(1024, 1024, Texture::RGBA, false);
waterCaustics = new Texture(1024, 1024, Texture::RGBA, false);
waterRefract = NULL;
waterReflect = new Texture( 512, 512, 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) {
atlas = NULL;
@@ -415,6 +423,12 @@ struct Level {
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() {
char def[255], ext[255];
@@ -721,6 +735,7 @@ struct Level {
void update() {
time += Core::deltaTime;
waterTimer += Core::deltaTime;
for (int i = 0; i < level.entitiesCount; i++)
if (level.entities[i].type != TR::Entity::NONE) {
@@ -861,10 +876,10 @@ struct Level {
Core::setBlending(bmAlpha);
Texture *target = targets[0]->cube ? targets[0] : targets[i * stride];
Core::setTarget(target, i);
Core::setViewport(0, 0, target->width, target->height);
Core::clear(vec4(0, 0, 0, 1));
renderScene(roomIndex);
}
Core::setTarget(NULL);
}
void renderShadows(int roomIndex) {
@@ -874,7 +889,6 @@ struct Level {
setPassShader(Core::passShadow);
Core::setBlending(bmNone);
Core::setTarget(shadow);
Core::setViewport(0, 0, shadow->width, shadow->height);
Core::clear(vec4(1.0));
Core::setCulling(cfBack);
renderScene(roomIndex);
@@ -892,71 +906,39 @@ struct Level {
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;
}
void render() {
clipHeight = 1000000.0f;
clipSign = 1.0f;
Core::resetStates();
// 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]);
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);
// 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 waterDrop() {
static vec3 lastPos = vec3(0.0);
vec3 head = lara->animation.getJoints(lara->getMatrix(), 14).pos;
bool flag = (head - lastPos).length() > 16.0f;
@@ -981,8 +963,6 @@ struct Level {
strength = 0.05f;
}
water[0]->bind(sDiffuse);
Core::setTarget(water[1]);
Core::active.shader->setParam(uType, Shader::WATER_DROP);
@@ -991,38 +971,63 @@ struct Level {
swap(water[0], water[1]);
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::setTarget(water[1]);
Core::active.shader->setParam(uType, Shader::WATER_STEP);
Core::active.shader->setParam(uType, Shader::WATER_MASK);
Core::active.shader->setParam(uViewProj, Core::mViewProj);
Core::active.shader->setParam(uScale, 1.0f);
Core::setBlending(bmNone);
Core::setCulling(cfNone);
glDepthMask(false);
glColorMask(false, false, false, true);
mesh->renderQuad();
swap(water[0], water[1]);
glColorMask(true, true, true, true);
glDepthMask(true);
water[0]->bind(sDiffuse);
Core::setTarget(water[1]);
Core::active.shader->setParam(uType, Shader::WATER_NORMAL);
mesh->renderQuad();
swap(water[0], water[1]);
// get refraction texture
checkRefractTexture();
waterRefract->bind(sDiffuse);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, Core::width, Core::height);
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);
Core::setTarget(waterCaustics);
Core::active.shader->setParam(uType, Shader::WATER_CAUSTICS);
mesh->renderQuad();
swap(water[0], water[1]);
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;
// simulate water
glDisable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
setPassShader(Core::passWater);
waterDrop();
waterSimulate();
Core::setTarget(NULL);
Core::setViewport(0, 0, Core::width, Core::height);
glEnable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
// render water plane
int 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) {
@@ -1037,6 +1042,9 @@ struct Level {
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) / 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);
waterReflect->bind(sReflect);
@@ -1044,9 +1052,25 @@ struct Level {
Core::setCulling(cfNone);
mesh->renderQuad();
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
camera->setup(true);
static int modelIndex = 0;
static bool lastStateK = false;
static int lastEntity = -1;
@@ -1081,7 +1105,6 @@ struct Level {
glLoadIdentity();
glOrtho(0, Core::width, 0, Core::height, 0, 1);
waterCaustics->bind(sDiffuse);
glEnable(GL_TEXTURE_2D);
glDisable(GL_CULL_FACE);
@@ -1108,7 +1131,7 @@ struct Level {
// Debug::Level::rooms(level, lara->pos, lara->getEntity().room);
// Debug::Level::lights(level, lara->getRoomIndex());
// Debug::Level::sectors(level, lara->getRoomIndex(), (int)lara->pos.y);
// Debug::Level::portals(level);
Debug::Level::portals(level);
// Debug::Level::meshes(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();

View File

@@ -39,6 +39,8 @@ struct MeshRange {
}
};
#define PLANE_DETAIL 100
struct Mesh {
GLuint ID[2];
GLuint *VAO;
@@ -142,6 +144,7 @@ struct MeshBuilder {
MeshRange shadowBlob;
MeshRange bar;
MeshRange quad;
MeshRange plane;
vec2 *animTexRanges;
vec2 *animTexOffsets;
@@ -181,6 +184,9 @@ struct MeshBuilder {
iCount += d.rCount * 6 + 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++) {
TR::Room::Mesh &m = r.meshes[j];
TR::StaticMesh *s = level.getMeshByID(m.meshID);
@@ -236,25 +242,33 @@ struct MeshBuilder {
shadowBlob.vStart = vCount;
shadowBlob.iStart = iCount;
shadowBlob.iCount = 8 * 3;
aCount++;
iCount += shadowBlob.iCount;
vCount += 8;
aCount++;
// bar (health, oxygen)
bar.vStart = vCount;
bar.iStart = iCount;
bar.iCount = 2 * 3;
aCount++;
iCount += bar.iCount;
vCount += 4;
aCount++;
// quad (post effect filter)
quad.vStart = vCount;
quad.iStart = iCount;
quad.iCount = 2 * 3;
aCount++;
iCount += quad.iCount;
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)
Index *indices = new Index[iCount];
@@ -272,6 +286,8 @@ struct MeshBuilder {
TR::Rectangle &f = d.rectangles[j];
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);
TR::Vertex n;
@@ -290,6 +306,8 @@ struct MeshBuilder {
TR::Triangle &f = d.triangles[j];
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);
TR::Vertex n;
@@ -405,6 +423,22 @@ struct MeshBuilder {
}
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
mesh = new Mesh(indices, iCount, vertices, vCount, aCount);
delete[] indices;
@@ -428,6 +462,7 @@ struct MeshBuilder {
mesh->initRange(shadowBlob);
mesh->initRange(bar);
mesh->initRange(quad);
mesh->initRange(plane);
}
~MeshBuilder() {
@@ -461,6 +496,70 @@ struct MeshBuilder {
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) {
TR::Color24 COLOR_WHITE = { 255, 255, 255 };
@@ -503,7 +602,6 @@ struct MeshBuilder {
}
}
vec2 getTexCoord(const TR::ObjectTexture &tex) {
int tile = tex.tile.index;
int tx = (tile % 4) * 256;
@@ -682,6 +780,10 @@ struct MeshBuilder {
mesh->render(quad);
}
void renderPlane() {
mesh->render(plane);
}
void renderBar(const vec2 &size, float value) {
/*
float w = size.y / 9.0f;

View File

@@ -330,6 +330,9 @@ int main(int argc, char** argv) {
Core::stats.tris = 0;
Game::render();
SwapBuffers(hDC);
#ifdef _DEBUG
Sleep(20);
#endif
if (fpsTime < getTime()) {
LOG("FPS: %d DIP: %d TRI: %d\n", fps, Core::stats.dips, Core::stats.tris);

View File

@@ -1,4 +1,9 @@
R"====(
#ifdef GL_ES
precision highp int;
precision highp float;
#endif
varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
#ifndef PASS_SHADOW
@@ -78,10 +83,6 @@ uniform int uType;
vTexCoord.xy = (aTexCoord.xy + offset) * TEXCOORD_SCALE; // first frame + offset * isAnimated
vNormal = vec4(mulQuat(rBasisRot, aNormal.xyz), aNormal.w);
if (aTexCoord.z > 0.0)
coord.w = -1.0;
} else {
coord.xyz += uViewInv[0].xyz * aTexCoord.z - uViewInv[1].xyz * aTexCoord.w;
vTexCoord.xy = aTexCoord.xy * TEXCOORD_SCALE;

View File

@@ -5,11 +5,11 @@
enum AttribType { aCoord, aTexCoord, aNormal, aColor, aMAX };
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 *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 {
GLuint ID;
@@ -18,12 +18,12 @@ struct Shader {
enum : GLint {
/* shader */ SPRITE = 0, FLASH = 1, ROOM = 2, ENTITY = 3, MIRROR = 4,
/* 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 = "") {
#ifdef MOBILE
#define GLSL_DEFINE "precision highp int;\nprecision highp float;\n"
#define GLSL_DEFINE ""
#else
#define GLSL_DEFINE "#version 120\n"
#endif

View File

@@ -95,6 +95,17 @@ float decrease(float delta, float &value, float &speed) {
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 {
float x, y;
vec2() {}

180
src/water.glsl Normal file
View 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
)===="