diff --git a/src/controller.h b/src/controller.h index a4c9a5b..9159604 100644 --- a/src/controller.h +++ b/src/controller.h @@ -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); diff --git a/src/core.h b/src/core.h index 6726cb8..5b10df2 100644 --- a/src/core.h +++ b/src/core.h @@ -6,6 +6,30 @@ #include #include #include +#elif ANDROID + #define MOBILE + #include + #include + #include + + #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 @@ -18,16 +42,11 @@ #include #include #include -/* - * 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 #include #include @@ -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) { diff --git a/src/format.h b/src/format.h index 0551770..9c5993a 100644 --- a/src/format.h +++ b/src/format.h @@ -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; diff --git a/src/game.h b/src/game.h index 4ab309b..8123e79 100644 --- a/src/game.h +++ b/src/game.h @@ -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(); diff --git a/src/lara.h b/src/lara.h index b556cbf..970de56 100644 --- a/src/lara.h +++ b/src/lara.h @@ -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); } } }; diff --git a/src/level.h b/src/level.h index 994eb3a..bd854dd 100644 --- a/src/level.h +++ b/src/level.h @@ -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*)¶ms)); - 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*)¶ms)); + 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); diff --git a/src/mesh.h b/src/mesh.h index f1e4a2b..d85c87a 100644 --- a/src/mesh.h +++ b/src/mesh.h @@ -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); diff --git a/src/platform/web/main.cpp b/src/platform/web/main.cpp index bcd5bf8..61cf4a7 100644 --- a/src/platform/web/main.cpp +++ b/src/platform/web/main.cpp @@ -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) { diff --git a/src/platform/win/OpenLara.vcxproj b/src/platform/win/OpenLara.vcxproj index e5a9775..8c2a530 100644 --- a/src/platform/win/OpenLara.vcxproj +++ b/src/platform/win/OpenLara.vcxproj @@ -149,6 +149,7 @@ true false false + true diff --git a/src/platform/win/main.cpp b/src/platform/win/main.cpp index c27cb42..8d0ad1f 100644 --- a/src/platform/win/main.cpp +++ b/src/platform/win/main.cpp @@ -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); diff --git a/src/shader.glsl b/src/shader.glsl index 5d47934..7665e12 100644 --- a/src/shader.glsl +++ b/src/shader.glsl @@ -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; diff --git a/src/shader.h b/src/shader.h index a7be391..c7cf2a0 100644 --- a/src/shader.h +++ b/src/shader.h @@ -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 = "") { diff --git a/src/sprite.h b/src/sprite.h index c237f1f..5d8f2a0 100644 --- a/src/sprite.h +++ b/src/sprite.h @@ -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); diff --git a/src/trigger.h b/src/trigger.h index e529be6..b1b0bf1 100644 --- a/src/trigger.h +++ b/src/trigger.h @@ -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); } }; diff --git a/src/utils.h b/src/utils.h index c352422..9942961 100644 --- a/src/utils.h +++ b/src/utils.h @@ -12,9 +12,6 @@ #ifndef ANDROID #define LOG(...) printf(__VA_ARGS__) - #else - #include - #define LOG(...) __android_log_print(ANDROID_LOG_INFO,"X5",__VA_ARGS__) #endif #else @@ -26,6 +23,13 @@ // #endif #endif +#ifdef ANDROID + #include + #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; diff --git a/src/water.glsl b/src/water.glsl index 7dea6ca..48d2d55 100644 --- a/src/water.glsl +++ b/src/water.glsl @@ -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() {