use super::components::Water;
use nalgebra_glm::{Vec2, Vec3};
const ITER_GEOMETRY: i32 = 3;
fn hash(p: Vec2) -> f32 {
let mut p3 = Vec3::new(p.x, p.y, p.x) * 0.1031;
p3 = Vec3::new(p3.x.fract(), p3.y.fract(), p3.z.fract());
let dot_val = p3.dot(&Vec3::new(p3.y + 33.33, p3.z + 33.33, p3.x + 33.33));
p3 += Vec3::new(dot_val, dot_val, dot_val);
((p3.x + p3.y) * p3.z).fract()
}
fn noise(p: Vec2) -> f32 {
let i = Vec2::new(p.x.floor(), p.y.floor());
let f = Vec2::new(p.x.fract(), p.y.fract());
let u = Vec2::new(f.x * f.x * (3.0 - 2.0 * f.x), f.y * f.y * (3.0 - 2.0 * f.y));
let h00 = hash(i + Vec2::new(0.0, 0.0));
let h10 = hash(i + Vec2::new(1.0, 0.0));
let h01 = hash(i + Vec2::new(0.0, 1.0));
let h11 = hash(i + Vec2::new(1.0, 1.0));
let mix_x0 = h00 + (h10 - h00) * u.x;
let mix_x1 = h01 + (h11 - h01) * u.x;
let mix_y = mix_x0 + (mix_x1 - mix_x0) * u.y;
-1.0 + 2.0 * mix_y
}
fn sea_octave(uv_in: Vec2, choppy: f32) -> f32 {
let noise_val = noise(uv_in);
let uv = uv_in + Vec2::new(noise_val, noise_val);
let mut wv = Vec2::new(1.0 - uv.x.sin().abs(), 1.0 - uv.y.sin().abs());
let swv = Vec2::new(uv.x.cos().abs(), uv.y.cos().abs());
wv = Vec2::new(wv.x + (swv.x - wv.x) * wv.x, wv.y + (swv.y - wv.y) * wv.y);
(1.0 - (wv.x * wv.y).powf(0.65)).powf(choppy)
}
fn map(water: &Water, p: Vec3, time: f32, iter: i32) -> f32 {
let mut freq = water.frequency;
let mut amp = water.wave_height;
let mut choppy = water.choppy;
let mut uv = Vec2::new(p.x * 0.75, p.z);
let sea_time = 1.0 + time * water.speed;
let mut h = 0.0;
for _ in 0..iter {
let d1 = sea_octave((uv + Vec2::new(sea_time, sea_time)) * freq, choppy);
let d2 = sea_octave((uv - Vec2::new(sea_time, sea_time)) * freq, choppy);
let d = d1 + d2;
h += d * amp;
let new_uv_x = uv.x * 1.6 + uv.y * 1.2;
let new_uv_y = uv.x * -1.2 + uv.y * 1.6;
uv = Vec2::new(new_uv_x, new_uv_y);
freq *= 1.9;
amp *= 0.22;
choppy = choppy + (1.0 - choppy) * 0.2;
}
p.y - (water.base_height + h)
}
pub fn sample_wave_height(water: &Water, x: f32, z: f32, time: f32) -> f32 {
let mut low = water.base_height - 5.0;
let mut high = water.base_height + water.wave_height * 4.0;
for _ in 0..8 {
let mid = (low + high) * 0.5;
let val = map(water, Vec3::new(x, mid, z), time, ITER_GEOMETRY);
if val < 0.0 {
low = mid;
} else {
high = mid;
}
}
(low + high) * 0.5
}