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