1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-08-08 06:06:51 +02:00

#23 water caustics, render target cache

This commit is contained in:
XProger
2017-02-06 04:37:56 +03:00
parent 40378ebd20
commit 831e072943
15 changed files with 188 additions and 92 deletions

Binary file not shown.

View File

@@ -48,8 +48,7 @@ struct Camera : Controller {
virtual bool activate(ActionCommand *cmd) { virtual bool activate(ActionCommand *cmd) {
Controller::activate(cmd); Controller::activate(cmd);
if (cmd->timer) this->timer = max(max(1.0f, this->timer), cmd->timer);
this->timer = cmd->timer;
if (cmd->action == TR::Action::CAMERA_TARGET) if (cmd->action == TR::Action::CAMERA_TARGET)
actTargetEntity = cmd->value; actTargetEntity = cmd->value;
if (cmd->action == TR::Action::CAMERA_SWITCH) { if (cmd->action == TR::Action::CAMERA_SWITCH) {

View File

@@ -13,6 +13,7 @@
#define MAX_LAYERS 4 #define MAX_LAYERS 4
struct IGame { struct IGame {
virtual ~IGame() {}
virtual TR::Level* getLevel() { return NULL; } virtual TR::Level* getLevel() { return NULL; }
virtual void waterDrop(const vec3 &pos, float radius, float strength) {} virtual void waterDrop(const vec3 &pos, float radius, float strength) {}
}; };
@@ -203,10 +204,10 @@ struct Controller {
float volume = (float)b.volume / 0x7FFF; float volume = (float)b.volume / 0x7FFF;
float pitch = b.flags.pitch ? (0.9f + randf() * 0.2f) : 1.0f; float pitch = b.flags.pitch ? (0.9f + randf() * 0.2f) : 1.0f;
if (b.flags.mode == 1) flags |= Sound::UNIQUE; if (b.flags.mode == 1) flags |= Sound::UNIQUE;
if (b.flags.mode == 2) flags |= Sound::REPLAY; //if (b.flags.mode == 2) flags |= Sound::REPLAY;
if (b.flags.mode == 3) flags |= Sound::SYNC; if (b.flags.mode == 3) flags |= Sound::SYNC;
if (b.flags.gain) volume = max(0.0f, volume - randf() * 0.25f); if (b.flags.gain) volume = max(0.0f, volume - randf() * 0.25f);
if (b.flags.fixed) flags &= ~Sound::PAN; if (b.flags.fixed) flags |= Sound::LOOP;
Sound::play(level->getSampleStream(index), pos, volume, pitch, flags, entity * 1000 + index); Sound::play(level->getSampleStream(index), pos, volume, pitch, flags, entity * 1000 + index);
} }
} }

View File

@@ -112,7 +112,7 @@
#define MAX_LIGHTS 3 #define MAX_LIGHTS 3
#define MAX_CACHED_LIGHTS 3 #define MAX_CACHED_LIGHTS 3
#define MAX_RENDER_BUFFERS 11 #define MAX_RENDER_BUFFERS 32
struct Shader; struct Shader;
struct Texture; struct Texture;
@@ -155,11 +155,18 @@ namespace Core {
enum Pass { passCompose, passShadow, passAmbient, passFilter, passWater } pass; enum Pass { passCompose, passShadow, passAmbient, passFilter, passWater } pass;
GLuint FBO; GLuint FBO;
GLuint renderBuffers[2][MAX_RENDER_BUFFERS]; struct RenderTargetCache {
int count;
struct Item {
GLuint ID;
int width;
int height;
} items[MAX_RENDER_BUFFERS];
} rtCache[2];
struct { struct {
Shader *shader; Shader *shader;
Texture *testures[8]; Texture *textures[8];
GLuint VAO; GLuint VAO;
} active; } active;
@@ -267,15 +274,7 @@ namespace Core {
LOG("\n"); LOG("\n");
glGenFramebuffers(1, &FBO); glGenFramebuffers(1, &FBO);
memset(rtCache, 0, sizeof(rtCache));
glGenRenderbuffers(MAX_RENDER_BUFFERS * 2, &renderBuffers[0][0]);
for (int j = 0; j < 2; j++)
for (int i = 0; i < MAX_RENDER_BUFFERS; i++) {
glBindRenderbuffer(GL_RENDERBUFFER, renderBuffers[j][i]);
glRenderbufferStorage(GL_RENDERBUFFER, j ? GL_RGB565 : GL_DEPTH_COMPONENT16, 1 << i, 1 << i);
}
glBindRenderbuffer(GL_RENDERBUFFER, 0);
Sound::init(); Sound::init();
@@ -293,11 +292,40 @@ namespace Core {
void free() { void free() {
delete blackTex; delete blackTex;
delete whiteTex; delete whiteTex;
// glDeleteRenderBuffers(MAX_RENDER_BUFFERS * 2, &renderBuffers[0][0]); /*
// glDeleteFrameBuffers(1, &FBO); glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDeleteFrameBuffers(1, &FBO);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
for (int b = 0; b < 2; b++)
for (int i = 0; i < rtCache[b].count; i++)
glDeleteRenderBuffers(1, &rtCache[b].items[i].ID);
*/
Sound::free(); Sound::free();
} }
int cacheRenderTarget(bool depth, int width, int height) {
RenderTargetCache &cache = rtCache[depth];
for (int i = 0; i < cache.count; i++)
if (cache.items[i].width == width && cache.items[i].height == height)
return i;
ASSERT(cache.count < MAX_RENDER_BUFFERS);
RenderTargetCache::Item &item = cache.items[cache.count];
glGenRenderbuffers(1, &item.ID);
item.width = width;
item.height = height;
glBindRenderbuffer(GL_RENDERBUFFER, item.ID);
glRenderbufferStorage(GL_RENDERBUFFER, depth ? GL_RGB565 : GL_DEPTH_COMPONENT16, width, height);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
return cache.count++;
}
void clear(const vec4 &color) { void clear(const vec4 &color) {
glClearColor(color.x, color.y, color.z, color.w); glClearColor(color.x, color.y, color.z, color.w);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
@@ -373,17 +401,12 @@ namespace Core {
if (target->cube) if (target->cube)
texTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face; texTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
int i = target->width, dummyBuffer = 0;
while (i > 1) {
dummyBuffer++;
i >>= 1;
}
ASSERT(target->width == (1 << dummyBuffer) )
glBindFramebuffer(GL_FRAMEBUFFER, FBO);
bool depth = target->format == Texture::DEPTH || target->format == Texture::SHADOW; bool depth = target->format == Texture::DEPTH || target->format == Texture::SHADOW;
int rtIndex = cacheRenderTarget(depth, target->width, target->height);
glBindFramebuffer(GL_FRAMEBUFFER, FBO);
glFramebufferTexture2D (GL_FRAMEBUFFER, depth ? GL_DEPTH_ATTACHMENT : GL_COLOR_ATTACHMENT0, texTarget, target->ID, 0); glFramebufferTexture2D (GL_FRAMEBUFFER, depth ? GL_DEPTH_ATTACHMENT : GL_COLOR_ATTACHMENT0, texTarget, target->ID, 0);
glFramebufferRenderbuffer (GL_FRAMEBUFFER, depth ? GL_COLOR_ATTACHMENT0 : GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderBuffers[depth][dummyBuffer]); glFramebufferRenderbuffer (GL_FRAMEBUFFER, depth ? GL_COLOR_ATTACHMENT0 : GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rtCache[depth].items[rtIndex].ID);
if (depth) if (depth)
glColorMask(false, false, false, false); glColorMask(false, false, false, false);

View File

@@ -38,7 +38,7 @@ namespace Debug {
glUseProgram(0); glUseProgram(0);
Core::active.shader = NULL; Core::active.shader = NULL;
Core::active.testures[0] = NULL; Core::active.textures[0] = NULL;
} }
void end() { void end() {

View File

@@ -923,7 +923,7 @@ struct Lara : Character {
virtual void hit(int damage, Controller *enemy = NULL) { virtual void hit(int damage, Controller *enemy = NULL) {
health -= damage; health -= damage;
if (enemy && health > 0) if (enemy && health > 0)
playSound(TR::SND_HIT, pos, Sound::PAN); playSound(TR::SND_HIT, pos, Sound::PAN | Sound::REPLAY);
}; };
bool waterOut() { bool waterOut() {
@@ -1394,12 +1394,15 @@ 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) {
game->waterDrop(pos, 256.0f, 0.2f);
Sprite::add(game, 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
} }
if (state == STATE_SWAN_DIVE) { if (state == STATE_SWAN_DIVE) {
angle.x = -PI * 0.5f; angle.x = -PI * 0.5f;
game->waterDrop(pos, 128.0f, 0.2f);
Sprite::add(game, TR::Entity::WATER_SPLASH, getRoomIndex(), (int)pos.x, (int)pos.y, (int)pos.z);
return STATE_DIVE; return STATE_DIVE;
} }
@@ -1413,15 +1416,17 @@ struct Lara : Character {
if (state == STATE_WATER_OUT) return state; if (state == STATE_WATER_OUT) return state;
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) {
game->waterDrop(pos, 128.0f, 0.2f);
return animation.setAnim(ANIM_TO_ONWATER); return animation.setAnim(ANIM_TO_ONWATER);
}
if (state == STATE_SURF_TREAD) { if (state == STATE_SURF_TREAD) {
if (animation.isFrameActive(0)) if (animation.isFrameActive(0))
game->waterDrop(animation.getJoints(getMatrix(), 14).pos, 96.0f, 0.01f); game->waterDrop(animation.getJoints(getMatrix(), 14).pos, 96.0f, 0.03f);
} else { } else {
if (animation.frameIndex % 4 == 0) if (animation.frameIndex % 4 == 0)
game->waterDrop(animation.getJoints(getMatrix(), 14).pos, 96.0f, 0.01f); game->waterDrop(animation.getJoints(getMatrix(), 14).pos, 96.0f, 0.02f);
} }
if (input & FORTH) { if (input & FORTH) {

View File

@@ -180,7 +180,7 @@ struct Level : IGame {
} *ambientCache; } *ambientCache;
struct WaterCache { struct WaterCache {
#define MAX_SURFACES 5 #define MAX_SURFACES 8
#define MAX_INVISIBLE_TIME 5.0f #define MAX_INVISIBLE_TIME 5.0f
#define SIMULATE_TIMESTEP (1.0f / 40.0f) #define SIMULATE_TIMESTEP (1.0f / 40.0f)
#define DETAIL (64.0f / 1024.0f) #define DETAIL (64.0f / 1024.0f)
@@ -191,7 +191,7 @@ struct Level : IGame {
Texture *reflect; Texture *reflect;
struct Item { struct Item {
int from, to; int from, to, caust;
float timer; float timer;
bool visible; bool visible;
bool blank; bool blank;
@@ -204,7 +204,7 @@ struct Level : IGame {
mask = caustics = data[0] = data[1] = NULL; mask = caustics = data[0] = data[1] = NULL;
} }
Item(int from, int to) : from(from), to(to), timer(SIMULATE_TIMESTEP), visible(true), blank(true) { Item(int from, int to) : from(from), to(to), caust(to), timer(SIMULATE_TIMESTEP), visible(true), blank(true) {
mask = caustics = data[0] = data[1] = NULL; mask = caustics = data[0] = data[1] = NULL;
} }
@@ -222,6 +222,8 @@ struct Level : IGame {
maxX = max(maxX, x); maxX = max(maxX, x);
maxZ = max(maxZ, z); maxZ = max(maxZ, z);
posY = s.ceiling * 256; posY = s.ceiling * 256;
if (s.roomBelow != TR::NO_ROOM)
caust = s.roomBelow;
} }
} }
maxX++; maxX++;
@@ -230,15 +232,29 @@ struct Level : IGame {
int w = nextPow2(maxX - minX); int w = nextPow2(maxX - minX);
int h = nextPow2(maxZ - minZ); int h = nextPow2(maxZ - minZ);
uint8 *m = new uint8[w * h]; uint16 *m = new uint16[w * h];
memset(m, 0, w * h); memset(m, 0, w * h * sizeof(m[0]));
for (int z = minZ; z < maxZ; z++) for (int z = minZ; z < maxZ; z++)
for (int x = minX; x < maxX; x++) { for (int x = minX; x < maxX; x++) {
TR::Room::Sector &s = r.sectors[x * r.zSectors + z]; 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;
bool hasWater = (s.roomAbove != TR::NO_ROOM && !level->level.rooms[s.roomAbove].flags.water);
bool hasFlow = false;
if (hasWater) {
TR::Level::FloorInfo info;
level->level.getFloorInfo(to, x + r.info.x, r.info.yBottom, z + r.info.z, info);
if (info.trigCmdCount && info.trigger == TR::Level::Trigger::ACTIVATE)
for (int i = 0; i < info.trigCmdCount; i++)
if (info.trigCmd[i].action == TR::Action::FLOW) {
hasFlow = true;
break;
} }
mask = new Texture(w, h, Texture::RED, false, m, false); }
m[(x - minX) + w * (z - minZ)] = hasWater ? (hasFlow ? 0xFFFF : 0xFF00) : 0;
}
mask = new Texture(w, h, Texture::RGB16, false, m, false);
delete[] m; delete[] m;
size = vec3(float((maxX - minX) * 512), 1.0f, float((maxZ - minZ) * 512)); // half size size = vec3(float((maxX - minX) * 512), 1.0f, float((maxZ - minZ) * 512)); // half size
@@ -246,7 +262,7 @@ struct Level : IGame {
data[0] = new Texture(nextPow2(w * 64), nextPow2(h * 64), Texture::RGBA_HALF, false); 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(512, 512, Texture::RGBA, false); caustics = new Texture(512, 512, Texture::RGB16, false);
blank = false; blank = false;
Core::setTarget(data[0]); Core::setTarget(data[0]);
@@ -276,7 +292,7 @@ struct Level : IGame {
} drops[MAX_DROPS]; } drops[MAX_DROPS];
WaterCache(Level *level) : level(level), refract(NULL), count(0), checkVisibility(false), dropCount(0) { WaterCache(Level *level) : level(level), refract(NULL), count(0), checkVisibility(false), dropCount(0) {
reflect = new Texture(512, 512, Texture::RGBA, false); reflect = new Texture(512, 512, Texture::RGB16, false);
} }
~WaterCache() { ~WaterCache() {
@@ -309,9 +325,9 @@ struct Level : IGame {
void setVisible(int roomIndex, int nextRoom = TR::NO_ROOM) { void setVisible(int roomIndex, int nextRoom = TR::NO_ROOM) {
if (!checkVisibility) return; if (!checkVisibility) return;
if (nextRoom == TR::NO_ROOM) { // setVisible(underwaterRoom) if (nextRoom == TR::NO_ROOM) { // setVisible(underwaterRoom) for caustics update
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
if (items[i].to == roomIndex) { if (items[i].caust == roomIndex) {
nextRoom = items[i].from; nextRoom = items[i].from;
if (!items[i].visible) { if (!items[i].visible) {
items[i].visible = true; items[i].visible = true;
@@ -350,7 +366,7 @@ struct Level : IGame {
void bindCaustics(int roomIndex) { void bindCaustics(int roomIndex) {
Item *item = NULL; Item *item = NULL;
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
if (items[i].to == roomIndex) { if (items[i].caust == roomIndex) {
item = &items[i]; item = &items[i];
break; break;
} }
@@ -390,8 +406,6 @@ struct Level : IGame {
level->mesh->renderQuad(); level->mesh->renderQuad();
swap(item.data[0], item.data[1]); swap(item.data[0], item.data[1]);
} }
dropCount = 0;
} }
void step(Item &item) { void step(Item &item) {
@@ -458,7 +472,7 @@ struct Level : IGame {
// get refraction texture // get refraction texture
if (!refract || Core::width > refract->width || Core::height > refract->height) { if (!refract || Core::width > refract->width || Core::height > refract->height) {
delete refract; delete refract;
refract = new Texture(nextPow2(Core::width), nextPow2(Core::height), Texture::RGBA, false); refract = new Texture(nextPow2(Core::width), nextPow2(Core::height), Texture::RGBA16, false);
} }
Core::copyTarget(refract, 0, 0, 0, 0, Core::width, Core::height); // copy framebuffer into refraction texture Core::copyTarget(refract, 0, 0, 0, 0, Core::width, Core::height); // copy framebuffer into refraction texture
@@ -500,12 +514,11 @@ struct Level : IGame {
item.mask->bind(sMask); item.mask->bind(sMask);
if (item.timer >= SIMULATE_TIMESTEP || dropCount) { if (item.timer >= SIMULATE_TIMESTEP || dropCount) {
Core::active.shader->setParam(uTexParam, vec4(1.0f / item.data[0]->width, 1.0f / item.data[0]->height, 1.0f, 1.0f)); Core::active.shader->setParam(uTexParam, vec4(1.0f / item.data[0]->width, 1.0f / item.data[0]->height, 1.0f, 1.0f));
// add water drops
drop(item); drop(item);
// simulation step
step(item); step(item);
} }
Core::setTarget(NULL); Core::setTarget(NULL);
@@ -526,7 +539,7 @@ struct Level : IGame {
Core::active.shader->setParam(uViewPos, Core::viewPos); Core::active.shader->setParam(uViewPos, Core::viewPos);
Core::active.shader->setParam(uLightPos, Core::lightPos[0], 1); Core::active.shader->setParam(uLightPos, Core::lightPos[0], 1);
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.05f, 0.02f));
float sx = item.size.x * DETAIL / (item.data[0]->width / 2); float sx = item.size.x * DETAIL / (item.data[0]->width / 2);
float sz = item.size.z * DETAIL / (item.data[0]->height / 2); float sz = item.size.z * DETAIL / (item.data[0]->height / 2);
@@ -546,6 +559,7 @@ struct Level : IGame {
Core::setCulling(cfFront); Core::setCulling(cfFront);
} }
dropCount = 0;
} }
#undef MAX_WATER_SURFACES #undef MAX_WATER_SURFACES
@@ -717,9 +731,13 @@ struct Level : IGame {
waterCache = new WaterCache(this); waterCache = new WaterCache(this);
initReflections(); initReflections();
for (int i = 0; i < level.soundSourcesCount; i++) {
TR::SoundSource &src = level.soundSources[i];
lara->playSound(src.id, vec3(src.x, src.y, src.z), Sound::PAN | Sound::LOOP);
}
} }
~Level() { virtual ~Level() {
#ifdef _DEBUG #ifdef _DEBUG
Debug::free(); Debug::free();
#endif #endif
@@ -931,6 +949,14 @@ struct Level : IGame {
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);
/*
// trace to water surface room
int wrIndex = roomIndex;
room.sectors[sx * room.zSectors + sz];
int sx = room.xSectors
*/
waterCache->bindCaustics(roomIndex); 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);
@@ -1299,6 +1325,15 @@ struct Level : IGame {
#ifdef _DEBUG #ifdef _DEBUG
camera->setup(true); camera->setup(true);
static int snd_index = 0;
if (Input::down[ikG]) {
snd_index = (snd_index + 1) % level.soundsInfoCount;
LOG("play sound: %d\n", snd_index);
lara->playSound(snd_index, lara->pos, 0);
Input::down[ikG] = false;
}
/*
static int modelIndex = 0; static int modelIndex = 0;
static bool lastStateK = false; static bool lastStateK = false;
static int lastEntity = -1; static int lastEntity = -1;
@@ -1322,7 +1357,7 @@ struct Level : IGame {
if (lastEntity > -1) if (lastEntity > -1)
renderEntity(level.entities[lastEntity]); renderEntity(level.entities[lastEntity]);
// renderModel(level.models[modelIndex], level.entities[4]); // renderModel(level.models[modelIndex], level.entities[4]);
*/
Debug::begin(); Debug::begin();
glMatrixMode(GL_MODELVIEW); glMatrixMode(GL_MODELVIEW);
@@ -1343,11 +1378,13 @@ struct Level : IGame {
glDisable(GL_BLEND); glDisable(GL_BLEND);
glColor3f(10, 10, 10); glColor3f(10, 10, 10);
int w = Core::active.textures[sDiffuse]->width / 2;
int h = Core::active.textures[sDiffuse]->height / 2;
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(w, 0);
glTexCoord2f(1, 1); glVertex2f(256, 256); glTexCoord2f(1, 1); glVertex2f(w, h);
glTexCoord2f(0, 1); glVertex2f(0, 256); glTexCoord2f(0, 1); glVertex2f(0, h);
glEnd(); glEnd();
glColor3f(1, 1, 1); glColor3f(1, 1, 1);
@@ -1369,7 +1406,7 @@ struct Level : IGame {
// Debug::Level::portals(level); // Debug::Level::portals(level);
// Core::setDepthTest(true); // Core::setDepthTest(true);
// Debug::Level::meshes(level); // Debug::Level::meshes(level);
// Debug::Level::entities(level); Debug::Level::entities(level);
/* /*
static int dbg_ambient = 0; static int dbg_ambient = 0;
dbg_ambient = int(time * 2) % 4; dbg_ambient = int(time * 2) % 4;

View File

@@ -39,7 +39,7 @@ struct MeshRange {
} }
}; };
#define PLANE_DETAIL 100 #define PLANE_DETAIL 48
struct Mesh { struct Mesh {
GLuint ID[2]; GLuint ID[2];

View File

@@ -2,7 +2,7 @@
cls cls
set SRC=main.cpp set SRC=main.cpp
set PROJ=OpenLara set PROJ=OpenLara
set FLAGS=-O3 -Wno-deprecated-register --llvm-opts 2 -fmax-type-align=2 -std=c++11 -I../../ set FLAGS=-O3 -Wno-deprecated-register --llvm-opts 2 -fmax-type-align=2 -std=c++11 -Wall -I../../
set PRELOAD=./LEVEL2.PSX set PRELOAD=./LEVEL2.PSX
echo. echo.
call em++ %SRC% %FLAGS% -o %PROJ%.js --preload-file %PRELOAD% call em++ %SRC% %FLAGS% -o %PROJ%.js --preload-file %PRELOAD%

View File

@@ -126,5 +126,8 @@
gamepad: PSX controls on XBox controller<br> gamepad: PSX controls on XBox controller<br>
FullScreen: Alt + Enter FullScreen: Alt + Enter
</span> </span>
<script>(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');ga('create', 'UA-60009035-1', 'auto');ga('send', 'pageview');</script>
</body> </body>
</html> </html>

View File

@@ -24,14 +24,18 @@ struct Shader {
Shader(const char *text, const char *defines = "") { Shader(const char *text, const char *defines = "") {
#ifdef MOBILE #ifdef MOBILE
#define GLSL_DEFINE "" #define GLSL_DEFINE ""
#define GLSL_VERT ""
#define GLSL_FRAG "#extension GL_OES_standard_derivatives : enable\n"
#else #else
#define GLSL_DEFINE "#version 120\n" #define GLSL_DEFINE "#version 120\n"
#define GLSL_VERT ""
#define GLSL_FRAG ""
#endif #endif
const int type[2] = { GL_VERTEX_SHADER, GL_FRAGMENT_SHADER }; const int type[2] = { GL_VERTEX_SHADER, GL_FRAGMENT_SHADER };
const char *code[2][3] = { const char *code[2][3] = {
{ GLSL_DEFINE "#define VERTEX\n", defines, text }, { GLSL_DEFINE GLSL_VERT "#define VERTEX\n", defines, text },
{ GLSL_DEFINE "#define FRAGMENT\n", defines, text } { GLSL_DEFINE GLSL_FRAG "#define FRAGMENT\n", defines, text }
}; };
GLchar info[256]; GLchar info[256];

View File

@@ -4,7 +4,7 @@
#include "core.h" #include "core.h"
struct Texture { struct Texture {
enum Format : uint32 { RGBA, RGBA_FLOAT, RGBA_HALF, RED, DEPTH, SHADOW, MAX }; enum Format : uint32 { RGBA, RGB16, RGBA16, RGBA_FLOAT, RGBA_HALF, DEPTH, SHADOW, MAX };
GLuint ID; GLuint ID;
int width, height; int width, height;
@@ -60,9 +60,10 @@ struct Texture {
GLenum type; GLenum type;
} formats[MAX] = { } formats[MAX] = {
{ GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE }, // RGBA { GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE }, // RGBA
{ GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5 }, // RGB16
{ GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1 }, // RGBA16
{ GL_RGBA32F, GL_RGBA, GL_FLOAT }, // RGBA_FLOAT { GL_RGBA32F, GL_RGBA, GL_FLOAT }, // RGBA_FLOAT
{ GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT }, // RGBA_HALF { GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT }, // RGBA_HALF
{ GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE }, // RED
{ GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT }, // DEPTH { GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT }, // DEPTH
{ GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT }, // SHADOW { GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT }, // SHADOW
}; };
@@ -80,6 +81,7 @@ struct Texture {
} }
void bind(int sampler) { void bind(int sampler) {
Core::active.textures[sampler] = this;
glActiveTexture(GL_TEXTURE0 + sampler); glActiveTexture(GL_TEXTURE0 + sampler);
glBindTexture(cube ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D, ID); glBindTexture(cube ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D, ID);
} }

View File

@@ -334,9 +334,11 @@ struct Waterfall : Trigger {
timer += SPLASH_TIMESTEP * (1.0f + randf() * 0.25f); timer += SPLASH_TIMESTEP * (1.0f + randf() * 0.25f);
drop = true; drop = true;
dropPos = pos + vec3(randf() * 1024.0f - 512.0f, 0.0f, randf() * 1024.0f - 512.0f); dropRadius = randf() * 128.0f + 128.0f;
dropRadius = 256.0f;//randf() * 128.0f + 128.0f; dropStrength = randf() * 0.1f + 0.05f;
dropStrength = 0.15f;//randf() * 0.1f + 0.05f;
vec2 p = (vec2(randf(), randf()) * 2.0f - 1.0f) * (512.0f - dropRadius);
dropPos = pos + vec3(p.x, 0.0f, p.y);
Sprite::add(game, 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);
} }

View File

@@ -112,11 +112,29 @@ struct vec2 {
vec2(float s) : x(s), y(s) {} vec2(float s) : x(s), y(s) {}
vec2(float x, float y) : x(x), y(y) {} vec2(float x, float y) : x(x), y(y) {}
vec2 operator + (const vec2 &v) const { return vec2(x+v.x, y+v.y); } float& operator [] (int index) const { ASSERT(index >= 0 && index <= 1); return ((float*)this)[index]; }
vec2 operator - (const vec2 &v) const { return vec2(x-v.x, y-v.y); }
vec2 operator * (float s) const { return vec2(x*s, y*s); } bool operator == (float s) const { return x == s && y == s; }
float dot(const vec2 &v) const { return x*v.x + y*v.y; } bool operator != (float s) const { return !(*this == s); }
float cross(const vec2 &v) const { return x*v.y - y*v.x; } vec2 operator - () const { return vec2(-x, -y); }
vec2& operator += (const vec2 &v) { x += v.x; y += v.y; return *this; }
vec2& operator -= (const vec2 &v) { x -= v.x; y -= v.y; return *this; }
vec2& operator *= (const vec2 &v) { x *= v.x; y *= v.y; return *this; }
vec2& operator += (float s) { x += s; y += s; return *this; }
vec2& operator -= (float s) { x -= s; y -= s; return *this; }
vec2& operator *= (float s) { x *= s; y *= s; return *this; }
vec2 operator + (const vec2 &v) const { return vec2(x + v.x, y + v.y); }
vec2 operator - (const vec2 &v) const { return vec2(x - v.x, y - v.y); }
vec2 operator * (const vec2 &v) const { return vec2(x * v.x, y * v.y); }
vec2 operator + (float s) const { return vec2(x + s, y + s ); }
vec2 operator - (float s) const { return vec2(x - s, y - s ); }
vec2 operator * (float s) const { return vec2(x * s, y * s ); }
float dot(const vec2 &v) const { return x * v.x + y * v.y; }
float cross(const vec2 &v) const { return x * v.y - y * v.x; }
float length2() const { return dot(*this); } float length2() const { return dot(*this); }
float length() const { return sqrtf(length2()); } float length() const { return sqrtf(length2()); }
vec2 normal() const { float s = length(); return s == 0.0 ? (*this) : (*this)*(1.0f/s); } vec2 normal() const { float s = length(); return s == 0.0 ? (*this) : (*this)*(1.0f/s); }
@@ -130,24 +148,29 @@ struct vec3 {
vec3(const vec2 &xy, float z = 0.0f) : x(xy.x), y(xy.y), z(z) {} vec3(const vec2 &xy, float z = 0.0f) : x(xy.x), y(xy.y), z(z) {}
vec3(float lng, float lat) : x(sinf(lat) * cosf(lng)), y(-sinf(lng)), z(cosf(lat) * cosf(lng)) {} vec3(float lng, float lat) : x(sinf(lat) * cosf(lng)), y(-sinf(lng)), z(cosf(lat) * cosf(lng)) {}
float& operator [] (int index) const { return ((float*)this)[index]; } float& operator [] (int index) const { ASSERT(index >= 0 && index <= 2); return ((float*)this)[index]; }
bool operator == (float s) const { return x == s && y == s && z == s; } bool operator == (float s) const { return x == s && y == s && z == s; }
bool operator != (float s) const { return !(*this == s); } bool operator != (float s) const { return !(*this == s); }
vec3 operator - () const { return vec3(-x, -y, -z); }
vec3& operator += (const vec3 &v) { x += v.x; y += v.y; z += v.z; return *this; } vec3& operator += (const vec3 &v) { x += v.x; y += v.y; z += v.z; return *this; }
vec3& operator -= (const vec3 &v) { x -= v.x; y -= v.y; z -= v.z; return *this; } vec3& operator -= (const vec3 &v) { x -= v.x; y -= v.y; z -= v.z; return *this; }
vec3& operator *= (const vec3 &v) { x *= v.x; y *= v.y; z *= v.z; return *this; } vec3& operator *= (const vec3 &v) { x *= v.x; y *= v.y; z *= v.z; return *this; }
vec3& operator += (float s) { x += s; y += s; z += s; return *this; }
vec3& operator -= (float s) { x -= s; y -= s; z -= s; return *this; }
vec3& operator *= (float s) { x *= s; y *= s; z *= s; return *this; } vec3& operator *= (float s) { x *= s; y *= s; z *= s; return *this; }
vec3 operator + (const vec3 &v) const { return vec3(x+v.x, y+v.y, z+v.z); } vec3 operator + (const vec3 &v) const { return vec3(x + v.x, y + v.y, z + v.z); }
vec3 operator - (const vec3 &v) const { return vec3(x-v.x, y-v.y, z-v.z); } vec3 operator - (const vec3 &v) const { return vec3(x - v.x, y - v.y, z - v.z); }
vec3 operator * (const vec3 &v) const { return vec3(x*v.x, y*v.y, z*v.z); } vec3 operator * (const vec3 &v) const { return vec3(x * v.x, y * v.y, z * v.z); }
vec3 operator * (float s) const { return vec3(x*s, y*s, z*s); } vec3 operator + (float s) const { return vec3(x + s, y + s, z + s); }
vec3 operator - () const { return vec3(-x, -y, -z); } vec3 operator - (float s) const { return vec3(x - s, y - s, z - s); }
vec3 operator * (float s) const { return vec3(x * s, y * s, z * s); }
float dot(const vec3 &v) const { return x * v.x + y * v.y + z * v.z; }
vec3 cross(const vec3 &v) const { return vec3(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x); }
float dot(const vec3 &v) const { return x*v.x + y*v.y + z*v.z; }
vec3 cross(const vec3 &v) const { return vec3(y*v.z - z*v.y, z*v.x - x*v.z, x*v.y - y*v.x); }
float length2() const { return dot(*this); } float length2() const { return dot(*this); }
float length() const { return sqrtf(length2()); } float length() const { return sqrtf(length2()); }
vec3 normal() const { float s = length(); return s == 0.0f ? (*this) : (*this)*(1.0f/s); } vec3 normal() const { float s = length(); return s == 0.0f ? (*this) : (*this)*(1.0f/s); }

View File

@@ -1,8 +1,5 @@
R"====( R"====(
#ifdef GL_ES #ifdef GL_ES
#ifdef FRAGMENT
#extension GL_OES_standard_derivatives : enable
#endif
precision highp int; precision highp int;
precision highp float; precision highp float;
#endif #endif
@@ -43,7 +40,7 @@ uniform sampler2D sNormal;
float height = 0.0; float height = 0.0;
if (uType == WATER_COMPOSE) { if (uType == WATER_COMPOSE) {
vTexCoord = (aCoord.xy * 0.01 * 0.5 + 0.5) * uTexParam.zw; vTexCoord = (aCoord.xy * (1.0 / 48.0) * 0.5 + 0.5) * uTexParam.zw;
height = texture2D(sNormal, vTexCoord).x; height = texture2D(sNormal, vTexCoord).x;
} }
@@ -120,11 +117,11 @@ uniform sampler2D sNormal;
v.zw = normalize( vec3(f.x - f.z, 64.0 / (1024.0 * 2.0), f.y - f.w) ).xz; v.zw = normalize( vec3(f.x - f.z, 64.0 / (1024.0 * 2.0), f.y - f.w) ).xz;
// integrate // integrate
const float vel = 1.8; const float vel = 1.4;
const float vis = 0.995; const float vis = 0.995;
v.y *= vis;
v.y += (average - v.x) * vel; v.y += (average - v.x) * vel;
v.y *= vis;
v.x += v.y; v.x += v.y;
return v; return v;