diff --git a/src/cache.h b/src/cache.h index 443bd29..74b1969 100644 --- a/src/cache.h +++ b/src/cache.h @@ -357,6 +357,7 @@ struct WaterCache { IGame *game; TR::Level *level; + Texture *screen; Texture *refract; Texture *reflect; @@ -482,11 +483,12 @@ struct WaterCache { Drop(const vec3 &pos, float radius, float strength) : pos(pos), radius(radius), strength(strength) {} } drops[MAX_DROPS]; - WaterCache(IGame *game) : game(game), level(game->getLevel()), refract(NULL), count(0), dropCount(0) { + WaterCache(IGame *game) : game(game), level(game->getLevel()), screen(NULL), refract(NULL), count(0), dropCount(0) { reflect = new Texture(512, 512, FMT_RGBA, OPT_TARGET); } - ~WaterCache() { + ~WaterCache() { + delete screen; delete refract; delete reflect; for (int i = 0; i < count; i++) @@ -702,27 +704,34 @@ struct WaterCache { Core::setCullMode(cmFront); } - void getTargetSize(int &w, int &h) { - if (Core::active.target != NULL) { - w = Core::active.target->width; - h = Core::active.target->height; - } else { - w = Core::viewportDef.width; - h = Core::viewportDef.height; - } - } - void getRefract() { - if (!visible) return; - PROFILE_MARKER("WATER_REFRACT"); - int w, h; - getTargetSize(w, h); + Texture* getScreenTex() { + int w = Core::viewportDef.width; + int h = Core::viewportDef.height; // get refraction texture - if (!refract || w > refract->origWidth || h > refract->origHeight) { + if (!refract || w != refract->origWidth || h != refract->origHeight) { + PROFILE_MARKER("WATER_REFRACT_INIT"); delete refract; refract = new Texture(w, h, FMT_RGBA, OPT_TARGET); + #ifdef _OS_IOS + delete screen; + screen = new Texture(w, h, FMT_RGBA, OPT_TARGET); + #endif } - Core::copyTarget(refract, 0, 0, int(Core::viewportDef.x), int(Core::viewportDef.y), w, h); // copy framebuffer into refraction texture + return screen; + } + + void copyScreenToRefract() { + PROFILE_MARKER("WATER_REFRACT_COPY"); + // get refraction texture + int x, y; + if (!screen) { + x = Core::viewportDef.x; + y = Core::viewportDef.y; + } else + x = y = 0; + + Core::copyTarget(refract, 0, 0, x, y, Core::viewportDef.width, Core::viewportDef.height); // copy framebuffer into refraction texture } void simulate() { @@ -828,9 +837,7 @@ struct WaterCache { Core::active.shader->setParam(uLightPos, Core::lightPos[0], 1); Core::active.shader->setParam(uLightColor, Core::lightColor[0], 1); - int w, h; - getTargetSize(w, h); - Core::active.shader->setParam(uParam, vec4(float(w) / refract->width, float(h) / refract->height, 0.05f, 0.03f)); + Core::active.shader->setParam(uParam, vec4(float(refract->origWidth) / refract->width, float(refract->origHeight) / refract->height, 0.05f, 0.03f)); float sx = item.size.x * DETAIL / (item.data[0]->width / 2); float sz = item.size.z * DETAIL / (item.data[0]->height / 2); @@ -858,6 +865,44 @@ struct WaterCache { dropCount = 0; } + void blitScreen() { + ASSERT(screen); + + Core::setDepthTest(false); + Core::setBlendMode(bmNone); + + game->setShader(Core::passGUI, Shader::DEFAULT); + + Core::mView.identity(); + Core::mProj = GAPI::ortho(0.0f, float(screen->origWidth), 0.0f, float(screen->origHeight), 0.0f, 1.0f); + Core::setViewProj(Core::mView, Core::mProj); + Core::active.shader->setParam(uViewProj, Core::mViewProj); + Core::active.shader->setParam(uMaterial, vec4(1.0f)); + + screen->bind(0); + int w = screen->width; + int h = screen->height; + + Index indices[6] = { 0, 1, 2, 0, 2, 3 }; + Vertex vertices[4]; + vertices[0].coord = short4(0, h, 0, 0); + vertices[1].coord = short4(w, h, 0, 0); + vertices[2].coord = short4(w, 0, 0, 0); + vertices[3].coord = short4(0, 0, 0, 0); + vertices[0].light = + vertices[1].light = + vertices[2].light = + vertices[3].light = ubyte4(255, 255, 255, 255); + vertices[0].texCoord = short4( 0, 32767, 0, 0); + vertices[1].texCoord = short4(32767, 32767, 0, 0); + vertices[2].texCoord = short4(32767, 0, 0, 0); + vertices[3].texCoord = short4( 0, 0, 0, 0); + + game->getMesh()->renderBuffer(indices, COUNT(indices), vertices, COUNT(vertices)); + + Core::setDepthTest(true); + } + #undef MAX_WATER_SURFACES #undef MAX_WATER_INVISIBLE_TIME #undef WATER_SIMULATE_TIMESTEP diff --git a/src/core.h b/src/core.h index 5f318c0..dc26c55 100644 --- a/src/core.h +++ b/src/core.h @@ -894,7 +894,7 @@ namespace Core { if (target == defaultTarget) // backbuffer setViewport(viewportDef); else - setViewport(0, 0, target->width, target->height); + setViewport(0, 0, target->origWidth, target->origHeight); reqTarget.texture = target; reqTarget.op = op; diff --git a/src/level.h b/src/level.h index 96d2bf8..4be8d1c 100644 --- a/src/level.h +++ b/src/level.h @@ -2002,8 +2002,10 @@ struct Level : IGame { controller->flags.rendered = false; } + Texture *screen = NULL; if (water) { - Core::setTarget(NULL, RT_CLEAR_COLOR | RT_CLEAR_DEPTH | RT_STORE_COLOR); // render to back buffer + screen = (waterCache && waterCache->visible) ? waterCache->getScreenTex() : NULL; + Core::setTarget(screen, RT_CLEAR_COLOR | RT_CLEAR_DEPTH | RT_STORE_COLOR); // render to screen texture (FUCK YOU iOS!) or back buffer setupBinding(); } @@ -2027,9 +2029,10 @@ struct Level : IGame { if (water && waterCache && waterCache->visible) { Core::Pass pass = Core::pass; waterCache->renderMask(); - waterCache->getRefract(); + waterCache->copyScreenToRefract(); setMainLight(player); waterCache->render(); + Core::pass = pass; setupBinding(); } @@ -2039,11 +2042,17 @@ struct Level : IGame { Core::setBlendMode(bmNone); - if (showUI) { - Core::Pass pass = Core::pass; - renderUI(); - Core::pass = pass; + Core::Pass pass = Core::pass; + + if (water && waterCache && waterCache->visible && screen) { + Core::setTarget(NULL, RT_CLEAR_COLOR | RT_CLEAR_DEPTH | RT_STORE_COLOR); + waterCache->blitScreen(); } + + if (showUI) + renderUI(); + + Core::pass = pass; } void setupCubeCamera(const vec3 &pos, int face) {