mirror of
https://github.com/XProger/OpenLara.git
synced 2025-01-17 21:09:00 +01:00
#23 water caustics, render target cache
This commit is contained in:
parent
40378ebd20
commit
831e072943
BIN
bin/OpenLara.exe
BIN
bin/OpenLara.exe
Binary file not shown.
@ -48,8 +48,7 @@ struct Camera : Controller {
|
||||
|
||||
virtual bool activate(ActionCommand *cmd) {
|
||||
Controller::activate(cmd);
|
||||
if (cmd->timer)
|
||||
this->timer = cmd->timer;
|
||||
this->timer = max(max(1.0f, this->timer), cmd->timer);
|
||||
if (cmd->action == TR::Action::CAMERA_TARGET)
|
||||
actTargetEntity = cmd->value;
|
||||
if (cmd->action == TR::Action::CAMERA_SWITCH) {
|
||||
|
@ -13,6 +13,7 @@
|
||||
#define MAX_LAYERS 4
|
||||
|
||||
struct IGame {
|
||||
virtual ~IGame() {}
|
||||
virtual TR::Level* getLevel() { return NULL; }
|
||||
virtual void waterDrop(const vec3 &pos, float radius, float strength) {}
|
||||
};
|
||||
@ -203,10 +204,10 @@ struct Controller {
|
||||
float volume = (float)b.volume / 0x7FFF;
|
||||
float pitch = b.flags.pitch ? (0.9f + randf() * 0.2f) : 1.0f;
|
||||
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.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);
|
||||
}
|
||||
}
|
||||
|
67
src/core.h
67
src/core.h
@ -112,7 +112,7 @@
|
||||
|
||||
#define MAX_LIGHTS 3
|
||||
#define MAX_CACHED_LIGHTS 3
|
||||
#define MAX_RENDER_BUFFERS 11
|
||||
#define MAX_RENDER_BUFFERS 32
|
||||
|
||||
struct Shader;
|
||||
struct Texture;
|
||||
@ -155,11 +155,18 @@ namespace Core {
|
||||
enum Pass { passCompose, passShadow, passAmbient, passFilter, passWater } pass;
|
||||
|
||||
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 {
|
||||
Shader *shader;
|
||||
Texture *testures[8];
|
||||
Texture *textures[8];
|
||||
GLuint VAO;
|
||||
} active;
|
||||
|
||||
@ -267,15 +274,7 @@ namespace Core {
|
||||
LOG("\n");
|
||||
|
||||
glGenFramebuffers(1, &FBO);
|
||||
|
||||
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);
|
||||
memset(rtCache, 0, sizeof(rtCache));
|
||||
|
||||
Sound::init();
|
||||
|
||||
@ -293,11 +292,40 @@ namespace Core {
|
||||
void free() {
|
||||
delete blackTex;
|
||||
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();
|
||||
}
|
||||
|
||||
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) {
|
||||
glClearColor(color.x, color.y, color.z, color.w);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
@ -373,17 +401,12 @@ namespace Core {
|
||||
if (target->cube)
|
||||
texTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
|
||||
|
||||
int i = target->width, dummyBuffer = 0;
|
||||
while (i > 1) {
|
||||
dummyBuffer++;
|
||||
i >>= 1;
|
||||
}
|
||||
bool depth = target->format == Texture::DEPTH || target->format == Texture::SHADOW;
|
||||
int rtIndex = cacheRenderTarget(depth, target->width, target->height);
|
||||
|
||||
ASSERT(target->width == (1 << dummyBuffer) )
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, FBO);
|
||||
bool depth = target->format == Texture::DEPTH || target->format == Texture::SHADOW;
|
||||
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)
|
||||
glColorMask(false, false, false, false);
|
||||
|
@ -38,7 +38,7 @@ namespace Debug {
|
||||
|
||||
glUseProgram(0);
|
||||
Core::active.shader = NULL;
|
||||
Core::active.testures[0] = NULL;
|
||||
Core::active.textures[0] = NULL;
|
||||
}
|
||||
|
||||
void end() {
|
||||
|
13
src/lara.h
13
src/lara.h
@ -923,7 +923,7 @@ struct Lara : Character {
|
||||
virtual void hit(int damage, Controller *enemy = NULL) {
|
||||
health -= damage;
|
||||
if (enemy && health > 0)
|
||||
playSound(TR::SND_HIT, pos, Sound::PAN);
|
||||
playSound(TR::SND_HIT, pos, Sound::PAN | Sound::REPLAY);
|
||||
};
|
||||
|
||||
bool waterOut() {
|
||||
@ -1394,12 +1394,15 @@ struct Lara : Character {
|
||||
return STATE_PICK_UP;
|
||||
|
||||
if (state == STATE_FORWARD_JUMP || state == STATE_UP_JUMP || state == STATE_BACK_JUMP || state == STATE_LEFT_JUMP || state == STATE_RIGHT_JUMP || state == STATE_FALL || state == STATE_REACH) {
|
||||
game->waterDrop(pos, 256.0f, 0.2f);
|
||||
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
|
||||
}
|
||||
|
||||
if (state == STATE_SWAN_DIVE) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1413,15 +1416,17 @@ struct Lara : Character {
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (state == STATE_SURF_TREAD) {
|
||||
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 {
|
||||
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) {
|
||||
|
89
src/level.h
89
src/level.h
@ -180,7 +180,7 @@ struct Level : IGame {
|
||||
} *ambientCache;
|
||||
|
||||
struct WaterCache {
|
||||
#define MAX_SURFACES 5
|
||||
#define MAX_SURFACES 8
|
||||
#define MAX_INVISIBLE_TIME 5.0f
|
||||
#define SIMULATE_TIMESTEP (1.0f / 40.0f)
|
||||
#define DETAIL (64.0f / 1024.0f)
|
||||
@ -191,7 +191,7 @@ struct Level : IGame {
|
||||
Texture *reflect;
|
||||
|
||||
struct Item {
|
||||
int from, to;
|
||||
int from, to, caust;
|
||||
float timer;
|
||||
bool visible;
|
||||
bool blank;
|
||||
@ -204,7 +204,7 @@ struct Level : IGame {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -222,6 +222,8 @@ struct Level : IGame {
|
||||
maxX = max(maxX, x);
|
||||
maxZ = max(maxZ, z);
|
||||
posY = s.ceiling * 256;
|
||||
if (s.roomBelow != TR::NO_ROOM)
|
||||
caust = s.roomBelow;
|
||||
}
|
||||
}
|
||||
maxX++;
|
||||
@ -230,15 +232,29 @@ struct Level : IGame {
|
||||
int w = nextPow2(maxX - minX);
|
||||
int h = nextPow2(maxZ - minZ);
|
||||
|
||||
uint8 *m = new uint8[w * h];
|
||||
memset(m, 0, w * h);
|
||||
uint16 *m = new uint16[w * h];
|
||||
memset(m, 0, w * h * sizeof(m[0]));
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
m[(x - minX) + w * (z - minZ)] = hasWater ? (hasFlow ? 0xFFFF : 0xFF00) : 0;
|
||||
}
|
||||
mask = new Texture(w, h, Texture::RED, false, m, false);
|
||||
mask = new Texture(w, h, Texture::RGB16, false, m, false);
|
||||
delete[] m;
|
||||
|
||||
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[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;
|
||||
|
||||
Core::setTarget(data[0]);
|
||||
@ -276,7 +292,7 @@ struct Level : IGame {
|
||||
} drops[MAX_DROPS];
|
||||
|
||||
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() {
|
||||
@ -309,9 +325,9 @@ struct Level : IGame {
|
||||
void setVisible(int roomIndex, int nextRoom = TR::NO_ROOM) {
|
||||
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++)
|
||||
if (items[i].to == roomIndex) {
|
||||
if (items[i].caust == roomIndex) {
|
||||
nextRoom = items[i].from;
|
||||
if (!items[i].visible) {
|
||||
items[i].visible = true;
|
||||
@ -350,7 +366,7 @@ struct Level : IGame {
|
||||
void bindCaustics(int roomIndex) {
|
||||
Item *item = NULL;
|
||||
for (int i = 0; i < count; i++)
|
||||
if (items[i].to == roomIndex) {
|
||||
if (items[i].caust == roomIndex) {
|
||||
item = &items[i];
|
||||
break;
|
||||
}
|
||||
@ -390,8 +406,6 @@ struct Level : IGame {
|
||||
level->mesh->renderQuad();
|
||||
swap(item.data[0], item.data[1]);
|
||||
}
|
||||
dropCount = 0;
|
||||
|
||||
}
|
||||
|
||||
void step(Item &item) {
|
||||
@ -458,7 +472,7 @@ struct Level : IGame {
|
||||
// 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);
|
||||
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
|
||||
|
||||
@ -500,12 +514,11 @@ struct Level : IGame {
|
||||
item.mask->bind(sMask);
|
||||
|
||||
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));
|
||||
|
||||
drop(item);
|
||||
// add water drops
|
||||
drop(item);
|
||||
// simulation step
|
||||
step(item);
|
||||
|
||||
}
|
||||
Core::setTarget(NULL);
|
||||
|
||||
@ -526,7 +539,7 @@ struct Level : IGame {
|
||||
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));
|
||||
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 sz = item.size.z * DETAIL / (item.data[0]->height / 2);
|
||||
@ -546,6 +559,7 @@ struct Level : IGame {
|
||||
|
||||
Core::setCulling(cfFront);
|
||||
}
|
||||
dropCount = 0;
|
||||
}
|
||||
|
||||
#undef MAX_WATER_SURFACES
|
||||
@ -717,9 +731,13 @@ struct Level : IGame {
|
||||
waterCache = new WaterCache(this);
|
||||
|
||||
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
|
||||
Debug::free();
|
||||
#endif
|
||||
@ -931,6 +949,14 @@ struct Level : IGame {
|
||||
if (room.flags.water) {
|
||||
Core::color = vec4(0.6f, 0.9f, 0.9f, intensity);
|
||||
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);
|
||||
} else {
|
||||
Core::color = vec4(1.0f, 1.0f, 1.0f, intensity);
|
||||
@ -1299,6 +1325,15 @@ struct Level : IGame {
|
||||
|
||||
#ifdef _DEBUG
|
||||
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 bool lastStateK = false;
|
||||
static int lastEntity = -1;
|
||||
@ -1322,7 +1357,7 @@ struct Level : IGame {
|
||||
if (lastEntity > -1)
|
||||
renderEntity(level.entities[lastEntity]);
|
||||
// renderModel(level.models[modelIndex], level.entities[4]);
|
||||
|
||||
*/
|
||||
Debug::begin();
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
@ -1343,11 +1378,13 @@ struct Level : IGame {
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
glColor3f(10, 10, 10);
|
||||
int w = Core::active.textures[sDiffuse]->width / 2;
|
||||
int h = Core::active.textures[sDiffuse]->height / 2;
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(0, 0); glVertex2f(0, 0);
|
||||
glTexCoord2f(1, 0); glVertex2f(256, 0);
|
||||
glTexCoord2f(1, 1); glVertex2f(256, 256);
|
||||
glTexCoord2f(0, 1); glVertex2f(0, 256);
|
||||
glTexCoord2f(1, 0); glVertex2f(w, 0);
|
||||
glTexCoord2f(1, 1); glVertex2f(w, h);
|
||||
glTexCoord2f(0, 1); glVertex2f(0, h);
|
||||
glEnd();
|
||||
glColor3f(1, 1, 1);
|
||||
|
||||
@ -1369,7 +1406,7 @@ struct Level : IGame {
|
||||
// Debug::Level::portals(level);
|
||||
// Core::setDepthTest(true);
|
||||
// Debug::Level::meshes(level);
|
||||
// Debug::Level::entities(level);
|
||||
Debug::Level::entities(level);
|
||||
/*
|
||||
static int dbg_ambient = 0;
|
||||
dbg_ambient = int(time * 2) % 4;
|
||||
|
@ -39,7 +39,7 @@ struct MeshRange {
|
||||
}
|
||||
};
|
||||
|
||||
#define PLANE_DETAIL 100
|
||||
#define PLANE_DETAIL 48
|
||||
|
||||
struct Mesh {
|
||||
GLuint ID[2];
|
||||
|
@ -2,7 +2,7 @@
|
||||
cls
|
||||
set SRC=main.cpp
|
||||
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
|
||||
echo.
|
||||
call em++ %SRC% %FLAGS% -o %PROJ%.js --preload-file %PRELOAD%
|
||||
|
@ -125,6 +125,9 @@
|
||||
keyboad: move - WASD / arrows, jump - Space, action - E/Ctrl, draw weapon - Q, change weapon - 1-4, walk - Shift, side steps - ZX/walk+direction, camera - MouseR)<br>
|
||||
gamepad: PSX controls on XBox controller<br>
|
||||
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>
|
||||
</html>
|
@ -24,14 +24,18 @@ struct Shader {
|
||||
Shader(const char *text, const char *defines = "") {
|
||||
#ifdef MOBILE
|
||||
#define GLSL_DEFINE ""
|
||||
#define GLSL_VERT ""
|
||||
#define GLSL_FRAG "#extension GL_OES_standard_derivatives : enable\n"
|
||||
#else
|
||||
#define GLSL_DEFINE "#version 120\n"
|
||||
#define GLSL_VERT ""
|
||||
#define GLSL_FRAG ""
|
||||
#endif
|
||||
|
||||
const int type[2] = { GL_VERTEX_SHADER, GL_FRAGMENT_SHADER };
|
||||
const char *code[2][3] = {
|
||||
{ GLSL_DEFINE "#define VERTEX\n", defines, text },
|
||||
{ GLSL_DEFINE "#define FRAGMENT\n", defines, text }
|
||||
{ GLSL_DEFINE GLSL_VERT "#define VERTEX\n", defines, text },
|
||||
{ GLSL_DEFINE GLSL_FRAG "#define FRAGMENT\n", defines, text }
|
||||
};
|
||||
|
||||
GLchar info[256];
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include "core.h"
|
||||
|
||||
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;
|
||||
int width, height;
|
||||
@ -58,13 +58,14 @@ struct Texture {
|
||||
struct FormatDesc {
|
||||
GLuint ifmt, fmt;
|
||||
GLenum type;
|
||||
} formats[MAX] = {
|
||||
{ GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE }, // RGBA
|
||||
{ GL_RGBA32F, GL_RGBA, GL_FLOAT }, // RGBA_FLOAT
|
||||
{ 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 }, // SHADOW
|
||||
} formats[MAX] = {
|
||||
{ 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_RGBA16F, GL_RGBA, GL_HALF_FLOAT }, // RGBA_HALF
|
||||
{ GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT }, // DEPTH
|
||||
{ GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT }, // SHADOW
|
||||
};
|
||||
|
||||
FormatDesc &desc = formats[format];
|
||||
@ -80,6 +81,7 @@ struct Texture {
|
||||
}
|
||||
|
||||
void bind(int sampler) {
|
||||
Core::active.textures[sampler] = this;
|
||||
glActiveTexture(GL_TEXTURE0 + sampler);
|
||||
glBindTexture(cube ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D, ID);
|
||||
}
|
||||
|
@ -334,9 +334,11 @@ struct Waterfall : Trigger {
|
||||
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 = 256.0f;//randf() * 128.0f + 128.0f;
|
||||
dropStrength = 0.15f;//randf() * 0.1f + 0.05f;
|
||||
dropRadius = randf() * 128.0f + 128.0f;
|
||||
dropStrength = 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);
|
||||
}
|
||||
|
49
src/utils.h
49
src/utils.h
@ -112,11 +112,29 @@ struct vec2 {
|
||||
vec2(float s) : x(s), y(s) {}
|
||||
vec2(float x, float y) : x(x), y(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); }
|
||||
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& operator [] (int index) const { ASSERT(index >= 0 && index <= 1); return ((float*)this)[index]; }
|
||||
|
||||
bool operator == (float s) const { return x == s && y == s; }
|
||||
bool operator != (float s) const { return !(*this == s); }
|
||||
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 length() const { return sqrtf(length2()); }
|
||||
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(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 !(*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 += (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 * (float s) const { return vec3(x*s, y*s, z*s); }
|
||||
vec3 operator - () const { return vec3(-x, -y, -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 * (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 length() const { return sqrtf(length2()); }
|
||||
vec3 normal() const { float s = length(); return s == 0.0f ? (*this) : (*this)*(1.0f/s); }
|
||||
|
@ -1,8 +1,5 @@
|
||||
R"====(
|
||||
#ifdef GL_ES
|
||||
#ifdef FRAGMENT
|
||||
#extension GL_OES_standard_derivatives : enable
|
||||
#endif
|
||||
precision highp int;
|
||||
precision highp float;
|
||||
#endif
|
||||
@ -43,7 +40,7 @@ uniform sampler2D sNormal;
|
||||
float height = 0.0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
// integrate
|
||||
const float vel = 1.8;
|
||||
const float vel = 1.4;
|
||||
const float vis = 0.995;
|
||||
|
||||
v.y *= vis;
|
||||
v.y += (average - v.x) * vel;
|
||||
v.y *= vis;
|
||||
v.x += v.y;
|
||||
|
||||
return v;
|
||||
|
Loading…
x
Reference in New Issue
Block a user