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

#23 uber-shaders

This commit is contained in:
XProger
2017-03-05 23:59:19 +03:00
parent 1849874dae
commit 6e6ed3b2d0
16 changed files with 578 additions and 398 deletions

View File

@@ -17,6 +17,7 @@ struct IGame {
virtual ~IGame() {}
virtual TR::Level* getLevel() { return NULL; }
virtual void waterDrop(const vec3 &pos, float radius, float strength) {}
virtual void setShader(Core::Pass pass, Shader::Type type, bool caustics) {}
};
struct Controller {
@@ -54,7 +55,7 @@ struct Controller {
Controller(IGame *game, int entity) : game(game), level(game->getLevel()), entity(entity), animation(level, getModel()), state(animation.state), layers(NULL), actionCommand(NULL) {
TR::Entity &e = getEntity();
pos = vec3((float)e.x, (float)e.y, (float)e.z);
pos = vec3(float(e.x), float(e.y), float(e.z));
angle = vec3(0.0f, e.rotation, 0.0f);
TR::Model *m = getModel();
joints = m ? new Basis[m->mCount] : NULL;
@@ -493,7 +494,7 @@ struct Controller {
}
*/
virtual void render(Frustum *frustum, MeshBuilder *mesh) { // TODO: animation.calcJoints
virtual void render(Frustum *frustum, MeshBuilder *mesh, Shader::Type type, bool caustics) { // TODO: animation.calcJoints
mat4 matrix = getMatrix();
Box box = animation.getBoundingBox(vec3(0, 0, 0), 0);

View File

@@ -6,6 +6,30 @@
#include <windows.h>
#include <gl/GL.h>
#include <gl/glext.h>
#elif ANDROID
#define MOBILE
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <dlfcn.h>
#define GL_TEXTURE_COMPARE_MODE 0x884C
#define GL_TEXTURE_COMPARE_FUNC 0x884D
#define GL_COMPARE_REF_TO_TEXTURE 0x884E
#undef GL_RGBA32F
#undef GL_RGBA16F
#undef GL_HALF_FLOAT
#define GL_RGBA32F GL_RGBA
#define GL_RGBA16F GL_RGBA
#define GL_HALF_FLOAT GL_HALF_FLOAT_OES
#define PFNGLGENVERTEXARRAYSPROC PFNGLGENVERTEXARRAYSOESPROC
#define PFNGLDELETEVERTEXARRAYSPROC PFNGLDELETEVERTEXARRAYSOESPROC
#define PFNGLBINDVERTEXARRAYPROC PFNGLBINDVERTEXARRAYOESPROC
#define glGenVertexArrays glGenVertexArraysOES
#define glDeleteVertexArrays glDeleteVertexArraysOES
#define glBindVertexArray glBindVertexArrayOES
#elif __linux__
#define LINUX 1
#include <GL/gl.h>
@@ -18,16 +42,11 @@
#include <OpenGL/gl.h>
#include <OpenGL/glext.h>
#include <AGL/agl.h>
/*
* In compatibility mode, Mac OS X only supports OpenGL 2 (no VAO), but it does
* support the Apple-specific VAO extension which is older and in all relevant
* parts 100% compatible. So use those functions instead.
*/
#define glBindVertexArray glBindVertexArrayAPPLE
#define glGenVertexArrays glGenVertexArraysAPPLE
#define glDeleteVertexArrays glDeleteVertexArraysAPPLE
#define glGenVertexArrays glGenVertexArraysAPPLE
#define glDeleteVertexArrays glDeleteVertexArraysAPPLE
#define glBindVertexArray glBindVertexArrayAPPLE
#elif __EMSCRIPTEN__
#define MOBILE 1
#define MOBILE
#include <emscripten.h>
#include <html5.h>
#include <GLES3/gl3.h>
@@ -46,68 +65,80 @@
#include "input.h"
#include "sound.h"
#if defined(WIN32) || defined(LINUX)
void* GetProc(const char *name) {
#ifdef WIN32
return (void*)wglGetProcAddress(name);
#elif LINUX
return (void*)glXGetProcAddress((GLubyte*)name);
#endif
}
#if defined(WIN32) || defined(LINUX) || defined(ANDROID)
#ifdef ANDROID
#define GetProc(x) dlsym(libGL, x);
#else
void* GetProc(const char *name) {
#ifdef WIN32
return (void*)wglGetProcAddress(name);
#elif LINUX
return (void*)glXGetProcAddress((GLubyte*)name);
#endif
}
#endif
#define GetProcOGL(x) x=(decltype(x))GetProc(#x);
// Texture
#ifdef WIN32
PFNGLACTIVETEXTUREPROC glActiveTexture;
PFNGLACTIVETEXTUREPROC glActiveTexture;
#endif
// Shader
PFNGLCREATEPROGRAMPROC glCreateProgram;
PFNGLDELETEPROGRAMPROC glDeleteProgram;
PFNGLLINKPROGRAMPROC glLinkProgram;
PFNGLUSEPROGRAMPROC glUseProgram;
PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog;
PFNGLCREATESHADERPROC glCreateShader;
PFNGLDELETESHADERPROC glDeleteShader;
PFNGLSHADERSOURCEPROC glShaderSource;
PFNGLATTACHSHADERPROC glAttachShader;
PFNGLCOMPILESHADERPROC glCompileShader;
PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;
PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation;
PFNGLUNIFORM1IVPROC glUniform1iv;
PFNGLUNIFORM1FVPROC glUniform1fv;
PFNGLUNIFORM2FVPROC glUniform2fv;
PFNGLUNIFORM3FVPROC glUniform3fv;
PFNGLUNIFORM4FVPROC glUniform4fv;
PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv;
PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation;
PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray;
PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray;
PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer;
// Mesh
PFNGLGENBUFFERSARBPROC glGenBuffers;
PFNGLDELETEBUFFERSARBPROC glDeleteBuffers;
PFNGLBINDBUFFERARBPROC glBindBuffer;
PFNGLBUFFERDATAARBPROC glBufferData;
#if defined(WIN32) || defined(LINUX)
// Profiling
#ifdef PROFILE
PFNGLOBJECTLABELPROC glObjectLabel;
PFNGLPUSHDEBUGGROUPPROC glPushDebugGroup;
PFNGLPOPDEBUGGROUPPROC glPopDebugGroup;
#endif
// Shader
PFNGLCREATEPROGRAMPROC glCreateProgram;
PFNGLDELETEPROGRAMPROC glDeleteProgram;
PFNGLLINKPROGRAMPROC glLinkProgram;
PFNGLUSEPROGRAMPROC glUseProgram;
PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog;
PFNGLCREATESHADERPROC glCreateShader;
PFNGLDELETESHADERPROC glDeleteShader;
PFNGLSHADERSOURCEPROC glShaderSource;
PFNGLATTACHSHADERPROC glAttachShader;
PFNGLCOMPILESHADERPROC glCompileShader;
PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;
PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation;
PFNGLUNIFORM1IVPROC glUniform1iv;
PFNGLUNIFORM1FVPROC glUniform1fv;
PFNGLUNIFORM2FVPROC glUniform2fv;
PFNGLUNIFORM3FVPROC glUniform3fv;
PFNGLUNIFORM4FVPROC glUniform4fv;
PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv;
PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation;
PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray;
PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray;
PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer;
// Render to texture
PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers;
PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer;
PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers;
PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer;
PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D;
PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer;
PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage;
PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus;
// Mesh
PFNGLGENBUFFERSARBPROC glGenBuffers;
PFNGLDELETEBUFFERSARBPROC glDeleteBuffers;
PFNGLBINDBUFFERARBPROC glBindBuffer;
PFNGLBUFFERDATAARBPROC glBufferData;
#endif
PFNGLGENVERTEXARRAYSPROC glGenVertexArrays;
PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays;
PFNGLBINDVERTEXARRAYPROC glBindVertexArray;
// Render to texture
PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers;
PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer;
PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers;
PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer;
PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D;
PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer;
PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage;
PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus;
PFNGLDRAWBUFFERSPROC glDrawBuffers;
// Profiling
#ifdef PROFILE
PFNGLOBJECTLABELPROC glObjectLabel;
PFNGLPUSHDEBUGGROUPPROC glPushDebugGroup;
PFNGLPOPDEBUGGROUPPROC glPopDebugGroup;
#endif
#endif
#ifdef MOBILE
PFNGLDISCARDFRAMEBUFFEREXTPROC glDiscardFramebufferEXT;
#endif
#define MAX_LIGHTS 3
@@ -152,7 +183,7 @@ namespace Core {
Texture *blackTex, *whiteTex;
enum Pass { passCompose, passShadow, passAmbient, passFilter, passWater } pass;
enum Pass { passCompose, passShadow, passAmbient, passFilter, passWater, passMAX } pass;
GLuint FBO;
struct RenderTargetCache {
@@ -167,6 +198,7 @@ namespace Core {
struct {
Shader *shader;
Texture *textures[8];
Texture *target;
GLuint VAO;
} active;
@@ -176,9 +208,10 @@ namespace Core {
} stats;
struct {
bool VAO;
bool depthTexture;
bool shadowSampler;
bool VAO;
bool discardFrame;
bool texFloat, texFloatLinear;
bool texHalf, texHalfLinear;
} support;
@@ -198,62 +231,76 @@ namespace Core {
}
void init() {
#if defined(WIN32) || defined(LINUX)
#ifdef WIN32
GetProcOGL(glActiveTexture);
#ifdef ANDROID
void *libGL = dlopen("libGLESv2.so", RTLD_LAZY);
#endif
GetProcOGL(glCreateProgram);
GetProcOGL(glDeleteProgram);
GetProcOGL(glLinkProgram);
GetProcOGL(glUseProgram);
GetProcOGL(glGetProgramInfoLog);
GetProcOGL(glCreateShader);
GetProcOGL(glDeleteShader);
GetProcOGL(glShaderSource);
GetProcOGL(glAttachShader);
GetProcOGL(glCompileShader);
GetProcOGL(glGetShaderInfoLog);
GetProcOGL(glGetUniformLocation);
GetProcOGL(glUniform1iv);
GetProcOGL(glUniform1fv);
GetProcOGL(glUniform2fv);
GetProcOGL(glUniform3fv);
GetProcOGL(glUniform4fv);
GetProcOGL(glUniformMatrix4fv);
GetProcOGL(glBindAttribLocation);
GetProcOGL(glEnableVertexAttribArray);
GetProcOGL(glDisableVertexAttribArray);
GetProcOGL(glVertexAttribPointer);
GetProcOGL(glGenBuffers);
GetProcOGL(glDeleteBuffers);
GetProcOGL(glBindBuffer);
GetProcOGL(glBufferData);
GetProcOGL(glGenVertexArrays);
GetProcOGL(glDeleteVertexArrays);
GetProcOGL(glBindVertexArray);
#if defined(WIN32) || defined(LINUX) || defined(ANDROID)
#ifdef WIN32
GetProcOGL(glActiveTexture);
#endif
GetProcOGL(glGenFramebuffers);
GetProcOGL(glBindFramebuffer);
GetProcOGL(glGenRenderbuffers);
GetProcOGL(glBindRenderbuffer);
GetProcOGL(glFramebufferTexture2D);
GetProcOGL(glFramebufferRenderbuffer);
GetProcOGL(glRenderbufferStorage);
GetProcOGL(glCheckFramebufferStatus);
GetProcOGL(glDrawBuffers);
#if defined(WIN32) || defined(LINUX)
#ifdef PROFILE
GetProcOGL(glObjectLabel);
GetProcOGL(glPushDebugGroup);
GetProcOGL(glPopDebugGroup);
#endif
#ifdef PROFILE
GetProcOGL(glObjectLabel);
GetProcOGL(glPushDebugGroup);
GetProcOGL(glPopDebugGroup);
GetProcOGL(glCreateProgram);
GetProcOGL(glDeleteProgram);
GetProcOGL(glLinkProgram);
GetProcOGL(glUseProgram);
GetProcOGL(glGetProgramInfoLog);
GetProcOGL(glCreateShader);
GetProcOGL(glDeleteShader);
GetProcOGL(glShaderSource);
GetProcOGL(glAttachShader);
GetProcOGL(glCompileShader);
GetProcOGL(glGetShaderInfoLog);
GetProcOGL(glGetUniformLocation);
GetProcOGL(glUniform1iv);
GetProcOGL(glUniform1fv);
GetProcOGL(glUniform2fv);
GetProcOGL(glUniform3fv);
GetProcOGL(glUniform4fv);
GetProcOGL(glUniformMatrix4fv);
GetProcOGL(glBindAttribLocation);
GetProcOGL(glEnableVertexAttribArray);
GetProcOGL(glDisableVertexAttribArray);
GetProcOGL(glVertexAttribPointer);
GetProcOGL(glGenFramebuffers);
GetProcOGL(glBindFramebuffer);
GetProcOGL(glGenRenderbuffers);
GetProcOGL(glBindRenderbuffer);
GetProcOGL(glFramebufferTexture2D);
GetProcOGL(glFramebufferRenderbuffer);
GetProcOGL(glRenderbufferStorage);
GetProcOGL(glCheckFramebufferStatus);
GetProcOGL(glGenBuffers);
GetProcOGL(glDeleteBuffers);
GetProcOGL(glBindBuffer);
GetProcOGL(glBufferData);
#endif
#ifdef MOBILE
GetProcOGL(glDiscardFramebufferEXT);
#endif
GetProcOGL(glGenVertexArrays);
GetProcOGL(glDeleteVertexArrays);
GetProcOGL(glBindVertexArray);
#endif
#endif
char *ext = (char*)glGetString(GL_EXTENSIONS);
//LOG("%s\n", ext);
support.depthTexture = extSupport(ext, "_depth_texture");
support.shadowSampler = extSupport(ext, "EXT_shadow_samplers") || extSupport(ext, "GL_ARB_shadow");
support.VAO = extSupport(ext, "_vertex_array_object");
support.depthTexture = extSupport(ext, "_depth_texture");
support.shadowSampler = false;//extSupport(ext, "_shadow_samplers") || extSupport(ext, "GL_ARB_shadow");
support.discardFrame = extSupport(ext, "_discard_framebuffer");
support.texFloatLinear = extSupport(ext, "GL_ARB_texture_float") || extSupport(ext, "_texture_float_linear");
support.texFloat = support.texFloatLinear || extSupport(ext, "_texture_float");
support.texHalfLinear = extSupport(ext, "GL_ARB_texture_float") || extSupport(ext, "_texture_half_float_linear");
@@ -265,9 +312,10 @@ namespace Core {
LOG("Version : %s\n", glGetString(GL_VERSION));
LOG("supports:\n");
LOG(" vertex arrays : %s\n", support.VAO ? "true" : "false");
LOG(" depth texture : %s\n", support.depthTexture ? "true" : "false");
LOG(" shadow sampler : %s\n", support.shadowSampler ? "true" : "false");
LOG(" vertex arrays : %s\n", support.VAO ? "true" : "false");
LOG(" discard frame : %s\n", support.discardFrame ? "true" : "false");
LOG(" float textures : float = %s, half = %s\n",
support.texFloat ? (support.texFloatLinear ? "linear" : "nearest") : "false",
support.texHalf ? (support.texHalfLinear ? "linear" : "nearest") : "false");
@@ -282,11 +330,11 @@ namespace Core {
lightColor[i] = vec4(0, 0, 0, 1);
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);
whiteTex = new Texture(1, 1, Texture::RGBA, false, &data);
}
void free() {
@@ -326,9 +374,10 @@ namespace Core {
return cache.count++;
}
void clear(const vec4 &color) {
void clear(bool clearColor, bool clearDepth, 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);
if (GLbitfield mask = (clearColor ? GL_COLOR_BUFFER_BIT : 0) | (clearDepth ? GL_DEPTH_BUFFER_BIT : 0))
glClear(mask);
}
void setViewport(int x, int y, int width, int height) {
@@ -352,6 +401,7 @@ namespace Core {
}
void setBlending(BlendMode mode) {
mode = bmNone;
switch (mode) {
case bmNone :
glDisable(GL_BLEND);
@@ -389,28 +439,43 @@ namespace Core {
glDisable(GL_DEPTH_TEST);
}
void setTarget(Texture *target, int face = 0) {
void invalidateTarget(bool color, bool depth) {
#ifdef MOBILE
if (support.discardFrame && (color || depth)) {
int count = 0;
GLenum discard[2];
if (color) discard[count++] = active.target ? GL_COLOR_ATTACHMENT0 : GL_COLOR_EXT;
if (depth) discard[count++] = active.target ? GL_DEPTH_ATTACHMENT : GL_DEPTH_EXT;
glDiscardFramebufferEXT(GL_FRAMEBUFFER, count, discard);
}
#endif
}
void setTarget(Texture *target, bool clear = false, int face = 0) {
if (!target) {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glColorMask(true, true, true, true);
setViewport(0, 0, Core::width, Core::height);
return;
} else {
GLenum texTarget = GL_TEXTURE_2D;
if (target->cube)
texTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
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);
glFramebufferRenderbuffer (GL_FRAMEBUFFER, depth ? GL_COLOR_ATTACHMENT0 : GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rtCache[depth].items[rtIndex].ID);
if (depth)
glColorMask(false, false, false, false);
setViewport(0, 0, target->width, target->height);
}
active.target = target;
GLenum texTarget = GL_TEXTURE_2D;
if (target->cube)
texTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
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);
glFramebufferRenderbuffer (GL_FRAMEBUFFER, depth ? GL_COLOR_ATTACHMENT0 : GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rtCache[depth].items[rtIndex].ID);
if (depth)
glColorMask(false, false, false, false);
setViewport(0, 0, target->width, target->height);
if (clear)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
}
void copyTarget(Texture *texture, int xOffset, int yOffset, int x, int y, int width, int height) {

View File

@@ -491,7 +491,7 @@ namespace TR {
} flags;
// not exists in file
uint16 align;
int16 modelIndex; // index of representation in models (index + 1) or spriteSequences (-(index + 1)) arrays
int32 modelIndex; // index of representation in models (index + 1) or spriteSequences (-(index + 1)) arrays
void *controller; // Controller implementation or NULL
bool isEnemy() {
@@ -842,6 +842,7 @@ namespace TR {
} extra;
Level(Stream &stream, bool demo) {
int startPos = stream.pos;
memset(this, 0, sizeof(*this));
cutEntity = -1;
Tile8 *tiles8 = NULL;
@@ -863,14 +864,13 @@ namespace TR {
if (version == VER_TR1_PSX) {
uint32 offsetTexTiles;
stream.seek(8);
stream.read(offsetTexTiles);
// sound offsets
uint16 numSounds;
stream.setPos(22);
stream.setPos(startPos + 22);
stream.read(numSounds);
stream.setPos(2086 + numSounds * 512);
stream.setPos(startPos + 2086 + numSounds * 512);
soundOffsetsCount = numSounds;
soundOffsets = new uint32[soundOffsetsCount];
soundSize = new uint32[soundOffsetsCount];
@@ -882,9 +882,9 @@ namespace TR {
soundDataSize += soundSize[i] = size * 8;
}
// sound data
stream.setPos(2600 + numSounds * 512);
stream.setPos(startPos + 2600 + numSounds * 512);
stream.read(soundData, soundDataSize);
stream.setPos(offsetTexTiles + 8);
stream.setPos(startPos + offsetTexTiles + 8);
} else if (version == VER_TR1_PC) {
// tiles
stream.read(tiles8, stream.read(tilesCount));
@@ -1580,8 +1580,8 @@ namespace TR {
info.trigger = Trigger::ACTIVATE;
info.trigCmdCount = 0;
if (s.floor == -127)
return;
if (uint8(s.floor) == TR::NO_ROOM)
return;
Room::Sector *sBelow = &s;
while (sBelow->roomBelow != NO_ROOM) sBelow = &getSector(sBelow->roomBelow, x, z, dx, dz);
@@ -1610,7 +1610,7 @@ namespace TR {
int dx = x % 1024;
int dz = z % 1024;
for (int i = 0; i < info.trigCmdCount; i++) {
for (int i = 0; i < info.trigCmdCount; i++) {
FloorData::TriggerCommand cmd = info.trigCmd[i];
if (cmd.action != Action::ACTIVATE) continue;

View File

@@ -8,30 +8,29 @@
namespace Game {
Level *level;
void startLevel(Stream &stream, const char *sndName, bool demo, bool home) {
void startLevel(Stream *lvl, Stream *snd, bool demo, bool home) {
delete level;
level = new Level(stream, demo, home);
level = new Level(*lvl, demo, home);
delete lvl;
#ifndef __EMSCRIPTEN__
//Sound::play(Sound::openWAD("05_Lara's_Themes.wav"), 1, 1, 0);
Sound::play(new Stream(sndName), vec3(0.0f), 1, 1, Sound::Flags::LOOP);
#endif
Sound::play(snd, vec3(0.0f), 1, 1, Sound::Flags::LOOP);
#endif
}
void startLevel(const char *lvlName, const char *sndName, bool demo, bool home) {
Stream stream(lvlName);
startLevel(stream, sndName, demo, home);
}
void init(char *lvlName = NULL, char *sndName = NULL) {
void init(Stream *lvl, Stream *snd) {
Core::init();
level = NULL;
startLevel(lvl, snd, false, false);
}
void init(char *lvlName = NULL, char *sndName = NULL) {
if (!lvlName) lvlName = (char*)"LEVEL2.PSX";
if (!sndName) sndName = (char*)"05.ogg";
startLevel(lvlName, sndName, false, false);
init(new Stream(lvlName), new Stream(sndName));
}
void free() {
delete level;
Core::free();

View File

@@ -405,7 +405,7 @@ struct Lara : Character {
if (level->extra.braid > -1)
braid = new Braid(this, vec3(-4.0f, 24.0f, -48.0f));
//reset(15, vec3(70067, -256, 29104), -0.68f); // level 2 (pool)
#ifdef _DEBUG
//reset(14, vec3(40448, 3584, 60928), PI * 0.5f, true); // gym (pool)
@@ -414,7 +414,7 @@ struct Lara : Character {
//reset(61, vec3(27221, -1024, 29205), PI * 0.5f); // level 2 (blade)
//reset(43, vec3(31400, -2560, 25200), PI); // level 2 (reach)
//reset(16, vec3(60907, 0, 39642), PI * 3 / 2); // level 2 (hang & climb)
reset(19, vec3(60843, 1024, 30557), PI); // level 2 (block)
//reset(19, vec3(60843, 1024, 30557), PI); // level 2 (block)
//reset(7, vec3(64108, -512, 16514), -PI * 0.5f); // level 2 (bat trigger)
//reset(15, vec3(70082, -512, 26935), PI * 0.5f); // level 2 (bear)
//reset(63, vec3(31390, -2048, 33472), 0.0f); // level 2 (trap floor)
@@ -2018,8 +2018,8 @@ struct Lara : Character {
Core::setBlending(bmNone);
}
virtual void render(Frustum *frustum, MeshBuilder *mesh) {
Controller::render(frustum, mesh);
virtual void render(Frustum *frustum, MeshBuilder *mesh, Shader::Type type, bool caustics) {
Controller::render(frustum, mesh, type, caustics);
chestOffset = animation.getJoints(getMatrix(), 7).pos; // TODO: move to update func
if (braid)
@@ -2027,10 +2027,9 @@ struct Lara : Character {
if (wpnCurrent != Weapon::SHOTGUN && Core::pass != Core::passShadow && (arms[0].shotTimer < MUZZLE_FLASH_TIME || arms[1].shotTimer < MUZZLE_FLASH_TIME)) {
mat4 matrix = getMatrix();
Core::active.shader->setParam(uType, Shader::FLASH);
game->setShader(Core::pass, Shader::FLASH, false);
renderMuzzleFlash(mesh, animation.getJoints(matrix, 10, true), vec3(-10, -50, 150), arms[0].shotTimer);
renderMuzzleFlash(mesh, animation.getJoints(matrix, 13, true), vec3( 10, -50, 150), arms[1].shotTimer);
Core::active.shader->setParam(uType, Shader::ENTITY);
}
}
};

View File

@@ -33,10 +33,7 @@ const char GUI[] =
#define WATER_FOG_DIST (8 * 1024)
struct Level : IGame {
enum { shCompose, shShadow, shAmbient, shFilter, shWater, shGUI, shMAX };
TR::Level level;
Shader *shaders[shMAX];
Texture *atlas;
Texture *cube;
MeshBuilder *mesh;
@@ -54,6 +51,70 @@ struct Level : IGame {
float clipHeight;
} params;
struct ShaderCache {
Shader *shaders[int(Core::passMAX) * Shader::MAX * 2];
ShaderCache(int animTexRangesCount, int animTexOffsetsCount) {
memset(shaders, 0, sizeof(shaders));
char def[255], ext[255];
ext[0] = 0;
if (Core::support.shadowSampler) {
#ifdef MOBILE
strcat(ext, "#extension GL_EXT_shadow_samplers : require\n");
#endif
strcat(ext, "#define SHADOW_SAMPLER\n");
} else
if (Core::support.depthTexture)
strcat(ext, "#define SHADOW_DEPTH\n");
else
strcat(ext, "#define SHADOW_COLOR\n");
{
const char *passNames[] = { "COMPOSE", "SHADOW", "AMBIENT" };
const char *typeNames[] = { "SPRITE", "FLASH", "ROOM", "ENTITY", "MIRROR" };
for (int pass = Core::passCompose; pass <= Core::passAmbient; pass++)
for (int caustics = 0; caustics < 2; caustics++)
for (int type = Shader::SPRITE; type <= Shader::MIRROR; type++) {
sprintf(def, "%s#define PASS_%s\n#define TYPE_%s\n#define MAX_LIGHTS %d\n#define MAX_RANGES %d\n#define MAX_OFFSETS %d\n#define FOG_DIST (1.0/%d.0)\n#define WATER_FOG_DIST (1.0/%d.0)\n", ext, passNames[pass], typeNames[type], MAX_LIGHTS, animTexRangesCount, animTexOffsetsCount, FOG_DIST, WATER_FOG_DIST);
if (caustics)
strcat(def, "#define CAUSTICS\n");
shaders[getIndex(Core::Pass(pass), Shader::Type(type), caustics == 1)] = new Shader(SHADER, def);
}
}
{
const char *typeNames[] = { "DROP", "STEP", "CAUSTICS", "MASK", "COMPOSE" };
for (int type = Shader::WATER_DROP; type <= Shader::WATER_COMPOSE; type++) {
sprintf(def, "%s#define WATER_%s\n#define WATER_FOG_DIST (1.0/%d.0)\n", ext, typeNames[type], WATER_FOG_DIST);
shaders[getIndex(Core::passWater, Shader::Type(type), false)] = new Shader(WATER, def);
}
}
shaders[getIndex(Core::passFilter, Shader::FILTER_DOWNSAMPLE, false)] = new Shader(FILTER, "");
}
~ShaderCache() {
for (int i = 0; i < sizeof(shaders) / sizeof(shaders[0]); i++)
delete shaders[i];
}
int getIndex(Core::Pass pass, Shader::Type type, bool caustics) {
int index = int(pass) * Shader::MAX * 2 + type * 2 + int(caustics);
ASSERT(index < sizeof(shaders) / sizeof(shaders[0]));
return index;
}
void bind(Core::Pass pass, Shader::Type type, bool caustics = false) {
Core::pass = pass;
int index = getIndex(pass, type, caustics);
ASSERT(shaders[index] != NULL);
shaders[index]->bind();
}
} *shaderCache;
struct AmbientCache {
Level *level;
@@ -125,8 +186,7 @@ struct Level : IGame {
// second pass - downsample it
Core::setDepthTest(false);
level->setPassShader(Core::passFilter);
Core::active.shader->setParam(uType, Shader::FILTER_DOWNSAMPLE);
level->shaderCache->bind(Core::passFilter, Shader::FILTER_DOWNSAMPLE, false);
for (int i = 1; i < 4; i++) {
int size = 64 >> (i << 1);
@@ -136,7 +196,7 @@ struct Level : IGame {
for (int j = 0; j < 6; j++) {
Texture *src = textures[j * 4 + i - 1];
Texture *dst = textures[j * 4 + i];
Core::setTarget(dst);
Core::setTarget(dst, true);
src->bind(sDiffuse);
level->mesh->renderQuad();
}
@@ -151,7 +211,6 @@ struct Level : IGame {
colors[j] = vec3(color.r / 255.0f, color.g / 255.0f, color.b / 255.0f);
colors[j] *= colors[j]; // to "linear" space
}
Core::setTarget(NULL);
Core::setDepthTest(true);
}
@@ -273,9 +332,8 @@ struct Level : IGame {
caustics = new Texture(512, 512, Texture::RGB16, false);
blank = false;
Core::setTarget(data[0]);
Core::clear(vec4(0.0f));
Core::setTarget(NULL);
Core::setTarget(data[0], true);
Core::invalidateTarget(false, true);
}
void free() {
@@ -399,10 +457,10 @@ struct Level : IGame {
void drop(Item &item) {
if (!dropCount) return;
level->setShader(Core::passWater, Shader::WATER_DROP, false);
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];
@@ -412,9 +470,10 @@ struct Level : IGame {
Core::active.shader->setParam(uParam, vec4(p.x, p.z, drop.radius * DETAIL, drop.strength));
item.data[0]->bind(sDiffuse);
Core::setTarget(item.data[1]);
Core::setTarget(item.data[1], true);
Core::setViewport(0, 0, int(item.size.x * DETAIL * 2.0f + 0.5f), int(item.size.z * DETAIL * 2.0f + 0.5f));
level->mesh->renderQuad();
Core::invalidateTarget(false, true);
swap(item.data[0], item.data[1]);
}
}
@@ -422,23 +481,24 @@ struct Level : IGame {
void step(Item &item) {
if (item.timer < SIMULATE_TIMESTEP) return;
Core::active.shader->setParam(uType, Shader::WATER_STEP);
level->setShader(Core::passWater, Shader::WATER_STEP, false);
Core::active.shader->setParam(uParam, vec4(0.995f, 1.0f, 0, 0));
while (item.timer >= SIMULATE_TIMESTEP) {
// water step
item.data[0]->bind(sDiffuse);
Core::setTarget(item.data[1]);
Core::setTarget(item.data[1], 0, true);
Core::setViewport(0, 0, int(item.size.x * DETAIL * 2.0f + 0.5f), int(item.size.z * DETAIL * 2.0f + 0.5f));
level->mesh->renderQuad();
Core::invalidateTarget(false, true);
swap(item.data[0], item.data[1]);
item.timer -= SIMULATE_TIMESTEP;
}
// calc caustics
level->setShader(Core::passWater, Shader::WATER_CAUSTICS, false);
vec3 rPosScale[2] = { vec3(0.0f), vec3(1.0f / PLANE_DETAIL) };
Core::active.shader->setParam(uType, Shader::WATER_CAUSTICS);
Core::active.shader->setParam(uPosScale, rPosScale[0], 2);
float sx = item.size.x * DETAIL / (item.data[0]->width / 2);
@@ -448,19 +508,19 @@ struct Level : IGame {
Core::whiteTex->bind(sReflect);
item.data[0]->bind(sNormal);
Core::setTarget(item.caustics);
Core::setTarget(item.caustics, true);
level->mesh->renderPlane();
Core::invalidateTarget(false, true);
}
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);
level->setShader(Core::passWater, Shader::WATER_MASK, false);
Core::active.shader->setParam(uTexParam, vec4(1.0f));
Core::setBlending(bmNone);
Core::setCulling(cfNone);
@@ -497,7 +557,7 @@ struct Level : IGame {
}
// render mirror reflection
Core::setTarget(reflect);
Core::setTarget(reflect, true);
vec3 p = item.pos;
vec3 n = vec3(0, 1, 0);
@@ -511,15 +571,14 @@ struct Level : IGame {
level->params.clipSign = underwater ? -1.0f : 1.0f;
level->params.clipHeight = item.pos.y * level->params.clipSign;
level->renderCompose(underwater ? item.from : item.to);
Core::invalidateTarget(false, true);
level->params.clipHeight = 1000000.0f;
level->params.clipSign = 1.0f;
level->camera->reflectPlane = NULL;
level->camera->setup(true);
// simulate water
level->setPassShader(Core::passWater);
Core::setDepthTest(false);
item.mask->bind(sMask);
@@ -542,7 +601,7 @@ struct Level : IGame {
Core::lightColor[0] = vec4(lum, lum, lum, float(light.radius) * float(light.radius));
}
Core::active.shader->setParam(uType, Shader::WATER_COMPOSE);
level->setShader(Core::passWater, Shader::WATER_COMPOSE, false);
Core::active.shader->setParam(uViewProj, Core::mViewProj);
Core::active.shader->setParam(uPosScale, item.pos, 2);
Core::active.shader->setParam(uViewPos, Core::viewPos);
@@ -627,6 +686,9 @@ struct Level : IGame {
waterCache->addDrop(pos, radius, strength);
}
virtual void setShader(Core::Pass pass, Shader::Type type, bool caustics) {
shaderCache->bind(pass, type, caustics);
}
Level(Stream &stream, bool demo, bool home) : level(stream, demo), lara(NULL), waterColor(0.6f, 0.9f, 0.9f) {
params.time = 0.0f;
@@ -637,7 +699,7 @@ struct Level : IGame {
mesh = new MeshBuilder(level);
initTextures();
initShaders();
shaderCache = new ShaderCache(mesh->animTexRangesCount, mesh->animTexOffsetsCount);
initOverrides();
for (int i = 0; i < level.entitiesBaseCount; i++) {
@@ -756,8 +818,7 @@ struct Level : IGame {
for (int i = 0; i < level.entitiesCount; i++)
delete (Controller*)level.entities[i].controller;
for (int i = 0; i < shMAX; i++)
delete shaders[i];
delete shaderCache;
delete shadow;
delete ambientCache;
@@ -815,33 +876,6 @@ struct Level : IGame {
level.tiles = NULL;
}
void initShaders() {
char def[255], ext[255];
ext[0] = 0;
if (Core::support.shadowSampler) {
#ifdef MOBILE
strcat(ext, "#extension GL_EXT_shadow_samplers : require\n");
#endif
strcat(ext, "#define SHADOW_SAMPLER\n");
} else
if (Core::support.depthTexture)
strcat(ext, "#define SHADOW_DEPTH\n");
else
strcat(ext, "#define SHADOW_COLOR\n");
sprintf(def, "%s#define PASS_COMPOSE\n#define MAX_LIGHTS %d\n#define MAX_RANGES %d\n#define MAX_OFFSETS %d\n#define FOG_DIST (1.0/%d.0)\n#define WATER_FOG_DIST (1.0/%d.0)\n", ext, MAX_LIGHTS, mesh->animTexRangesCount, mesh->animTexOffsetsCount, FOG_DIST, WATER_FOG_DIST);
shaders[shCompose] = new Shader(SHADER, def);
sprintf(def, "%s#define PASS_SHADOW\n", ext);
shaders[shShadow] = new Shader(SHADER, def);
sprintf(def, "%s#define PASS_AMBIENT\n", ext);
shaders[shAmbient] = new Shader(SHADER, def);
shaders[shFilter] = new Shader(FILTER, "");
sprintf(def, "#define WATER_FOG_DIST (1.0/%d.0)\n", WATER_FOG_DIST);
shaders[shWater] = new Shader(WATER, def);
shaders[shGUI] = new Shader(GUI, "");
}
void initOverrides() {
/*
for (int i = 0; i < level.entitiesCount; i++) {
@@ -954,15 +988,18 @@ struct Level : IGame {
}
#endif
void setRoomParams(int roomIndex, float intensity) {
if (Core::pass == Core::passShadow)
void setRoomParams(int roomIndex, float intensity, Shader::Type type) {
if (Core::pass == Core::passShadow) {
setShader(Core::pass, type, false);
return;
}
TR::Room &room = level.rooms[roomIndex];
setShader(Core::pass, type, room.flags.water);
if (room.flags.water) {
Core::color = vec4(waterColor, intensity);
Core::active.shader->setParam(uCaustics, 1);
/*
// trace to water surface room
int wrIndex = roomIndex;
@@ -972,10 +1009,9 @@ struct Level : IGame {
int sx = room.xSectors
*/
waterCache->bindCaustics(roomIndex);
} else {
} else
Core::color = vec4(1.0f, 1.0f, 1.0f, intensity);
Core::active.shader->setParam(uCaustics, 0);
}
Core::active.shader->setParam(uColor, Core::color);
}
@@ -994,13 +1030,13 @@ struct Level : IGame {
room.flags.rendered = true;
if (Core::pass != Core::passShadow) {
setRoomParams(roomIndex, intensityf(room.ambient));
setRoomParams(roomIndex, intensityf(room.ambient), Shader::ROOM);
Shader *sh = Core::active.shader;
sh->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS);
sh->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS);
Basis qTemp = Core::basis;
Core::basis.translate(offset);
Shader *sh = Core::active.shader;
sh->setParam(uType, Shader::ROOM);
sh->setParam(uBasis, Core::basis);
// render room geometry
@@ -1008,9 +1044,11 @@ struct Level : IGame {
// render room sprites
if (mesh->hasRoomSprites(roomIndex)) {
Core::color.w = 1.0;
sh->setParam(uType, Shader::SPRITE);
sh->setParam(uColor, Core::color);
setRoomParams(roomIndex, 1.0, Shader::SPRITE);
sh = Core::active.shader;
sh->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS);
sh->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS);
sh->setParam(uBasis, Core::basis);
mesh->renderRoomSprites(roomIndex);
}
@@ -1108,7 +1146,11 @@ struct Level : IGame {
return;
int16 lum = entity.intensity == -1 ? room.ambient : entity.intensity;
setRoomParams(entity.room, isModel ? controller->specular : intensityf(lum));
Shader::Type type = isModel ? Shader::ENTITY : Shader::SPRITE;
if (entity.type == TR::Entity::CRYSTAL)
type = Shader::MIRROR;
setRoomParams(entity.room, isModel ? controller->specular : intensityf(lum), type);
if (isModel) { // model
vec3 pos = controller->getPos();
@@ -1119,18 +1161,18 @@ struct Level : IGame {
memcpy(controller->ambient, cube.colors, sizeof(cube.colors)); // store last calculated ambient into controller
}
getLight(pos, entity.room);
Core::active.shader->setParam(uType, Shader::ENTITY);
Core::active.shader->setParam(uAmbient, controller->ambient[0], 6);
} else { // sprite
Core::active.shader->setParam(uType, Shader::SPRITE);
Core::lightPos[0] = vec3(0);
Core::lightColor[0] = vec4(0, 0, 0, 1);
}
Core::active.shader->setParam(uViewProj, Core::mViewProj);
Core::active.shader->setParam(uLightProj, Core::mLightProj);
Core::active.shader->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS);
Core::active.shader->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS);
controller->render(camera->frustum, mesh);
controller->render(camera->frustum, mesh, type, room.flags.water);
}
void update() {
@@ -1155,6 +1197,9 @@ struct Level : IGame {
waterCache->update();
}
void setup() {
PROFILE_MARKER("SETUP");
@@ -1168,19 +1213,20 @@ struct Level : IGame {
if (!Core::support.VAO)
mesh->bind();
//Core::mViewProj = Core::mLightProj;
// set frame constants for all shaders
Shader *sh = Core::active.shader;
sh->bind();
sh->setParam(uViewProj, Core::mViewProj);
sh->setParam(uLightProj, Core::mLightProj);
sh->setParam(uViewInv, Core::mViewInv);
sh->setParam(uViewPos, Core::viewPos);
sh->setParam(uParam, *((vec4*)&params));
sh->setParam(uLightsCount, 3);
sh->setParam(uAnimTexRanges, mesh->animTexRanges[0], mesh->animTexRangesCount);
sh->setParam(uAnimTexOffsets, mesh->animTexOffsets[0], mesh->animTexOffsetsCount);
for (int i = 0; i < sizeof(shaderCache->shaders) / sizeof(shaderCache->shaders[0]); i++) {
Shader *sh = shaderCache->shaders[i];
if (!sh) continue;
sh->bind();
sh->setParam(uViewProj, Core::mViewProj);
sh->setParam(uLightProj, Core::mLightProj);
sh->setParam(uViewInv, Core::mViewInv);
sh->setParam(uViewPos, Core::viewPos);
sh->setParam(uParam, *((vec4*)&params));
sh->setParam(uAnimTexRanges, mesh->animTexRanges[0], mesh->animTexRangesCount);
sh->setParam(uAnimTexOffsets, mesh->animTexOffsets[0], mesh->animTexOffsetsCount);
}
Core::basis.identity();
// clear visibility flag for rooms
@@ -1196,8 +1242,6 @@ struct Level : IGame {
PROFILE_MARKER("ROOMS");
getLight(lara->pos, lara->getRoomIndex());
Core::active.shader->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS);
Core::active.shader->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS);
#ifdef LEVEL_EDITOR
for (int i = 0; i < level.roomsCount; i++)
@@ -1264,62 +1308,51 @@ struct Level : IGame {
return true;
}
void setPassShader(Core::Pass pass) {
Core::pass = pass;
Shader *sh = NULL;
switch (pass) {
case Core::passCompose : sh = shaders[shCompose]; break;
case Core::passShadow : sh = shaders[shShadow]; break;
case Core::passAmbient : sh = shaders[shAmbient]; break;
case Core::passFilter : sh = shaders[shFilter]; break;
case Core::passWater : sh = shaders[shWater]; break;
}
ASSERT(sh);
sh->bind();
}
void renderEnvironment(int roomIndex, const vec3 &pos, Texture **targets, int stride = 0) {
PROFILE_MARKER("ENVIRONMENT");
// first pass render level into cube faces
for (int i = 0; i < 6; i++) {
setupCubeCamera(pos, i);
setPassShader(Core::passAmbient);
Core::pass = Core::passAmbient;
Texture *target = targets[0]->cube ? targets[0] : targets[i * stride];
Core::setTarget(target, i);
Core::clear(vec4(0, 0, 0, 1));
Core::setTarget(target, true, i);
renderScene(roomIndex);
Core::invalidateTarget(false, true);
}
Core::setTarget(NULL);
}
void renderShadows(int roomIndex) {
PROFILE_MARKER("PASS_SHADOW");
Core::pass = Core::passShadow;
if (!setupLightCamera()) return;
shadow->unbind(sShadow);
setPassShader(Core::passShadow);
Core::setBlending(bmNone);
Core::setTarget(shadow);
Core::clear(vec4(1.0));
bool colorShadow = shadow->format == Texture::Format::RGBA ? true : false;
if (colorShadow)
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
Core::setTarget(shadow, true);
Core::setCulling(cfBack);
renderScene(roomIndex);
Core::setCulling(cfFront);
Core::setTarget(NULL);
Core::invalidateTarget(!colorShadow, colorShadow);
Core::setCulling(cfFront);
if (colorShadow)
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
}
void renderCompose(int roomIndex) {
PROFILE_MARKER("PASS_COMPOSE");
setPassShader(Core::passCompose);
Core::pass = Core::passCompose;
Core::setBlending(bmAlpha);
Core::setDepthTest(true);
Core::setDepthWrite(true);
Core::clear(vec4(0.0f, 0.0f, 0.0f, 1.0f));
shadow->bind(sShadow);
renderScene(roomIndex);
Core::setBlending(bmNone);
}
void render() {
Core::invalidateTarget(true, true);
params.clipHeight = 1000000.0f;
params.clipSign = 1.0f;
params.waterHeight = params.clipHeight;
@@ -1329,6 +1362,7 @@ struct Level : IGame {
waterCache->reset();
renderShadows(lara->getRoomIndex());
Core::setTarget(NULL, true);
Core::setViewport(0, 0, Core::width, Core::height);
waterCache->checkVisibility = true;
@@ -1410,7 +1444,6 @@ struct Level : IGame {
/*
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
@@ -1419,10 +1452,7 @@ struct Level : IGame {
glLoadIdentity();
glOrtho(0, Core::width, 0, Core::height, 0, 1);
if (waterCache->count)
waterCache->items[0].data[0]->bind(sDiffuse);
else
atlas->bind(sDiffuse);
shadow->bind(sDiffuse);
glEnable(GL_TEXTURE_2D);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
@@ -1448,12 +1478,12 @@ struct Level : IGame {
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
*/
Core::setBlending(bmAlpha);
// Debug::Level::rooms(level, lara->pos, lara->getEntity().room);
// Debug::Level::lights(level, lara->getRoomIndex());
Debug::Level::sectors(level, lara->getRoomIndex(), (int)lara->pos.y);
// Debug::Level::sectors(level, lara->getRoomIndex(), (int)lara->pos.y);
// Core::setDepthTest(false);
// Debug::Level::portals(level);
// Core::setDepthTest(true);

View File

@@ -437,6 +437,7 @@ struct MeshBuilder {
iCount += 6;
}
}
LOG("MegaMesh: %d %d %d\n", iCount, vCount, aCount);
// compile buffer and ranges
mesh = new Mesh(indices, iCount, vertices, vCount, aCount);

View File

@@ -18,9 +18,8 @@ extern "C" {
}
void EMSCRIPTEN_KEEPALIVE game_level_load(char *data, int size, int home) {
Stream stream(data, size);
Game::startLevel(stream, NULL, false, home);
}
Game::startLevel(new Stream(data, size), NULL, false, home);
}
}
InputKey joyToInputKey(int code) {

View File

@@ -149,6 +149,7 @@
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<AssemblyDebug>true</AssemblyDebug>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">

View File

@@ -119,6 +119,44 @@ void joyUpdate() {
joyFree();
}
// touch
typedef BOOL (__stdcall *PREGISTERTOUCHWINDOW)(HWND, ULONG);
typedef BOOL (__stdcall *PGETTOUCHINPUTINFO)(HTOUCHINPUT, UINT, PTOUCHINPUT, int);
typedef BOOL (__stdcall *PCLOSETOUCHINPUTHANDLE)(HTOUCHINPUT);
PREGISTERTOUCHWINDOW RegisterTouchWindowX;
PGETTOUCHINPUTINFO GetTouchInputInfoX;
PCLOSETOUCHINPUTHANDLE CloseTouchInputHandleX;
#define MAX_TOUCH_COUNT 10
void touchInit(HWND hWnd) {
int value = GetSystemMetrics(SM_DIGITIZER);
if (value) {
HMODULE hUser32 = LoadLibrary("user32.dll");
RegisterTouchWindowX = (PREGISTERTOUCHWINDOW)GetProcAddress(hUser32, "RegisterTouchWindow");
GetTouchInputInfoX = (PGETTOUCHINPUTINFO)GetProcAddress(hUser32, "GetTouchInputInfo");
CloseTouchInputHandleX = (PCLOSETOUCHINPUTHANDLE)GetProcAddress(hUser32, "CloseTouchInputHandle");
if (RegisterTouchWindowX && GetTouchInputInfoX && CloseTouchInputHandleX)
RegisterTouchWindowX(hWnd, 0);
}
}
void touchUpdate(HTOUCHINPUT hTouch, int count) {
TOUCHINPUT touches[MAX_TOUCH_COUNT];
count = min(count, MAX_TOUCH_COUNT);
if (!GetTouchInputInfoX(hTouch, count, touches, sizeof(TOUCHINPUT)))
return;
LOG("touch [ ", count);
for (int i = 0; i < count; i++)
LOG("%d (%d, %d) ", i, touches[i].x, touches[i].y);
LOG("]\n");
CloseTouchInputHandleX(hTouch);
}
// sound
#define SND_SIZE 4704*2
@@ -182,7 +220,7 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPara
Input::reset();
break;
case WM_SIZE:
Core::width = LOWORD(lParam);
Core::width = LOWORD(lParam);
Core::height = HIWORD(lParam);
break;
case WM_DESTROY:
@@ -242,6 +280,9 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPara
joyInit();
return 1;
// touch
case WM_TOUCH :
touchUpdate((HTOUCHINPUT)lParam, wParam);
break;
// TODO
// sound
default :
@@ -293,6 +334,7 @@ int main(int argc, char** argv) {
Sound::channelsCount = 0;
touchInit(hWnd);
joyInit();
sndInit(hWnd);

View File

@@ -1,7 +1,11 @@
R"====(
#ifdef GL_ES
precision highp int;
precision lowp int;
precision highp float;
#else
#define lowp
#define mediump
#define highp
#endif
varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
@@ -16,14 +20,6 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
varying vec4 vColor;
#endif
#define TYPE_SPRITE 0
#define TYPE_FLASH 1
#define TYPE_ROOM 2
#define TYPE_ENTITY 3
#define TYPE_MIRROR 4
uniform int uType;
#ifdef PASS_COMPOSE
uniform vec3 uViewPos;
uniform int uCaustics;
@@ -78,7 +74,7 @@ uniform int uType;
#endif
#ifdef PASS_COMPOSE
if (uType != TYPE_SPRITE) {
#ifndef TYPE_SPRITE
// animated texture coordinates
vec2 range = uAnimTexRanges[int(aTexCoord.z)]; // x - start index, y - count
@@ -88,16 +84,15 @@ uniform int uType;
vTexCoord.xy = (aTexCoord.xy + offset) * TEXCOORD_SCALE; // first frame + offset * isAnimated
vNormal = vec4(mulQuat(rBasisRot, aNormal.xyz), aNormal.w);
if (uCaustics != 0) {
#ifdef CAUSTICS
float sum = coord.x + coord.y + coord.z;
vColor.xyz *= abs(sin(sum / 512.0 + uParam.x)) * 1.5 + 0.5; // color dodge
}
} else {
#endif
#else
coord.xyz += uViewInv[0].xyz * aTexCoord.z - uViewInv[1].xyz * aTexCoord.w;
vTexCoord.xy = aTexCoord.xy * TEXCOORD_SCALE;
vNormal = vec4(uViewPos.xyz - coord.xyz, 0.0);
}
#endif
vTexCoord.zw = clamp((coord.xz - uRoomSize.xy) / (uRoomSize.zw - uRoomSize.xy), vec2(0.0), vec2(1.0));
@@ -118,7 +113,6 @@ uniform int uType;
uniform vec4 uColor;
#ifdef PASS_COMPOSE
uniform samplerCube sEnvironment;
uniform int uLightsCount;
uniform vec3 uLightPos[MAX_LIGHTS];
uniform vec4 uLightColor[MAX_LIGHTS];
uniform vec3 uAmbient[6];
@@ -140,14 +134,14 @@ uniform int uType;
#ifdef SHADOW_SAMPLER
uniform sampler2DShadow sShadow;
#ifdef MOBILE
#ifdef GL_ES
#define SHADOW(V) (shadow2DEXT(sShadow, V))
#else
#define SHADOW(V) (shadow2D(sShadow, V).x)
#endif
#else
uniform sampler2D sShadow;
#define CMP(a,b) float(a > b)
#define CMP(a,b) step(b, a)
#ifdef SHADOW_DEPTH
#define compare(p, z) CMP(texture2D(sShadow, (p)).x, (z));
@@ -160,6 +154,8 @@ uniform int uType;
#endif
float SHADOW(vec3 p) {
return compare(p.xy, p.z);
/*
vec2 t = vec2(0.0, 1.0 / 1024.0);
vec2 c = floor(p.xy * 1024.0 + 0.5) / 1024.0;
vec4 s;
@@ -169,40 +165,55 @@ uniform int uType;
s.w = compare(c + t.yy, p.z);
vec2 f = fract(p.xy * 1024.0 + 0.5);
return mix(mix(s.x, s.y, f.y), mix(s.z, s.w, f.y), f.x);
*/
}
#endif
float getShadow(vec4 lightProj) {
vec3 p = lightProj.xyz / lightProj.w;
if (lightProj.w < 0.0) return 1.0;
vec2 poissonDisk[16];
poissonDisk[ 0] = vec2( -0.94201624, -0.39906216 );
poissonDisk[ 1] = vec2( 0.94558609, -0.76890725 );
poissonDisk[ 2] = vec2( -0.09418410, -0.92938870 );
poissonDisk[ 3] = vec2( 0.34495938, 0.29387760 );
poissonDisk[ 4] = vec2( -0.91588581, 0.45771432 );
poissonDisk[ 5] = vec2( -0.81544232, -0.87912464 );
poissonDisk[ 6] = vec2( -0.38277543, 0.27676845 );
poissonDisk[ 7] = vec2( 0.97484398, 0.75648379 );
poissonDisk[ 8] = vec2( 0.44323325, -0.97511554 );
poissonDisk[ 9] = vec2( 0.53742981, -0.47373420 );
poissonDisk[10] = vec2( -0.26496911, -0.41893023 );
poissonDisk[11] = vec2( 0.79197514, 0.19090188 );
poissonDisk[12] = vec2( -0.24188840, 0.99706507 );
poissonDisk[13] = vec2( -0.81409955, 0.91437590 );
poissonDisk[14] = vec2( 0.19984126, 0.78641367 );
poissonDisk[15] = vec2( 0.14383161, -0.14100790 );
vec3 poissonDisk[16];
poissonDisk[ 0] = vec3(-0.94201624, -0.39906216, 0.0) * (1.5 / 1024.0);
poissonDisk[ 1] = vec3( 0.94558609, -0.76890725, 0.0) * (1.5 / 1024.0);
poissonDisk[ 2] = vec3(-0.09418410, -0.92938870, 0.0) * (1.5 / 1024.0);
poissonDisk[ 3] = vec3( 0.34495938, 0.29387760, 0.0) * (1.5 / 1024.0);
poissonDisk[ 4] = vec3(-0.91588581, 0.45771432, 0.0) * (1.5 / 1024.0);
poissonDisk[ 5] = vec3(-0.81544232, -0.87912464, 0.0) * (1.5 / 1024.0);
poissonDisk[ 6] = vec3(-0.38277543, 0.27676845, 0.0) * (1.5 / 1024.0);
poissonDisk[ 7] = vec3( 0.97484398, 0.75648379, 0.0) * (1.5 / 1024.0);
poissonDisk[ 8] = vec3( 0.44323325, -0.97511554, 0.0) * (1.5 / 1024.0);
poissonDisk[ 9] = vec3( 0.53742981, -0.47373420, 0.0) * (1.5 / 1024.0);
poissonDisk[10] = vec3(-0.26496911, -0.41893023, 0.0) * (1.5 / 1024.0);
poissonDisk[11] = vec3( 0.79197514, 0.19090188, 0.0) * (1.5 / 1024.0);
poissonDisk[12] = vec3(-0.24188840, 0.99706507, 0.0) * (1.5 / 1024.0);
poissonDisk[13] = vec3(-0.81409955, 0.91437590, 0.0) * (1.5 / 1024.0);
poissonDisk[14] = vec3( 0.19984126, 0.78641367, 0.0) * (1.5 / 1024.0);
poissonDisk[15] = vec3( 0.14383161, -0.14100790, 0.0) * (1.5 / 1024.0);
float rShadow = 0.0;
for (int i = 0; i < 16; i += 1)
rShadow += SHADOW(p + vec3(poissonDisk[i] * 1.5, 0.0) * (1.0 / 1024.0));
vec3 p = lightProj.xyz / lightProj.w;
rShadow += SHADOW(p + poissonDisk[0]);
rShadow += SHADOW(p + poissonDisk[1]);
rShadow += SHADOW(p + poissonDisk[2]);
rShadow += SHADOW(p + poissonDisk[3]);
rShadow += SHADOW(p + poissonDisk[4]);
rShadow += SHADOW(p + poissonDisk[5]);
rShadow += SHADOW(p + poissonDisk[6]);
rShadow += SHADOW(p + poissonDisk[7]);
rShadow += SHADOW(p + poissonDisk[8]);
rShadow += SHADOW(p + poissonDisk[9]);
rShadow += SHADOW(p + poissonDisk[10]);
rShadow += SHADOW(p + poissonDisk[11]);
rShadow += SHADOW(p + poissonDisk[12]);
rShadow += SHADOW(p + poissonDisk[13]);
rShadow += SHADOW(p + poissonDisk[14]);
rShadow += SHADOW(p + poissonDisk[15]);
rShadow /= 16.0;
vec3 lv = uLightPos[0].xyz - vCoord.xyz;
float fade = clamp(dot(lv, lv) / uLightColor[0].w, 0.0, 1.0);
return mix(rShadow, 1.0, fade);
return clamp(mix(rShadow, 1.0, fade), -lightProj.w, 1.0);
}
vec3 calcLight(vec3 normal, vec3 pos, vec4 color) {
@@ -227,13 +238,12 @@ uniform int uType;
sqr.z * mix(uAmbient[5], uAmbient[4], pos.z);
}
float calcCaustics(vec3 n) {
if (uCaustics != 0) {
#ifdef CAUSTICS
float calcCaustics(vec3 n) {
vec2 fade = smoothstep(uRoomSize.xy, uRoomSize.xy + vec2(256.0), vCoord.xz) * (1.0 - smoothstep(uRoomSize.zw - vec2(256.0), uRoomSize.zw, vCoord.xz));
return texture2D(sReflect, vTexCoord.zw).r * (max(0.0, -n.y)) * fade.x * fade.y;
} else
return 0.0;
}
}
#endif
vec3 applyFog(vec3 color, vec3 fogColor, float factor) {
float fog = clamp(1.0 / exp(factor), 0.0, 1.0);
@@ -268,9 +278,10 @@ uniform int uType;
#endif
vec4 color = texture2D(sDiffuse, vTexCoord.xy);
if (color.w <= 0.6) {
discard;
}
// if (color.w <= 0.6) {
// discard;
// }
#ifdef PASS_SHADOW
#ifdef SHADOW_COLOR
@@ -288,7 +299,7 @@ uniform int uType;
color.xyz *= vColor.w;
#else
// calc point lights
if (uType != TYPE_FLASH) {
#ifndef TYPE_FLASH
vec3 normal = normalize(vNormal.xyz);
//vec3 n = getNormal();;
@@ -299,50 +310,62 @@ uniform int uType;
vec3 viewVec = normalize(vViewVec);
vec3 light = vec3(0.0);
for (int i = 1; i < MAX_LIGHTS; i++) // additional lights
light += calcLight(normal, uLightPos[i], uLightColor[i]);
// for (int i = 1; i < 3; i++) // additional lights
light += calcLight(normal, uLightPos[1], uLightColor[1]);
light += calcLight(normal, uLightPos[2], uLightColor[2]);
// apply lighting
if (uType == TYPE_SPRITE) {
#ifdef TYPE_SPRITE
light += vColor.w * uColor.w;
}
#endif
if (uType == TYPE_ROOM) {
#ifdef TYPE_ROOM
float rShadow = dot(normal, uLightPos[0].xyz - vCoord) > 0.0 ? getShadow(vLightProj) : 1.0;
//light += calcLight(normal, uLightPos[0], uLightColor[0]);
light += mix(min(uColor.w, vColor.w), vColor.w, rShadow);
light += calcCaustics(normal);
}
#ifdef CAUSTICS
light += calcCaustics(normal);
#endif
//color.xyz = vec3(rShadow);
//light.xyz = vec3(1.0);
#endif
if (uType == TYPE_ENTITY) {
#ifdef TYPE_ENTITY
vec3 rAmbient = calcAmbient(normal);
float rShadow = getShadow(vLightProj);
light += calcLight(normal, uLightPos[0], uLightColor[0]) * rShadow + rAmbient;
color.xyz += calcSpecular(normal, viewVec, uLightPos[0], uLightColor[0], uColor.w * rShadow + 0.03);
light += calcCaustics(normal);
}
#ifdef CAUSTICS
light += calcCaustics(normal);
#endif
//color.xyz = vec3(rShadow);
//light.xyz = vec3(1.0);
#endif
if (uType == TYPE_MIRROR) {
#ifdef TYPE_MIRROR
vec3 rv = reflect(-viewVec, normal);
color.xyz = uColor.xyz * pow(abs(textureCube(sEnvironment, normalize(rv)).xyz), vec3(2.2));
light.xyz = vec3(1.0);
}
#endif
color.xyz *= light;
} else {
#else // ifndef TYPE_FLASH
color.w = uColor.w;
}
#endif
#endif
color = sqrt(color); // back to "gamma" space
#ifdef PASS_COMPOSE
color.xyz = applyFog(color.xyz, vec3(0.0), length(vViewVec) * FOG_DIST);
if (uCaustics != 0) {
#ifdef CAUSTICS
float d = abs((vCoord.y - max(uViewPos.y, uParam.y)) / normalize(vViewVec).y);
d *= step(0.0, vCoord.y - uParam.y);
color.xyz = applyFog(color.xyz, uColor.xyz * 0.2, d * WATER_FOG_DIST);
}
#endif
#endif
gl_FragColor = color;

View File

@@ -5,20 +5,22 @@
enum AttribType { aCoord, aTexCoord, aNormal, aColor, aMAX };
enum SamplerType { sDiffuse, sNormal, sReflect, sShadow, sEnvironment, sMask, sMAX };
enum UniformType { uType, uCaustics, uParam, uTexParam, uViewProj, uViewInv, uBasis, uLightProj, uColor, uAmbient, uViewPos, uLightsCount, uLightPos, uLightColor, uAnimTexRanges, uAnimTexOffsets, uRoomSize, uPosScale, uMAX };
enum UniformType { uParam, uTexParam, uViewProj, uViewInv, uBasis, uLightProj, uColor, uAmbient, uViewPos, uLightPos, uLightColor, uAnimTexRanges, uAnimTexOffsets, uRoomSize, uPosScale, uMAX };
const char *AttribName[aMAX] = { "aCoord", "aTexCoord", "aNormal", "aColor" };
const char *SamplerName[sMAX] = { "sDiffuse", "sNormal", "sReflect", "sShadow", "sEnvironment", "sMask" };
const char *UniformName[uMAX] = { "uType", "uCaustics", "uParam", "uTexParam", "uViewProj", "uViewInv", "uBasis", "uLightProj", "uColor", "uAmbient", "uViewPos", "uLightsCount", "uLightPos", "uLightColor", "uAnimTexRanges", "uAnimTexOffsets", "uRoomSize", "uPosScale" };
const char *UniformName[uMAX] = { "uParam", "uTexParam", "uViewProj", "uViewInv", "uBasis", "uLightProj", "uColor", "uAmbient", "uViewPos", "uLightPos", "uLightColor", "uAnimTexRanges", "uAnimTexOffsets", "uRoomSize", "uPosScale" };
struct Shader {
GLuint ID;
GLint uID[uMAX];
enum : GLint {
enum Type : GLint {
NONE = 0,
/* shader */ SPRITE = 0, FLASH = 1, ROOM = 2, ENTITY = 3, MIRROR = 4,
/* filter */ FILTER_DOWNSAMPLE = 0,
/* water */ WATER_DROP = 0, WATER_STEP = 1, WATER_CAUSTICS = 2, WATER_MASK = 3, WATER_COMPOSE = 4,
MAX = 5
};
Shader(const char *text, const char *defines = "") {

View File

@@ -61,7 +61,7 @@ struct Sprite : Controller {
}
}
virtual void render(Frustum *frustum, MeshBuilder *mesh) {
virtual void render(Frustum *frustum, MeshBuilder *mesh, Shader::Type type, bool caustics) {
Basis basis(Core::basis);
basis.translate(pos);
Core::active.shader->setParam(uBasis, basis);

View File

@@ -299,13 +299,11 @@ struct Crystal : Controller {
delete environment;
}
virtual void render(Frustum *frustum, MeshBuilder *mesh) {
virtual void render(Frustum *frustum, MeshBuilder *mesh, Shader::Type type, bool caustics) {
Shader *sh = Core::active.shader;
sh->setParam(uType, Shader::MIRROR);
sh->setParam(uColor, vec4(0.4f, 0.4f, 16.0f, 1.0f)); // blue color dodge
environment->bind(sEnvironment);
Controller::render(frustum, mesh);
sh->setParam(uType, Shader::ENTITY);
Controller::render(frustum, mesh, type, caustics);
}
};

View File

@@ -12,9 +12,6 @@
#ifndef ANDROID
#define LOG(...) printf(__VA_ARGS__)
#else
#include <android/log.h>
#define LOG(...) __android_log_print(ANDROID_LOG_INFO,"X5",__VA_ARGS__)
#endif
#else
@@ -26,6 +23,13 @@
// #endif
#endif
#ifdef ANDROID
#include <android/log.h>
#undef LOG
#define LOG(...) __android_log_print(ANDROID_LOG_INFO,"OpenLara",__VA_ARGS__)
#endif
#define EPS FLT_EPSILON
#define INF INFINITY
#define PI 3.14159265358979323846f
@@ -34,9 +38,9 @@
#define RAD2DEG (180.0f / PI)
#define randf() ((float)rand()/RAND_MAX)
typedef char int8;
typedef short int16;
typedef int int32;
typedef signed char int8;
typedef signed short int16;
typedef signed int int32;
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;

View File

@@ -1,24 +1,23 @@
R"====(
#ifdef GL_ES
precision highp int;
precision lowp int;
precision highp float;
#endif
varying vec3 vCoord;
varying vec2 vTexCoord;
varying vec4 vProjCoord;
varying vec3 vRefPos1;
varying vec3 vRefPos2;
varying vec4 vOldPos;
varying vec4 vNewPos;
varying vec3 vViewVec;
varying vec3 vLightVec;
/*
#define WATER_DROP 0
#define WATER_STEP 1
#define WATER_CAUSTICS 2
#define WATER_MASK 3
#define WATER_COMPOSE 4
uniform int uType;
*/
uniform vec3 uViewPos;
uniform mat4 uViewProj;
uniform vec3 uLightPos;
@@ -39,14 +38,14 @@ uniform sampler2D sNormal;
void main() {
vTexCoord = (aCoord.xy * 0.5 + 0.5) * uTexParam.zw;
if (uType >= WATER_MASK) {
#if defined(WATER_MASK) || defined(WATER_COMPOSE)
float height = 0.0;
if (uType == WATER_COMPOSE) {
#ifdef WATER_COMPOSE
vTexCoord = (aCoord.xy * (1.0 / 48.0) * 0.5 + 0.5) * uTexParam.zw;
height = texture2D(sNormal, vTexCoord).x;
}
#endif
vCoord = vec3(aCoord.x, height, aCoord.y) * uPosScale[1] + uPosScale[0];
@@ -54,28 +53,28 @@ uniform sampler2D sNormal;
vProjCoord = cp;
gl_Position = cp;
} else {
#else
vProjCoord = vec4(0.0);
vCoord = vec3(aCoord.xy, 0.0);
if (uType == WATER_CAUSTICS) {
vec3 rCoord = vec3(aCoord.x, 0.0, aCoord.y) * uPosScale[1];
#ifdef WATER_CAUSTICS
vec3 rCoord = vec3(aCoord.x, aCoord.y, 0.0) * uPosScale[1].xzy;
vec4 info = texture2D(sNormal, (rCoord.xz * 0.5 + 0.5) * uTexParam.zw);
vec3 normal = vec3(info.z, -sqrt(1.0 - dot(info.zw, info.zw)), info.w);
vec4 info = texture2D(sNormal, (rCoord.xy * 0.5 + 0.5) * uTexParam.zw);
vec3 normal = vec3(info.z, info.w, sqrt(1.0 - dot(info.zw, info.zw)));
vec3 light = vec3(0.0, -1.0, 0.0);
vec3 refractedLight = refract(-light, vec3(0.0, 1.0, 0.0), ETA_AIR / ETA_WATER);
vec3 ray = refract(-light, normal, ETA_AIR / ETA_WATER);
vec3 light = vec3(0.0, 0.0, 1.0);
vec3 refOld = refract(-light, vec3(0.0, 0.0, 1.0), 0.75);
vec3 refNew = refract(-light, normal, 0.75);
vRefPos1 = rCoord + vec3(0.0, 0.0, 0.0);
vRefPos2 = rCoord + vec3(0.0, info.r, 0.0) + ray / ray.y;
vOldPos = vec4(rCoord + refOld * (-0.25 / refOld.z) + refOld * ((-refOld.z - 1.0) / refOld.z), 1.0);
vNewPos = vec4(rCoord + refNew * ((info.r - 0.25) / refNew.z) + refOld * ((-refNew.z - 1.0) / refOld.z), 1.0);
gl_Position = vec4((vRefPos2.xz + 0.0 * refractedLight.xz / refractedLight.y), 0.0, 1.0);
} else {
vRefPos1 = vRefPos2 = vec3(0.0);
gl_Position = vec4(vNewPos.xy + refOld.xy / refOld.z, 0.0, 1.0);
#else
vOldPos = vNewPos = vec4(0.0);
gl_Position = vec4(aCoord.xyz, 1.0);
}
}
#endif
#endif
vViewVec = uViewPos - vCoord.xyz;
vLightVec = uLightPos - vCoord.xyz;
}
@@ -137,9 +136,10 @@ uniform sampler2D sNormal;
}
vec4 caustics() {
float area1 = length(dFdx(vRefPos1)) * length(dFdy(vRefPos1));
float area2 = length(dFdx(vRefPos2)) * length(dFdy(vRefPos2));
return vec4(vec3(area1 / area2 * 0.2), 1.0);
float rOldArea = length(dFdx(vOldPos.xyz)) * length(dFdy(vOldPos.xyz));
float rNewArea = length(dFdx(vNewPos.xyz)) * length(dFdy(vNewPos.xyz));
float value = clamp(rOldArea / rNewArea * 0.2, 0.0, 1.0) * vOldPos.w;
return vec4(vec3(value), 1.0);
}
vec4 mask() {
@@ -178,12 +178,28 @@ uniform sampler2D sNormal;
}
vec4 pass() {
if (uType == WATER_DROP) return drop();
if (uType == WATER_STEP) return calc();
if (uType == WATER_CAUSTICS) return caustics();
if (uType == WATER_MASK) return mask();
if (uType == WATER_COMPOSE) return compose();
return vec4(1.0, 0.0, 0.0, 1.0);
return
#ifdef WATER_DROP
drop();
#endif
#ifdef WATER_STEP
calc();
#endif
#ifdef WATER_CAUSTICS
caustics();
#endif
#ifdef WATER_MASK
mask();
#endif
#ifdef WATER_COMPOSE
compose();
#endif
vec4(1.0, 0.0, 0.0, 1.0);
}
void main() {