From bdac3bb9556adbe826bfd86048acd78a2ac3fe7f Mon Sep 17 00:00:00 2001 From: Issac332 <119879937+Issac8658@users.noreply.github.com> Date: Fri, 29 May 2026 22:02:33 +0300 Subject: [PATCH] dynamic water --- CMakeLists.txt | 1 + shader/tilemap.vert | 3 + shader/tilemapWater.frag | 117 +++++++++++++++++++++++++++++++++++++++ src/shader.cpp | 19 +++++++ src/shader.h | 12 ++++ src/tilemap.cpp | 23 +++++++- src/tilemap.h | 2 + 7 files changed, 175 insertions(+), 2 deletions(-) create mode 100644 shader/tilemapWater.frag diff --git a/CMakeLists.txt b/CMakeLists.txt index a511644..6855a5e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -192,6 +192,7 @@ set(EMBEDDED_INPUT shader/sprite.frag shader/worldMachine.frag shader/water.frag + shader/tilemapWater.frag shader/plane.frag shader/gray.frag shader/bitmapBlit.frag diff --git a/shader/tilemap.vert b/shader/tilemap.vert index 8a11f2b..ba34e2f 100644 --- a/shader/tilemap.vert +++ b/shader/tilemap.vert @@ -3,6 +3,7 @@ uniform mat4 projMat; uniform vec2 texSizeInv; uniform vec2 translation; +uniform vec2 offset; uniform float aniIndex; @@ -10,6 +11,7 @@ attribute vec2 position; attribute vec2 texCoord; varying vec2 v_texCoord; +varying vec2 worldCoord; const float atAreaW = 96.0; const float atAreaH = 128.0*7.0; @@ -24,4 +26,5 @@ void main(){ gl_Position = projMat * vec4(position + translation, 0, 1); v_texCoord = tex * texSizeInv; + worldCoord = position + offset * 32.0; } diff --git a/shader/tilemapWater.frag b/shader/tilemapWater.frag new file mode 100644 index 0000000..676d93c --- /dev/null +++ b/shader/tilemapWater.frag @@ -0,0 +1,117 @@ + + +uniform sampler2D texture; + +uniform float uTime; +uniform float aniIndex; + +varying vec2 v_texCoord; +varying vec2 worldCoord; + +uniform vec2 texSizeInv; + +const float WATER_DISTORTION = 0.75; + +const float atAreaW = 96.0; +const float atAreaH = 128.0*7.0; +const float SpriteAreaH = 128.0; +const float atAniOffset = 32.0*3.0; +const vec2 AtlasSize = vec2(96.0, 128.0); + +vec4 mod289(vec4 x) +{ + return x - floor(x * (1.0 / 289.0)) * 289.0; +} + +vec4 permute(vec4 x) +{ + return mod289(((x*34.0)+1.0)*x); +} + +vec4 taylorInvSqrt(vec4 r) +{ + return 1.79284291400159 - 0.85373472095314 * r; +} + +vec2 fade(vec2 t) { + return t*t*t*(t*(t*6.0-15.0)+10.0); +} + +float pnoise(vec2 P) +{ + vec4 Pi = floor(P.xyxy) + vec4(0.0, 0.0, 1.0, 1.0); + vec4 Pf = fract(P.xyxy) - vec4(0.0, 0.0, 1.0, 1.0); + Pi = mod289(Pi); // To avoid truncation effects in permutation + vec4 ix = Pi.xzxz; + vec4 iy = Pi.yyww; + vec4 fx = Pf.xzxz; + vec4 fy = Pf.yyww; + + vec4 i = permute(permute(ix) + iy); + + vec4 gx = fract(i * (1.0 / 41.0)) * 2.0 - 1.0 ; + vec4 gy = abs(gx) - 0.5 ; + vec4 tx = floor(gx + 0.5); + gx = gx - tx; + + vec2 g00 = vec2(gx.x,gy.x); + vec2 g10 = vec2(gx.y,gy.y); + vec2 g01 = vec2(gx.z,gy.z); + vec2 g11 = vec2(gx.w,gy.w); + + vec4 norm = taylorInvSqrt(vec4(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11))); + g00 *= norm.x; + g01 *= norm.y; + g10 *= norm.z; + g11 *= norm.w; + + float n00 = dot(g00, vec2(fx.x, fy.x)); + float n10 = dot(g10, vec2(fx.y, fy.y)); + float n01 = dot(g01, vec2(fx.z, fy.z)); + float n11 = dot(g11, vec2(fx.w, fy.w)); + + vec2 fade_xy = fade(Pf.xy); + vec2 n_x = mix(vec2(n00, n01), vec2(n10, n11), fade_xy.x); + float n_xy = mix(n_x.x, n_x.y, fade_xy.y); + return 2.3 * n_xy; +} + +void main(){ + vec4 textureColor = texture2D(texture, v_texCoord); + + vec2 paletteUv = floor(v_texCoord / texSizeInv / AtlasSize) * AtlasSize; + vec4 waterColor1 = texture2D(texture, (vec2(33.0, 1.0) + paletteUv) * texSizeInv) / 2.0; + vec4 waterColor2 = texture2D(texture, (vec2(35.0, 1.0) + paletteUv) * texSizeInv) / 2.0; + vec4 waterColor3 = texture2D(texture, (vec2(37.0, 1.0) + paletteUv) * texSizeInv) / 2.0; + vec4 waterColorCheck = texture2D(texture, (vec2(33.0, 31.0) + paletteUv) * texSizeInv); + + vec2 uv = worldCoord / 16.0 * vec2(1.0, 4.0); + uv = floor(uv * vec2(8.0, 2.0)) / vec2(8.0, 2.0); + + float noise = (pnoise(uv) + 1.0) / 2.0; + + float offsetTime = uTime + 100.0; + + vec2 uv1 = uv - vec2(offsetTime, offsetTime * 0.5 + 0.5) * 0.56; + float noise1 = (pnoise(uv1 + vec2(WATER_DISTORTION, -WATER_DISTORTION) * noise) + 1.0) / 2.0; + float p = pow(noise1 + 0.2, 10.0); + + vec2 uv2 = uv - vec2(offsetTime - 1.5, -offsetTime * 0.5) * 0.24; + float noise2 = (pnoise(uv2 + vec2(WATER_DISTORTION, -WATER_DISTORTION) * noise) + 1.0) / 2.0; + float p2 = pow(noise2 + 0.2, 10.0); + + vec4 frag = mix(vec4(waterColor1.rgb, 1.0), vec4(waterColor2.rgb, 1.0), noise1) + vec4(vec3(mix(p, 1.0, textureColor.r)) * waterColor3.rgb, 1.0); + frag += mix(vec4(waterColor1.rgb, 1.0), vec4(waterColor2.rgb, 1.0), noise2) + vec4(vec3(mix(p2, 1.0, textureColor.r)) * waterColor3.rgb, 1.0); + + float isWater = float( + waterColorCheck == vec4(1, 0, 0, 1) + + && abs(textureColor.r - textureColor.g) < 0.02 + && abs(textureColor.g - textureColor.b) < 0.02 + + && textureColor.a > 0.05 + && waterColor2.a > 0.05 + ); + + gl_FragColor = mix(textureColor, frag, isWater); +} diff --git a/src/shader.cpp b/src/shader.cpp index f905bc6..177ef64 100644 --- a/src/shader.cpp +++ b/src/shader.cpp @@ -32,6 +32,7 @@ #include "sprite.frag.xxd" #include "worldMachine.frag.xxd" #include "water.frag.xxd" +#include "tilemapWater.frag.xxd" #include "hue.frag.xxd" #include "trans.frag.xxd" #include "transSimple.frag.xxd" @@ -491,6 +492,24 @@ void TilemapShader::setAniIndex(int value){ } +TilemapWaterShader::TilemapWaterShader(){ + INIT_SHADER(tilemap, tilemapWater, TilemapWaterShader); + + ShaderBase::init(); + + GET_U(aniIndex); + GET_U(offset); +} + +void TilemapWaterShader::setAniIndex(int value){ + gl.Uniform1f(u_aniIndex, value); +} + +void TilemapWaterShader::setOffset(const Vec2i &value){ + gl.Uniform2f(u_offset, value.x, value.y); +} + + FlashMapShader::FlashMapShader(){ INIT_SHADER(simpleColor, flashMap, FlashMapShader); diff --git a/src/shader.h b/src/shader.h index e746351..1a647e6 100644 --- a/src/shader.h +++ b/src/shader.h @@ -191,6 +191,17 @@ public: WaterShader(); }; +class TilemapWaterShader : public ShaderBase{ +public: + TilemapWaterShader(); + + void setAniIndex(int value); + void setOffset(const Vec2i &value); + +private: + GLint u_aniIndex, u_offset; +}; + class PlaneShader : public ShaderBase{ public: PlaneShader(); @@ -319,6 +330,7 @@ private: X(sprite, SpriteShader, Sprite) \ X(worldMachine, WMShader, WorldMachine) \ X(water, WaterShader, Water) \ + X(tilemapWater, TilemapWaterShader, TilemapWater) \ X(plane, PlaneShader, Plane) \ X(gray, GrayShader, Gray) \ X(tilemap, TilemapShader, TileMap) \ diff --git a/src/tilemap.cpp b/src/tilemap.cpp index b26f585..6d56430 100644 --- a/src/tilemap.cpp +++ b/src/tilemap.cpp @@ -40,6 +40,7 @@ #include "tilemap-common.h" #include +#include #include #include @@ -222,6 +223,8 @@ struct ZLayer : public ViewportElement { }; struct TilemapPrivate { + boost::chrono::high_resolution_clock::time_point startTime = boost::chrono::high_resolution_clock::now(); + Viewport *viewport; Bitmap *autotiles[autotileCount]; @@ -726,12 +729,28 @@ struct TilemapPrivate { } void bindShader(ShaderBase *&shaderVar){ - if (tiles.animated){ + if (tiles.animated){ // it is advisable to check for water in some way ッ + TilemapWaterShader &tilemapShader = shState->shaders().tilemapWater; + tilemapShader.bind(); + + if (tiles.animated) + tilemapShader.setAniIndex(tiles.frameIdx); + + tilemapShader.setOffset(viewpPos); + + boost::chrono::high_resolution_clock::time_point currentTime = boost::chrono::high_resolution_clock::now(); + boost::chrono::duration elapsed = currentTime - startTime; + tilemapShader.setTime(elapsed.count()); + + shaderVar = &tilemapShader; + }/* + else if(tiles.animated){ TilemapShader &tilemapShader = shState->shaders().tilemap; tilemapShader.bind(); tilemapShader.setAniIndex(tiles.frameIdx); + shaderVar = &tilemapShader; - } + }*/ else{ shaderVar = &shState->shaders().simple; shaderVar->bind(); diff --git a/src/tilemap.h b/src/tilemap.h index 85b8a42..6172757 100644 --- a/src/tilemap.h +++ b/src/tilemap.h @@ -25,6 +25,7 @@ #include "disposable.h" #include "util.h" +#include class Viewport; class Bitmap; @@ -34,6 +35,7 @@ struct TilemapPrivate; class Tilemap : public Disposable{ public: + class Autotiles{ public: void set(int i, Bitmap *bitmap);