mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-09 14:47:02 +02:00
This commit is contained in:
@@ -26,7 +26,7 @@ struct Camera : Controller {
|
||||
Camera(TR::Level *level, Lara *owner) : Controller(level, owner ? owner->entity : 0), owner(owner), frustum(new Frustum()), timer(0.0f), actTargetEntity(-1), actCamera(-1), reflectPlane(NULL) {
|
||||
fov = 65.0f;
|
||||
znear = 16;
|
||||
zfar = 32.0f * 1024.0f;
|
||||
zfar = 40.0f * 1024.0f;
|
||||
angleAdv = vec3(0.0f);
|
||||
|
||||
if (owner) {
|
||||
@@ -207,13 +207,15 @@ struct Camera : Controller {
|
||||
|
||||
virtual void setup(bool calcMatrices) {
|
||||
if (calcMatrices) {
|
||||
if (reflectPlane)
|
||||
if (reflectPlane) {
|
||||
Core::mViewInv = mat4(*reflectPlane) * mViewInv;
|
||||
else
|
||||
Core::mViewInv.scale(vec3(1.0f, -1.0f, 1.0f));
|
||||
} else
|
||||
Core::mViewInv = mViewInv;
|
||||
|
||||
Core::mView = Core::mViewInv.inverse();
|
||||
Core::mProj = mat4(fov, (float)Core::width / (float)Core::height, znear, zfar);
|
||||
|
||||
// TODO: camera shake
|
||||
// TODO: temporal anti-aliasing
|
||||
// Core::mProj.e02 = (randf() - 0.5f) * 32.0f / Core::width;
|
||||
|
29
src/core.h
29
src/core.h
@@ -150,6 +150,8 @@ namespace Core {
|
||||
vec4 lightColor[MAX_LIGHTS];
|
||||
vec4 color;
|
||||
|
||||
Texture *blackTex, *whiteTex;
|
||||
|
||||
enum Pass { passCompose, passShadow, passAmbient, passFilter, passWater } pass;
|
||||
|
||||
GLuint FBO;
|
||||
@@ -281,9 +283,16 @@ namespace Core {
|
||||
lightColor[i] = vec4(0, 0, 0, 1);
|
||||
|
||||
frameIndex = 0;
|
||||
|
||||
uint32 data = 0xFF000000;
|
||||
blackTex = new Texture(1, 1, Texture::RGBA, false, &data);
|
||||
data = 0xFFFFFFFF;
|
||||
whiteTex = new Texture(1, 1, Texture::RGBA, false, &data);
|
||||
}
|
||||
|
||||
void free() {
|
||||
delete blackTex;
|
||||
delete whiteTex;
|
||||
// glDeleteRenderBuffers(MAX_RENDER_BUFFERS * 2, &renderBuffers[0][0]);
|
||||
// glDeleteFrameBuffers(1, &FBO);
|
||||
Sound::free();
|
||||
@@ -337,6 +346,21 @@ namespace Core {
|
||||
glEnable(GL_BLEND);
|
||||
}
|
||||
|
||||
void setColorWrite(bool r, bool g, bool b, bool a) {
|
||||
glColorMask(r, g, b, a);
|
||||
}
|
||||
|
||||
void setDepthWrite(bool write) {
|
||||
glDepthMask(write);
|
||||
}
|
||||
|
||||
void setDepthTest(bool test) {
|
||||
if (test)
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
else
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
}
|
||||
|
||||
void setTarget(Texture *target, int face = 0) {
|
||||
if (!target) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
@@ -366,6 +390,11 @@ namespace Core {
|
||||
setViewport(0, 0, target->width, target->height);
|
||||
}
|
||||
|
||||
void copyTarget(Texture *texture, int xOffset, int yOffset, int x, int y, int width, int height) {
|
||||
texture->bind(sDiffuse);
|
||||
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, x, y, width, height);
|
||||
}
|
||||
|
||||
void resetStates() {
|
||||
memset(&active, 0, sizeof(active));
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
@@ -627,7 +627,7 @@ namespace Debug {
|
||||
case_name(TR::Entity, KEY_4 );
|
||||
case_name(TR::Entity, HOLE_KEY );
|
||||
case_name(TR::Entity, VIEW_TARGET );
|
||||
case_name(TR::Entity, SOURCE_WATER );
|
||||
case_name(TR::Entity, WATERFALL );
|
||||
}
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
@@ -16,7 +16,6 @@ uniform int uType;
|
||||
void main() {
|
||||
vTexCoord = aCoord.zw;
|
||||
gl_Position = vec4(aCoord.xy, 0.0, 1.0);
|
||||
|
||||
}
|
||||
#else
|
||||
uniform sampler2D sDiffuse;
|
||||
|
27
src/format.h
27
src/format.h
@@ -3,7 +3,7 @@
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#define MAX_RESERVED_ENTITIES 64
|
||||
#define MAX_RESERVED_ENTITIES 128
|
||||
#define MAX_SECRETS_COUNT 16
|
||||
#define MAX_TRIGGER_COMMANDS 32
|
||||
#define MAX_MESHES 512
|
||||
@@ -12,6 +12,7 @@ namespace TR {
|
||||
|
||||
enum {
|
||||
FLOOR_BLOCK = -127,
|
||||
NO_ROOM = 0xFF,
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -256,6 +257,18 @@ namespace TR {
|
||||
uint16 roomIndex;
|
||||
Vertex normal;
|
||||
Vertex vertices[4];
|
||||
|
||||
vec3 getCenter() const {
|
||||
return vec3(float( (int(vertices[0].x) + int(vertices[1].x) + int(vertices[2].x) + int(vertices[3].x)) / 4 ),
|
||||
float( (int(vertices[0].y) + int(vertices[1].y) + int(vertices[2].y) + int(vertices[3].y)) / 4 ),
|
||||
float( (int(vertices[0].z) + int(vertices[1].z) + int(vertices[2].z) + int(vertices[3].z)) / 4 ));
|
||||
}
|
||||
|
||||
vec3 getSize() const {
|
||||
return vec3(float( abs(int(vertices[0].x) - int(vertices[2].x)) / 2 ),
|
||||
float( abs(int(vertices[0].y) - int(vertices[2].y)) / 2 ),
|
||||
float( abs(int(vertices[0].z) - int(vertices[2].z)) / 2 ));
|
||||
}
|
||||
} *portals;
|
||||
|
||||
struct Sector {
|
||||
@@ -461,8 +474,8 @@ namespace TR {
|
||||
|
||||
MUZZLE_FLASH = 166,
|
||||
|
||||
VIEW_TARGET = 169,
|
||||
SOURCE_WATER = 170,
|
||||
VIEW_TARGET = 169, // invisible
|
||||
WATERFALL = 170, // invisible (water splash generator)
|
||||
|
||||
GLYPH = 190, // sprite
|
||||
|
||||
@@ -897,14 +910,14 @@ namespace TR {
|
||||
stream.read(d.vertices, stream.read(d.vCount));
|
||||
|
||||
if (version == VER_TR1_PSX)
|
||||
for (int i = 0; i < d.vCount; i++) // convert vertex luminance from PSX to PC format
|
||||
d.vertices[i].lighting = 0x1FFF - (d.vertices[i].lighting << 5);
|
||||
for (int j = 0; j < d.vCount; j++) // convert vertex luminance from PSX to PC format
|
||||
d.vertices[j].lighting = 0x1FFF - (d.vertices[j].lighting << 5);
|
||||
|
||||
stream.read(d.rectangles, stream.read(d.rCount));
|
||||
|
||||
if (version == VER_TR1_PSX)
|
||||
for (int i = 0; i < d.rCount; i++) // swap indices (quad strip -> quad list)
|
||||
swap(d.rectangles[i].vertices[2], d.rectangles[i].vertices[3]);
|
||||
for (int j = 0; j < d.rCount; j++) // swap indices (quad strip -> quad list)
|
||||
swap(d.rectangles[j].vertices[2], d.rectangles[j].vertices[3]);
|
||||
|
||||
stream.read(d.triangles, stream.read(d.tCount));
|
||||
stream.read(d.sprites, stream.read(d.sCount));
|
||||
|
12
src/lara.h
12
src/lara.h
@@ -229,28 +229,28 @@ struct Lara : Character {
|
||||
arms[i].rot = quat(0, 0, 0, 1);
|
||||
arms[i].rotAbs = quat(0, 0, 0, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
pos = vec3(40448, 3584, 60928);
|
||||
angle = vec3(0.0f, PI * 0.5f, 0.0f);
|
||||
getEntity().room = 14;
|
||||
stand = STAND_ONWATER;
|
||||
animation.setAnim(ANIM_TO_ONWATER);
|
||||
updateEntity();
|
||||
|
||||
*/
|
||||
#ifdef _DEBUG
|
||||
/*
|
||||
// gym
|
||||
pos = vec3(43182, 2473, 51556);
|
||||
angle = vec3(0.0f, PI * 0.5f, 0.0f);
|
||||
getEntity().room = 12;
|
||||
*/
|
||||
|
||||
// gym (pool)
|
||||
pos = vec3(40448, 3584, 60928);
|
||||
angle = vec3(0.0f, PI * 0.5f, 0.0f);
|
||||
getEntity().room = 14;
|
||||
stand = STAND_ONWATER;
|
||||
animation.setAnim(ANIM_TO_ONWATER);
|
||||
/*
|
||||
|
||||
// level 2 (pool)
|
||||
pos = vec3(70067, -256, 29104);
|
||||
angle = vec3(0.0f, -0.68f, 0.0f);
|
||||
@@ -936,7 +936,7 @@ struct Lara : Character {
|
||||
|
||||
int h = int(pos.y - infoDst.floor);
|
||||
|
||||
if (h > 0 && h <= 256 && (state == STATE_SURF_TREAD || animation.setState(STATE_SURF_TREAD)) && animation.setState(STATE_STOP)) { // possibility check
|
||||
if (h >= 0 && h <= 356 && (state == STATE_SURF_TREAD || animation.setState(STATE_SURF_TREAD)) && animation.setState(STATE_STOP)) { // possibility check
|
||||
alignToWall(-96.0f);
|
||||
pos.y = infoDst.floor;
|
||||
//pos = dst; // set new position
|
||||
@@ -1394,7 +1394,7 @@ struct Lara : Character {
|
||||
return STATE_PICK_UP;
|
||||
|
||||
if (state == STATE_FORWARD_JUMP || state == STATE_UP_JUMP || state == STATE_BACK_JUMP || state == STATE_LEFT_JUMP || state == STATE_RIGHT_JUMP || state == STATE_FALL || state == STATE_REACH) {
|
||||
Sprite::add(level, TR::Entity::Type::WATER_SPLASH, getRoomIndex(), (int)pos.x, (int)pos.y, (int)pos.z);
|
||||
Sprite::add(level, TR::Entity::WATER_SPLASH, getRoomIndex(), (int)pos.x, (int)pos.y, (int)pos.z);
|
||||
return animation.setAnim(ANIM_WATER_FALL); // TODO: wronng animation
|
||||
}
|
||||
|
||||
|
589
src/level.h
589
src/level.h
@@ -42,13 +42,6 @@ struct Level {
|
||||
Camera *camera;
|
||||
Texture *shadow;
|
||||
|
||||
Texture *water[2];
|
||||
|
||||
Texture *waterRefract;
|
||||
Texture *waterReflect;
|
||||
Texture *waterCaustics;
|
||||
float waterTimer;
|
||||
|
||||
float time;
|
||||
float clipHeight;
|
||||
float clipSign;
|
||||
@@ -186,6 +179,348 @@ struct Level {
|
||||
}
|
||||
} *ambientCache;
|
||||
|
||||
struct WaterCache {
|
||||
#define MAX_SURFACES 5
|
||||
#define MAX_INVISIBLE_TIME 5.0f
|
||||
#define SIMULATE_TIMESTEP (1.0f / 40.0f)
|
||||
#define DETAIL (64.0f / 1024.0f)
|
||||
#define MAX_DROPS 32
|
||||
|
||||
Level *level;
|
||||
Texture *refract;
|
||||
Texture *reflect;
|
||||
|
||||
struct Item {
|
||||
int from, to;
|
||||
float timer;
|
||||
bool visible;
|
||||
bool blank;
|
||||
vec3 pos, size;
|
||||
Texture *data[2];
|
||||
Texture *caustics;
|
||||
|
||||
Item() {
|
||||
data[0] = data[1] = caustics = NULL;
|
||||
}
|
||||
|
||||
Item(int from, int to, const vec3 &pos, const vec3 &size) : from(from), to(to), timer(SIMULATE_TIMESTEP), visible(true), blank(true), pos(pos), size(size) {
|
||||
data[0] = data[1] = caustics = NULL;
|
||||
}
|
||||
|
||||
void init() {
|
||||
data[0] = new Texture(nextPow2(int(size.x * DETAIL * 2.0f) - 1), nextPow2(int(size.z * DETAIL * 2.0f) - 1), Texture::RGBA_HALF, false);
|
||||
data[1] = new Texture(data[0]->width, data[0]->height, Texture::RGBA_HALF, false);
|
||||
caustics = new Texture(256, 256, Texture::RGBA, false);
|
||||
blank = false;
|
||||
}
|
||||
|
||||
void free() {
|
||||
delete data[0];
|
||||
delete data[1];
|
||||
delete caustics;
|
||||
data[0] = data[1] = caustics = NULL;
|
||||
}
|
||||
|
||||
} items[MAX_SURFACES];
|
||||
int count, visible;
|
||||
bool checkVisibility;
|
||||
|
||||
int dropCount;
|
||||
struct Drop {
|
||||
vec3 pos;
|
||||
float radius;
|
||||
float strength;
|
||||
Drop() {}
|
||||
Drop(const vec3 &pos, float radius, float strength) : pos(pos), radius(radius), strength(strength) {}
|
||||
} drops[MAX_DROPS];
|
||||
|
||||
WaterCache(Level *level) : level(level), refract(NULL), count(0), checkVisibility(false), dropCount(0) {
|
||||
reflect = new Texture(512, 512, Texture::RGBA, false);
|
||||
}
|
||||
|
||||
~WaterCache() {
|
||||
delete refract;
|
||||
delete reflect;
|
||||
for (int i = 0; i < count; i++)
|
||||
items[i].free();
|
||||
}
|
||||
|
||||
void update() {
|
||||
int i = 0;
|
||||
while (i < count) {
|
||||
Item &item = items[i];
|
||||
if (item.timer > MAX_INVISIBLE_TIME) {
|
||||
items[i].free();
|
||||
items[i] = items[--count];
|
||||
continue;
|
||||
}
|
||||
item.timer += Core::deltaTime;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void reset() {
|
||||
for (int i = 0; i < count; i++)
|
||||
items[i].visible = false;
|
||||
visible = 0;
|
||||
}
|
||||
|
||||
void setVisible(int roomIndex, int nextRoom) {
|
||||
if (!checkVisibility) return;
|
||||
|
||||
int from, to; // from surface room to underwater room
|
||||
if (level->level.rooms[roomIndex].flags.water) {
|
||||
from = nextRoom;
|
||||
to = roomIndex;
|
||||
} else {
|
||||
from = roomIndex;
|
||||
to = nextRoom;
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
Item &item = items[i];
|
||||
if (item.from == from && item.to == to) {
|
||||
if (!item.visible) {
|
||||
visible++;
|
||||
item.visible = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (count == MAX_SURFACES) return;
|
||||
|
||||
|
||||
TR::Room &r = level->level.rooms[to]; // underwater room
|
||||
|
||||
int minX = r.xSectors, minZ = r.zSectors, maxX = 0, maxZ = 0;
|
||||
|
||||
for (int z = 0; z < r.zSectors; z++)
|
||||
for (int x = 0; x < r.xSectors; x++) {
|
||||
int above = r.sectors[x * r.zSectors + z].roomAbove;
|
||||
if (above != TR::NO_ROOM && !level->level.rooms[above].flags.water) {
|
||||
minX = min(minX, x);
|
||||
minZ = min(minZ, z);
|
||||
maxX = max(maxX, x);
|
||||
maxZ = max(maxZ, z);
|
||||
}
|
||||
}
|
||||
maxX++;
|
||||
maxZ++;
|
||||
|
||||
vec3 size(float((maxX - minX) * 512), 0.0f, float((maxZ - minZ) * 512)); // half size
|
||||
vec3 pos(r.info.x + minX * 1024 + size.x, r.info.yTop, r.info.z + minZ * 1024 + size.z);
|
||||
|
||||
items[count++] = Item(from, to, pos, size);
|
||||
visible++;
|
||||
}
|
||||
|
||||
void bindCaustics(int roomIndex) {
|
||||
Item *item = NULL;
|
||||
for (int i = 0; i < count; i++)
|
||||
if (items[i].to == roomIndex) {
|
||||
item = &items[i];
|
||||
break;
|
||||
}
|
||||
|
||||
if (!item || !item->caustics) {
|
||||
Core::blackTex->bind(sReflect);
|
||||
Core::active.shader->setParam(uRoomSize, vec4(0.0f));
|
||||
} else {
|
||||
item->caustics->bind(sReflect);
|
||||
Core::active.shader->setParam(uRoomSize, vec4(item->pos.x - item->size.x, item->pos.z - item->size.z, item->pos.x + item->size.x, item->pos.z + item->size.z));
|
||||
}
|
||||
}
|
||||
|
||||
void simulate(Item &item) {
|
||||
if (item.timer < SIMULATE_TIMESTEP) return;
|
||||
|
||||
Core::active.shader->setParam(uParam, vec4(1.0f / item.data[0]->width, 1.0f / item.data[0]->height, 0.0f, 0.0f));
|
||||
Core::active.shader->setParam(uType, Shader::WATER_STEP);
|
||||
|
||||
while (item.timer >= SIMULATE_TIMESTEP) {
|
||||
// water step
|
||||
item.data[0]->bind(sDiffuse);
|
||||
Core::setTarget(item.data[1]);
|
||||
level->mesh->renderQuad();
|
||||
swap(item.data[0], item.data[1]);
|
||||
item.timer -= SIMULATE_TIMESTEP;
|
||||
}
|
||||
|
||||
// calc caustics
|
||||
vec3 rPosScale[2] = { vec3(0.0f), vec3(1.0f / PLANE_DETAIL) };
|
||||
Core::active.shader->setParam(uPosScale, rPosScale[0], 2);
|
||||
item.data[0]->bind(sNormal);
|
||||
item.caustics->unbind(sReflect);
|
||||
Core::setTarget(item.caustics);
|
||||
Core::active.shader->setParam(uType, Shader::WATER_CAUSTICS);
|
||||
level->mesh->renderPlane();
|
||||
}
|
||||
|
||||
void addDrop(const vec3 &pos, float radius, float strength) {
|
||||
if (dropCount >= MAX_DROPS) return;
|
||||
drops[dropCount++] = Drop(pos, radius, strength);
|
||||
}
|
||||
|
||||
void drop(Item &item) {
|
||||
static vec3 lastPos = vec3(0.0);
|
||||
Lara *lara = level->lara;
|
||||
vec3 head = lara->animation.getJoints(lara->getMatrix(), 14).pos;
|
||||
bool flag = (head - lastPos).length() > 16.0f;
|
||||
bool fall = (lara->animation.index == Lara::ANIM_WATER_FALL || lara->animation.index == 152) && lara->animation.frameIndex == 0;
|
||||
bool flag2 = lara->animation.frameIndex == 20 || fall;
|
||||
flag &= lara->stand == Lara::STAND_ONWATER || fall;
|
||||
flag2 &= lara->stand == Lara::STAND_ONWATER || fall;
|
||||
|
||||
if (Input::down[ikU] || flag || flag2) {
|
||||
vec3 p(randf(), 0.0f, randf());
|
||||
if (flag || flag2) {
|
||||
p = head;
|
||||
lastPos = head;
|
||||
}
|
||||
float radius = (flag2 ? 1.0f : randf() + 0.2f);
|
||||
float strength = flag2 ? 0.01f : randf() * 0.03f;
|
||||
|
||||
if (fall) {
|
||||
radius = 1.5f;
|
||||
strength = 0.05f;
|
||||
}
|
||||
|
||||
addDrop(p, radius, strength);
|
||||
|
||||
Input::down[ikU] = false;
|
||||
}
|
||||
|
||||
if (!dropCount) return;
|
||||
|
||||
item.data[0]->bind(sDiffuse);
|
||||
Core::setTarget(item.data[1]);
|
||||
vec3 rPosScale[2] = { vec3(0.0f), vec3(1.0f) };
|
||||
Core::active.shader->setParam(uPosScale, rPosScale[0], 2);
|
||||
Core::active.shader->setParam(uType, Shader::WATER_DROP);
|
||||
|
||||
for (int i = 0; i < dropCount; i++) {
|
||||
Drop &drop = drops[i];
|
||||
|
||||
vec3 p;
|
||||
p.x = (drop.pos.x - item.pos.x) / (item.size.x * 2.0f) + 0.5;
|
||||
p.z = (drop.pos.z - item.pos.z) / (item.size.z * 2.0f) + 0.5;
|
||||
Core::active.shader->setParam(uParam, vec4(p.x, p.z, 128.0f / (item.size.x * 2.0f) * drop.radius, drop.strength));
|
||||
level->mesh->renderQuad();
|
||||
}
|
||||
dropCount = 0;
|
||||
|
||||
swap(item.data[0], item.data[1]);
|
||||
}
|
||||
|
||||
void render() {
|
||||
if (!visible) return;
|
||||
|
||||
// mask underwater geometry by zero alpha
|
||||
level->setPassShader(Core::passWater);
|
||||
level->atlas->bind(sNormal);
|
||||
level->atlas->bind(sReflect);
|
||||
|
||||
Core::active.shader->setParam(uType, Shader::WATER_MASK);
|
||||
Core::setBlending(bmNone);
|
||||
Core::setCulling(cfNone);
|
||||
Core::setDepthWrite(false);
|
||||
Core::setColorWrite(false, false, false, true);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
Item &item = items[i];
|
||||
if (!item.visible) continue;
|
||||
|
||||
Core::active.shader->setParam(uPosScale, item.pos, 2);
|
||||
|
||||
level->mesh->renderQuad();
|
||||
}
|
||||
|
||||
Core::setColorWrite(true, true, true, true);
|
||||
Core::setDepthWrite(true);
|
||||
Core::setCulling(cfFront);
|
||||
|
||||
// get refraction texture
|
||||
if (!refract || Core::width > refract->width || Core::height > refract->height) {
|
||||
delete refract;
|
||||
refract = new Texture(nextPow2(Core::width), nextPow2(Core::height), Texture::RGBA, false);
|
||||
}
|
||||
Core::copyTarget(refract, 0, 0, 0, 0, Core::width, Core::height); // copy framebuffer into refraction texture
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
Item &item = items[i];
|
||||
if (!item.visible) continue;
|
||||
|
||||
if (item.blank) {
|
||||
item.init();
|
||||
item.blank = false;
|
||||
}
|
||||
|
||||
// render mirror reflection
|
||||
Core::setTarget(reflect);
|
||||
vec3 p = item.pos;
|
||||
vec3 n = vec3(0, 1, 0);
|
||||
|
||||
vec4 reflectPlane = vec4(n.x, n.y, n.z, -n.dot(p));
|
||||
|
||||
bool underwater = level->level.rooms[level->camera->getRoomIndex()].flags.water;
|
||||
|
||||
//bool underwater = level->camera->pos.y > item.pos.y;
|
||||
|
||||
level->camera->reflectPlane = &reflectPlane;
|
||||
level->clipSign = underwater ? -1.0f : 1.0f;
|
||||
level->clipHeight = item.pos.y * level->clipSign;
|
||||
level->renderCompose(underwater ? item.from : item.to);
|
||||
level->clipHeight = 1000000.0f;
|
||||
level->clipSign = 1.0f;
|
||||
|
||||
level->camera->reflectPlane = NULL;
|
||||
level->camera->setup(true);
|
||||
|
||||
// simulate water
|
||||
Core::setBlending(bmNone);
|
||||
Core::setDepthTest(false);
|
||||
|
||||
level->setPassShader(Core::passWater);
|
||||
drop(item);
|
||||
simulate(item);
|
||||
Core::setTarget(NULL);
|
||||
|
||||
Core::setBlending(bmAlpha);
|
||||
Core::setDepthTest(true);
|
||||
|
||||
// render water plane
|
||||
int dx, dz;
|
||||
TR::Room::Sector &s = level->level.getSector(item.from, int(item.pos.x), int(item.pos.z), dx, dz);
|
||||
if (s.roomAbove != TR::NO_ROOM && level->level.rooms[s.roomAbove].lightsCount) {
|
||||
TR::Room::Light &light = level->level.rooms[s.roomAbove].lights[0];
|
||||
Core::lightPos[0] = vec3(float(light.x), float(light.y), float(light.z));
|
||||
float lum = intensityf(light.intensity);
|
||||
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(uViewProj, Core::mViewProj);
|
||||
Core::active.shader->setParam(uPosScale, item.pos, 2);
|
||||
Core::active.shader->setParam(uViewPos, Core::viewPos);
|
||||
Core::active.shader->setParam(uLightPos, Core::lightPos[0], 1);
|
||||
Core::active.shader->setParam(uLightColor, Core::lightColor[0], 1);
|
||||
Core::active.shader->setParam(uParam, vec4(float(Core::width) / refract->width, float(Core::height) / refract->height, 0.075f, 0.02f));
|
||||
|
||||
refract->bind(sDiffuse);
|
||||
reflect->bind(sReflect);
|
||||
item.data[0]->bind(sNormal);
|
||||
Core::setCulling(cfNone);
|
||||
level->mesh->renderQuad();
|
||||
Core::setCulling(cfFront);
|
||||
}
|
||||
}
|
||||
|
||||
#undef MAX_WATER_SURFACES
|
||||
#undef MAX_WATER_INVISIBLE_TIME
|
||||
#undef WATER_SIMULATE_TIMESTEP
|
||||
#undef DETAIL
|
||||
} *waterCache;
|
||||
|
||||
/*
|
||||
struct LightCache {
|
||||
|
||||
@@ -319,6 +654,9 @@ struct Level {
|
||||
case TR::Entity::HOLE_KEY :
|
||||
entity.controller = new Trigger(&level, i, false);
|
||||
break;
|
||||
case TR::Entity::WATERFALL :
|
||||
entity.controller = new Waterfall(&level, i);
|
||||
break;
|
||||
default :
|
||||
if (entity.modelIndex > 0)
|
||||
entity.controller = new Controller(&level, i);
|
||||
@@ -332,9 +670,10 @@ struct Level {
|
||||
|
||||
level.cameraController = camera;
|
||||
|
||||
initReflections();
|
||||
|
||||
ambientCache = new AmbientCache(this);
|
||||
waterCache = new WaterCache(this);
|
||||
|
||||
initReflections();
|
||||
}
|
||||
|
||||
~Level() {
|
||||
@@ -349,13 +688,7 @@ struct Level {
|
||||
|
||||
delete shadow;
|
||||
delete ambientCache;
|
||||
|
||||
delete water[0];
|
||||
delete water[1];
|
||||
|
||||
delete waterRefract;
|
||||
delete waterReflect;
|
||||
delete waterCaustics;
|
||||
delete waterCache;
|
||||
|
||||
delete atlas;
|
||||
delete cube;
|
||||
@@ -364,24 +697,9 @@ 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 = 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;
|
||||
return;
|
||||
@@ -423,12 +741,6 @@ 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];
|
||||
|
||||
@@ -567,25 +879,24 @@ struct Level {
|
||||
}
|
||||
#endif
|
||||
|
||||
void setRoomParams(const TR::Room &room, float intensity) {
|
||||
void setRoomParams(int roomIndex, float intensity) {
|
||||
if (Core::pass == Core::passShadow)
|
||||
return;
|
||||
|
||||
TR::Room &room = level.rooms[roomIndex];
|
||||
|
||||
if (room.flags.water) {
|
||||
Core::color = vec4(0.6f, 0.9f, 0.9f, intensity);
|
||||
Core::active.shader->setParam(uCaustics, 1);
|
||||
waterCache->bindCaustics(roomIndex);
|
||||
} else {
|
||||
Core::color = vec4(1.0f, 1.0f, 1.0f, intensity);
|
||||
Core::active.shader->setParam(uCaustics, 0);
|
||||
}
|
||||
Core::active.shader->setParam(uColor, Core::color);
|
||||
|
||||
waterCaustics->bind(sReflect);
|
||||
vec4 roomSize = vec4(room.info.x, room.info.z, room.info.x + room.xSectors * 1024, room.info.z + room.zSectors * 1024);
|
||||
Core::active.shader->setParam(uRoomSize, roomSize);
|
||||
}
|
||||
|
||||
void renderRoom(int roomIndex, int from = -1) {
|
||||
void renderRoom(int roomIndex, int from = TR::NO_ROOM) {
|
||||
ASSERT(roomIndex >= 0 && roomIndex < level.roomsCount);
|
||||
PROFILE_MARKER("ROOM");
|
||||
|
||||
@@ -597,7 +908,7 @@ struct Level {
|
||||
room.flags.rendered = true;
|
||||
|
||||
if (Core::pass != Core::passShadow) {
|
||||
setRoomParams(room, intensityf(room.ambient));
|
||||
setRoomParams(roomIndex, intensityf(room.ambient));
|
||||
|
||||
Basis qTemp = Core::basis;
|
||||
Core::basis.translate(offset);
|
||||
@@ -643,9 +954,12 @@ struct Level {
|
||||
};
|
||||
|
||||
frustum = *camFrustum;
|
||||
if (frustum.clipByPortal(v, 4, p.normal))
|
||||
if (frustum.clipByPortal(v, 4, p.normal)) {
|
||||
if ((level.rooms[roomIndex].flags.water ^ level.rooms[p.roomIndex].flags.water) && v[0].y == v[1].y && v[0].y == v[2].y)
|
||||
waterCache->setVisible(roomIndex, p.roomIndex);
|
||||
renderRoom(p.roomIndex, roomIndex);
|
||||
}
|
||||
}
|
||||
camera->frustum = camFrustum; // pop camera frustum
|
||||
}
|
||||
|
||||
@@ -708,7 +1022,7 @@ struct Level {
|
||||
return;
|
||||
|
||||
int16 lum = entity.intensity == -1 ? room.ambient : entity.intensity;
|
||||
setRoomParams(room, isModel ? controller->specular : intensityf(lum));
|
||||
setRoomParams(entity.room, isModel ? controller->specular : intensityf(lum));
|
||||
|
||||
if (isModel) { // model
|
||||
vec3 pos = controller->getPos();
|
||||
@@ -735,16 +1049,24 @@ 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) {
|
||||
Controller *controller = (Controller*)level.entities[i].controller;
|
||||
if (controller)
|
||||
for (int i = 0; i < level.entitiesCount; i++) {
|
||||
TR::Entity &e = level.entities[i];
|
||||
if (e.type != TR::Entity::NONE) {
|
||||
Controller *controller = (Controller*)e.controller;
|
||||
if (controller) {
|
||||
controller->update();
|
||||
|
||||
if (e.type == TR::Entity::WATERFALL && ((Waterfall*)controller)->drop) { // add water drops for waterfalls
|
||||
Waterfall *w = (Waterfall*)controller;
|
||||
waterCache->addDrop(w->dropPos, w->dropRadius, w->dropStrength);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
camera->update();
|
||||
waterCache->update();
|
||||
}
|
||||
|
||||
void setup() {
|
||||
@@ -906,165 +1228,22 @@ struct Level {
|
||||
renderScene(roomIndex);
|
||||
}
|
||||
|
||||
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 waterDrop() {
|
||||
static vec3 lastPos = vec3(0.0);
|
||||
vec3 head = lara->animation.getJoints(lara->getMatrix(), 14).pos;
|
||||
bool flag = (head - lastPos).length() > 16.0f;
|
||||
bool fall = (lara->animation.index == Lara::ANIM_WATER_FALL || lara->animation.index == 152) && lara->animation.frameIndex == 0;
|
||||
bool flag2 = lara->animation.frameIndex == 20 || fall;
|
||||
flag &= lara->stand == Lara::STAND_ONWATER || fall;
|
||||
flag2 &= lara->stand == Lara::STAND_ONWATER || fall;
|
||||
|
||||
if (Input::down[ikU] || flag || flag2) {
|
||||
vec2 p(randf(), randf());
|
||||
if (flag || flag2) {
|
||||
vec3 c(40448, 0.0, 60928);
|
||||
p.x = (head.x - c.x) / 5120.0f + 0.5;
|
||||
p.y = (head.z - c.z) / 5120.0f + 0.5;
|
||||
lastPos = head;
|
||||
}
|
||||
float radius = (flag2 ? 1.0f : randf() + 0.2f);
|
||||
float strength = flag2 ? 0.01f : randf() * 0.03f;
|
||||
|
||||
if (fall) {
|
||||
radius = 1.5f;
|
||||
strength = 0.05f;
|
||||
}
|
||||
|
||||
water[0]->bind(sDiffuse);
|
||||
Core::setTarget(water[1]);
|
||||
Core::active.shader->setParam(uType, Shader::WATER_DROP);
|
||||
Core::active.shader->setParam(uParam, vec4(p.x, p.y, 128.0f / 5120.0f * radius, strength));
|
||||
mesh->renderQuad();
|
||||
swap(water[0], water[1]);
|
||||
Input::down[ikU] = false;
|
||||
}
|
||||
}
|
||||
|
||||
void renderWater() {
|
||||
bool underwater = level.rooms[camera->getRoomIndex()].flags.water;
|
||||
|
||||
// mask underwater geometry by zero alpha
|
||||
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::active.shader->setParam(uScale, 1.0f);
|
||||
Core::setBlending(bmNone);
|
||||
Core::setCulling(cfNone);
|
||||
glDepthMask(false);
|
||||
glColorMask(false, false, false, true);
|
||||
mesh->renderQuad();
|
||||
glColorMask(true, true, true, true);
|
||||
glDepthMask(true);
|
||||
|
||||
// get refraction texture
|
||||
checkRefractTexture();
|
||||
waterRefract->bind(sDiffuse);
|
||||
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, Core::width, Core::height);
|
||||
|
||||
// render mirror reflection
|
||||
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;
|
||||
|
||||
|
||||
// simulate water
|
||||
glDisable(GL_BLEND);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
setPassShader(Core::passWater);
|
||||
waterDrop();
|
||||
waterSimulate();
|
||||
Core::setTarget(NULL);
|
||||
|
||||
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) {
|
||||
TR::Room::Light &light = level.rooms[s.roomAbove].lights[0];
|
||||
Core::lightPos[0] = vec3(float(light.x), float(light.y), float(light.z));
|
||||
float lum = intensityf(light.intensity);
|
||||
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(uViewProj, Core::mViewProj);
|
||||
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);
|
||||
water[0]->bind(sNormal);
|
||||
Core::setCulling(cfNone);
|
||||
mesh->renderQuad();
|
||||
Core::setCulling(cfFront);
|
||||
}
|
||||
|
||||
void render() {
|
||||
clipHeight = 1000000.0f;
|
||||
clipSign = 1.0f;
|
||||
Core::resetStates();
|
||||
|
||||
ambientCache->precessQueue();
|
||||
waterCache->reset();
|
||||
|
||||
renderShadows(lara->getRoomIndex());
|
||||
Core::setViewport(0, 0, Core::width, Core::height);
|
||||
renderCompose(camera->getRoomIndex());
|
||||
|
||||
renderWater();
|
||||
waterCache->checkVisibility = true;
|
||||
renderCompose(camera->getRoomIndex());
|
||||
waterCache->checkVisibility = false;
|
||||
|
||||
waterCache->render();
|
||||
|
||||
// Core::mViewInv = camera->mViewInv;
|
||||
// Core::mView = Core::mViewInv.inverse();
|
||||
@@ -1105,10 +1284,11 @@ struct Level {
|
||||
glLoadIdentity();
|
||||
glOrtho(0, Core::width, 0, Core::height, 0, 1);
|
||||
|
||||
waterCaustics->bind(sDiffuse);
|
||||
waterCache->reflect->bind(sDiffuse);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
glColor3f(1, 1, 1);
|
||||
glBegin(GL_QUADS);
|
||||
@@ -1121,6 +1301,7 @@ struct Level {
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glEnable(GL_CULL_FACE);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_BLEND);
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPopMatrix();
|
||||
@@ -1131,7 +1312,9 @@ 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);
|
||||
// Core::setDepthTest(false);
|
||||
// Debug::Level::portals(level);
|
||||
// Core::setDepthTest(true);
|
||||
// Debug::Level::meshes(level);
|
||||
// Debug::Level::entities(level);
|
||||
/*
|
||||
|
60
src/mesh.h
60
src/mesh.h
@@ -184,7 +184,6 @@ 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++) {
|
||||
@@ -503,57 +502,64 @@ struct MeshBuilder {
|
||||
return false;
|
||||
}
|
||||
|
||||
void roomRemoveWaterSurfaces(TR::Room room, int &iCount, int &vCount) {
|
||||
void roomRemoveWaterSurfaces(TR::Room &room, int &iCount, int &vCount) {
|
||||
if (!roomCheckWaterPortal(room)) return;
|
||||
|
||||
// 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];
|
||||
if (f.vertices[0] == 0xFFFF) continue;
|
||||
|
||||
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
|
||||
if (a.y != b.y || a.y != c.y || a.y != d.y) // skip non-horizontal or non-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;
|
||||
int yt = abs(a.y - room.info.yTop);
|
||||
int yb = abs(room.info.yBottom - a.y);
|
||||
|
||||
if (c.x < pMin.x || c.x > pMax.x || c.z < pMin.z || c.z > pMax.z) // check for portal borders
|
||||
continue;
|
||||
if (yt > 0 && yb > 0) continue;
|
||||
|
||||
f.vertices[0] = 0xFFFF; // mark it as unused
|
||||
iCount -= 3 * 2;
|
||||
int sx = (int(a.x) + int(b.x) + int(c.x) + int(d.x)) / 4 / 1024;
|
||||
int sz = (int(a.z) + int(b.z) + int(c.z) + int(d.z)) / 4 / 1024;
|
||||
|
||||
TR::Room::Sector &s = room.sectors[sx * room.zSectors + sz];
|
||||
|
||||
if ((yt == 0 && s.roomAbove != TR::NO_ROOM && (level->rooms[s.roomAbove].flags.water ^ room.flags.water)) ||
|
||||
(yb == 0 && s.roomBelow != TR::NO_ROOM && (level->rooms[s.roomBelow].flags.water ^ room.flags.water))) {
|
||||
f.vertices[0] = 0xFFFF; // mark as unused
|
||||
iCount -= 6;
|
||||
vCount -= 4;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < room.data.tCount; i++) {
|
||||
TR::Triangle &f = room.data.triangles[i];
|
||||
if (f.vertices[0] == 0xFFFF) continue;
|
||||
|
||||
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
|
||||
if (a.y != b.y || a.y != c.y) // skip non-horizontal or non-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;
|
||||
int yt = abs(a.y - room.info.yTop);
|
||||
int yb = abs(room.info.yBottom - a.y);
|
||||
|
||||
if (c.x < pMin.x || c.x > pMax.x || c.z < pMin.z || c.z > pMax.z) // check for portal borders
|
||||
continue;
|
||||
if (yt > 1 && yb > 1) continue;
|
||||
|
||||
f.vertices[0] = 0xFFFF; // mark it as unused
|
||||
int sx = (int(a.x) + int(b.x) + int(c.x)) / 3 / 1024;
|
||||
int sz = (int(a.z) + int(b.z) + int(c.z)) / 3 / 1024;
|
||||
|
||||
TR::Room::Sector &s = room.sectors[sx * room.zSectors + sz];
|
||||
|
||||
if ((yt <= 1 && s.roomAbove != TR::NO_ROOM && (level->rooms[s.roomAbove].flags.water ^ room.flags.water)) ||
|
||||
(yb <= 1 && s.roomBelow != TR::NO_ROOM && (level->rooms[s.roomBelow].flags.water ^ room.flags.water))) {
|
||||
f.vertices[0] = 0xFFFF; // mark as unused
|
||||
iCount -= 3;
|
||||
vCount -= 3;
|
||||
}
|
||||
|
@@ -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, uScale, uMAX };
|
||||
enum UniformType { uType, uCaustics, uParam, uViewProj, uViewInv, uBasis, uLightProj, uColor, uAmbient, uViewPos, uLightsCount, uLightPos, uLightColor, uAnimTexRanges, uAnimTexOffsets, uRoomSize, uPosScale, 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", "uScale" };
|
||||
const char *UniformName[uMAX] = { "uType", "uCaustics", "uParam", "uViewProj", "uViewInv", "uBasis", "uLightProj", "uColor", "uAmbient", "uViewPos", "uLightsCount", "uLightPos", "uLightColor", "uAnimTexRanges", "uAnimTexOffsets", "uRoomSize", "uPosScale" };
|
||||
|
||||
struct Shader {
|
||||
GLuint ID;
|
||||
|
@@ -309,4 +309,39 @@ struct Crystal : Controller {
|
||||
}
|
||||
};
|
||||
|
||||
struct Waterfall : Trigger {
|
||||
#define SPLASH_TIMESTEP (1.0f / 30.0f)
|
||||
|
||||
float timer;
|
||||
bool drop;
|
||||
float dropRadius;
|
||||
float dropStrength;
|
||||
vec3 dropPos;
|
||||
|
||||
Waterfall(TR::Level *level, int entity) : Trigger(level, entity, true), timer(0.0f) {}
|
||||
|
||||
virtual void update() {
|
||||
drop = false;
|
||||
Trigger::update();
|
||||
if (!getEntity().flags.active) return;
|
||||
|
||||
vec3 delta = (((Controller*)level->cameraController)->pos - pos) * (1.0f / 1024.0f);
|
||||
if (delta.length2() > 100.0f)
|
||||
return;
|
||||
|
||||
timer -= Core::deltaTime;
|
||||
if (timer > 0.0f) return;
|
||||
timer += SPLASH_TIMESTEP * (1.0f + randf() * 0.25f);
|
||||
|
||||
drop = true;
|
||||
dropPos = pos + vec3(randf() * 1024.0f - 512.0f, 0.0f, randf() * 1024.0f - 512.0f);
|
||||
dropRadius = randf() + 0.5f;
|
||||
dropStrength = randf() * 0.25f;
|
||||
|
||||
Sprite::add(level, TR::Entity::WATER_SPLASH, getRoomIndex(), (int)dropPos.x, (int)dropPos.y, (int)dropPos.z);
|
||||
}
|
||||
|
||||
#undef SPLASH_TIMESTEP
|
||||
};
|
||||
|
||||
#endif
|
@@ -22,6 +22,7 @@ varying vec3 vRefPos2;
|
||||
uniform int uType;
|
||||
uniform vec3 uViewPos;
|
||||
uniform mat4 uViewProj;
|
||||
uniform vec3 uPosScale[2];
|
||||
uniform float uScale;
|
||||
|
||||
uniform sampler2D sNormal;
|
||||
@@ -33,12 +34,11 @@ uniform sampler2D sNormal;
|
||||
attribute vec4 aCoord;
|
||||
|
||||
void main() {
|
||||
vec4 rCoord = aCoord * uScale;
|
||||
vTexCoord = aCoord.xy * 0.5 + 0.5;
|
||||
|
||||
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);
|
||||
vCoord = vec3(aCoord.x, 0.0, aCoord.y) * uPosScale[1] + uPosScale[0];
|
||||
vec4 cp = uViewProj * vec4(vCoord, 1.0);
|
||||
|
||||
vProjCoord = cp;
|
||||
@@ -46,26 +46,27 @@ uniform sampler2D sNormal;
|
||||
} else {
|
||||
vProjCoord = vec4(0.0);
|
||||
if (uType == WATER_CAUSTICS) {
|
||||
vec4 info = texture2D(sNormal, rCoord.xy * 0.5 + 0.5);
|
||||
vec3 rCoord = vec3(aCoord.x, 0.0, aCoord.y) * uPosScale[1];
|
||||
|
||||
vec4 info = texture2D(sNormal, rCoord.xz * 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;
|
||||
|
||||
vRefPos1 = rCoord + vec3(0.0, 1.0, 0.0);
|
||||
vRefPos2 = rCoord + 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);
|
||||
vCoord = vec3(aCoord.xy, 0.0);
|
||||
|
||||
gl_Position = vec4(rCoord.xyz, 1.0);
|
||||
gl_Position = vec4(aCoord.xyz, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
vTexCoord = rCoord.xy * 0.5 + 0.5;
|
||||
}
|
||||
#else
|
||||
uniform sampler2D sDiffuse;
|
||||
@@ -153,12 +154,12 @@ uniform sampler2D sNormal;
|
||||
vec3 rv = reflect(-viewVec, normal);
|
||||
vec3 lv = normalize(uLightPos - vCoord.xyz);
|
||||
|
||||
float spec = pow(max(0.0, dot(rv, -lv)), 64.0) * 0.5;
|
||||
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);
|
||||
vec4 refl = texture2D(sReflect, vec2(tc.x, 1.0 - tc.y) + dudv * uParam.w);
|
||||
|
||||
float fresnel = calcFresnel(dot(normal, viewVec), 0.1, 2.0);
|
||||
return mix(refr, refl, fresnel) + spec;
|
||||
|
Reference in New Issue
Block a user