Skip to content

Commit

Permalink
update water waves
Browse files Browse the repository at this point in the history
  • Loading branch information
Amatsugu committed Oct 23, 2024
1 parent b3c44c5 commit f2ff8f7
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 63 deletions.
44 changes: 27 additions & 17 deletions engine/world_generation/src/generators/mesh_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,7 @@ pub fn generate_chunk_water_mesh(chunk: &MeshChunkData, sealevel: f32, map_width

create_tile_water_surface(
tile_pos,
height,
chunk.min_height,
chunk.distance_to_land[idx],
&n,
neighbor_has_land,
&mut verts,
Expand All @@ -142,26 +141,25 @@ pub fn generate_chunk_water_mesh(chunk: &MeshChunkData, sealevel: f32, map_width

fn create_tile_water_surface(
pos: Vec3,
height: f32,
min_height: f32,
neighbors: &[f32; 6],
dist_to_land: f32,
neighbors: &[(f32, Option<f32>); 6],
neighbor_has_land: bool,
verts: &mut Vec<Vec3>,
uvs: &mut Vec<Vec2>,
indices: &mut Vec<u32>,
normals: &mut Vec<Vec3>,
) {
if !neighbor_has_land {
crate_tile_water_inner_surface(pos, height, min_height, verts, uvs, indices, normals);
crate_tile_water_inner_surface(pos, dist_to_land, neighbors, verts, uvs, indices, normals);
return;
}
crate_tile_water_shore_surface(pos, height, min_height, neighbors, verts, uvs, indices, normals);
crate_tile_water_shore_surface(pos, dist_to_land, neighbors, verts, uvs, indices, normals);
}

fn crate_tile_water_inner_surface(
pos: Vec3,
height: f32,
min_height: f32,
dist_to_land: f32,
neighbors: &[(f32, Option<f32>); 6],
verts: &mut Vec<Vec3>,
uvs: &mut Vec<Vec2>,
indices: &mut Vec<u32>,
Expand All @@ -172,7 +170,14 @@ fn crate_tile_water_inner_surface(
for i in 0..6 {
let p = pos + HEX_CORNERS[i];
verts.push(p);
uvs.push(Vec2::new(0.0, height.remap(min_height, pos.y, 0.0, 1.0)));
let n1 = if let Some(v) = neighbors[i].1 { v } else { dist_to_land };
let n2 = if let Some(v) = neighbors[(i + 5) % 6].1 {
v
} else {
dist_to_land
};
let d = (n1 + n2 + dist_to_land) / 3.0;
uvs.push(Vec2::new(0.0, d.remap(0., 4., 1.0, 0.0)));
normals.push(Vec3::Y);
}
for i in 0..3 {
Expand All @@ -188,9 +193,8 @@ fn crate_tile_water_inner_surface(

fn crate_tile_water_shore_surface(
pos: Vec3,
height: f32,
min_height: f32,
neighbors: &[f32; 6],
dist_to_land: f32,
neighbors: &[(f32, Option<f32>); 6],
verts: &mut Vec<Vec3>,
uvs: &mut Vec<Vec2>,
indices: &mut Vec<u32>,
Expand All @@ -199,23 +203,29 @@ fn crate_tile_water_shore_surface(
let idx = verts.len() as u32;
//todo: only use triangle fan when on shoreline
verts.push(pos);
uvs.push(Vec2::new(0.0, height.remap(min_height, pos.y, 0.0, 1.0)));
uvs.push(Vec2::new(0.0, dist_to_land.remap(0., 4., 1.0, 0.0)));
normals.push(Vec3::Y);
for i in 0..12 {
let p = pos + WATER_HEX_CORNERS[i];
verts.push(p);
let mut uv = Vec2::new(0.0, height.remap(min_height, pos.y, 0.0, 1.0));
let ni = i / 2;
let n = neighbors[ni];
let nn = neighbors[(ni + 5) % 6];
let mut uv = Vec2::new(0.0, dist_to_land.remap(0., 4., 1.0, 0.0));

if nn > pos.y || n > pos.y {
if nn.0 > pos.y || n.0 > pos.y {
uv.x = 1.0;
}
if ni * 2 != i {
if n <= pos.y {
if n.0 <= pos.y {
uv.x = 0.0;
}
let d = if let Some(v) = n.1 { v } else { dist_to_land };
uv.y = ((d + dist_to_land) / 2.0).remap(0., 4., 1.0, 0.0);
} else {
let d = if let Some(v) = n.1 { v } else { dist_to_land };
let d2 = if let Some(v) = nn.1 { v } else { dist_to_land };
uv.y = ((d + d2 + dist_to_land) / 3.0).remap(0., 4., 1.0, 0.0);
}

indices.push(idx);
Expand Down
153 changes: 112 additions & 41 deletions engine/world_generation/src/map/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,47 @@ impl Map {
sealevel: self.sealevel,
heights: chunk.heights.clone(),
textures: chunk.textures.clone(),
distance_to_land: self.get_distance_from_land(chunk.chunk_offset, 4),
};
}

fn get_distance_from_land(&self, chunk_offset: IVec2, range: usize) -> [f32; Chunk::AREA] {
#[cfg(feature = "tracing")]
let _spawn_span = info_span!("Chunk Land Dist Data").entered();
let mut dists = [0.0; Chunk::AREA];
let cx = chunk_offset.x as usize * Chunk::SIZE;
let cz = chunk_offset.y as usize * Chunk::SIZE;
for z in 0..Chunk::SIZE {
for x in 0..Chunk::SIZE {
let coord = HexCoord::from_grid_pos(x + cx, z + cz);
let index = coord.to_chunk_local_index();

if !self.is_in_bounds(&coord) {
warn!("Coord is not in bounds!?");
}

//Current tile is land tile
if self.sample_height(&coord) > self.sealevel {
dists[index] = 0.0;
continue;
}

//Find closest land tile
if let Some(d) = self.hex_select_first(&coord, range, false, |_t, h, r| {
if h > self.sealevel {
return Some(r as f32);
}
return None;
}) {
dists[index] = d;
} else {
dists[index] = range as f32;
}
}
}
return dists;
}

pub fn get_neighbors(&self, pos: &HexCoord) -> [Option<f32>; 6] {
let mut results: [Option<f32>; 6] = [None; 6];
let w = self.width * Chunk::SIZE;
Expand Down Expand Up @@ -96,47 +134,6 @@ impl Map {
let chunk = &self.chunks[pos.to_chunk_index(self.width)];
return chunk.biome_id[pos.to_chunk_local_index()];
}
/*
pub fn get_biome_noise(&self, pos: &HexCoord) -> &BiomeData {
assert!(
self.is_in_bounds(pos),
"The provided coordinate is not within the map bounds"
);
let chunk = &self.chunks[pos.to_chunk_index(self.width)];
return &chunk.biome_data[pos.to_chunk_local_index()];
}
pub fn get_moisture(&self, pos: &HexCoord) -> f32 {
assert!(
self.is_in_bounds(pos),
"The provided coordinate is not within the map bounds"
);
let chunk = &self.chunks[pos.to_chunk_index(self.width)];
return chunk.biome_data[pos.to_chunk_local_index()].moisture;
}
pub fn get_tempurature(&self, pos: &HexCoord) -> f32 {
assert!(
self.is_in_bounds(pos),
"The provided coordinate is not within the map bounds"
);
let chunk = &self.chunks[pos.to_chunk_index(self.width)];
return chunk.biome_data[pos.to_chunk_local_index()].temperature;
}
pub fn get_continentality(&self, pos: &HexCoord) -> f32 {
assert!(
self.is_in_bounds(pos),
"The provided coordinate is not within the map bounds"
);
let chunk = &self.chunks[pos.to_chunk_index(self.width)];
return chunk.biome_data[pos.to_chunk_local_index()].continentality;
}
*/

pub fn get_center(&self) -> Vec3 {
let w = self.get_world_width();
Expand Down Expand Up @@ -206,6 +203,80 @@ impl Map {
return result;
}

pub fn hex_select_first<OP, Ret>(
&self,
center: &HexCoord,
radius: usize,
include_center: bool,
op: OP,
) -> Option<Ret>
where
OP: (Fn(&HexCoord, f32, usize) -> Option<Ret>) + Sync + Send,
{
assert!(radius != 0, "Radius cannot be zero");

if include_center {
let h = self.sample_height(&center);
let r = (op)(center, h, 0);
if r.is_some() {
return r;
}
}

for k in 0..(radius + 1) {
let mut p = center.scale(4, k);
for i in 0..6 {
for _j in 0..k {
p = p.get_neighbor(i);
if self.is_in_bounds(&p) {
let h = self.sample_height(&p);
let r = (op)(&p, h, k);
if r.is_some() {
return r;
}
}
}
}
}

return None;
}

pub fn ring_select_first<OP, Ret>(
&self,
center: &HexCoord,
start_radius: usize,
end_radius: usize,
op: OP,
) -> Option<Ret>
where
OP: (Fn(&HexCoord, f32, usize) -> Option<Ret>) + Sync + Send,
{
assert!(start_radius != 0, "Start radius cannot be zero");
assert!(
start_radius > end_radius,
"Start radius cannot be lower than end radius"
);

for k in start_radius..(end_radius + 1) {
let mut p = center.scale(4, k);
for i in 0..6 {
for _j in 0..k {
p = p.get_neighbor(i);
if self.is_in_bounds(&p) {
let h = self.sample_height(&p);
let r = (op)(&p, h, k);
if r.is_some() {
return r;
}
}
}
}
}

return None;
}

pub fn hex_select_mut<OP, Ret>(
&mut self,
center: &HexCoord,
Expand Down
10 changes: 6 additions & 4 deletions engine/world_generation/src/map/mesh_chunk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub struct MeshChunkData {
pub textures: [[u32; 2]; Chunk::AREA],
pub min_height: f32,
pub sealevel: f32,
pub distance_to_land: [f32; Chunk::AREA],
}

impl MeshChunkData {
Expand All @@ -24,17 +25,18 @@ impl MeshChunkData {
return data;
}

pub fn get_neighbors_with_water_info(&self, coord: &HexCoord) -> ([f32; 6], bool) {
pub fn get_neighbors_with_water_info(&self, coord: &HexCoord) -> ([(f32, Option<f32>); 6], bool) {
let mut has_land = false;
let mut data = [self.min_height; 6];
let mut data = [(self.min_height, None); 6];
let n_tiles = coord.get_neighbors();
for i in 0..6 {
let n = n_tiles[i];
if !n.is_in_bounds(Chunk::SIZE, Chunk::SIZE) {
continue;
}
data[i] = self.heights[n.to_index(Chunk::SIZE)];
if data[i] > self.sealevel {
let idx = n.to_index(Chunk::SIZE);
data[i] = (self.heights[idx], Some(self.distance_to_land[idx]));
if data[i].0 > self.sealevel {
has_land = true;
}
}
Expand Down
2 changes: 1 addition & 1 deletion game/main/assets

0 comments on commit f2ff8f7

Please sign in to comment.