diff --git a/src/cache.h b/src/cache.h index 7facf8d..ceca791 100644 --- a/src/cache.h +++ b/src/cache.h @@ -9,6 +9,10 @@ #define NO_CLIP_PLANE 1000000.0f //#define LOG_SHADERS +#if defined(_OS_IOS) || defined(_GAPI_D3D9) || defined(_GAPI_GXM) + #define USE_SCREEN_TEX +#endif + struct ShaderCache { enum Effect { FX_NONE = 0, FX_UNDERWATER = 1, FX_ALPHA_TEST = 2, FX_CLIP_PLANE = 4 }; @@ -519,8 +523,8 @@ struct WaterCache { maxX++; maxZ++; - int w = nextPow2(maxX - minX); - int h = nextPow2(maxZ - minZ); + int w = maxX - minX; + int h = maxZ - minZ; uint16 *m = new uint16[w * h]; memset(m, 0, w * h * sizeof(m[0])); @@ -542,9 +546,9 @@ struct WaterCache { } } - m[(x - minX) + w * (z - minZ)] = hasWater ? 0xF800 : 0; + m[(x - minX) + w * (z - minZ)] = hasWater ? 0xFFFF : 0x0000; // TODO: flow map } - mask = new Texture(w, h, FMT_RGB16, OPT_NEAREST, m); + mask = new Texture(w, h, FMT_RGBA16, OPT_NEAREST, m); delete[] m; size = vec3(float((maxX - minX) * 512), 1.0f, float((maxZ - minZ) * 512)); // half size @@ -718,7 +722,7 @@ struct WaterCache { Core::active.shader->setParam(uParam, vec4(p.x, p.z, drop.radius * DETAIL, -drop.strength)); - item.data[0]->bind(sDiffuse); + item.data[0]->bind(sNormal); Core::setTarget(item.data[1], NULL, RT_STORE_COLOR); Core::setViewport(0, 0, int(s.x + 0.5f), int(s.y + 0.5f)); game->getMesh()->renderQuad(); @@ -732,12 +736,13 @@ struct WaterCache { vec2 s(item.size.x * DETAIL * 2.0f, item.size.z * DETAIL * 2.0f); game->setShader(Core::passWater, Shader::WATER_SIMULATE); - Core::active.shader->setParam(uParam, vec4(0.995f, 1.0f, 0, Core::params.x)); + Core::active.shader->setParam(uParam, vec4(0.995f, 1.0f, randf() * 0.5f, randf() * 0.5f)); Core::active.shader->setParam(uTexParam, vec4(1.0f / item.data[0]->width, 1.0f / item.data[0]->height, s.x / item.data[0]->width, s.y / item.data[0]->height)); - + Core::active.shader->setParam(uRoomSize, vec4(1.0f / item.mask->origWidth, 1.0f / item.mask->origHeight, float(item.mask->origWidth) / item.mask->width, float(item.mask->origHeight) / item.mask->height)); + while (item.timer >= SIMULATE_TIMESTEP) { // water step - item.data[0]->bind(sDiffuse); + item.data[0]->bind(sNormal); Core::setTarget(item.data[1], NULL, RT_STORE_COLOR); Core::setViewport(0, 0, int(s.x + 0.5f), int(s.y + 0.5f)); game->getMesh()->renderQuad(); @@ -850,9 +855,9 @@ struct WaterCache { PROFILE_MARKER("WATER_REFRACT_INIT"); delete refract; refract = new Texture(w, h, FMT_RGBA, OPT_TARGET); - #ifdef _OS_IOS + #ifdef USE_SCREEN_TEX delete screen; - screen = new Texture(w, h, FMT_RGBA, OPT_TARGET); + screen = new Texture(w, h, FMT_RGBA, OPT_TARGET); #endif } return screen; @@ -886,6 +891,7 @@ struct WaterCache { if (!item.visible) continue; if (item.timer >= SIMULATE_TIMESTEP || dropCount) { + Core::noiseTex->bind(sDiffuse); item.mask->bind(sMask); // add water drops drop(item); @@ -984,6 +990,7 @@ struct WaterCache { float sz = item.size.z * DETAIL / (item.data[0]->height / 2); Core::active.shader->setParam(uTexParam, vec4(0.0f, 0.0f, sx, sz)); + Core::active.shader->setParam(uRoomSize, vec4(1.0f / item.mask->origWidth, 1.0f / item.mask->origHeight, float(item.mask->origWidth) / item.mask->width, float(item.mask->origHeight) / item.mask->height)); refract->bind(sDiffuse); reflect->bind(sReflect); @@ -1035,6 +1042,13 @@ struct WaterCache { vertices[2].texCoord = short4(32767, 0, 0, 0); vertices[3].texCoord = short4( 0, 0, 0, 0); +#if defined(_GAPI_D3D9) || defined(_GAPI_GXM) + vertices[0].texCoord = short4( 0, 0, 0, 0); + vertices[1].texCoord = short4(32767, 0, 0, 0); + vertices[2].texCoord = short4(32767, 32767, 0, 0); + vertices[3].texCoord = short4( 0, 32767, 0, 0); +#endif + Core::setDepthTest(false); Core::setBlendMode(bmNone); diff --git a/src/core.h b/src/core.h index 8d9405d..10aad11 100644 --- a/src/core.h +++ b/src/core.h @@ -339,6 +339,7 @@ namespace Core { #define MAX_LIGHTS 4 #define MAX_RENDER_BUFFERS 32 #define MAX_CONTACTS 15 +#define NOISE_TEX_SIZE 32 struct Shader; struct Texture; @@ -540,7 +541,7 @@ namespace Core { vec4 fogParams; vec4 contacts[MAX_CONTACTS]; - Texture *whiteTex, *whiteCube, *blackTex, *ditherTex; + Texture *whiteTex, *whiteCube, *blackTex, *ditherTex, *noiseTex; enum Pass { passCompose, passShadow, passAmbient, passWater, passFilter, passGUI, passMAX } pass; @@ -681,6 +682,7 @@ namespace Core { data = 0; blackTex = new Texture(1, 1, FMT_RGBA, OPT_NEAREST, &data); + // generate dithering texture uint8 ditherData[] = { 0x00, 0x7F, 0x1F, 0x9F, 0x07, 0x87, 0x27, 0xA7, 0xBF, 0x3F, 0xDF, 0x5F, 0xC7, 0x47, 0xE7, 0x67, @@ -693,6 +695,15 @@ namespace Core { }; ditherTex = new Texture(8, 8, FMT_LUMINANCE, OPT_REPEAT | OPT_NEAREST, &ditherData); + // generate noise texture + uint8 *noiseData = new uint8[SQR(NOISE_TEX_SIZE)]; + for (int i = 0; i < SQR(NOISE_TEX_SIZE); i++) { + noiseData[i] = rand() % 255; + } + noiseTex = new Texture(NOISE_TEX_SIZE, NOISE_TEX_SIZE, FMT_LUMINANCE, OPT_REPEAT, noiseData); + delete[] noiseData; + + // init settings settings.version = SETTINGS_VERSION; @@ -793,6 +804,7 @@ namespace Core { delete whiteCube; delete blackTex; delete ditherTex; + delete noiseTex; GAPI::deinit(); NAPI::deinit(); diff --git a/src/platform/win/main.cpp b/src/platform/win/main.cpp index 13bb6c6..023a1d3 100644 --- a/src/platform/win/main.cpp +++ b/src/platform/win/main.cpp @@ -269,11 +269,11 @@ void joyUpdate() { if (caps.wNumAxes > 0) { Input::setJoyPos(j, jkL, joyDir(joyAxis(info.dwXpos, caps.wXmin, caps.wXmax), - joyAxis(info.dwYpos, caps.wYmin, caps.wYmax))); + joyAxis(info.dwYpos, caps.wYmin, caps.wYmax))); if ((caps.wCaps & JOYCAPS_HASR) && (caps.wCaps & JOYCAPS_HASU)) Input::setJoyPos(j, jkR, joyDir(joyAxis(info.dwUpos, caps.wUmin, caps.wUmax), - joyAxis(info.dwRpos, caps.wRmin, caps.wRmax))); + joyAxis(info.dwRpos, caps.wRmin, caps.wRmax))); if (caps.wCaps & JOYCAPS_HASZ) { float z = joyAxis(info.dwZpos, caps.wZmin, caps.wZmax); @@ -294,6 +294,7 @@ void joyUpdate() { for (int i = 0; i < 10; i++) Input::setJoyDown(j, JoyKey(jkA + i), (info.dwButtons & (1 << i)) > 0); + } else { joyFree(); joyInit(); diff --git a/src/shaders/water.glsl b/src/shaders/water.glsl index f8f4481..5b4e329 100644 --- a/src/shaders/water.glsl +++ b/src/shaders/water.glsl @@ -20,6 +20,10 @@ varying vec3 vLightVec; varying vec3 vNewPos; #endif +#if defined(WATER_COMPOSE) || defined(WATER_SIMULATE) + varying vec2 vMaskCoord; +#endif + uniform vec4 uViewPos; uniform mat4 uViewProj; uniform vec4 uLightPos[MAX_LIGHTS]; @@ -27,6 +31,7 @@ uniform vec4 uPosScale[2]; uniform vec4 uTexParam; uniform vec4 uParam; +uniform vec4 uRoomSize; uniform sampler2D sNormal; @@ -38,6 +43,10 @@ uniform sampler2D sNormal; vTexCoord = (coord.xy * 0.5 + 0.5) * uTexParam.zw; + #if defined(WATER_COMPOSE) || defined(WATER_SIMULATE) + vMaskCoord = (coord.xy * 0.5 + 0.5) * uRoomSize.zw; + #endif + #if defined(WATER_MASK) || defined(WATER_COMPOSE) float height = 0.0; @@ -59,7 +68,7 @@ uniform sampler2D sNormal; 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); + vec3 refNew = refract(-light, normalize(normal + vec3(0.0, 0.0, 0.25)), 0.75); vOldPos = rCoord + refOld * (-1.0 / refOld.z) + refOld * ((-refOld.z - 1.0) / refOld.z); vNewPos = rCoord + refNew * ((info.r - 1.0) / refNew.z) + refOld * ((-refNew.z - 1.0) / refOld.z); @@ -94,7 +103,7 @@ uniform sampler2D sNormal; } vec4 drop() { - vec4 v = texture2D(sDiffuse, vTexCoord); + vec4 v = texture2D(sNormal, vTexCoord); float drop = max(0.0, 1.0 - length(uParam.xy - vTexCoord / uTexParam.xy) / uParam.z); drop = 0.5 - cos(drop * PI) * 0.5; @@ -103,48 +112,18 @@ uniform sampler2D sNormal; return v; } - vec3 hash33(vec3 p3) { - p3 = fract(p3 * vec3(.1031,.11369,.13787)); - p3 += dot(p3, p3.yxz+19.19); - return -1.0 + 2.0 * fract(vec3((p3.x + p3.y)*p3.z, (p3.x+p3.z)*p3.y, (p3.y+p3.z)*p3.x)); - } - - float simplex_noise(vec3 p) { // https://www.shadertoy.com/view/4sc3z2 - const float K1 = 0.333333333; - const float K2 = 0.166666667; - - vec3 i = floor(p + (p.x + p.y + p.z) * K1); - vec3 d0 = p - (i - (i.x + i.y + i.z) * K2); - - vec3 e = step(vec3(0.0), d0 - d0.yzx); - vec3 i1 = e * (1.0 - e.zxy); - vec3 i2 = 1.0 - e.zxy * (1.0 - e); - - vec3 d1 = d0 - (i1 - 1.0 * K2); - vec3 d2 = d0 - (i2 - 2.0 * K2); - vec3 d3 = d0 - (1.0 - 3.0 * K2); - - vec4 h = max(0.6 - vec4(dot(d0, d0), dot(d1, d1), dot(d2, d2), dot(d3, d3)), 0.0); - vec4 n = h * h * h * h * vec4(dot(d0, hash33(i)), dot(d1, hash33(i + i1)), dot(d2, hash33(i + i2)), dot(d3, hash33(i + 1.0))); - - return dot(vec4(31.316), n); - } - - float h(vec2 tc) { - return simplex_noise(vec3(tc * 16.0, uParam.w)) * 0.0005; - } - +#ifdef WATER_SIMULATE vec4 simulate() { vec2 tc = vTexCoord; - if (texture2D(sMask, tc).x < 0.5) + if (texture2D(sMask, vMaskCoord).a < 0.5) return vec4(0.0); - vec4 v = texture2D(sDiffuse, tc); // height, speed, normal.xz + vec4 v = texture2D(sNormal, tc); // height, speed, normal.xz vec3 d = vec3(uTexParam.xy, 0.0); - vec4 f = vec4(texture2D(sDiffuse, tc + d.xz).x, texture2D(sDiffuse, tc + d.zy).x, - texture2D(sDiffuse, tc - d.xz).x, texture2D(sDiffuse, tc - d.zy).x); + vec4 f = vec4(texture2D(sNormal, tc + d.xz).x, texture2D(sNormal, tc + d.zy).x, + texture2D(sNormal, tc - d.xz).x, texture2D(sNormal, tc - d.zy).x); float average = dot(f, vec4(0.25)); // normal @@ -153,13 +132,14 @@ uniform sampler2D sNormal; // integrate const float vel = 1.4; const float vis = 0.995; - v.y += (average - v.x) * vel; v.y *= vis; - v.x += v.y + h(tc); + float noise = texture2D(sDiffuse, tc + uParam.zw * 0.5).x; + v.x += v.y + (noise * 2.0 - 1.0) * 0.00025; return v; } +#endif #ifdef WATER_CAUSTICS vec4 caustics() { @@ -173,13 +153,13 @@ uniform sampler2D sNormal; #ifdef WATER_RAYS -float boxIntersect(vec3 rayPos, vec3 rayDir, vec3 center, vec3 hsize) { - center -= rayPos; - vec3 bMin = (center - hsize) / rayDir; - vec3 bMax = (center + hsize) / rayDir; - vec3 m = min(bMin, bMax); - return max(0.0, max(m.x, max(m.y, m.z))); -} + float boxIntersect(vec3 rayPos, vec3 rayDir, vec3 center, vec3 hsize) { + center -= rayPos; + vec3 bMin = (center - hsize) / rayDir; + vec3 bMax = (center + hsize) / rayDir; + vec3 m = min(bMin, bMax); + return max(0.0, max(m.x, max(m.y, m.z))); + } vec4 rays() { #define RAY_STEPS 16.0 @@ -222,6 +202,7 @@ float boxIntersect(vec3 rayPos, vec3 rayDir, vec3 center, vec3 hsize) { color.xyz = mix(UNDERWATER_COLOR * 0.2, color.xyz, fog); } +#ifdef WATER_COMPOSE vec4 compose() { vec3 viewVec = normalize(vViewVec); @@ -244,11 +225,12 @@ float boxIntersect(vec3 rayPos, vec3 rayDir, vec3 center, vec3 hsize) { float fresnel = calcFresnel(max(0.0, dot(normal, viewVec)), 0.12); vec4 color = mix(refr, refl, fresnel) + spec * 1.5; - color.w *= texture2D(sMask, vTexCoord).x; + color.w *= texture2D(sMask, vMaskCoord).a; applyFog(color.xyz, vViewVec.y / viewVec.y); return color; } +#endif vec4 pass() { #ifdef WATER_DROP diff --git a/src/shaders/water.hlsl b/src/shaders/water.hlsl index c506a31..75eae48 100644 --- a/src/shaders/water.hlsl +++ b/src/shaders/water.hlsl @@ -16,7 +16,19 @@ float2 invUV(float2 uv) { } float3 getInvUV(float2 uv, float4 param) { - return float3((float2(uv.x, -uv.y) * 0.5 + 0.5) * param.zw + 0.5 * param.xy, 0.0); + float2 p = (float2(uv.x, -uv.y) * 0.5 + 0.5) * param.zw; +#ifndef _GAPI_GXM + p.xy += 0.5 * param.xy; +#endif + return float3(p, 0.0); +} + +float2 getUV(float2 uv, float4 param) { + float2 p = (uv.xy * 0.5 + 0.5) * param.zw; +#ifndef _GAPI_GXM + //p.xy += 0.5 * param.xy; +#endif + return p; } #ifdef VERTEX @@ -33,18 +45,22 @@ VS_OUTPUT main(VS_INPUT In) { float3 coord = In.aCoord.xyz * (1.0 / 32767.0); + Out.texCoord = getUV(coord.xy, uTexParam); + if (WATER_COMPOSE) { Out.coord = float3(coord.x, 0.0, coord.y) * uPosScale[1].xyz + uPosScale[0].xyz; Out.pos = mul(uViewProj, float4(Out.coord, 1.0)); Out.viewVec = uViewPos.xyz - Out.coord.xyz; Out.lightVec = uLightPos[0].xyz - Out.coord.xyz; Out.oldPos = getInvUV(coord.xy, uTexParam); + Out.texCoord = getUV(coord.xy, uRoomSize); } else if (WATER_DROP) { Out.pos = float4(coord.xyz, 1.0); Out.oldPos = getInvUV(coord.xy, uTexParam); } else if (WATER_SIMULATE) { - Out.pos = float4(coord.xyz, 1.0); - Out.oldPos = getInvUV(coord.xy, uTexParam); + Out.pos = float4(coord.xyz, 1.0); + Out.oldPos = getInvUV(coord.xy, uTexParam); + Out.texCoord = getUV(coord.xy, uRoomSize); } else if (WATER_CAUSTICS) { float3 rCoord = float3(coord.x, coord.y, 0.0) * uPosScale[1].xzy; float2 uv = getInvUV(rCoord.xy, uTexParam).xy; @@ -68,8 +84,7 @@ VS_OUTPUT main(VS_INPUT In) { Out.pos = mul(uViewProj, float4(Out.coord, 1.0)); } - Out.texCoord = (coord.xy * 0.5 + 0.5) * uTexParam.zw + 0.5 * uTexParam.xy; // + half texel offset - Out.hpos = Out.pos; + Out.hpos = Out.pos; return Out; } @@ -84,7 +99,7 @@ float calcFresnel(float VoH, float f0) { float4 drop(VS_OUTPUT In) { float2 iuv = In.oldPos.xy; - float4 v = tex2D(sDiffuse, iuv); + float4 v = tex2D(sNormal, iuv); float value = max(0.0, 1.0 - length(uParam.xy - In.texCoord / uTexParam.xy) / uParam.z); value = 0.5 - cos(value * PI) * 0.5; @@ -94,50 +109,19 @@ float4 drop(VS_OUTPUT In) { return v; } -float3 hash33(float3 p3) { - p3 = frac(p3 * float3(.1031,.11369,.13787)); - p3 += dot(p3, p3.yxz+19.19); - return -1.0 + 2.0 * frac(float3((p3.x + p3.y)*p3.z, (p3.x+p3.z)*p3.y, (p3.y+p3.z)*p3.x)); -} - -float simplex_noise(float3 p) { // https://www.shadertoy.com/view/4sc3z2 - const float K1 = 0.333333333; - const float K2 = 0.166666667; - - float3 i = floor(p + (p.x + p.y + p.z) * K1); - float3 d0 = p - (i - (i.x + i.y + i.z) * K2); - - float3 e = step((float3)0.0, d0 - d0.yzx); - float3 i1 = e * (1.0 - e.zxy); - float3 i2 = 1.0 - e.zxy * (1.0 - e); - - float3 d1 = d0 - (i1 - 1.0 * K2); - float3 d2 = d0 - (i2 - 2.0 * K2); - float3 d3 = d0 - (1.0 - 3.0 * K2); - - float4 h = max(0.6 - float4(dot(d0, d0), dot(d1, d1), dot(d2, d2), dot(d3, d3)), 0.0); - float4 n = h * h * h * h * float4(dot(d0, hash33(i)), dot(d1, hash33(i + i1)), dot(d2, hash33(i + i2)), dot(d3, hash33(i + 1.0))); - - return dot((float4)31.316, n); -} - -float h(float2 tc) { - return simplex_noise(float3(tc * 16.0, uParam.w)) * 0.0005; -} - float4 simulate(VS_OUTPUT In) { float2 iuv = In.oldPos.xy; float2 uv = In.texCoord; - if (tex2D(sMask, uv).x < 0.5) + if (tex2D(sMask, uv).a < 0.5) return 0.0; - float4 v = tex2D(sDiffuse, iuv); // height, speed, normal.xz + float4 v = tex2D(sNormal, iuv); // height, speed, normal.xz float3 d = float3(float2(uTexParam.x, -uTexParam.y), 0.0); float4 f = float4( - tex2D(sDiffuse, iuv + d.xz).x, tex2D(sDiffuse, iuv + d.zy).x, - tex2D(sDiffuse, iuv - d.xz).x, tex2D(sDiffuse, iuv - d.zy).x + tex2D(sNormal, iuv + d.xz).x, tex2D(sNormal, iuv + d.zy).x, + tex2D(sNormal, iuv - d.xz).x, tex2D(sNormal, iuv - d.zy).x ); float average = dot(f, (float4)0.25); @@ -151,7 +135,7 @@ float4 simulate(VS_OUTPUT In) { v.y += (average - v.x) * vel; v.y *= vis; - v.x += v.y + h(uv); + v.x += v.y + (tex2D(sDiffuse, uv + uParam.zw).x * 2.0 - 1.0) * 0.00025; return v; } @@ -228,7 +212,7 @@ float4 compose(VS_OUTPUT In) { float fresnel = calcFresnel(max(0.0, dot(normal, viewVec)), 0.12); float4 color = lerp(refr, refl, fresnel) + spec * 1.5; - color.w *= tex2D(sMask, In.texCoord).x; + color.w *= tex2D(sMask, In.texCoord).a; float dist = In.viewVec.y / viewVec.y; dist *= step(In.coord.y, uViewPos.y);