diff --git a/src/cache.h b/src/cache.h index 346f8fd..032fef4 100644 --- a/src/cache.h +++ b/src/cache.h @@ -288,6 +288,8 @@ struct AmbientCache { float(max((s.floor - 2) * 256, (s.floor + s.ceiling) * 256 / 2)), float((sector % r.zSectors) * 1024 + 512 + r.info.z)); + Core::setClearColor(vec4(0, 0, 0, 1)); + // first pass - render environment from position (room geometry & static meshes) game->renderEnvironment(room, pos, textures, 4); @@ -304,7 +306,7 @@ struct AmbientCache { for (int j = 0; j < 6; j++) { Texture *src = textures[j * 4 + i - 1]; Texture *dst = textures[j * 4 + i]; - Core::setRenderTarget(dst, RT_CLEAR_COLOR | RT_CLEAR_DEPTH | RT_STORE_COLOR); + Core::setTarget(dst, RT_STORE_COLOR); src->bind(sDiffuse); game->getMesh()->renderQuad(); } @@ -312,11 +314,12 @@ struct AmbientCache { // get result color from 1x1 textures for (int j = 0; j < 6; j++) { - Core::setRenderTarget(textures[j * 4 + 3], RT_STORE_COLOR); + Core::setTarget(textures[j * 4 + 3], RT_LOAD_COLOR); colors[j] = Core::copyPixel(0, 0).xyz(); } Core::setDepthTest(true); + Core::setClearColor(vec4(0, 0, 0, 0)); } void processQueue() { @@ -628,7 +631,7 @@ struct WaterCache { Core::active.shader->setParam(uParam, vec4(p.x, p.z, drop.radius * DETAIL, -drop.strength)); item.data[0]->bind(sDiffuse); - Core::setRenderTarget(item.data[1], RT_STORE_COLOR); + Core::setTarget(item.data[1], RT_STORE_COLOR); Core::setViewport(0, 0, int(item.size.x * DETAIL * 2.0f + 0.5f), int(item.size.z * DETAIL * 2.0f + 0.5f)); game->getMesh()->renderQuad(); swap(item.data[0], item.data[1]); @@ -636,7 +639,6 @@ struct WaterCache { } void step(Item &item) { - item.timer = SIMULATE_TIMESTEP; if (item.timer < SIMULATE_TIMESTEP) return; game->setShader(Core::passWater, Shader::WATER_STEP); @@ -646,7 +648,7 @@ struct WaterCache { while (item.timer >= SIMULATE_TIMESTEP) { // water step item.data[0]->bind(sDiffuse); - Core::setRenderTarget(item.data[1], RT_STORE_COLOR); + Core::setTarget(item.data[1], RT_STORE_COLOR); Core::setViewport(0, 0, int(item.size.x * DETAIL * 2.0f + 0.5f), int(item.size.z * DETAIL * 2.0f + 0.5f)); game->getMesh()->renderQuad(); swap(item.data[0], item.data[1]); @@ -665,7 +667,7 @@ struct WaterCache { Core::whiteTex->bind(sReflect); item.data[0]->bind(sNormal); - Core::setRenderTarget(item.caustics, RT_STORE_COLOR); + Core::setTarget(item.caustics, RT_STORE_COLOR); game->getMesh()->renderPlane(); #ifdef BLUR_CAUSTICS // v blur @@ -765,7 +767,7 @@ struct WaterCache { } // render mirror reflection - Core::setRenderTarget(reflect, RT_CLEAR_COLOR | RT_CLEAR_DEPTH | RT_STORE_COLOR); + Core::setTarget(reflect, RT_CLEAR_COLOR | RT_CLEAR_DEPTH | RT_STORE_COLOR); Camera *camera = (Camera*)game->getCamera(); game->setupBinding(); diff --git a/src/core.h b/src/core.h index 18b0f9f..e302cd5 100644 --- a/src/core.h +++ b/src/core.h @@ -22,6 +22,8 @@ #undef OS_PTHREAD_MT #elif ANDROID #define MOBILE + #define RENDER_TBR + #include #include #include @@ -57,6 +59,8 @@ extern void osToggleVR(bool enable); #elif __RPI__ #define MOBILE + #define RENDER_TBR + #include #include #include @@ -101,6 +105,8 @@ #if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR #define MOBILE + #define RENDER_TBR + #include #include #include @@ -1237,6 +1243,8 @@ namespace Core { sceGuDrawBufferList(GU_PSM_5650, target->offset, target->width); */ #else + bool depth = false; + Core::stats.rt++; if (!target) { // may be a null glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO); @@ -1245,7 +1253,8 @@ namespace Core { if (target->opt & Texture::CUBEMAP) texTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face; - bool depth = target->format == Texture::DEPTH || target->format == Texture::SHADOW; + depth = target->format == Texture::DEPTH || target->format == Texture::SHADOW; + int rtIndex = cacheRenderTarget(depth, target->width, target->height); glBindFramebuffer(GL_FRAMEBUFFER, FBO); @@ -1254,6 +1263,11 @@ namespace Core { } #endif + #ifdef RENDER_TBR + if (!(reqTarget.op & RT_LOAD_COLOR) && !depth) reqTarget.op |= RT_CLEAR_COLOR; + if (!(reqTarget.op & RT_LOAD_DEPTH) && depth) reqTarget.op |= RT_CLEAR_DEPTH; + #endif + active.target = target; active.targetOp = reqTarget.op; active.targetFace = face; @@ -1454,7 +1468,7 @@ namespace Core { renderState &= ~RS_DEPTH_TEST; } - void setRenderTarget(Texture *target, int op, int face = 0) { + void setTarget(Texture *target, int op, int face = 0) { if (!target) target = defaultTarget; diff --git a/src/inventory.h b/src/inventory.h index 8598b12..9868386 100644 --- a/src/inventory.h +++ b/src/inventory.h @@ -1121,21 +1121,21 @@ struct Inventory { // #else // vertical blur - Core::setRenderTarget(background[1], RT_STORE_COLOR); + Core::setTarget(background[1], RT_STORE_COLOR); game->setShader(Core::passFilter, Shader::FILTER_BLUR, false, false); Core::active.shader->setParam(uParam, vec4(0, 1, 1.0f / INVENTORY_BG_SIZE, 0));; background[0]->bind(sDiffuse); game->getMesh()->renderQuad(); // horizontal blur - Core::setRenderTarget(background[0], RT_STORE_COLOR); + Core::setTarget(background[0], RT_STORE_COLOR); game->setShader(Core::passFilter, Shader::FILTER_BLUR, false, false); Core::active.shader->setParam(uParam, vec4(1, 0, 1.0f / INVENTORY_BG_SIZE, 0));; background[1]->bind(sDiffuse); game->getMesh()->renderQuad(); // grayscale - Core::setRenderTarget(background[1], RT_STORE_COLOR); + Core::setTarget(background[1], RT_STORE_COLOR); game->setShader(Core::passFilter, Shader::FILTER_GRAYSCALE, false, false); Core::active.shader->setParam(uParam, vec4(1, 0, 0, 0)); background[0]->bind(sDiffuse); diff --git a/src/level.h b/src/level.h index 9851a53..181402b 100644 --- a/src/level.h +++ b/src/level.h @@ -414,18 +414,22 @@ struct Level : IGame { virtual void renderEnvironment(int roomIndex, const vec3 &pos, Texture **targets, int stride = 0, Core::Pass pass = Core::passAmbient) { PROFILE_MARKER("ENVIRONMENT"); - Core::eye = 0.0f; setupBinding(); + float tmpEye = Core::eye; Core::Pass tmpPass = Core::pass; - // first pass render level into cube faces + Core::eye = 0.0f; + + // render level into cube faces or texture images for (int i = 0; i < 6; i++) { setupCubeCamera(pos, i); Core::pass = pass; Texture *target = (targets[0]->opt & Texture::CUBEMAP) ? targets[0] : targets[i * stride]; - Core::setRenderTarget(target, RT_CLEAR_COLOR | RT_CLEAR_DEPTH | RT_STORE_COLOR, i); + Core::setTarget(target, RT_CLEAR_COLOR | RT_CLEAR_DEPTH | RT_STORE_COLOR, i); renderView(roomIndex, false, false); } + Core::pass = tmpPass; + Core::eye = tmpEye; } virtual void setEffect(Controller *controller, TR::Effect::Type effect) { @@ -1869,7 +1873,7 @@ struct Level : IGame { } if (water) { - Core::setRenderTarget(NULL, RT_CLEAR_COLOR | RT_CLEAR_DEPTH | RT_STORE_COLOR); // render to back buffer + Core::setTarget(NULL, RT_CLEAR_COLOR | RT_CLEAR_DEPTH | RT_STORE_COLOR); // render to back buffer setupBinding(); } @@ -2041,7 +2045,7 @@ struct Level : IGame { bool colorShadow = shadow->format == Texture::RGBA ? true : false; if (colorShadow) Core::setClearColor(vec4(1.0f)); - Core::setRenderTarget(shadow, RT_CLEAR_DEPTH | (colorShadow ? (RT_CLEAR_COLOR | RT_STORE_COLOR) : RT_STORE_DEPTH)); + Core::setTarget(shadow, RT_CLEAR_DEPTH | (colorShadow ? (RT_CLEAR_COLOR | RT_STORE_COLOR) : RT_STORE_DEPTH)); Core::validateRenderState(); Core::setCulling(cfBack); @@ -2478,7 +2482,7 @@ struct Level : IGame { } void renderInventory() { - Core::setRenderTarget(NULL, RT_CLEAR_DEPTH | RT_STORE_COLOR); + Core::setTarget(NULL, RT_CLEAR_DEPTH | RT_STORE_COLOR); if (!(level.isTitle() || inventory.titleTimer > 0.0f)) inventory.renderBackground(); @@ -2501,7 +2505,7 @@ struct Level : IGame { lastTitle = title; if (isEnded) { - Core::setRenderTarget(NULL, RT_CLEAR_COLOR); + Core::setTarget(NULL, RT_CLEAR_COLOR); UI::begin(); UI::updateAspect(float(Core::width) / float(Core::height)); UI::textOut(vec2(0, 480 - 16), STR_LOADING, UI::aCenter, UI::width); diff --git a/src/shaders/shader.glsl b/src/shaders/shader.glsl index 7a15025..adceeb3 100644 --- a/src/shaders/shader.glsl +++ b/src/shaders/shader.glsl @@ -4,18 +4,17 @@ R"====( precision highp float; #endif -#ifdef OPT_CONTACT +#if defined(PASS_COMPOSE) && !defined(TYPE_FLASH) varying vec3 vCoord; #endif varying vec4 vTexCoord; // xy - atlas coords, zw - trapezoidal correction #ifdef OPT_CAUSTICS - varying vec2 vCausticsCoord; // - xy caustics texture coord uniform vec4 uRoomSize; // xy - minXZ, zw - maxXZ #endif -uniform mat4 uLightProj; +uniform mat4 uLightProj[SHADOW_OBJ_MAX]; uniform mat4 uViewProj; uniform vec3 uViewPos; uniform vec4 uParam; // x - time, y - water height, z - clip plane sign, w - clip plane height @@ -32,7 +31,6 @@ uniform vec4 uMaterial; // x - diffuse, y - ambient, z - specular, w - alpha #ifndef TYPE_FLASH #ifdef PASS_COMPOSE - varying vec4 vLightProj; varying vec4 vLightVec; // xyz - dir, w - fog factor #ifdef OPT_SHADOW @@ -131,7 +129,7 @@ uniform vec4 uMaterial; // x - diffuse, y - ambient, z - specular, w - alpha vLightVec.w = clamp(1.0 / exp(fog), 0.0, 1.0); #endif - #ifdef OPT_CONTACT + #if defined(PASS_COMPOSE) && !defined(TYPE_FLASH) vCoord = coord.xyz; #endif return coord; @@ -227,10 +225,6 @@ uniform vec4 uMaterial; // x - diffuse, y - ambient, z - specular, w - alpha #if defined(PASS_COMPOSE) && !defined(TYPE_SPRITE) vTexCoord.xy *= vTexCoord.zw; #endif - - #ifdef OPT_CAUSTICS - vCausticsCoord.xy = clamp((coord.xz - uRoomSize.xy) / (uRoomSize.zw - uRoomSize.xy), vec2(0.0), vec2(1.0)); - #endif } void main() { @@ -239,10 +233,6 @@ uniform vec4 uMaterial; // x - diffuse, y - ambient, z - specular, w - alpha #ifndef PASS_SHADOW _diffuse(); _lighting(coord.xyz); - - #if defined(PASS_COMPOSE) && !defined(TYPE_FLASH) - vLightProj = uLightProj * coord; - #endif #endif _uv(coord.xyz); @@ -293,8 +283,6 @@ uniform vec4 uMaterial; // x - diffuse, y - ambient, z - specular, w - alpha } #endif - #define SHADOW_TEXEL (2.0 / SHADOW_TEX_SIZE) - float random(vec3 seed, float freq) { float dt = dot(floor(seed * freq), vec3(53.1215, 21.1352, 9.1322)); return fract(sin(dt) * 2105.2354); @@ -308,8 +296,18 @@ uniform vec4 uMaterial; // x - diffuse, y - ambient, z - specular, w - alpha return vec3(v.x * sc.y + v.y * sc.x, v.x * -sc.x + v.y * sc.y, 0.0); } - float getShadow(vec4 lightProj) { + float getShadow(vec4 lightProj, vec2 tileOffset) { vec3 p = lightProj.xyz / lightProj.w; + float vis = + #ifdef TYPE_ROOM + min(dot(vNormal.xyz, vLightVec.xyz), lightProj.w); + #else + lightProj.w; + #endif + vis = min(min(p.x, p.y), vis); + if (vis <= 0.0 || max(p.x, p.y) > 1.0) return 1.0; + + p.xy = p.xy * vec2(0.25, 0.5) + tileOffset; float rShadow = SHADOW(SHADOW_TEXEL * vec3(-0.93289, -0.03146, 0.0) + p) + SHADOW(SHADOW_TEXEL * vec3( 0.81628, -0.05965, 0.0) + p) + @@ -337,13 +335,17 @@ uniform vec4 uMaterial; // x - diffuse, y - ambient, z - specular, w - alpha return rShadow + (1.0 - rShadow) * fade; } - float getShadow() { - #ifdef TYPE_ROOM - float vis = min(dot(vNormal.xyz, vLightVec.xyz), vLightProj.w); - #else - float vis = vLightProj.w; - #endif - return vis > 0.0 ? getShadow(vLightProj) : 1.0; + float getShadow() { // hardcoded for 4x2 shadow atlas + vec4 c = vec4(vCoord, 1.0); + return min(min(min(min(min(min(min( + getShadow(uLightProj[0] * c, vec2(0.00, 0.0)), + getShadow(uLightProj[1] * c, vec2(0.25, 0.0))), + getShadow(uLightProj[2] * c, vec2(0.50, 0.0))), + getShadow(uLightProj[3] * c, vec2(0.75, 0.0))), + getShadow(uLightProj[4] * c, vec2(0.00, 0.5))), + getShadow(uLightProj[5] * c, vec2(0.25, 0.5))), + getShadow(uLightProj[6] * c, vec2(0.50, 0.5))), + getShadow(uLightProj[7] * c, vec2(0.75, 0.5))); } #endif @@ -351,7 +353,7 @@ uniform vec4 uMaterial; // x - diffuse, y - ambient, z - specular, w - alpha uniform sampler2D sReflect; float calcCaustics(vec3 n) { - vec2 cc = vCausticsCoord.xy; + vec2 cc = clamp((vCoord.xz - uRoomSize.xy) / (uRoomSize.zw - uRoomSize.xy), vec2(0.0), vec2(1.0)); vec2 border = vec2(256.0) / (uRoomSize.zw - uRoomSize.xy); vec2 fade = smoothstep(vec2(0.0), border, cc) * (1.0 - smoothstep(vec2(1.0) - border, vec2(1.0), cc)); return texture2D(sReflect, cc).x * max(0.0, -n.y) * fade.x * fade.y;