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:
@@ -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;
|
||||
|
@@ -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() {
|
||||
|
11
src/debug.h
11
src/debug.h
@@ -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 {
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,9 @@
|
||||
R"====(
|
||||
#ifdef GL_ES
|
||||
precision highp int;
|
||||
precision highp float;
|
||||
#endif
|
||||
|
||||
varying vec2 vTexCoord;
|
||||
|
||||
#define FILTER_DOWNSAMPLE 0
|
||||
|
20
src/format.h
20
src/format.h
@@ -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) {
|
||||
|
@@ -1,4 +1,9 @@
|
||||
R"====(
|
||||
#ifdef GL_ES
|
||||
precision highp int;
|
||||
precision highp float;
|
||||
#endif
|
||||
|
||||
varying vec2 vTexCoord;
|
||||
|
||||
#ifdef VERTEX
|
||||
|
201
src/level.h
201
src/level.h
@@ -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();
|
||||
|
110
src/mesh.h
110
src/mesh.h
@@ -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;
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
|
@@ -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
|
||||
|
11
src/utils.h
11
src/utils.h
@@ -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
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