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

№23 global IGame interface, variable size of water texture

This commit is contained in:
XProger
2017-02-02 12:27:18 +03:00
parent 6ee2aa68cf
commit 38934fb41a
14 changed files with 303 additions and 226 deletions

View File

@@ -23,7 +23,7 @@ struct Camera : Controller {
vec4 *reflectPlane; 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; fov = 65.0f;
znear = 16; znear = 16;
zfar = 40.0f * 1024.0f; zfar = 40.0f * 1024.0f;

View File

@@ -29,7 +29,7 @@ struct Character : Controller {
vec3 velocity; vec3 velocity;
float angleExt; 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(); animation.initOverrides();
rotHead = rotChest = quat(0, 0, 0, 1); rotHead = rotChest = quat(0, 0, 0, 1);
} }

View File

@@ -12,7 +12,13 @@
#define MAX_LAYERS 4 #define MAX_LAYERS 4
struct IGame {
virtual TR::Level* getLevel() { return NULL; }
virtual void waterDrop(const vec3 &pos, float radius, float strength) {}
};
struct Controller { struct Controller {
IGame *game;
TR::Level *level; TR::Level *level;
int entity; 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(int emitter, TR::Action action, int value, float timer, ActionCommand *next = NULL) : emitter(emitter), action(action), value(value), timer(timer), next(next) {}
} *actionCommand; } *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(); TR::Entity &e = getEntity();
pos = vec3((float)e.x, (float)e.y, (float)e.z); pos = vec3((float)e.x, (float)e.y, (float)e.z);
angle = vec3(0.0f, e.rotation, 0.0f); angle = vec3(0.0f, e.rotation, 0.0f);

View File

