mirror of
https://github.com/XProger/OpenLara.git
synced 2025-02-24 15:32:30 +01:00
№23 global IGame interface, variable size of water texture
This commit is contained in:
parent
6ee2aa68cf
commit
38934fb41a
@ -23,7 +23,7 @@ struct Camera : Controller {
|
||||
|
||||
vec4 *reflectPlane;
|
||||
|
||||
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) {
|
||||
Camera(IGame *game, Lara *owner) : Controller(game, owner ? owner->entity : 0), owner(owner), frustum(new Frustum()), timer(0.0f), actTargetEntity(-1), actCamera(-1), reflectPlane(NULL) {
|
||||
fov = 65.0f;
|
||||
znear = 16;
|
||||
zfar = 40.0f * 1024.0f;
|
||||
|
@ -29,7 +29,7 @@ struct Character : Controller {
|
||||
vec3 velocity;
|
||||
float angleExt;
|
||||
|
||||
Character(TR::Level *level, int entity, int health) : Controller(level, entity), target(-1), health(health), tilt(0.0f), stand(STAND_GROUND), lastInput(0), velocity(0.0f) {
|
||||
Character(IGame *game, int entity, int health) : Controller(game, entity), target(-1), health(health), tilt(0.0f), stand(STAND_GROUND), lastInput(0), velocity(0.0f) {
|
||||
animation.initOverrides();
|
||||
rotHead = rotChest = quat(0, 0, 0, 1);
|
||||
}
|
||||
|
@ -12,7 +12,13 @@
|
||||
|
||||
#define MAX_LAYERS 4
|
||||
|
||||
struct IGame {
|
||||
virtual TR::Level* getLevel() { return NULL; }
|
||||
virtual void waterDrop(const vec3 &pos, float radius, float strength) {}
|
||||
};
|
||||
|
||||
struct Controller {
|
||||
IGame *game;
|
||||
TR::Level *level;
|
||||
int entity;
|
||||
|
||||
@ -44,7 +50,7 @@ struct Controller {
|
||||
ActionCommand(int emitter, TR::Action action, int value, float timer, ActionCommand *next = NULL) : emitter(emitter), action(action), value(value), timer(timer), next(next) {}
|
||||
} *actionCommand;
|
||||
|
||||
Controller(TR::Level *level, int entity) : level(level), entity(entity), animation(level, getModel()), state(animation.state), layers(NULL), actionCommand(NULL) {
|
||||
Controller(IGame *game, int entity) : game(game), level(game->getLevel()), entity(entity), animation(level, getModel()), state(animation.state), layers(NULL), actionCommand(NULL) {
|
||||
TR::Entity &e = getEntity();
|
||||
pos = vec3((float)e.x, (float)e.y, (float)e.z);
|
||||
angle = vec3(0.0f, e.rotation, 0.0f);
|
||||
|
10
src/enemy.h
10
src/enemy.h
@ -6,7 +6,7 @@
|
||||
struct Enemy : Character {
|
||||
bool bitten;
|
||||
|
||||
Enemy(TR::Level *level, int entity, int health) : Character(level, entity, health), bitten(false) {}
|
||||
Enemy(IGame *game, int entity, int health) : Character(game, entity, health), bitten(false) {}
|
||||
|
||||
virtual bool activate(ActionCommand *cmd) {
|
||||
#ifdef LEVEL_EDITOR
|
||||
@ -134,7 +134,7 @@ struct Enemy : Character {
|
||||
ASSERT(target > -1);
|
||||
Character *c = (Character*)level->entities[target].controller;
|
||||
c->hit(damage, this);
|
||||
Sprite::add(level, TR::Entity::BLOOD, c->getRoomIndex(), (int)pos.x, (int)pos.y, (int)pos.z, Sprite::FRAME_ANIMATED);
|
||||
Sprite::add(game, TR::Entity::BLOOD, c->getRoomIndex(), (int)pos.x, (int)pos.y, (int)pos.z, Sprite::FRAME_ANIMATED);
|
||||
}
|
||||
};
|
||||
|
||||
@ -171,7 +171,7 @@ struct Wolf : Enemy {
|
||||
JOINT_HEAD = 3
|
||||
};
|
||||
|
||||
Wolf(TR::Level *level, int entity) : Enemy(level, entity, 6) {}
|
||||
Wolf(IGame *game, int entity) : Enemy(game, entity, 6) {}
|
||||
|
||||
virtual int getStateGround() {
|
||||
TR::Entity &e = getEntity();
|
||||
@ -268,7 +268,7 @@ struct Bear : Enemy {
|
||||
JOINT_HEAD = 3
|
||||
};
|
||||
|
||||
Bear(TR::Level *level, int entity) : Enemy(level, entity, 20) {}
|
||||
Bear(IGame *game, int entity) : Enemy(game, entity, 20) {}
|
||||
|
||||
virtual int getStateGround() {
|
||||
switch (state) {
|
||||
@ -343,7 +343,7 @@ struct Bat : Enemy {
|
||||
STATE_DEATH = 5,
|
||||
};
|
||||
|
||||
Bat(TR::Level *level, int entity) : Enemy(level, entity, 1) { stand = STAND_AIR; }
|
||||
Bat(IGame *game, int entity) : Enemy(game, entity, 1) { stand = STAND_AIR; }
|
||||
|
||||
virtual int getStateAir() {
|
||||
if (!getEntity().flags.active) {
|
||||
|
24
src/lara.h
24
src/lara.h
@ -202,7 +202,7 @@ struct Lara : Character {
|
||||
int lastPickUp;
|
||||
int viewTarget;
|
||||
|
||||
Lara(TR::Level *level, int entity, bool home) : Character(level, entity, 1000), home(home), wpnCurrent(Weapon::EMPTY), wpnNext(Weapon::EMPTY), chestOffset(pos), viewTarget(-1) {
|
||||
Lara(IGame *game, int entity, bool home) : Character(game, entity, 1000), home(home), wpnCurrent(Weapon::EMPTY), wpnNext(Weapon::EMPTY), chestOffset(pos), viewTarget(-1) {
|
||||
|
||||
if (getEntity().type == TR::Entity::LARA) {
|
||||
if (getRoom().flags.water)
|
||||
@ -598,10 +598,10 @@ struct Lara : Character {
|
||||
if (target > -1 && checkHit(target, p, hit, hit)) {
|
||||
((Character*)level->entities[target].controller)->hit(wpnGetDamage());
|
||||
hit -= d * 64.0f;
|
||||
Sprite::add(level, TR::Entity::BLOOD, room, (int)hit.x, (int)hit.y, (int)hit.z, Sprite::FRAME_ANIMATED);
|
||||
Sprite::add(game, TR::Entity::BLOOD, room, (int)hit.x, (int)hit.y, (int)hit.z, Sprite::FRAME_ANIMATED);
|
||||
} else {
|
||||
hit -= d * 64.0f;
|
||||
Sprite::add(level, TR::Entity::SPARK, room, (int)hit.x, (int)hit.y, (int)hit.z, Sprite::FRAME_RANDOM);
|
||||
Sprite::add(game, TR::Entity::SPARK, room, (int)hit.x, (int)hit.y, (int)hit.z, Sprite::FRAME_RANDOM);
|
||||
|
||||
float dist = (hit - p).length();
|
||||
if (dist < nearDist) {
|
||||
@ -938,7 +938,7 @@ struct Lara : Character {
|
||||
|
||||
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.y = float(infoDst.floor);
|
||||
//pos = dst; // set new position
|
||||
|
||||
specular = LARA_WET_SPECULAR;
|
||||
@ -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::WATER_SPLASH, getRoomIndex(), (int)pos.x, (int)pos.y, (int)pos.z);
|
||||
Sprite::add(game, TR::Entity::WATER_SPLASH, getRoomIndex(), (int)pos.x, (int)pos.y, (int)pos.z);
|
||||
return animation.setAnim(ANIM_WATER_FALL); // TODO: wronng animation
|
||||
}
|
||||
|
||||
@ -1416,13 +1416,25 @@ struct Lara : Character {
|
||||
if (state != STATE_SURF_TREAD && state != STATE_SURF_LEFT && state != STATE_SURF_RIGHT && state != STATE_SURF_SWIM && state != STATE_SURF_BACK && state != STATE_STOP)
|
||||
return animation.setAnim(ANIM_TO_ONWATER);
|
||||
|
||||
if (state == STATE_SURF_TREAD) {
|
||||
if (animation.isFrameActive(0))
|
||||
game->waterDrop(animation.getJoints(getMatrix(), 14).pos, 96.0f, 0.01f);
|
||||
} else {
|
||||
if (animation.frameIndex % 4 == 0)
|
||||
game->waterDrop(animation.getJoints(getMatrix(), 14).pos, 128.0f, 0.05f);
|
||||
}
|
||||
|
||||
if (input & FORTH) {
|
||||
if (input & JUMP) {
|
||||
angle.x = -PI * 0.25f;
|
||||
game->waterDrop(pos, 256.0f, 0.2f);
|
||||
return animation.setAnim(ANIM_TO_UNDERWATER);
|
||||
}
|
||||
|
||||
if ((input & ACTION) && waterOut()) return state;
|
||||
if ((input & ACTION) && waterOut()) {
|
||||
game->waterDrop(pos, 128.0f, 0.2f);
|
||||
return state;
|
||||
}
|
||||
|
||||
return STATE_SURF_SWIM;
|
||||
}
|
||||
|
307
src/level.h
307
src/level.h
@ -29,7 +29,7 @@ const char GUI[] =
|
||||
#include "gui.glsl"
|
||||
;
|
||||
|
||||
struct Level {
|
||||
struct Level : IGame {
|
||||
enum { shCompose, shShadow, shAmbient, shFilter, shWater, shGUI, shMAX };
|
||||
|
||||
TR::Level level;
|
||||
@ -196,29 +196,70 @@ struct Level {
|
||||
bool visible;
|
||||
bool blank;
|
||||
vec3 pos, size;
|
||||
Texture *data[2];
|
||||
Texture *mask;
|
||||
Texture *caustics;
|
||||
Texture *data[2];
|
||||
|
||||
Item() {
|
||||
data[0] = data[1] = caustics = NULL;
|
||||
mask = caustics = data[0] = data[1] = 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;
|
||||
Item(int from, int to) : from(from), to(to), timer(SIMULATE_TIMESTEP), visible(true), blank(true) {
|
||||
mask = caustics = data[0] = data[1] = 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);
|
||||
void init(Level *level) {
|
||||
TR::Room &r = level->level.rooms[to]; // underwater room
|
||||
|
||||
int minX = r.xSectors, minZ = r.zSectors, maxX = 0, maxZ = 0, posY;
|
||||
|
||||
for (int z = 0; z < r.zSectors; z++)
|
||||
for (int x = 0; x < r.xSectors; x++) {
|
||||
TR::Room::Sector &s = r.sectors[x * r.zSectors + z];
|
||||
if (s.roomAbove != TR::NO_ROOM && !level->level.rooms[s.roomAbove].flags.water) {
|
||||
minX = min(minX, x);
|
||||
minZ = min(minZ, z);
|
||||
maxX = max(maxX, x);
|
||||
maxZ = max(maxZ, z);
|
||||
posY = s.ceiling * 256;
|
||||
}
|
||||
}
|
||||
maxX++;
|
||||
maxZ++;
|
||||
|
||||
int w = nextPow2(maxX - minX);
|
||||
int h = nextPow2(maxZ - minZ);
|
||||
|
||||
uint8 *m = new uint8[w * h];
|
||||
memset(m, 0, w * h);
|
||||
|
||||
for (int z = minZ; z < maxZ; z++)
|
||||
for (int x = minX; x < maxX; x++) {
|
||||
TR::Room::Sector &s = r.sectors[x * r.zSectors + z];
|
||||
m[(x - minX) + w * (z - minZ)] = (s.roomAbove != TR::NO_ROOM && !level->level.rooms[s.roomAbove].flags.water) ? 255 : 0;
|
||||
}
|
||||
mask = new Texture(w, h, Texture::RED, false, m, false);
|
||||
delete[] m;
|
||||
|
||||
size = vec3(float((maxX - minX) * 512), 1.0f, float((maxZ - minZ) * 512)); // half size
|
||||
pos = vec3(r.info.x + minX * 1024 + size.x, float(posY), r.info.z + minZ * 1024 + size.z);
|
||||
|
||||
data[0] = new Texture(nextPow2(w * 64), nextPow2(h * 64), Texture::RGBA_HALF, false);
|
||||
data[1] = new Texture(data[0]->width, data[0]->height, Texture::RGBA_HALF, false);
|
||||
caustics = new Texture(256, 256, Texture::RGBA, false);
|
||||
caustics = new Texture(512, 512, Texture::RGBA, false);
|
||||
blank = false;
|
||||
|
||||
Core::setTarget(data[0]);
|
||||
Core::clear(vec4(0.0f));
|
||||
Core::setTarget(NULL);
|
||||
}
|
||||
|
||||
void free() {
|
||||
delete data[0];
|
||||
delete data[1];
|
||||
delete caustics;
|
||||
data[0] = data[1] = caustics = NULL;
|
||||
delete mask;
|
||||
mask = caustics = data[0] = data[1] = NULL;
|
||||
}
|
||||
|
||||
} items[MAX_SURFACES];
|
||||
@ -265,9 +306,20 @@ struct Level {
|
||||
visible = 0;
|
||||
}
|
||||
|
||||
void setVisible(int roomIndex, int nextRoom) {
|
||||
void setVisible(int roomIndex, int nextRoom = TR::NO_ROOM) {
|
||||
if (!checkVisibility) return;
|
||||
|
||||
if (nextRoom == TR::NO_ROOM) { // setVisible(underwaterRoom)
|
||||
for (int i = 0; i < count; i++)
|
||||
if (items[i].to == roomIndex) {
|
||||
nextRoom = items[i].from;
|
||||
break;
|
||||
}
|
||||
|
||||
if (nextRoom == TR::NO_ROOM)
|
||||
return;
|
||||
}
|
||||
|
||||
int from, to; // from surface room to underwater room
|
||||
if (level->level.rooms[roomIndex].flags.water) {
|
||||
from = nextRoom;
|
||||
@ -289,28 +341,8 @@ struct Level {
|
||||
}
|
||||
if (count == MAX_SURFACES) return;
|
||||
|
||||
items[count++] = Item(from, to);
|
||||
|
||||
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++;
|
||||
}
|
||||
|
||||
@ -331,69 +363,14 @@ struct Level {
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
@ -402,14 +379,50 @@ struct Level {
|
||||
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));
|
||||
p.x = (drop.pos.x - (item.pos.x - item.size.x)) * DETAIL;
|
||||
p.z = (drop.pos.z - (item.pos.z - item.size.z)) * DETAIL;
|
||||
Core::active.shader->setParam(uParam, vec4(p.x, p.z, drop.radius * DETAIL, drop.strength));
|
||||
|
||||
item.data[0]->bind(sDiffuse);
|
||||
Core::setTarget(item.data[1]);
|
||||
Core::setViewport(0, 0, int(item.size.x * DETAIL * 2.0f + 0.5f), int(item.size.z * DETAIL * 2.0f + 0.5f));
|
||||
level->mesh->renderQuad();
|
||||
swap(item.data[0], item.data[1]);
|
||||
}
|
||||
dropCount = 0;
|
||||
|
||||
swap(item.data[0], item.data[1]);
|
||||
}
|
||||
|
||||
void step(Item &item) {
|
||||
if (item.timer < SIMULATE_TIMESTEP) return;
|
||||
|
||||
Core::active.shader->setParam(uType, Shader::WATER_STEP);
|
||||
Core::active.shader->setParam(uParam, vec4(0.995f, 1.0f, 0, 0));
|
||||
|
||||
while (item.timer >= SIMULATE_TIMESTEP) {
|
||||
// water step
|
||||
item.data[0]->bind(sDiffuse);
|
||||
Core::setTarget(item.data[1]);
|
||||
Core::setViewport(0, 0, int(item.size.x * DETAIL * 2.0f + 0.5f), int(item.size.z * DETAIL * 2.0f + 0.5f));
|
||||
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(uType, Shader::WATER_CAUSTICS);
|
||||
Core::active.shader->setParam(uPosScale, rPosScale[0], 2);
|
||||
|
||||
float sx = item.size.x * DETAIL / (item.data[0]->width / 2);
|
||||
float sz = item.size.z * DETAIL / (item.data[0]->height / 2);
|
||||
|
||||
Core::active.shader->setParam(uTexParam, vec4(1.0f, 1.0f, sx, sz));
|
||||
|
||||
item.data[0]->bind(sNormal);
|
||||
item.caustics->unbind(sReflect);
|
||||
Core::setTarget(item.caustics);
|
||||
level->mesh->renderPlane();
|
||||
}
|
||||
|
||||
void render() {
|
||||
@ -420,7 +433,8 @@ struct Level {
|
||||
level->atlas->bind(sNormal);
|
||||
level->atlas->bind(sReflect);
|
||||
|
||||
Core::active.shader->setParam(uType, Shader::WATER_MASK);
|
||||
Core::active.shader->setParam(uType, Shader::WATER_MASK);
|
||||
Core::active.shader->setParam(uTexParam, vec4(1.0f));
|
||||
Core::setBlending(bmNone);
|
||||
Core::setCulling(cfNone);
|
||||
Core::setDepthWrite(false);
|
||||
@ -451,7 +465,7 @@ struct Level {
|
||||
if (!item.visible) continue;
|
||||
|
||||
if (item.blank) {
|
||||
item.init();
|
||||
item.init(level);
|
||||
item.blank = false;
|
||||
}
|
||||
|
||||
@ -477,22 +491,26 @@ struct Level {
|
||||
level->camera->setup(true);
|
||||
|
||||
// simulate water
|
||||
Core::setBlending(bmNone);
|
||||
Core::setDepthTest(false);
|
||||
|
||||
level->setPassShader(Core::passWater);
|
||||
drop(item);
|
||||
simulate(item);
|
||||
|
||||
if (item.timer >= SIMULATE_TIMESTEP || dropCount) {
|
||||
Core::setBlending(bmNone);
|
||||
Core::setDepthTest(false);
|
||||
|
||||
Core::active.shader->setParam(uTexParam, vec4(1.0f / item.data[0]->width, 1.0f / item.data[0]->height, 1.0f, 1.0f));
|
||||
|
||||
item.mask->bind(sEnvironment);
|
||||
drop(item);
|
||||
step(item);
|
||||
|
||||
Core::setBlending(bmAlpha);
|
||||
Core::setDepthTest(true);
|
||||
}
|
||||
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];
|
||||
if (level->level.rooms[item.from].lightsCount) {
|
||||
TR::Room::Light &light = level->level.rooms[item.from].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));
|
||||
@ -506,11 +524,23 @@ struct Level {
|
||||
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));
|
||||
|
||||
float sx = item.size.x * DETAIL / (item.data[0]->width / 2);
|
||||
float sz = item.size.z * DETAIL / (item.data[0]->height / 2);
|
||||
|
||||
Core::active.shader->setParam(uTexParam, vec4(1.0f, 1.0f, sx, sz));
|
||||
|
||||
|
||||
refract->bind(sDiffuse);
|
||||
reflect->bind(sReflect);
|
||||
item.data[0]->bind(sNormal);
|
||||
Core::setCulling(cfNone);
|
||||
//vec3 rPosScale[2] = { item.pos, item.size * vec3(1.0f / PLANE_DETAIL, 1.0f, 1.0f / PLANE_DETAIL) };
|
||||
//Core::active.shader->setParam(uPosScale, rPosScale[0], 2);
|
||||
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
level->mesh->renderQuad();
|
||||
//level->mesh->renderPlane();
|
||||
//glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
|
||||
Core::setCulling(cfFront);
|
||||
}
|
||||
}
|
||||
@ -561,6 +591,16 @@ struct Level {
|
||||
}
|
||||
} lightCache;
|
||||
*/
|
||||
|
||||
virtual TR::Level* getLevel() {
|
||||
return &level;
|
||||
}
|
||||
|
||||
virtual void waterDrop(const vec3 &pos, float radius, float strength) {
|
||||
waterCache->addDrop(pos, radius, strength);
|
||||
}
|
||||
|
||||
|
||||
Level(Stream &stream, bool demo, bool home) : level(stream, demo), lara(NULL), time(0.0f) {
|
||||
#ifdef _DEBUG
|
||||
Debug::init();
|
||||
@ -576,16 +616,16 @@ struct Level {
|
||||
switch (entity.type) {
|
||||
case TR::Entity::LARA :
|
||||
case TR::Entity::CUT_1 :
|
||||
entity.controller = (lara = new Lara(&level, i, home));
|
||||
entity.controller = (lara = new Lara(this, i, home));
|
||||
break;
|
||||
case TR::Entity::ENEMY_WOLF :
|
||||
entity.controller = new Wolf(&level, i);
|
||||
entity.controller = new Wolf(this, i);
|
||||
break;
|
||||
case TR::Entity::ENEMY_BEAR :
|
||||
entity.controller = new Bear(&level, i);
|
||||
entity.controller = new Bear(this, i);
|
||||
break;
|
||||
case TR::Entity::ENEMY_BAT :
|
||||
entity.controller = new Bat(&level, i);
|
||||
entity.controller = new Bat(this, i);
|
||||
break;
|
||||
case TR::Entity::ENEMY_TWIN :
|
||||
case TR::Entity::ENEMY_CROCODILE_LAND :
|
||||
@ -602,7 +642,7 @@ struct Level {
|
||||
case TR::Entity::ENEMY_CENTAUR :
|
||||
case TR::Entity::ENEMY_MUMMY :
|
||||
case TR::Entity::ENEMY_LARSON :
|
||||
entity.controller = new Enemy(&level, i, 100);
|
||||
entity.controller = new Enemy(this, i, 100);
|
||||
break;
|
||||
case TR::Entity::DOOR_1 :
|
||||
case TR::Entity::DOOR_2 :
|
||||
@ -612,61 +652,61 @@ struct Level {
|
||||
case TR::Entity::DOOR_6 :
|
||||
case TR::Entity::DOOR_BIG_1 :
|
||||
case TR::Entity::DOOR_BIG_2 :
|
||||
entity.controller = new Door(&level, i);
|
||||
entity.controller = new Door(this, i);
|
||||
break;
|
||||
case TR::Entity::TRAP_DOOR_1 :
|
||||
case TR::Entity::TRAP_DOOR_2 :
|
||||
entity.controller = new TrapDoor(&level, i);
|
||||
entity.controller = new TrapDoor(this, i);
|
||||
break;
|
||||
case TR::Entity::BRIDGE_0 :
|
||||
case TR::Entity::BRIDGE_1 :
|
||||
case TR::Entity::BRIDGE_2 :
|
||||
entity.controller = new Bridge(&level, i);
|
||||
entity.controller = new Bridge(this, i);
|
||||
break;
|
||||
case TR::Entity::GEARS_1 :
|
||||
case TR::Entity::GEARS_2 :
|
||||
case TR::Entity::GEARS_3 :
|
||||
entity.controller = new Boulder(&level, i);
|
||||
entity.controller = new Boulder(this, i);
|
||||
break;
|
||||
case TR::Entity::TRAP_FLOOR :
|
||||
entity.controller = new TrapFloor(&level, i);
|
||||
entity.controller = new TrapFloor(this, i);
|
||||
break;
|
||||
case TR::Entity::CRYSTAL :
|
||||
entity.controller = new Crystal(&level, i);
|
||||
entity.controller = new Crystal(this, i);
|
||||
break;
|
||||
case TR::Entity::TRAP_BLADE :
|
||||
case TR::Entity::TRAP_SPIKES :
|
||||
entity.controller = new Trigger(&level, i, true);
|
||||
entity.controller = new Trigger(this, i, true);
|
||||
break;
|
||||
case TR::Entity::TRAP_BOULDER :
|
||||
entity.controller = new Boulder(&level, i);
|
||||
entity.controller = new Boulder(this, i);
|
||||
break;
|
||||
case TR::Entity::TRAP_DARTGUN :
|
||||
entity.controller = new Dartgun(&level, i);
|
||||
entity.controller = new Dartgun(this, i);
|
||||
break;
|
||||
case TR::Entity::BLOCK_1 :
|
||||
case TR::Entity::BLOCK_2 :
|
||||
entity.controller = new Block(&level, i);
|
||||
entity.controller = new Block(this, i);
|
||||
break;
|
||||
case TR::Entity::SWITCH :
|
||||
case TR::Entity::SWITCH_WATER :
|
||||
case TR::Entity::HOLE_PUZZLE :
|
||||
case TR::Entity::HOLE_KEY :
|
||||
entity.controller = new Trigger(&level, i, false);
|
||||
entity.controller = new Trigger(this, i, false);
|
||||
break;
|
||||
case TR::Entity::WATERFALL :
|
||||
entity.controller = new Waterfall(&level, i);
|
||||
entity.controller = new Waterfall(this, i);
|
||||
break;
|
||||
default :
|
||||
if (entity.modelIndex > 0)
|
||||
entity.controller = new Controller(&level, i);
|
||||
entity.controller = new Controller(this, i);
|
||||
else
|
||||
entity.controller = new Sprite(&level, i, 0);
|
||||
entity.controller = new Sprite(this, i, 0);
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT(lara != NULL);
|
||||
camera = new Camera(&level, lara);
|
||||
camera = new Camera(this, lara);
|
||||
|
||||
level.cameraController = camera;
|
||||
|
||||
@ -905,6 +945,9 @@ struct Level {
|
||||
|
||||
// room geometry & sprites
|
||||
if (!room.flags.rendered) { // skip if already rendered
|
||||
if (room.flags.water)
|
||||
waterCache->setVisible(roomIndex);
|
||||
|
||||
room.flags.rendered = true;
|
||||
|
||||
if (Core::pass != Core::passShadow) {
|
||||
@ -1063,8 +1106,8 @@ struct Level {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
camera->update();
|
||||
waterCache->update();
|
||||
}
|
||||
@ -1265,7 +1308,7 @@ struct Level {
|
||||
}
|
||||
vec3 p = lara->pos + lara->getDir() * 256.0f;
|
||||
lastEntity = level.entityAdd(level.models[modelIndex].type, lara->getRoomIndex(), p.x, p.y - 512, p.z, lara->getEntity().rotation, -1);
|
||||
level.entities[lastEntity].controller = new Controller(&level, lastEntity);
|
||||
level.entities[lastEntity].controller = new Controller(this, lastEntity);
|
||||
}
|
||||
} else
|
||||
lastStateK = false;
|
||||
@ -1284,19 +1327,23 @@ struct Level {
|
||||
glLoadIdentity();
|
||||
glOrtho(0, Core::width, 0, Core::height, 0, 1);
|
||||
|
||||
waterCache->reflect->bind(sDiffuse);
|
||||
if (waterCache->count)
|
||||
waterCache->items[0].data[0]->bind(sDiffuse);
|
||||
else
|
||||
atlas->bind(sDiffuse);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
glColor3f(1, 1, 1);
|
||||
glColor3f(10, 10, 10);
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(0, 0); glVertex2f(0, 0);
|
||||
glTexCoord2f(1, 0); glVertex2f(256, 0);
|
||||
glTexCoord2f(1, 1); glVertex2f(256, 256);
|
||||
glTexCoord2f(0, 1); glVertex2f(0, 256);
|
||||
glEnd();
|
||||
glColor3f(1, 1, 1);
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glEnable(GL_CULL_FACE);
|
||||
@ -1310,7 +1357,7 @@ struct Level {
|
||||
|
||||
|
||||
// Debug::Level::rooms(level, lara->pos, lara->getEntity().room);
|
||||
// Debug::Level::lights(level, lara->getRoomIndex());
|
||||
Debug::Level::lights(level, lara->getRoomIndex());
|
||||
// Debug::Level::sectors(level, lara->getRoomIndex(), (int)lara->pos.y);
|
||||
// Core::setDepthTest(false);
|
||||
// Debug::Level::portals(level);
|
||||
|
20
src/mesh.h
20
src/mesh.h
@ -517,17 +517,17 @@ struct MeshBuilder {
|
||||
|
||||
if (a.y != b.y || a.y != c.y || a.y != d.y) // skip non-horizontal or non-portal plane primitive
|
||||
continue;
|
||||
|
||||
int yt = abs(a.y - room.info.yTop);
|
||||
int yb = abs(room.info.yBottom - a.y);
|
||||
|
||||
if (yt > 0 && yb > 0) continue;
|
||||
|
||||
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];
|
||||
|
||||
int yt = abs(a.y - s.ceiling * 256);
|
||||
int yb = abs(s.floor * 256 - a.y);
|
||||
|
||||
if (yt > 0 && yb > 0) continue;
|
||||
|
||||
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
|
||||
@ -546,17 +546,17 @@ struct MeshBuilder {
|
||||
|
||||
if (a.y != b.y || a.y != c.y) // skip non-horizontal or non-portal plane primitive
|
||||
continue;
|
||||
|
||||
int yt = abs(a.y - room.info.yTop);
|
||||
int yb = abs(room.info.yBottom - a.y);
|
||||
|
||||
if (yt > 1 && yb > 1) continue;
|
||||
|
||||
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];
|
||||
|
||||
int yt = abs(a.y - s.ceiling * 256);
|
||||
int yb = abs(s.floor * 256 - a.y);
|
||||
|
||||
if (yt > 0 && yb > 0) continue;
|
||||
|
||||
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
|
||||
|
@ -27,6 +27,7 @@ uniform int uType;
|
||||
#ifdef PASS_COMPOSE
|
||||
uniform int uCaustics;
|
||||
uniform vec4 uParam;
|
||||
uniform vec4 uRoomSize; // xy - minXZ, zw - maxXZ
|
||||
#endif
|
||||
|
||||
#ifdef VERTEX
|
||||
@ -42,7 +43,6 @@ uniform int uType;
|
||||
uniform vec3 uViewPos;
|
||||
uniform vec2 uAnimTexRanges[MAX_RANGES];
|
||||
uniform vec2 uAnimTexOffsets[MAX_OFFSETS];
|
||||
uniform vec4 uRoomSize; // xy - minXZ, zw - maxXZ
|
||||
#endif
|
||||
|
||||
attribute vec4 aCoord;
|
||||
@ -102,7 +102,7 @@ uniform int uType;
|
||||
float sum = coord.x + coord.y + coord.z;
|
||||
vColor.xyz *= abs(sin(sum / 512.0 + uParam.x)) * 1.5 + 0.5; // color dodge
|
||||
}
|
||||
vTexCoord.zw = smoothstep(uRoomSize.xy, uRoomSize.zw, coord.xz);
|
||||
vTexCoord.zw = clamp((coord.xz - uRoomSize.xy) / (uRoomSize.zw - uRoomSize.xy), vec2(0.0), vec2(1.0));
|
||||
|
||||
vViewVec = uViewPos - coord.xyz;
|
||||
vLightProj = uLightProj * coord;
|
||||
@ -228,7 +228,11 @@ uniform int uType;
|
||||
}
|
||||
|
||||
float calcCaustics(vec3 n) {
|
||||
return texture2D(sReflect, vTexCoord.zw).r * (float(uCaustics) * max(0.0, -n.y));
|
||||
if (uCaustics != 0) {
|
||||
vec2 fade = smoothstep(uRoomSize.xy, uRoomSize.xy + vec2(256.0), vCoord.xz) * (1.0f - smoothstep(uRoomSize.zw - vec2(256.0), uRoomSize.zw, vCoord.xz));
|
||||
return texture2D(sReflect, vTexCoord.zw).r * (max(0.0, -n.y)) * fade.x * fade.y;
|
||||
} else
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -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, uPosScale, uMAX };
|
||||
enum UniformType { uType, uCaustics, uParam, uTexParam, 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", "uPosScale" };
|
||||
const char *UniformName[uMAX] = { "uType", "uCaustics", "uParam", "uTexParam", "uViewProj", "uViewInv", "uBasis", "uLightProj", "uColor", "uAmbient", "uViewPos", "uLightsCount", "uLightPos", "uLightColor", "uAnimTexRanges", "uAnimTexOffsets", "uRoomSize", "uPosScale" };
|
||||
|
||||
struct Shader {
|
||||
GLuint ID;
|
||||
|
@ -465,8 +465,8 @@ namespace Sound {
|
||||
int idxA = int(t);
|
||||
int idxB = (j == (count - 1)) ? idxA : (idxA + 1);
|
||||
float k = t - idxA;
|
||||
result[j].L += lerp(buffer[idxA].L, buffer[idxB].L, k);
|
||||
result[j].R += lerp(buffer[idxA].R, buffer[idxB].R, k);
|
||||
result[j].L += int(lerp(buffer[idxA].L, buffer[idxB].L, k));
|
||||
result[j].R += int(lerp(buffer[idxA].R, buffer[idxB].R, k));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ struct Sprite : Controller {
|
||||
int frame, flag;
|
||||
float time;
|
||||
|
||||
Sprite(TR::Level *level, int entity, bool instant = true, int frame = FRAME_ANIMATED) : Controller(level, entity), instant(instant), flag(frame), time(0.0f) {
|
||||
Sprite(IGame *game, int entity, bool instant = true, int frame = FRAME_ANIMATED) : Controller(game, entity), instant(instant), flag(frame), time(0.0f) {
|
||||
if (frame >= 0) { // specific frame
|
||||
this->frame = frame;
|
||||
} else if (frame == FRAME_RANDOM) { // random frame
|
||||
@ -24,11 +24,12 @@ struct Sprite : Controller {
|
||||
}
|
||||
}
|
||||
|
||||
static void add(TR::Level *level, TR::Entity::Type type, int room, int x, int y, int z, int frame = -1) {
|
||||
static void add(IGame *game, TR::Entity::Type type, int room, int x, int y, int z, int frame = -1) {
|
||||
TR::Level *level = game->getLevel();
|
||||
int index = level->entityAdd(type, room, x, y, z, 0, -1);
|
||||
if (index > -1) {
|
||||
level->entities[index].intensity = 0x1FFF - level->rooms[room].ambient;
|
||||
level->entities[index].controller = new Sprite(level, index, true, frame);
|
||||
level->entities[index].controller = new Sprite(game, index, true, frame);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,12 +11,10 @@ struct Texture {
|
||||
Format format;
|
||||
bool cube;
|
||||
|
||||
Texture(int width, int height, Format format, bool cube, void *data = NULL) : width(width), height(height), cube(cube) {
|
||||
Texture(int width, int height, Format format, bool cube, void *data = NULL, bool filter = true) : width(width), height(height), cube(cube) {
|
||||
glGenTextures(1, &ID);
|
||||
bind(0);
|
||||
|
||||
bool filter = true;
|
||||
|
||||
GLenum target = cube ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D;
|
||||
|
||||
if (format == SHADOW && !Core::support.shadowSampler) {
|
||||
|
@ -11,7 +11,7 @@ struct Trigger : Controller {
|
||||
float timer;
|
||||
int baseState;
|
||||
|
||||
Trigger(TR::Level *level, int entity, bool immediate) : Controller(level, entity), immediate(immediate), timer(0.0f) {
|
||||
Trigger(IGame *game, int entity, bool immediate) : Controller(game, entity), immediate(immediate), timer(0.0f) {
|
||||
baseState = state;
|
||||
getEntity().flags.collision = false;
|
||||
}
|
||||
@ -65,7 +65,7 @@ struct Dart : Controller {
|
||||
vec3 dir;
|
||||
bool inWall; // dart starts from wall
|
||||
|
||||
Dart(TR::Level *level, int entity) : Controller(level, entity), inWall(true) {
|
||||
Dart(IGame *game, int entity) : Controller(game, entity), inWall(true) {
|
||||
dir = vec3(sinf(angle.y), 0, cosf(angle.y));
|
||||
}
|
||||
|
||||
@ -80,7 +80,7 @@ struct Dart : Controller {
|
||||
TR::Entity &e = getEntity();
|
||||
|
||||
vec3 p = pos - dir * 64.0f; // wall offset = 64
|
||||
Sprite::add(level, TR::Entity::SPARK, e.room, (int)p.x, (int)p.y, (int)p.z, Sprite::FRAME_RANDOM);
|
||||
Sprite::add(game, TR::Entity::SPARK, e.room, (int)p.x, (int)p.y, (int)p.z, Sprite::FRAME_RANDOM);
|
||||
|
||||
level->entityRemove(entity);
|
||||
delete this;
|
||||
@ -93,7 +93,7 @@ struct Dart : Controller {
|
||||
struct Dartgun : Trigger {
|
||||
vec3 origin;
|
||||
|
||||
Dartgun(TR::Level *level, int entity) : Trigger(level, entity, true), origin(pos) {}
|
||||
Dartgun(IGame *game, int entity) : Trigger(game, entity, true), origin(pos) {}
|
||||
|
||||
virtual bool activate(ActionCommand *cmd) {
|
||||
if (!Trigger::activate(cmd))
|
||||
@ -106,9 +106,9 @@ struct Dartgun : Trigger {
|
||||
|
||||
int dartIndex = level->entityAdd(TR::Entity::TRAP_DART, entity.room, (int)p.x, (int)p.y, (int)p.z, entity.rotation, entity.intensity);
|
||||
if (dartIndex > -1)
|
||||
level->entities[dartIndex].controller = new Dart(level, dartIndex);
|
||||
level->entities[dartIndex].controller = new Dart(game, dartIndex);
|
||||
|
||||
Sprite::add(level, TR::Entity::SMOKE, entity.room, (int)p.x, (int)p.y, (int)p.z);
|
||||
Sprite::add(game, TR::Entity::SMOKE, entity.room, (int)p.x, (int)p.y, (int)p.z);
|
||||
|
||||
playSound(TR::SND_DART, pos, Sound::Flags::PAN);
|
||||
|
||||
@ -119,7 +119,7 @@ struct Dartgun : Trigger {
|
||||
|
||||
struct Boulder : Trigger {
|
||||
|
||||
Boulder(TR::Level *level, int entity) : Trigger(level, entity, true) {}
|
||||
Boulder(IGame *game, int entity) : Trigger(game, entity, true) {}
|
||||
|
||||
virtual void update() {
|
||||
if (getEntity().flags.active) {
|
||||
@ -138,7 +138,7 @@ struct Block : Controller {
|
||||
STATE_PULL,
|
||||
};
|
||||
|
||||
Block(TR::Level *level, int entity) : Controller(level, entity) {
|
||||
Block(IGame *game, int entity) : Controller(game, entity) {
|
||||
updateFloor(true);
|
||||
}
|
||||
|
||||
@ -181,7 +181,7 @@ struct Block : Controller {
|
||||
struct Door : Trigger {
|
||||
int8 *floor[2], orig[2];
|
||||
|
||||
Door(TR::Level *level, int entity) : Trigger(level, entity, true) {
|
||||
Door(IGame *game, int entity) : Trigger(game, entity, true) {
|
||||
TR::Entity &e = getEntity();
|
||||
TR::Level::FloorInfo info;
|
||||
vec3 p = pos - getDir() * 1024.0f;
|
||||
@ -222,7 +222,7 @@ struct Door : Trigger {
|
||||
|
||||
struct TrapDoor : Trigger {
|
||||
|
||||
TrapDoor(TR::Level *level, int entity) : Trigger(level, entity, true) {
|
||||
TrapDoor(IGame *game, int entity) : Trigger(game, entity, true) {
|
||||
getEntity().flags.collision = true;
|
||||
}
|
||||
|
||||
@ -245,7 +245,7 @@ struct TrapFloor : Trigger {
|
||||
};
|
||||
float velocity;
|
||||
|
||||
TrapFloor(TR::Level *level, int entity) : Trigger(level, entity, true), velocity(0) {
|
||||
TrapFloor(IGame *game, int entity) : Trigger(game, entity, true), velocity(0) {
|
||||
TR::Entity &e = getEntity();
|
||||
e.flags.collision = true;
|
||||
}
|
||||
@ -283,7 +283,7 @@ struct TrapFloor : Trigger {
|
||||
|
||||
struct Bridge : Trigger {
|
||||
|
||||
Bridge(TR::Level *level, int entity) : Trigger(level, entity, true) {
|
||||
Bridge(IGame *game, int entity) : Trigger(game, entity, true) {
|
||||
getEntity().flags.collision = true;
|
||||
}
|
||||
};
|
||||
@ -291,7 +291,7 @@ struct Bridge : Trigger {
|
||||
struct Crystal : Controller {
|
||||
Texture *environment;
|
||||
|
||||
Crystal(TR::Level *level, int entity) : Controller(level, entity) {
|
||||
Crystal(IGame *game, int entity) : Controller(game, entity) {
|
||||
environment = new Texture(64, 64, Texture::RGBA, true);
|
||||
}
|
||||
|
||||
@ -318,7 +318,7 @@ struct Waterfall : Trigger {
|
||||
float dropStrength;
|
||||
vec3 dropPos;
|
||||
|
||||
Waterfall(TR::Level *level, int entity) : Trigger(level, entity, true), timer(0.0f) {}
|
||||
Waterfall(IGame *game, int entity) : Trigger(game, entity, true), timer(0.0f) {}
|
||||
|
||||
virtual void update() {
|
||||
drop = false;
|
||||
@ -335,10 +335,10 @@ struct Waterfall : Trigger {
|
||||
|
||||
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;
|
||||
dropRadius = randf() * 256.0f + 128.0f;
|
||||
dropStrength = randf() * 0.1f + 0.1f;
|
||||
|
||||
Sprite::add(level, TR::Entity::WATER_SPLASH, getRoomIndex(), (int)dropPos.x, (int)dropPos.y, (int)dropPos.z);
|
||||
Sprite::add(game, TR::Entity::WATER_SPLASH, getRoomIndex(), (int)dropPos.x, (int)dropPos.y, (int)dropPos.z);
|
||||
}
|
||||
|
||||
#undef SPLASH_TIMESTEP
|
||||
|
@ -23,7 +23,9 @@ uniform int uType;
|
||||
uniform vec3 uViewPos;
|
||||
uniform mat4 uViewProj;
|
||||
uniform vec3 uPosScale[2];
|
||||
uniform float uScale;
|
||||
|
||||
uniform vec4 uTexParam;
|
||||
uniform vec4 uParam;
|
||||
|
||||
uniform sampler2D sNormal;
|
||||
|
||||
@ -34,10 +36,9 @@ uniform sampler2D sNormal;
|
||||
attribute vec4 aCoord;
|
||||
|
||||
void main() {
|
||||
vTexCoord = aCoord.xy * 0.5 + 0.5;
|
||||
vTexCoord = (aCoord.xy * 0.5 + 0.5) * uTexParam.zw;
|
||||
|
||||
if (uType >= WATER_MASK) {
|
||||
// hardcoded pool geometry
|
||||
vCoord = vec3(aCoord.x, 0.0, aCoord.y) * uPosScale[1] + uPosScale[0];
|
||||
vec4 cp = uViewProj * vec4(vCoord, 1.0);
|
||||
|
||||
@ -48,15 +49,14 @@ uniform sampler2D sNormal;
|
||||
if (uType == WATER_CAUSTICS) {
|
||||
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;
|
||||
vec4 info = texture2D(sNormal, (rCoord.xz * 0.5 + 0.5) * uTexParam.zw);
|
||||
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 + vec3(0.0, 1.0, 0.0);
|
||||
vRefPos1 = rCoord + vec3(0.0, 0.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);
|
||||
@ -64,76 +64,86 @@ uniform sampler2D sNormal;
|
||||
vRefPos1 = vRefPos2 = vec3(0.0);
|
||||
vCoord = vec3(aCoord.xy, 0.0);
|
||||
|
||||
gl_Position = vec4(aCoord.xyz, 1.0);
|
||||
gl_Position = vec4(aCoord.xyz, 1.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
uniform sampler2D sDiffuse;
|
||||
uniform sampler2D sReflect;
|
||||
|
||||
uniform vec4 uParam; // texture size
|
||||
uniform sampler2D sEnvironment;
|
||||
|
||||
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;
|
||||
}
|
||||
#define PI 3.141592653589793
|
||||
|
||||
float calcFresnel(float NdotL, float fbias, float fpow) {
|
||||
float f = (1.0 - abs(NdotL));
|
||||
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);
|
||||
vec2 tc = gl_FragCoord.xy * uTexParam.xy;
|
||||
vec4 v = texture2D(sDiffuse, tc);
|
||||
|
||||
float drop = max(0.0, 1.0 - length(uParam.xy - gl_FragCoord.xy) / uParam.z);
|
||||
drop = 0.5 - cos(drop * PI) * 0.5;
|
||||
value.r += drop * uParam.w;
|
||||
return value;
|
||||
v.x += drop * uParam.w;
|
||||
|
||||
return v * texture2D(sEnvironment, tc).x; // apply coast mask
|
||||
}
|
||||
|
||||
|
||||
float getHeight(float ref, vec2 tc) {
|
||||
return mix(ref, texture2D(sDiffuse, tc).x, texture2D(sEnvironment, tc).x);
|
||||
}
|
||||
|
||||
vec4 step() {
|
||||
vec2 dx = vec2(uParam.x, 0.0);
|
||||
vec2 dy = vec2(0.0, uParam.y);
|
||||
vec2 tc = gl_FragCoord.xy * uTexParam.xy;
|
||||
|
||||
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);
|
||||
vec4 v = texture2D(sDiffuse, tc); // height, speed, normal.xz
|
||||
|
||||
/*
|
||||
vec4 dx = vec4(0.25, 0.96, -0.25, -0.96) * uTexParam.xyxy + tc.xyxy;
|
||||
vec4 dy = vec4(0.25, 0.96, -0.25, -0.96) * uTexParam.yxyx + tc.yxyx;
|
||||
float average = (texture2D(sDiffuse, dy.yx).x +
|
||||
texture2D(sDiffuse, dx.zy).x +
|
||||
texture2D(sDiffuse, dy.wz).x +
|
||||
texture2D(sDiffuse, dx.xw).x) * 0.25;
|
||||
|
||||
vec3 d = vec3(uTexParam.xy, 0.0);
|
||||
vec2 f = vec2(texture2D(sDiffuse, tc + d.xz).x, texture2D(sDiffuse, tc + d.zy).x);
|
||||
*/
|
||||
|
||||
vec3 d = vec3(uTexParam.xy, 0.0);
|
||||
vec4 f = vec4(getHeight(v.x, tc + d.xz), getHeight(v.x, tc + d.zy),
|
||||
getHeight(v.x, tc - d.xz), getHeight(v.x, tc - d.zy));
|
||||
|
||||
// vec4 f = vec4(texture2D(sDiffuse, tc + d.xz).x, texture2D(sDiffuse, tc + d.zy).x,
|
||||
// texture2D(sDiffuse, tc - d.xz).x, texture2D(sDiffuse, tc - d.zy).x);
|
||||
|
||||
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;
|
||||
f.xy -= v.x;
|
||||
vec3 nx = vec3(d.x, f.x, 0.0);
|
||||
vec3 ny = vec3(0.0, f.y, d.y);
|
||||
v.zw = normalize(cross(ny, nx)).xz * 0.5;
|
||||
|
||||
// velocity
|
||||
v.g += (average - v.r) * 2.0;
|
||||
v.g *= 0.995;
|
||||
v.y += (average - v.x) * 1.9;
|
||||
v.y *= uParam.x; // fadeout
|
||||
|
||||
// amplitude
|
||||
v.r += v.g * 0.4;
|
||||
v.x += v.y * uParam.y;
|
||||
|
||||
return v;
|
||||
return v * texture2D(sEnvironment, tc).x; // apply coast mask
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -146,7 +156,6 @@ uniform sampler2D sNormal;
|
||||
|
||||
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;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user