@@ -6,7 +6,7 @@
struct Enemy : Character { struct Enemy : Character {
bool bitten; 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) { virtual bool activate(ActionCommand *cmd) {
#ifdef LEVEL_EDITOR #ifdef LEVEL_EDITOR
@@ -134,7 +134,7 @@ struct Enemy : Character {
ASSERT(target > -1); ASSERT(target > -1);
Character *c = (Character*)level->entities[target].controller; Character *c = (Character*)level->entities[target].controller;
c->hit(damage, this); 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 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() { virtual int getStateGround() {
TR::Entity &e = getEntity(); TR::Entity &e = getEntity();
@@ -268,7 +268,7 @@ struct Bear : Enemy {
JOINT_HEAD = 3 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() { virtual int getStateGround() {
switch (state) { switch (state) {
@@ -343,7 +343,7 @@ struct Bat : Enemy {
STATE_DEATH = 5, 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() { virtual int getStateAir() {
if (!getEntity().flags.active) { if (!getEntity().flags.active) {

View File

@@ -202,7 +202,7 @@ struct Lara : Character {
int lastPickUp; int lastPickUp;
int viewTarget; 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 (getEntity().type == TR::Entity::LARA) {
if (getRoom().flags.water) if (getRoom().flags.water)
@@ -598,10 +598,10 @@ struct Lara : Character {
if (target > -1 && checkHit(target, p, hit, hit)) { if (target > -1 && checkHit(target, p, hit, hit)) {
((Character*)level->entities[target].controller)->hit(wpnGetDamage()); ((Character*)level->entities[target].controller)->hit(wpnGetDamage());
hit -= d * 64.0f; 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 { } else {
hit -= d * 64.0f; 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(); float dist = (hit - p).length();
if (dist < nearDist) { 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 if (h >= 0 && h <= 356 && (state == STATE_SURF_TREAD || animation.setState(STATE_SURF_TREAD)) && animation.setState(STATE_STOP)) { // possibility check
alignToWall(-96.0f); alignToWall(-96.0f);
pos.y = infoDst.floor; pos.y = float(infoDst.floor);
//pos = dst; // set new position //pos = dst; // set new position
specular = LARA_WET_SPECULAR; specular = LARA_WET_SPECULAR;
@@ -1394,7 +1394,7 @@ struct Lara : Character {
return STATE_PICK_UP; 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) { 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 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) 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); 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 & FORTH) {
if (input & JUMP) { if (input & JUMP) {
angle.x = -PI * 0.25f; angle.x = -PI * 0.25f;
game->waterDrop(pos, 256.0f, 0.2f);
return animation.setAnim(ANIM_TO_UNDERWATER); 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; return STATE_SURF_SWIM;
} }

View File

@@ -29,7 +29,7 @@ const char GUI[] =
#include "gui.glsl" #include "gui.glsl"
; ;
struct Level { struct Level : IGame {
enum { shCompose, shShadow, shAmbient, shFilter, shWater, shGUI, shMAX }; enum { shCompose, shShadow, shAmbient, shFilter, shWater, shGUI, shMAX };
TR::Level level; TR::Level level;
@@ -196,29 +196,70 @@ struct Level {
bool visible; bool visible;
bool blank; bool blank;
vec3 pos, size; vec3 pos, size;
Texture *data[2]; Texture *mask;
Texture *caustics; Texture *caustics;
Texture *data[2];
Item() { 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) { Item(int from, int to) : from(from), to(to), timer(SIMULATE_TIMESTEP), visible(true), blank(true) {
data[0] = data[1] = caustics = NULL; mask = caustics = data[0] = data[1] = NULL;
} }
void init() { void init(Level *level) {
data[0] = new Texture(nextPow2(int(size.x * DETAIL * 2.0f) - 1), nextPow2(int(size.z * DETAIL * 2.0f) - 1), Texture::RGBA_HALF, false); 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); 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; blank = false;
Core::setTarget(data[0]);
Core::clear(vec4(0.0f));
Core::setTarget(NULL);
} }
void free() { void free() {
delete data[0]; delete data[0];
delete data[1]; delete data[1];
delete caustics; delete caustics;
data[0] = data[1] = caustics = NULL; delete mask;
mask = caustics = data[0] = data[1] = NULL;
} }
} items[MAX_SURFACES]; } items[MAX_SURFACES];
@@ -265,9 +306,20 @@ struct Level {
visible = 0; visible = 0;
} }
void setVisible(int roomIndex, int nextRoom) { void setVisible(int roomIndex, int nextRoom = TR::NO_ROOM) {
if (!checkVisibility) return; 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 int from, to; // from surface room to underwater room
if (level->level.rooms[roomIndex].flags.water) { if (level->level.rooms[roomIndex].flags.water) {
from = nextRoom; from = nextRoom;
@@ -289,28 +341,8 @@ struct Level {
} }
if (count == MAX_SURFACES) return; 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++; 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) { void addDrop(const vec3 &pos, float radius, float strength) {
if (dropCount >= MAX_DROPS) return; if (dropCount >= MAX_DROPS) return;
drops[dropCount++] = Drop(pos, radius, strength); drops[dropCount++] = Drop(pos, radius, strength);
} }
void drop(Item &item) { 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; if (!dropCount) return;
item.data[0]->bind(sDiffuse);
Core::setTarget(item.data[1]);
vec3 rPosScale[2] = { vec3(0.0f), vec3(1.0f) }; vec3 rPosScale[2] = { vec3(0.0f), vec3(1.0f) };
Core::active.shader->setParam(uPosScale, rPosScale[0], 2); Core::active.shader->setParam(uPosScale, rPosScale[0], 2);
Core::active.shader->setParam(uType, Shader::WATER_DROP); Core::active.shader->setParam(uType, Shader::WATER_DROP);
@@ -402,14 +379,50 @@ struct Level {
Drop &drop = drops[i]; Drop &drop = drops[i];
vec3 p; vec3 p;
p.x = (drop.pos.x - item.pos.x) / (item.size.x * 2.0f) + 0.5; p.x = (drop.pos.x - (item.pos.x - item.size.x)) * DETAIL;
p.z = (drop.pos.z - item.pos.z) / (item.size.z * 2.0f) + 0.5; p.z = (drop.pos.z - (item.pos.z - item.size.z)) * DETAIL;
Core::active.shader->setParam(uParam, vec4(p.x, p.z, 128.0f / (item.size.x * 2.0f) * drop.radius, drop.strength)); 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(); level->mesh->renderQuad();
swap(item.data[0], item.data[1]);
} }
dropCount = 0; 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() { void render() {
@@ -420,7 +433,8 @@ struct Level {
level->atlas->bind(sNormal); level->atlas->bind(sNormal);
level->atlas->bind(sReflect); 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::setBlending(bmNone);
Core::setCulling(cfNone); Core::setCulling(cfNone);
Core::setDepthWrite(false); Core::setDepthWrite(false);
@@ -451,7 +465,7 @@ struct Level {
if (!item.visible) continue; if (!item.visible) continue;
if (item.blank) { if (item.blank) {
item.init(); item.init(level);
item.blank = false; item.blank = false;
} }
@@ -477,22 +491,26 @@ struct Level {
level->camera->setup(true); level->camera->setup(true);
// simulate water // simulate water
Core::setBlending(bmNone);
Core::setDepthTest(false);
level->setPassShader(Core::passWater); 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::setTarget(NULL);
Core::setBlending(bmAlpha);
Core::setDepthTest(true);
// render water plane // render water plane
int dx, dz; if (level->level.rooms[item.from].lightsCount) {
TR::Room::Sector &s = level->level.getSector(item.from, int(item.pos.x), int(item.pos.z), dx, dz); TR::Room::Light &light = level->level.rooms[item.from].lights[0];
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)); Core::lightPos[0] = vec3(float(light.x), float(light.y), float(light.z));
float lum = intensityf(light.intensity); float lum = intensityf(light.intensity);
Core::lightColor[0] = vec4(lum, lum, lum, float(light.radius) * float(light.radius)); Core::lightColor[0] = vec4(lum, lum, lum, float(light.radius) * float(light.radius));
@@ -506,11 +524,23 @@ struct Level {
Core::active.shader->setParam(uLightColor, Core::lightColor[0], 1); Core::active.shader->setParam(uLightColor, Core::lightColor[0], 1);
Core::active.shader->setParam(uParam, vec4(float(Core::width) / refract->width, float(Core::height) / refract->height, 0.075f, 0.02f)); 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); refract->bind(sDiffuse);
reflect->bind(sReflect); reflect->bind(sReflect);
item.data[0]->bind(sNormal); item.data[0]->bind(sNormal);
Core::setCulling(cfNone); 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->renderQuad();
//level->mesh->renderPlane();
//glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
Core::setCulling(cfFront); Core::setCulling(cfFront);
} }
} }
@@ -561,6 +591,16 @@ struct Level {
} }
} lightCache; } 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) { Level(Stream &stream, bool demo, bool home) : level(stream, demo), lara(NULL), time(0.0f) {
#ifdef _DEBUG #ifdef _DEBUG
Debug::init(); Debug::init();
@@ -576,16 +616,16 @@ struct Level {
switch (entity.type) { switch (entity.type) {
case TR::Entity::LARA : case TR::Entity::LARA :
case TR::Entity::CUT_1 : case TR::Entity::CUT_1 :
entity.controller = (lara = new Lara(&level, i, home)); entity.controller = (lara = new Lara(this, i, home));
break; break;
case TR::Entity::ENEMY_WOLF : case TR::Entity::ENEMY_WOLF :
entity.controller = new Wolf(&level, i); entity.controller = new Wolf(this, i);
break; break;
case TR::Entity::ENEMY_BEAR : case TR::Entity::ENEMY_BEAR :
entity.controller = new Bear(&level, i); entity.controller = new Bear(this, i);
break; break;
case TR::Entity::ENEMY_BAT : case TR::Entity::ENEMY_BAT :
entity.controller = new Bat(&level, i); entity.controller = new Bat(this, i);
break; break;
case TR::Entity::ENEMY_TWIN : case TR::Entity::ENEMY_TWIN :
case TR::Entity::ENEMY_CROCODILE_LAND : case TR::Entity::ENEMY_CROCODILE_LAND :
@@ -602,7 +642,7 @@ struct Level {
case TR::Entity::ENEMY_CENTAUR : case TR::Entity::ENEMY_CENTAUR :
case TR::Entity::ENEMY_MUMMY : case TR::Entity::ENEMY_MUMMY :
case TR::Entity::ENEMY_LARSON : case TR::Entity::ENEMY_LARSON :
entity.controller = new Enemy(&level, i, 100); entity.controller = new Enemy(this, i, 100);
break; break;
case TR::Entity::DOOR_1 : case TR::Entity::DOOR_1 :
case TR::Entity::DOOR_2 : case TR::Entity::DOOR_2 :
@@ -612,61 +652,61 @@ struct Level {
case TR::Entity::DOOR_6 : case TR::Entity::DOOR_6 :
case TR::Entity::DOOR_BIG_1 : case TR::Entity::DOOR_BIG_1 :
case TR::Entity::DOOR_BIG_2 : case TR::Entity::DOOR_BIG_2 :
entity.controller = new Door(&level, i); entity.controller = new Door(this, i);
break; break;
case TR::Entity::TRAP_DOOR_1 : case TR::Entity::TRAP_DOOR_1 :
case TR::Entity::TRAP_DOOR_2 : case TR::Entity::TRAP_DOOR_2 :
entity.controller = new TrapDoor(&level, i); entity.controller = new TrapDoor(this, i);
break; break;
case TR::Entity::BRIDGE_0 : case TR::Entity::BRIDGE_0 :
case TR::Entity::BRIDGE_1 : case TR::Entity::BRIDGE_1 :
case TR::Entity::BRIDGE_2 : case TR::Entity::BRIDGE_2 :
entity.controller = new Bridge(&level, i); entity.controller = new Bridge(this, i);
break; break;
case TR::Entity::GEARS_1 : case TR::Entity::GEARS_1 :
case TR::Entity::GEARS_2 : case TR::Entity::GEARS_2 :
case TR::Entity::GEARS_3 : case TR::Entity::GEARS_3 :
entity.controller = new Boulder(&level, i); entity.controller = new Boulder(this, i);
break; break;
case TR::Entity::TRAP_FLOOR : case TR::Entity::TRAP_FLOOR :
entity.controller = new TrapFloor(&level, i); entity.controller = new TrapFloor(this, i);
break; break;
case TR::Entity::CRYSTAL : case TR::Entity::CRYSTAL :
entity.controller = new Crystal(&level, i); entity.controller = new Crystal(this, i);
break; break;
case TR::Entity::TRAP_BLADE : case TR::Entity::TRAP_BLADE :
case TR::Entity::TRAP_SPIKES : case TR::Entity::TRAP_SPIKES :
entity.controller = new Trigger(&level, i, true); entity.controller = new Trigger(this, i, true);
break; break;
case TR::Entity::TRAP_BOULDER : case TR::Entity::TRAP_BOULDER :
entity.controller = new Boulder(&level, i); entity.controller = new Boulder(this, i);
break; break;
case TR::Entity::TRAP_DARTGUN : case TR::Entity::TRAP_DARTGUN :
entity.controller = new Dartgun(&level, i); entity.controller = new Dartgun(this, i);
break; break;
case TR::Entity::BLOCK_1 : case TR::Entity::BLOCK_1 :
case TR::Entity::BLOCK_2 : case TR::Entity::BLOCK_2 :
entity.controller = new Block(&level, i); entity.controller = new Block(this, i);
break; break;
case TR::Entity::SWITCH : case TR::Entity::SWITCH :
case TR::Entity::SWITCH_WATER : case TR::Entity::SWITCH_WATER :
case TR::Entity::HOLE_PUZZLE : case TR::Entity::HOLE_PUZZLE :
case TR::Entity::HOLE_KEY : case TR::Entity::HOLE_KEY :
entity.controller = new Trigger(&level, i, false); entity.controller = new Trigger(this, i, false);
break; break;
case TR::Entity::WATERFALL : case TR::Entity::WATERFALL :
entity.controller = new Waterfall(&level, i); entity.controller = new Waterfall(this, i);
break; break;
default : default :
if (entity.modelIndex > 0) if (entity.modelIndex > 0)
entity.controller = new Controller(&level, i); entity.controller = new Controller(this, i);
else else
entity.controller = new Sprite(&level, i, 0); entity.controller = new Sprite(this, i, 0);
} }
} }
ASSERT(lara != NULL); ASSERT(lara != NULL);
camera = new Camera(&level, lara); camera = new Camera(this, lara);
level.cameraController = camera; level.cameraController = camera;
@@ -905,6 +945,9 @@ struct Level {
// room geometry & sprites // room geometry & sprites
if (!room.flags.rendered) { // skip if already rendered if (!room.flags.rendered) { // skip if already rendered
if (room.flags.water)
waterCache->setVisible(roomIndex);
room.flags.rendered = true; room.flags.rendered = true;
if (Core::pass != Core::passShadow) { if (Core::pass != Core::passShadow) {
@@ -1265,7 +1308,7 @@ struct Level {
} }
vec3 p = lara->pos + lara->getDir() * 256.0f; 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); 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 } else
lastStateK = false; lastStateK = false;
@@ -1284,19 +1327,23 @@ struct Level {
glLoadIdentity(); glLoadIdentity();
glOrtho(0, Core::width, 0, Core::height, 0, 1); 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); glEnable(GL_TEXTURE_2D);
glDisable(GL_CULL_FACE); glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
glDisable(GL_BLEND); glDisable(GL_BLEND);
glColor3f(1, 1, 1); glColor3f(10, 10, 10);
glBegin(GL_QUADS); glBegin(GL_QUADS);
glTexCoord2f(0, 0); glVertex2f(0, 0); glTexCoord2f(0, 0); glVertex2f(0, 0);
glTexCoord2f(1, 0); glVertex2f(256, 0); glTexCoord2f(1, 0); glVertex2f(256, 0);
glTexCoord2f(1, 1); glVertex2f(256, 256); glTexCoord2f(1, 1); glVertex2f(256, 256);
glTexCoord2f(0, 1); glVertex2f(0, 256); glTexCoord2f(0, 1); glVertex2f(0, 256);
glEnd(); glEnd();
glColor3f(1, 1, 1);
glDisable(GL_TEXTURE_2D); glDisable(GL_TEXTURE_2D);
glEnable(GL_CULL_FACE); glEnable(GL_CULL_FACE);
@@ -1310,7 +1357,7 @@ struct Level {
// Debug::Level::rooms(level, lara->pos, lara->getEntity().room); // Debug::Level::rooms(level, lara->pos, lara->getEntity().room);
// Debug::Level::lights(level, lara->getRoomIndex()); Debug::Level::lights(level, lara->getRoomIndex());
// Debug::Level::sectors(level, lara->getRoomIndex(), (int)lara->pos.y); // Debug::Level::sectors(level, lara->getRoomIndex(), (int)lara->pos.y);
// Core::setDepthTest(false); // Core::setDepthTest(false);
// Debug::Level::portals(level); // Debug::Level::portals(level);

View File

@@ -518,16 +518,16 @@ struct MeshBuilder {
if (a.y != b.y || a.y != c.y || a.y != d.y) // skip non-horizontal or non-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; 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 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; 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]; 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)) || 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))) { (yb == 0 && s.roomBelow != TR::NO_ROOM && (level->rooms[s.roomBelow].flags.water ^ room.flags.water))) {
f.vertices[0] = 0xFFFF; // mark as unused f.vertices[0] = 0xFFFF; // mark as unused
@@ -547,16 +547,16 @@ struct MeshBuilder {
if (a.y != b.y || a.y != c.y) // skip non-horizontal or non-portal plane primitive if (a.y != b.y || a.y != c.y) // skip non-horizontal or non-portal plane primitive
continue; 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 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; int sz = (int(a.z) + int(b.z) + int(c.z)) / 3 / 1024;
TR::Room::Sector &s = room.sectors[sx * room.zSectors + sz]; 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)) || 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))) { (yb <= 1 && s.roomBelow != TR::NO_ROOM && (level->rooms[s.roomBelow].flags.water ^ room.flags.water))) {
f.vertices[0] = 0xFFFF; // mark as unused f.vertices[0] = 0xFFFF; // mark as unused

View File

@@ -27,6 +27,7 @@ uniform int uType;
#ifdef PASS_COMPOSE #ifdef PASS_COMPOSE
uniform int uCaustics; uniform int uCaustics;
uniform vec4 uParam; uniform vec4 uParam;
uniform vec4 uRoomSize; // xy - minXZ, zw - maxXZ
#endif #endif
#ifdef VERTEX #ifdef VERTEX
@@ -42,7 +43,6 @@ uniform int uType;
uniform vec3 uViewPos; uniform vec3 uViewPos;
uniform vec2 uAnimTexRanges[MAX_RANGES]; uniform vec2 uAnimTexRanges[MAX_RANGES];
uniform vec2 uAnimTexOffsets[MAX_OFFSETS]; uniform vec2 uAnimTexOffsets[MAX_OFFSETS];
uniform vec4 uRoomSize; // xy - minXZ, zw - maxXZ
#endif #endif
attribute vec4 aCoord; attribute vec4 aCoord;
@@ -102,7 +102,7 @@ uniform int uType;
float sum = coord.x + coord.y + coord.z; float sum = coord.x + coord.y + coord.z;
vColor.xyz *= abs(sin(sum / 512.0 + uParam.x)) * 1.5 + 0.5; // color dodge 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; vViewVec = uViewPos - coord.xyz;
vLightProj = uLightProj * coord; vLightProj = uLightProj * coord;
@@ -228,7 +228,11 @@ uniform int uType;
} }
float calcCaustics(vec3 n) { 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 #endif

View File

@@ -5,11 +5,11 @@
enum AttribType { aCoord, aTexCoord, aNormal, aColor, aMAX }; enum AttribType { aCoord, aTexCoord, aNormal, aColor, aMAX };
enum SamplerType { sDiffuse, sNormal, sReflect, sShadow, sEnvironment, sMAX }; enum SamplerType { sDiffuse, sNormal, sReflect, sShadow, sEnvironment, sMAX };
enum UniformType { uType, uCaustics, uParam, uViewProj, uViewInv, uBasis, uLightProj, uColor, uAmbient, uViewPos, uLightsCount, uLightPos, uLightColor, uAnimTexRanges, uAnimTexOffsets, uRoomSize, 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 *AttribName[aMAX] = { "aCoord", "aTexCoord", "aNormal", "aColor" };
const char *SamplerName[sMAX] = { "sDiffuse", "sNormal", "sReflect", "sShadow", "sEnvironment" }; const char *SamplerName[sMAX] = { "sDiffuse", "sNormal", "sReflect", "sShadow", "sEnvironment" };
const char *UniformName[uMAX] = { "uType", "uCaustics", "uParam", "uViewProj", "uViewInv", "uBasis", "uLightProj", "uColor", "uAmbient", "uViewPos", "uLightsCount", "uLightPos", "uLightColor", "uAnimTexRanges", "uAnimTexOffsets", "uRoomSize", "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 { struct Shader {
GLuint ID; GLuint ID;

View File

@@ -465,8 +465,8 @@ namespace Sound {
int idxA = int(t); int idxA = int(t);
int idxB = (j == (count - 1)) ? idxA : (idxA + 1); int idxB = (j == (count - 1)) ? idxA : (idxA + 1);
float k = t - idxA; float k = t - idxA;
result[j].L += lerp(buffer[idxA].L, buffer[idxB].L, k); result[j].L += int(lerp(buffer[idxA].L, buffer[idxB].L, k));
result[j].R += lerp(buffer[idxA].R, buffer[idxB].R, k); result[j].R += int(lerp(buffer[idxA].R, buffer[idxB].R, k));
} }
} }
} }

View File

@@ -14,7 +14,7 @@ struct Sprite : Controller {
int frame, flag; int frame, flag;
float time; 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 if (frame >= 0) { // specific frame
this->frame = frame; this->frame = frame;
} else if (frame == FRAME_RANDOM) { // random 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); int index = level->entityAdd(type, room, x, y, z, 0, -1);
if (index > -1) { if (index > -1) {
level->entities[index].intensity = 0x1FFF - level->rooms[room].ambient; 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);
} }
} }

View File

@@ -11,12 +11,10 @@ struct Texture {
Format format; Format format;
bool cube; 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); glGenTextures(1, &ID);
bind(0); bind(0);
bool filter = true;
GLenum target = cube ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D; GLenum target = cube ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D;
if (format == SHADOW && !Core::support.shadowSampler) { if (format == SHADOW && !Core::support.shadowSampler) {

View File

@@ -11,7 +11,7 @@ struct Trigger : Controller {
float timer; float timer;
int baseState; 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; baseState = state;
getEntity().flags.collision = false; getEntity().flags.collision = false;
} }
@@ -65,7 +65,7 @@ struct Dart : Controller {
vec3 dir; vec3 dir;
bool inWall; // dart starts from wall 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)); dir = vec3(sinf(angle.y), 0, cosf(angle.y));
} }
@@ -80,7 +80,7 @@ struct Dart : Controller {
TR::Entity &e = getEntity(); TR::Entity &e = getEntity();
vec3 p = pos - dir * 64.0f; // wall offset = 64 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); level->entityRemove(entity);
delete this; delete this;
@@ -93,7 +93,7 @@ struct Dart : Controller {
struct Dartgun : Trigger { struct Dartgun : Trigger {
vec3 origin; 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) { virtual bool activate(ActionCommand *cmd) {
if (!Trigger::activate(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); 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) 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); playSound(TR::SND_DART, pos, Sound::Flags::PAN);
@@ -119,7 +119,7 @@ struct Dartgun : Trigger {
struct Boulder : 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() { virtual void update() {
if (getEntity().flags.active) { if (getEntity().flags.active) {
@@ -138,7 +138,7 @@ struct Block : Controller {
STATE_PULL, STATE_PULL,
}; };
Block(TR::Level *level, int entity) : Controller(level, entity) { Block(IGame *game, int entity) : Controller(game, entity) {
updateFloor(true); updateFloor(true);
} }
@@ -181,7 +181,7 @@ struct Block : Controller {
struct Door : Trigger { struct Door : Trigger {
int8 *floor[2], orig[2]; 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::Entity &e = getEntity();
TR::Level::FloorInfo info; TR::Level::FloorInfo info;
vec3 p = pos - getDir() * 1024.0f; vec3 p = pos - getDir() * 1024.0f;
@@ -222,7 +222,7 @@ struct Door : Trigger {
struct TrapDoor : 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; getEntity().flags.collision = true;
} }
@@ -245,7 +245,7 @@ struct TrapFloor : Trigger {
}; };
float velocity; 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(); TR::Entity &e = getEntity();
e.flags.collision = true; e.flags.collision = true;
} }
@@ -283,7 +283,7 @@ struct TrapFloor : Trigger {
struct Bridge : 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; getEntity().flags.collision = true;
} }
}; };
@@ -291,7 +291,7 @@ struct Bridge : Trigger {
struct Crystal : Controller { struct Crystal : Controller {
Texture *environment; 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); environment = new Texture(64, 64, Texture::RGBA, true);
} }
@@ -318,7 +318,7 @@ struct Waterfall : Trigger {
float dropStrength; float dropStrength;
vec3 dropPos; 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() { virtual void update() {
drop = false; drop = false;
@@ -335,10 +335,10 @@ struct Waterfall : Trigger {
drop = true; drop = true;
dropPos = pos + vec3(randf() * 1024.0f - 512.0f, 0.0f, randf() * 1024.0f - 512.0f); dropPos = pos + vec3(randf() * 1024.0f - 512.0f, 0.0f, randf() * 1024.0f - 512.0f);
dropRadius = randf() + 0.5f; dropRadius = randf() * 256.0f + 128.0f;
dropStrength = randf() * 0.25f; 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 #undef SPLASH_TIMESTEP

View File

@@ -23,7 +23,9 @@ uniform int uType;
uniform vec3 uViewPos; uniform vec3 uViewPos;
uniform mat4 uViewProj; uniform mat4 uViewProj;
uniform vec3 uPosScale[2]; uniform vec3 uPosScale[2];
uniform float uScale;
uniform vec4 uTexParam;
uniform vec4 uParam;
uniform sampler2D sNormal; uniform sampler2D sNormal;
@@ -34,10 +36,9 @@ uniform sampler2D sNormal;
attribute vec4 aCoord; attribute vec4 aCoord;
void main() { void main() {
vTexCoord = aCoord.xy * 0.5 + 0.5; vTexCoord = (aCoord.xy * 0.5 + 0.5) * uTexParam.zw;
if (uType >= WATER_MASK) { if (uType >= WATER_MASK) {
// hardcoded pool geometry
vCoord = vec3(aCoord.x, 0.0, aCoord.y) * uPosScale[1] + uPosScale[0]; vCoord = vec3(aCoord.x, 0.0, aCoord.y) * uPosScale[1] + uPosScale[0];
vec4 cp = uViewProj * vec4(vCoord, 1.0); vec4 cp = uViewProj * vec4(vCoord, 1.0);
@@ -48,15 +49,14 @@ uniform sampler2D sNormal;
if (uType == WATER_CAUSTICS) { if (uType == WATER_CAUSTICS) {
vec3 rCoord = vec3(aCoord.x, 0.0, aCoord.y) * uPosScale[1]; vec3 rCoord = vec3(aCoord.x, 0.0, aCoord.y) * uPosScale[1];
vec4 info = texture2D(sNormal, rCoord.xz * 0.5 + 0.5); vec4 info = texture2D(sNormal, (rCoord.xz * 0.5 + 0.5) * uTexParam.zw);
info.ba *= 0.5;
vec3 normal = vec3(info.b, -sqrt(1.0 - dot(info.ba, info.ba)), info.a); 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 light = vec3(0.0, -1.0, 0.0);
vec3 refractedLight = refract(-light, vec3(0.0, 1.0, 0.0), ETA_AIR / ETA_WATER); vec3 refractedLight = refract(-light, vec3(0.0, 1.0, 0.0), ETA_AIR / ETA_WATER);
vec3 ray = refract(-light, normal, 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; 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); gl_Position = vec4((vRefPos2.xz + 0.0 * refractedLight.xz / refractedLight.y), 0.0, 1.0);
@@ -71,69 +71,79 @@ uniform sampler2D sNormal;
#else #else
uniform sampler2D sDiffuse; uniform sampler2D sDiffuse;
uniform sampler2D sReflect; uniform sampler2D sReflect;
uniform sampler2D sEnvironment;
uniform vec4 uParam; // texture size
uniform vec3 uLightPos; uniform vec3 uLightPos;
uniform vec4 uLightColor; uniform vec4 uLightColor;
#define PI 3.141592653589793 #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 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); return clamp(fbias + (1.0 - fbias) * pow(f, fpow), 0.0, 1.0);
} }
vec4 drop() { vec4 drop() {
vec4 value = texture2D(sDiffuse, vTexCoord); vec2 tc = gl_FragCoord.xy * uTexParam.xy;
float drop = max(0.0, 1.0 - length(uParam.xy - vTexCoord) / uParam.z); 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; drop = 0.5 - cos(drop * PI) * 0.5;
value.r += drop * uParam.w; v.x += drop * uParam.w;
return value;
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() { vec4 step() {
vec2 dx = vec2(uParam.x, 0.0); vec2 tc = gl_FragCoord.xy * uTexParam.xy;
vec2 dy = vec2(0.0, uParam.y);
vec4 v = texture2D(sDiffuse, vTexCoord); vec4 v = texture2D(sDiffuse, tc); // height, speed, normal.xz
vec4 f = vec4(texture2D(sDiffuse, vTexCoord + dx).r, texture2D(sDiffuse, vTexCoord + dy).r,
texture2D(sDiffuse, vTexCoord - dx).r, texture2D(sDiffuse, vTexCoord - dy).r); /*
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)); float average = dot(f, vec4(0.25));
// normal // normal
f.xy -= v.r; f.xy -= v.x;
vec3 nx = vec3(uParam.x, f.x, 0.0); vec3 nx = vec3(d.x, f.x, 0.0);
vec3 ny = vec3(0.0, f.y, uParam.y); vec3 ny = vec3(0.0, f.y, d.y);
v.ba = normalize(cross(ny, nx)).xz; v.zw = normalize(cross(ny, nx)).xz * 0.5;
// velocity // velocity
v.g += (average - v.r) * 2.0; v.y += (average - v.x) * 1.9;
v.g *= 0.995; v.y *= uParam.x; // fadeout
// amplitude // 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 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 area1 = length(dFdx(vRefPos1)) * length(dFdy(vRefPos1));
float area2 = length(dFdx(vRefPos2)) * length(dFdy(vRefPos2)); float area2 = length(dFdx(vRefPos2)) * length(dFdy(vRefPos2));
return vec4(vec3(area1 / area2 * 0.2), 1.0); return vec4(vec3(area1 / area2 * 0.2), 1.0);
} }
@@ -146,7 +156,6 @@ uniform sampler2D sNormal;
vec4 value = texture2D(sNormal, vTexCoord); 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)); 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; vec2 dudv = (uViewProj * vec4(normal.x, 0.0, normal.z, 0.0)).xy;